summaryrefslogtreecommitdiffstats
path: root/src/gui/painting
diff options
context:
space:
mode:
authorBenjamin Poulain <benjamin.poulain@nokia.com>2010-02-23 17:45:41 (GMT)
committerBenjamin Poulain <benjamin.poulain@nokia.com>2010-02-23 17:45:41 (GMT)
commit615972e09981a0916422716b4f6572c6401789da (patch)
tree82203c15bceebd5426c823852ef5c85ad025e92b /src/gui/painting
parent60fd302e8d88b92ade59d68872c99310128c3a6c (diff)
parentde4332a4728e739b37e9c7b04c021e150e096270 (diff)
downloadQt-615972e09981a0916422716b4f6572c6401789da.zip
Qt-615972e09981a0916422716b4f6572c6401789da.tar.gz
Qt-615972e09981a0916422716b4f6572c6401789da.tar.bz2
Merge branch 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-1
Diffstat (limited to 'src/gui/painting')
-rw-r--r--src/gui/painting/qbezier.cpp36
-rw-r--r--src/gui/painting/qbezier_p.h6
-rw-r--r--src/gui/painting/qcups.cpp4
-rw-r--r--src/gui/painting/qdrawhelper.cpp89
-rw-r--r--src/gui/painting/qdrawhelper_mmx_p.h45
-rw-r--r--src/gui/painting/qdrawhelper_neon.cpp130
-rw-r--r--src/gui/painting/qdrawhelper_p.h3
-rw-r--r--src/gui/painting/qdrawhelper_sse2.cpp211
-rw-r--r--src/gui/painting/qdrawhelper_x86_p.h8
-rw-r--r--src/gui/painting/qemulationpaintengine.cpp5
-rw-r--r--src/gui/painting/qemulationpaintengine_p.h1
-rw-r--r--src/gui/painting/qmath_p.h6
-rw-r--r--src/gui/painting/qpaintbuffer.cpp141
-rw-r--r--src/gui/painting/qpaintbuffer_p.h5
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp59
-rw-r--r--src/gui/painting/qpaintengine_raster_p.h5
-rw-r--r--src/gui/painting/qpaintengine_x11.cpp3
-rw-r--r--src/gui/painting/qpaintengineex_p.h3
-rw-r--r--src/gui/painting/qpainter.cpp171
-rw-r--r--src/gui/painting/qpainter.h15
-rw-r--r--src/gui/painting/qpathclipper.cpp265
-rw-r--r--src/gui/painting/qpathclipper_p.h3
-rw-r--r--src/gui/painting/qpdf.cpp12
-rw-r--r--src/gui/painting/qpdf_p.h2
-rw-r--r--src/gui/painting/qprintengine.h2
-rw-r--r--src/gui/painting/qprintengine_mac.mm10
-rw-r--r--src/gui/painting/qprintengine_qws.cpp5
-rw-r--r--src/gui/painting/qprintengine_win.cpp9
-rw-r--r--src/gui/painting/qprintengine_win_p.h1
-rw-r--r--src/gui/painting/qprinter.cpp99
-rw-r--r--src/gui/painting/qprinter.h4
-rw-r--r--src/gui/painting/qtextureglyphcache.cpp43
-rw-r--r--src/gui/painting/qtextureglyphcache_p.h11
-rw-r--r--src/gui/painting/qwindowsurface_raster.cpp4
-rw-r--r--src/gui/painting/qwindowsurface_s60.cpp21
35 files changed, 1191 insertions, 246 deletions
diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp
index bbffda1..ea7fe4f 100644
--- a/src/gui/painting/qbezier.cpp
+++ b/src/gui/painting/qbezier.cpp
@@ -112,6 +112,11 @@ QPolygonF QBezier::toPolygon() const
return polygon;
}
+QBezier QBezier::mapBy(const QTransform &transform) const
+{
+ return QBezier::fromPoints(transform.map(pt1()), transform.map(pt2()), transform.map(pt3()), transform.map(pt4()));
+}
+
//0.5 is really low
static const qreal flatness = 0.5;
@@ -140,6 +145,25 @@ static inline void flattenBezierWithoutInflections(QBezier &bez,
}
}
+QBezier QBezier::getSubRange(qreal t0, qreal t1) const
+{
+ QBezier result;
+ QBezier temp;
+
+ // cut at t1
+ if (qFuzzyIsNull(t1 - qreal(1.))) {
+ result = *this;
+ } else {
+ temp = *this;
+ temp.parameterSplitLeft(t1, &result);
+ }
+
+ // cut at t0
+ if (!qFuzzyIsNull(t0))
+ result.parameterSplitLeft(t0 / t1, &temp);
+
+ return result;
+}
static inline int quadraticRoots(qreal a, qreal b, qreal c,
qreal *x1, qreal *x2)
@@ -1018,13 +1042,19 @@ int QBezier::stationaryYPoints(qreal &t0, qreal &t1) const
const qreal b = 2 * y1 - 4 * y2 + 2 * y3;
const qreal c = -y1 + y2;
- qreal reciprocal = b * b - 4 * a * c;
+ if (qFuzzyIsNull(a)) {
+ if (qFuzzyIsNull(b))
+ return 0;
- QList<qreal> result;
+ t0 = -c / b;
+ return t0 > 0 && t0 < 1;
+ }
+
+ qreal reciprocal = b * b - 4 * a * c;
if (qFuzzyIsNull(reciprocal)) {
t0 = -b / (2 * a);
- return 1;
+ return t0 > 0 && t0 < 1;
} else if (reciprocal > 0) {
qreal temp = qSqrt(reciprocal);
diff --git a/src/gui/painting/qbezier_p.h b/src/gui/painting/qbezier_p.h
index 3409bc7..f015ea8 100644
--- a/src/gui/painting/qbezier_p.h
+++ b/src/gui/painting/qbezier_p.h
@@ -59,6 +59,7 @@
#include "QtCore/qvector.h"
#include "QtCore/qlist.h"
#include "QtCore/qpair.h"
+#include "QtGui/qtransform.h"
QT_BEGIN_NAMESPACE
@@ -96,6 +97,8 @@ public:
QPointF pt3() const { return QPointF(x3, y3); }
QPointF pt4() const { return QPointF(x4, y4); }
+ QBezier mapBy(const QTransform &transform) const;
+
inline QPointF midPoint() const;
inline QLineF midTangent() const;
@@ -104,6 +107,7 @@ public:
inline void parameterSplitLeft(qreal t, QBezier *left);
inline void split(QBezier *firstHalf, QBezier *secondHalf) const;
+
int shifted(QBezier *curveSegments, int maxSegmets,
qreal offset, float threshold) const;
@@ -117,6 +121,8 @@ public:
static bool findIntersections(const QBezier &a, const QBezier &b,
QVector<QPair<qreal, qreal> > *t);
+ QBezier getSubRange(qreal t0, qreal t1) const;
+
qreal x1, y1, x2, y2, x3, y3, x4, y4;
};
diff --git a/src/gui/painting/qcups.cpp b/src/gui/painting/qcups.cpp
index 7903762..ac41692 100644
--- a/src/gui/painting/qcups.cpp
+++ b/src/gui/painting/qcups.cpp
@@ -342,7 +342,9 @@ bool QCUPSSupport::printerHasPPD(const char *printerName)
{
if (!isAvailable())
return false;
- return _cupsGetPPD(printerName) != 0;
+ const char *ppdFile = _cupsGetPPD(printerName);
+ unlink(ppdFile);
+ return (ppdFile != 0);
}
QString QCUPSSupport::unicodeString(const char *s)
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 40fe499..c37e49a 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -1268,32 +1268,28 @@ static const uint L2CacheLineLengthInInts = L2CacheLineLength/sizeof(uint);
result = 0
d = d * cia
*/
+#define comp_func_Clear_impl(dest, length, const_alpha)\
+{\
+ if (const_alpha == 255) {\
+ QT_MEMFILL_UINT(dest, length, 0);\
+ } else {\
+ int ialpha = 255 - const_alpha;\
+ PRELOAD_INIT(dest)\
+ for (int i = 0; i < length; ++i) {\
+ PRELOAD_COND(dest)\
+ dest[i] = BYTE_MUL(dest[i], ialpha);\
+ }\
+ }\
+}
+
static void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha)
{
- if (const_alpha == 255) {
- QT_MEMFILL_UINT(dest, length, 0);
- } else {
- int ialpha = 255 - const_alpha;
- PRELOAD_INIT(dest)
- for (int i = 0; i < length; ++i) {
- PRELOAD_COND(dest)
- dest[i] = BYTE_MUL(dest[i], ialpha);
- }
- }
+ comp_func_Clear_impl(dest, length, const_alpha);
}
static void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha)
{
- if (const_alpha == 255) {
- QT_MEMFILL_UINT(dest, length, 0);
- } else {
- int ialpha = 255 - const_alpha;
- PRELOAD_INIT(dest)
- for (int i = 0; i < length; ++i) {
- PRELOAD_COND(dest)
- dest[i] = BYTE_MUL(dest[i], ialpha);
- }
- }
+ comp_func_Clear_impl(dest, length, const_alpha);
}
/*
@@ -2409,7 +2405,11 @@ static inline int soft_light_op(int dst, int src, int da, int sa)
else if (4 * dst <= da)
return (dst * sa * 255 + da * (src2 - sa) * ((((16 * dst_np - 12 * 255) * dst_np + 3 * 65025) * dst_np) / 65025) + temp) / 65025;
else {
+# ifdef Q_CC_RVCT // needed to avoid compiler crash in RVCT 2.2
+ return (dst * sa * 255 + da * (src2 - sa) * (qIntSqrtInt(dst_np * 255) - dst_np) + temp) / 65025;
+# else
return (dst * sa * 255 + da * (src2 - sa) * (int(sqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025;
+# endif
}
}
@@ -7897,20 +7897,43 @@ void qInitDrawhelperAsm()
qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_sse3dnow;
}
#endif // 3DNOW
- extern void qt_blend_rgb32_on_rgb32_sse(uchar *destPixels, int dbpl,
- const uchar *srcPixels, int sbpl,
- int w, int h,
- int const_alpha);
- extern void qt_blend_argb32_on_argb32_sse(uchar *destPixels, int dbpl,
- const uchar *srcPixels, int sbpl,
- int w, int h,
- int const_alpha);
- qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse;
- qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse;
- qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse;
- qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse;
- }
+
+#ifdef QT_HAVE_SSE2
+ if (features & SSE2) {
+ extern void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
+ const uchar *srcPixels, int sbpl,
+ int w, int h,
+ int const_alpha);
+ extern void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
+ const uchar *srcPixels, int sbpl,
+ int w, int h,
+ int const_alpha);
+
+
+ qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
+ qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
+ qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
+ qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
+ } else
+#endif
+ {
+ extern void qt_blend_rgb32_on_rgb32_sse(uchar *destPixels, int dbpl,
+ const uchar *srcPixels, int sbpl,
+ int w, int h,
+ int const_alpha);
+ extern void qt_blend_argb32_on_argb32_sse(uchar *destPixels, int dbpl,
+ const uchar *srcPixels, int sbpl,
+ int w, int h,
+ int const_alpha);
+
+
+ qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse;
+ qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse;
+ qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse;
+ qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse;
+ }
+}
#endif // SSE
#ifdef QT_HAVE_IWMMXT
diff --git a/src/gui/painting/qdrawhelper_mmx_p.h b/src/gui/painting/qdrawhelper_mmx_p.h
index 8482262..59b3804 100644
--- a/src/gui/painting/qdrawhelper_mmx_p.h
+++ b/src/gui/painting/qdrawhelper_mmx_p.h
@@ -146,36 +146,30 @@ struct QMMXCommonIntrinsics
result = 0
d = d * cia
*/
+#define comp_func_Clear_impl(dest, length, const_alpha)\
+{\
+ if (const_alpha == 255) {\
+ qt_memfill(static_cast<quint32*>(dest), quint32(0), length);\
+ } else {\
+ C_FF; C_80; C_00;\
+ m64 ia = MM::negate(MM::load_alpha(const_alpha));\
+ for (int i = 0; i < length; ++i) {\
+ dest[i] = MM::store(MM::byte_mul(MM::load(dest[i]), ia));\
+ }\
+ MM::end();\
+ }\
+}
+
template <class MM>
static void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha)
{
- if (!length)
- return;
-
- if (const_alpha == 255) {
- qt_memfill(static_cast<quint32*>(dest), quint32(0), length);
- } else {
- C_FF; C_80; C_00;
- m64 ia = MM::negate(MM::load_alpha(const_alpha));
- for (int i = 0; i < length; ++i) {
- dest[i] = MM::store(MM::byte_mul(MM::load(dest[i]), ia));
- }
- }
- MM::end();
+ comp_func_Clear_impl(dest, length, const_alpha);
}
template <class MM>
static void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha)
{
- if (const_alpha == 255) {
- qt_memfill(static_cast<quint32*>(dest), quint32(0), length);
- } else {
- C_FF; C_80; C_00;
- m64 ia = MM::negate(MM::load_alpha(const_alpha));
- for (int i = 0; i < length; ++i)
- dest[i] = MM::store(MM::byte_mul(MM::load(dest[i]), ia));
- }
- MM::end();
+ comp_func_Clear_impl(dest, length, const_alpha);
}
/*
@@ -246,7 +240,10 @@ static void QT_FASTCALL comp_func_SourceOver(uint *dest, const uint *src, int le
C_FF; C_80; C_00;
if (const_alpha == 255) {
for (int i = 0; i < length; ++i) {
- if ((0xff000000 & src[i]) == 0xff000000) {
+ const uint alphaMaskedSource = 0xff000000 & src[i];
+ if (alphaMaskedSource == 0)
+ continue;
+ if (alphaMaskedSource == 0xff000000) {
dest[i] = src[i];
} else {
m64 s = MM::load(src[i]);
@@ -257,6 +254,8 @@ static void QT_FASTCALL comp_func_SourceOver(uint *dest, const uint *src, int le
} else {
m64 ca = MM::load_alpha(const_alpha);
for (int i = 0; i < length; ++i) {
+ if ((0xff000000 & src[i]) == 0)
+ continue;
m64 s = MM::byte_mul(MM::load(src[i]), ca);
m64 ia = MM::negate(MM::alpha(s));
dest[i] = MM::store(MM::add(s, MM::byte_mul(MM::load(dest[i]), ia)));
diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp
index 25860a0..77c5202 100644
--- a/src/gui/painting/qdrawhelper_neon.cpp
+++ b/src/gui/painting/qdrawhelper_neon.cpp
@@ -48,43 +48,43 @@
QT_BEGIN_NAMESPACE
-static inline int16x8_t qvdiv_255_s16(int16x8_t x, int16x8_t half)
+static inline uint16x8_t qvdiv_255_u16(uint16x8_t x, uint16x8_t half)
{
// result = (x + (x >> 8) + 0x80) >> 8
- const int16x8_t temp = vshrq_n_s16(x, 8); // x >> 8
- const int16x8_t sum_part = vaddq_s16(x, half); // x + 0x80
- const int16x8_t sum = vaddq_s16(temp, sum_part);
+ const uint16x8_t temp = vshrq_n_u16(x, 8); // x >> 8
+ const uint16x8_t sum_part = vaddq_u16(x, half); // x + 0x80
+ const uint16x8_t sum = vaddq_u16(temp, sum_part);
- return vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(sum), 8));
+ return vshrq_n_u16(sum, 8);
}
-static inline int16x8_t qvbyte_mul_s16(int16x8_t x, int16x8_t alpha, int16x8_t half)
+static inline uint16x8_t qvbyte_mul_u16(uint16x8_t x, uint16x8_t alpha, uint16x8_t half)
{
// t = qRound(x * alpha / 255.0)
- const int16x8_t t = vmulq_s16(x, alpha); // t
- return qvdiv_255_s16(t, half);
+ const uint16x8_t t = vmulq_u16(x, alpha); // t
+ return qvdiv_255_u16(t, half);
}
-static inline int16x8_t qvinterpolate_pixel_255(int16x8_t x, int16x8_t a, int16x8_t y, int16x8_t b, int16x8_t half)
+static inline uint16x8_t qvinterpolate_pixel_255(uint16x8_t x, uint16x8_t a, uint16x8_t y, uint16x8_t b, uint16x8_t half)
{
// t = x * a + y * b
- const int16x8_t ta = vmulq_s16(x, a);
- const int16x8_t tb = vmulq_s16(y, b);
+ const uint16x8_t ta = vmulq_u16(x, a);
+ const uint16x8_t tb = vmulq_u16(y, b);
- return qvdiv_255_s16(vaddq_s16(ta, tb), half);
+ return qvdiv_255_u16(vaddq_u16(ta, tb), half);
}
-static inline int16x8_t qvsource_over_s16(int16x8_t src16, int16x8_t dst16, int16x8_t half, int16x8_t full)
+static inline uint16x8_t qvsource_over_u16(uint16x8_t src16, uint16x8_t dst16, uint16x8_t half, uint16x8_t full)
{
- const int16x4_t alpha16_high = vdup_lane_s16(vget_high_s16(src16), 3);
- const int16x4_t alpha16_low = vdup_lane_s16(vget_low_s16(src16), 3);
+ const uint16x4_t alpha16_high = vdup_lane_u16(vget_high_u16(src16), 3);
+ const uint16x4_t alpha16_low = vdup_lane_u16(vget_low_u16(src16), 3);
- const int16x8_t alpha16 = vsubq_s16(full, vcombine_s16(alpha16_low, alpha16_high));
+ const uint16x8_t alpha16 = vsubq_u16(full, vcombine_u16(alpha16_low, alpha16_high));
- return vaddq_s16(src16, qvbyte_mul_s16(dst16, alpha16, half));
+ return vaddq_u16(src16, qvbyte_mul_u16(dst16, alpha16, half));
}
void qt_blend_argb32_on_argb32_neon(uchar *destPixels, int dbpl,
@@ -94,21 +94,21 @@ void qt_blend_argb32_on_argb32_neon(uchar *destPixels, int dbpl,
{
const uint *src = (const uint *) srcPixels;
uint *dst = (uint *) destPixels;
- int16x8_t half = vdupq_n_s16(0x80);
- int16x8_t full = vdupq_n_s16(0xff);
+ uint16x8_t half = vdupq_n_u16(0x80);
+ uint16x8_t full = vdupq_n_u16(0xff);
if (const_alpha == 256) {
for (int y = 0; y < h; ++y) {
int x = 0;
for (; x < w-3; x += 4) {
- int32x4_t src32 = vld1q_s32((int32_t *)&src[x]);
+ uint32x4_t src32 = vld1q_u32((uint32_t *)&src[x]);
if ((src[x] & src[x+1] & src[x+2] & src[x+3]) >= 0xff000000) {
// all opaque
- vst1q_s32((int32_t *)&dst[x], src32);
+ vst1q_u32((uint32_t *)&dst[x], src32);
} else if (src[x] | src[x+1] | src[x+2] | src[x+3]) {
- int32x4_t dst32 = vld1q_s32((int32_t *)&dst[x]);
+ uint32x4_t dst32 = vld1q_u32((uint32_t *)&dst[x]);
- const uint8x16_t src8 = vreinterpretq_u8_s32(src32);
- const uint8x16_t dst8 = vreinterpretq_u8_s32(dst32);
+ const uint8x16_t src8 = vreinterpretq_u8_u32(src32);
+ const uint8x16_t dst8 = vreinterpretq_u8_u32(dst32);
const uint8x8_t src8_low = vget_low_u8(src8);
const uint8x8_t dst8_low = vget_low_u8(dst8);
@@ -116,19 +116,19 @@ void qt_blend_argb32_on_argb32_neon(uchar *destPixels, int dbpl,
const uint8x8_t src8_high = vget_high_u8(src8);
const uint8x8_t dst8_high = vget_high_u8(dst8);
- const int16x8_t src16_low = vreinterpretq_s16_u16(vmovl_u8(src8_low));
- const int16x8_t dst16_low = vreinterpretq_s16_u16(vmovl_u8(dst8_low));
+ const uint16x8_t src16_low = vmovl_u8(src8_low);
+ const uint16x8_t dst16_low = vmovl_u8(dst8_low);
- const int16x8_t src16_high = vreinterpretq_s16_u16(vmovl_u8(src8_high));
- const int16x8_t dst16_high = vreinterpretq_s16_u16(vmovl_u8(dst8_high));
+ const uint16x8_t src16_high = vmovl_u8(src8_high);
+ const uint16x8_t dst16_high = vmovl_u8(dst8_high);
- const int16x8_t result16_low = qvsource_over_s16(src16_low, dst16_low, half, full);
- const int16x8_t result16_high = qvsource_over_s16(src16_high, dst16_high, half, full);
+ const uint16x8_t result16_low = qvsource_over_u16(src16_low, dst16_low, half, full);
+ const uint16x8_t result16_high = qvsource_over_u16(src16_high, dst16_high, half, full);
- const int32x2_t result32_low = vreinterpret_s32_s8(vmovn_s16(result16_low));
- const int32x2_t result32_high = vreinterpret_s32_s8(vmovn_s16(result16_high));
+ const uint32x2_t result32_low = vreinterpret_u32_u8(vmovn_u16(result16_low));
+ const uint32x2_t result32_high = vreinterpret_u32_u8(vmovn_u16(result16_high));
- vst1q_s32((int32_t *)&dst[x], vcombine_s32(result32_low, result32_high));
+ vst1q_u32((uint32_t *)&dst[x], vcombine_u32(result32_low, result32_high));
}
}
for (; x<w; ++x) {
@@ -143,16 +143,16 @@ void qt_blend_argb32_on_argb32_neon(uchar *destPixels, int dbpl,
}
} else if (const_alpha != 0) {
const_alpha = (const_alpha * 255) >> 8;
- int16x8_t const_alpha16 = vdupq_n_s16(const_alpha);
+ uint16x8_t const_alpha16 = vdupq_n_u16(const_alpha);
for (int y = 0; y < h; ++y) {
int x = 0;
for (; x < w-3; x += 4) {
if (src[x] | src[x+1] | src[x+2] | src[x+3]) {
- int32x4_t src32 = vld1q_s32((int32_t *)&src[x]);
- int32x4_t dst32 = vld1q_s32((int32_t *)&dst[x]);
+ uint32x4_t src32 = vld1q_u32((uint32_t *)&src[x]);
+ uint32x4_t dst32 = vld1q_u32((uint32_t *)&dst[x]);
- const uint8x16_t src8 = vreinterpretq_u8_s32(src32);
- const uint8x16_t dst8 = vreinterpretq_u8_s32(dst32);
+ const uint8x16_t src8 = vreinterpretq_u8_u32(src32);
+ const uint8x16_t dst8 = vreinterpretq_u8_u32(dst32);
const uint8x8_t src8_low = vget_low_u8(src8);
const uint8x8_t dst8_low = vget_low_u8(dst8);
@@ -160,22 +160,22 @@ void qt_blend_argb32_on_argb32_neon(uchar *destPixels, int dbpl,
const uint8x8_t src8_high = vget_high_u8(src8);
const uint8x8_t dst8_high = vget_high_u8(dst8);
- const int16x8_t src16_low = vreinterpretq_s16_u16(vmovl_u8(src8_low));
- const int16x8_t dst16_low = vreinterpretq_s16_u16(vmovl_u8(dst8_low));
+ const uint16x8_t src16_low = vmovl_u8(src8_low);
+ const uint16x8_t dst16_low = vmovl_u8(dst8_low);
- const int16x8_t src16_high = vreinterpretq_s16_u16(vmovl_u8(src8_high));
- const int16x8_t dst16_high = vreinterpretq_s16_u16(vmovl_u8(dst8_high));
+ const uint16x8_t src16_high = vmovl_u8(src8_high);
+ const uint16x8_t dst16_high = vmovl_u8(dst8_high);
- const int16x8_t srcalpha16_low = qvbyte_mul_s16(src16_low, const_alpha16, half);
- const int16x8_t srcalpha16_high = qvbyte_mul_s16(src16_high, const_alpha16, half);
+ const uint16x8_t srcalpha16_low = qvbyte_mul_u16(src16_low, const_alpha16, half);
+ const uint16x8_t srcalpha16_high = qvbyte_mul_u16(src16_high, const_alpha16, half);
- const int16x8_t result16_low = qvsource_over_s16(srcalpha16_low, dst16_low, half, full);
- const int16x8_t result16_high = qvsource_over_s16(srcalpha16_high, dst16_high, half, full);
+ const uint16x8_t result16_low = qvsource_over_u16(srcalpha16_low, dst16_low, half, full);
+ const uint16x8_t result16_high = qvsource_over_u16(srcalpha16_high, dst16_high, half, full);
- const int32x2_t result32_low = vreinterpret_s32_s8(vmovn_s16(result16_low));
- const int32x2_t result32_high = vreinterpret_s32_s8(vmovn_s16(result16_high));
+ const uint32x2_t result32_low = vreinterpret_u32_u8(vmovn_u16(result16_low));
+ const uint32x2_t result32_high = vreinterpret_u32_u8(vmovn_u16(result16_high));
- vst1q_s32((int32_t *)&dst[x], vcombine_s32(result32_low, result32_high));
+ vst1q_u32((uint32_t *)&dst[x], vcombine_u32(result32_low, result32_high));
}
}
for (; x<w; ++x) {
@@ -206,19 +206,19 @@ void qt_blend_rgb32_on_rgb32_neon(uchar *destPixels, int dbpl,
if (const_alpha != 0) {
const uint *src = (const uint *) srcPixels;
uint *dst = (uint *) destPixels;
- int16x8_t half = vdupq_n_s16(0x80);
+ uint16x8_t half = vdupq_n_u16(0x80);
const_alpha = (const_alpha * 255) >> 8;
int one_minus_const_alpha = 255 - const_alpha;
- int16x8_t const_alpha16 = vdupq_n_s16(const_alpha);
- int16x8_t one_minus_const_alpha16 = vdupq_n_s16(255 - const_alpha);
+ uint16x8_t const_alpha16 = vdupq_n_u16(const_alpha);
+ uint16x8_t one_minus_const_alpha16 = vdupq_n_u16(255 - const_alpha);
for (int y = 0; y < h; ++y) {
int x = 0;
for (; x < w-3; x += 4) {
- int32x4_t src32 = vld1q_s32((int32_t *)&src[x]);
- int32x4_t dst32 = vld1q_s32((int32_t *)&dst[x]);
+ uint32x4_t src32 = vld1q_u32((uint32_t *)&src[x]);
+ uint32x4_t dst32 = vld1q_u32((uint32_t *)&dst[x]);
- const uint8x16_t src8 = vreinterpretq_u8_s32(src32);
- const uint8x16_t dst8 = vreinterpretq_u8_s32(dst32);
+ const uint8x16_t src8 = vreinterpretq_u8_u32(src32);
+ const uint8x16_t dst8 = vreinterpretq_u8_u32(dst32);
const uint8x8_t src8_low = vget_low_u8(src8);
const uint8x8_t dst8_low = vget_low_u8(dst8);
@@ -226,19 +226,19 @@ void qt_blend_rgb32_on_rgb32_neon(uchar *destPixels, int dbpl,
const uint8x8_t src8_high = vget_high_u8(src8);
const uint8x8_t dst8_high = vget_high_u8(dst8);
- const int16x8_t src16_low = vreinterpretq_s16_u16(vmovl_u8(src8_low));
- const int16x8_t dst16_low = vreinterpretq_s16_u16(vmovl_u8(dst8_low));
+ const uint16x8_t src16_low = vmovl_u8(src8_low);
+ const uint16x8_t dst16_low = vmovl_u8(dst8_low);
- const int16x8_t src16_high = vreinterpretq_s16_u16(vmovl_u8(src8_high));
- const int16x8_t dst16_high = vreinterpretq_s16_u16(vmovl_u8(dst8_high));
+ const uint16x8_t src16_high = vmovl_u8(src8_high);
+ const uint16x8_t dst16_high = vmovl_u8(dst8_high);
- const int16x8_t result16_low = qvinterpolate_pixel_255(src16_low, const_alpha16, dst16_low, one_minus_const_alpha16, half);
- const int16x8_t result16_high = qvinterpolate_pixel_255(src16_high, const_alpha16, dst16_high, one_minus_const_alpha16, half);
+ const uint16x8_t result16_low = qvinterpolate_pixel_255(src16_low, const_alpha16, dst16_low, one_minus_const_alpha16, half);
+ const uint16x8_t result16_high = qvinterpolate_pixel_255(src16_high, const_alpha16, dst16_high, one_minus_const_alpha16, half);
- const int32x2_t result32_low = vreinterpret_s32_s8(vmovn_s16(result16_low));
- const int32x2_t result32_high = vreinterpret_s32_s8(vmovn_s16(result16_high));
+ const uint32x2_t result32_low = vreinterpret_u32_u8(vmovn_u16(result16_low));
+ const uint32x2_t result32_high = vreinterpret_u32_u8(vmovn_u16(result16_high));
- vst1q_s32((int32_t *)&dst[x], vcombine_s32(result32_low, result32_high));
+ vst1q_u32((uint32_t *)&dst[x], vcombine_u32(result32_low, result32_high));
}
for (; x<w; ++x) {
uint s = src[x];
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index 474ebcf..df4d9c5 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -1540,6 +1540,9 @@ template<> inline void qt_memfill(quint8 *dest, quint8 color, int count)
template <class T>
inline void qt_memfill(T *dest, T value, int count)
{
+ if (!count)
+ return;
+
int n = (count + 7) / 8;
switch (count & 0x07)
{
diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp
index dd6fa1b..6ac64d3 100644
--- a/src/gui/painting/qdrawhelper_sse2.cpp
+++ b/src/gui/painting/qdrawhelper_sse2.cpp
@@ -57,6 +57,217 @@
QT_BEGIN_NAMESPACE
+/*
+ * Multiply the components of pixelVector by alphaChannel
+ * Each 32bits components of alphaChannel must be in the form 0x00AA00AA
+ * colorMask must have 0x00ff00ff on each 32 bits component
+ * half must have the value 128 (0x80) for each 32 bits compnent
+ */
+#define BYTE_MUL_SSE2(result, pixelVector, alphaChannel, colorMask, half) \
+{ \
+ /* 1. separate the colors in 2 vectors so each color is on 16 bits \
+ (in order to be multiplied by the alpha \
+ each 32 bit of dstVectorAG are in the form 0x00AA00GG \
+ each 32 bit of dstVectorRB are in the form 0x00RR00BB */\
+ __m128i pixelVectorAG = _mm_srli_epi16(pixelVector, 8); \
+ __m128i pixelVectorRB = _mm_and_si128(pixelVector, colorMask); \
+ \
+ /* 2. multiply the vectors by the alpha channel */\
+ pixelVectorAG = _mm_mullo_epi16(pixelVectorAG, alphaChannel); \
+ pixelVectorRB = _mm_mullo_epi16(pixelVectorRB, alphaChannel); \
+ \
+ /* 3. devide by 255, that's the tricky part. \
+ we do it like for BYTE_MUL(), with bit shift: X/255 ~= (X + X/256 + rounding)/256 */ \
+ /** so first (X + X/256 + rounding) */\
+ pixelVectorRB = _mm_add_epi16(pixelVectorRB, _mm_srli_epi16(pixelVectorRB, 8)); \
+ pixelVectorRB = _mm_add_epi16(pixelVectorRB, half); \
+ pixelVectorAG = _mm_add_epi16(pixelVectorAG, _mm_srli_epi16(pixelVectorAG, 8)); \
+ pixelVectorAG = _mm_add_epi16(pixelVectorAG, half); \
+ \
+ /** second devide by 256 */\
+ pixelVectorRB = _mm_srli_epi16(pixelVectorRB, 8); \
+ /** for AG, we could >> 8 to divide followed by << 8 to put the \
+ bytes in the correct position. By masking instead, we execute \
+ only one instruction */\
+ pixelVectorAG = _mm_andnot_si128(colorMask, pixelVectorAG); \
+ \
+ /* 4. combine the 2 pairs of colors */ \
+ result = _mm_or_si128(pixelVectorAG, pixelVectorRB); \
+}
+
+/*
+ * Each 32bits components of alphaChannel must be in the form 0x00AA00AA
+ * oneMinusAlphaChannel must be 255 - alpha for each 32 bits component
+ * colorMask must have 0x00ff00ff on each 32 bits component
+ * half must have the value 128 (0x80) for each 32 bits compnent
+ */
+#define INTERPOLATE_PIXEL_255_SSE2(result, srcVector, dstVector, alphaChannel, oneMinusAlphaChannel, colorMask, half) { \
+ /* interpolate AG */\
+ __m128i srcVectorAG = _mm_srli_epi16(srcVector, 8); \
+ __m128i dstVectorAG = _mm_srli_epi16(dstVector, 8); \
+ __m128i srcVectorAGalpha = _mm_mullo_epi16(srcVectorAG, alphaChannel); \
+ __m128i dstVectorAGoneMinusAlphalpha = _mm_mullo_epi16(dstVectorAG, oneMinusAlphaChannel); \
+ __m128i finalAG = _mm_add_epi16(srcVectorAGalpha, dstVectorAGoneMinusAlphalpha); \
+ finalAG = _mm_add_epi16(finalAG, _mm_srli_epi16(finalAG, 8)); \
+ finalAG = _mm_add_epi16(finalAG, half); \
+ finalAG = _mm_andnot_si128(colorMask, finalAG); \
+ \
+ /* interpolate RB */\
+ __m128i srcVectorRB = _mm_and_si128(srcVector, colorMask); \
+ __m128i dstVectorRB = _mm_and_si128(dstVector, colorMask); \
+ __m128i srcVectorRBalpha = _mm_mullo_epi16(srcVectorRB, alphaChannel); \
+ __m128i dstVectorRBoneMinusAlphalpha = _mm_mullo_epi16(dstVectorRB, oneMinusAlphaChannel); \
+ __m128i finalRB = _mm_add_epi16(srcVectorRBalpha, dstVectorRBoneMinusAlphalpha); \
+ finalRB = _mm_add_epi16(finalRB, _mm_srli_epi16(finalRB, 8)); \
+ finalRB = _mm_add_epi16(finalRB, half); \
+ finalRB = _mm_srli_epi16(finalRB, 8); \
+ \
+ /* combine */\
+ result = _mm_or_si128(finalAG, finalRB); \
+}
+
+void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
+ const uchar *srcPixels, int sbpl,
+ int w, int h,
+ int const_alpha)
+{
+ const quint32 *src = (const quint32 *) srcPixels;
+ quint32 *dst = (uint *) destPixels;
+ if (const_alpha == 256) {
+ const __m128i alphaMask = _mm_set1_epi32(0xff000000);
+ const __m128i nullVector = _mm_set1_epi32(0);
+ const __m128i half = _mm_set1_epi16(0x80);
+ const __m128i one = _mm_set1_epi16(0xff);
+ const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+ for (int y = 0; y < h; ++y) {
+ int x = 0;
+ for (; x < w-3; x += 4) {
+ const __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]);
+ const __m128i srcVectorAlpha = _mm_and_si128(srcVector, alphaMask);
+ if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, alphaMask)) == 0xffff) {
+ // all opaque
+ _mm_storeu_si128((__m128i *)&dst[x], srcVector);
+ } else if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, nullVector)) != 0xffff) {
+ // not fully transparent
+ // result = s + d * (1-alpha)
+
+ // extract the alpha channel on 2 x 16 bits
+ // so we have room for the multiplication
+ // each 32 bits will be in the form 0x00AA00AA
+ // with A being the 1 - alpha
+ __m128i alphaChannel = _mm_srli_epi32(srcVector, 24);
+ alphaChannel = _mm_or_si128(alphaChannel, _mm_slli_epi32(alphaChannel, 16));
+ alphaChannel = _mm_sub_epi16(one, alphaChannel);
+
+ const __m128i dstVector = _mm_loadu_si128((__m128i *)&dst[x]);
+ __m128i destMultipliedByOneMinusAlpha;
+ BYTE_MUL_SSE2(destMultipliedByOneMinusAlpha, dstVector, alphaChannel, colorMask, half);
+
+ // result = s + d * (1-alpha)
+ const __m128i result = _mm_add_epi8(srcVector, destMultipliedByOneMinusAlpha);
+ _mm_storeu_si128((__m128i *)&dst[x], result);
+ }
+ }
+ for (; x<w; ++x) {
+ uint s = src[x];
+ if (s >= 0xff000000)
+ dst[x] = s;
+ else if (s != 0)
+ dst[x] = s + BYTE_MUL(dst[x], qAlpha(~s));
+ }
+ dst = (quint32 *)(((uchar *) dst) + dbpl);
+ src = (const quint32 *)(((const uchar *) src) + sbpl);
+ }
+ } else if (const_alpha != 0) {
+ // dest = (s + d * sia) * ca + d * cia
+ // = s * ca + d * (sia * ca + cia)
+ // = s * ca + d * (1 - sa*ca)
+ const_alpha = (const_alpha * 255) >> 8;
+ const __m128i nullVector = _mm_set1_epi32(0);
+ const __m128i half = _mm_set1_epi16(0x80);
+ const __m128i one = _mm_set1_epi16(0xff);
+ const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+ const __m128i constAlphaVector = _mm_set1_epi16(const_alpha);
+ for (int y = 0; y < h; ++y) {
+ int x = 0;
+ for (; x < w-3; x += 4) {
+ __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]);
+ if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVector, nullVector)) != 0xffff) {
+ BYTE_MUL_SSE2(srcVector, srcVector, constAlphaVector, colorMask, half);
+
+ __m128i alphaChannel = _mm_srli_epi32(srcVector, 24);
+ alphaChannel = _mm_or_si128(alphaChannel, _mm_slli_epi32(alphaChannel, 16));
+ alphaChannel = _mm_sub_epi16(one, alphaChannel);
+
+ const __m128i dstVector = _mm_loadu_si128((__m128i *)&dst[x]);
+ __m128i destMultipliedByOneMinusAlpha;
+ BYTE_MUL_SSE2(destMultipliedByOneMinusAlpha, dstVector, alphaChannel, colorMask, half);
+
+ const __m128i result = _mm_add_epi8(srcVector, destMultipliedByOneMinusAlpha);
+ _mm_storeu_si128((__m128i *)&dst[x], result);
+ }
+ }
+ for (; x<w; ++x) {
+ quint32 s = src[x];
+ if (s != 0) {
+ s = BYTE_MUL(s, const_alpha);
+ dst[x] = s + BYTE_MUL(dst[x], qAlpha(~s));
+ }
+ }
+ dst = (quint32 *)(((uchar *) dst) + dbpl);
+ src = (const quint32 *)(((const uchar *) src) + sbpl);
+ }
+ }
+}
+
+// qblendfunctions.cpp
+void qt_blend_rgb32_on_rgb32(uchar *destPixels, int dbpl,
+ const uchar *srcPixels, int sbpl,
+ int w, int h,
+ int const_alpha);
+
+void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
+ const uchar *srcPixels, int sbpl,
+ int w, int h,
+ int const_alpha)
+{
+ const quint32 *src = (const quint32 *) srcPixels;
+ quint32 *dst = (uint *) destPixels;
+ if (const_alpha != 256) {
+ if (const_alpha != 0) {
+ const __m128i nullVector = _mm_set1_epi32(0);
+ const __m128i half = _mm_set1_epi16(0x80);
+ const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+
+ const_alpha = (const_alpha * 255) >> 8;
+ int one_minus_const_alpha = 255 - const_alpha;
+ const __m128i constAlphaVector = _mm_set1_epi16(const_alpha);
+ const __m128i oneMinusConstAlpha = _mm_set1_epi16(one_minus_const_alpha);
+ for (int y = 0; y < h; ++y) {
+ int x = 0;
+ for (; x < w-3; x += 4) {
+ __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]);
+ if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVector, nullVector)) != 0xffff) {
+ const __m128i dstVector = _mm_loadu_si128((__m128i *)&dst[x]);
+ __m128i result;
+ INTERPOLATE_PIXEL_255_SSE2(result, srcVector, dstVector, constAlphaVector, oneMinusConstAlpha, colorMask, half);
+ _mm_storeu_si128((__m128i *)&dst[x], result);
+ }
+ }
+ for (; x<w; ++x) {
+ quint32 s = src[x];
+ s = BYTE_MUL(s, const_alpha);
+ dst[x] = INTERPOLATE_PIXEL_255(src[x], const_alpha, dst[x], one_minus_const_alpha);
+ }
+ dst = (quint32 *)(((uchar *) dst) + dbpl);
+ src = (const quint32 *)(((const uchar *) src) + sbpl);
+ }
+ }
+ } else {
+ qt_blend_rgb32_on_rgb32(destPixels, dbpl, srcPixels, sbpl, w, h, const_alpha);
+ }
+}
+
void qt_memfill32_sse2(quint32 *dest, quint32 value, int count)
{
if (count < 7) {
diff --git a/src/gui/painting/qdrawhelper_x86_p.h b/src/gui/painting/qdrawhelper_x86_p.h
index 30aadd0..d7282a7 100644
--- a/src/gui/painting/qdrawhelper_x86_p.h
+++ b/src/gui/painting/qdrawhelper_x86_p.h
@@ -114,6 +114,14 @@ void qt_bitmapblit32_sse2(QRasterBuffer *rasterBuffer, int x, int y,
void qt_bitmapblit16_sse2(QRasterBuffer *rasterBuffer, int x, int y,
quint32 color,
const uchar *src, int width, int height, int stride);
+void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
+ const uchar *srcPixels, int sbpl,
+ int w, int h,
+ int const_alpha);
+void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
+ const uchar *srcPixels, int sbpl,
+ int w, int h,
+ int const_alpha);
#endif // QT_HAVE_SSE2
#ifdef QT_HAVE_IWMMXT
diff --git a/src/gui/painting/qemulationpaintengine.cpp b/src/gui/painting/qemulationpaintengine.cpp
index fd42736..0510b10 100644
--- a/src/gui/painting/qemulationpaintengine.cpp
+++ b/src/gui/painting/qemulationpaintengine.cpp
@@ -205,6 +205,11 @@ void QEmulationPaintEngine::drawTextItem(const QPointF &p, const QTextItem &text
real_engine->drawTextItem(p, textItem);
}
+void QEmulationPaintEngine::drawStaticTextItem(QStaticTextItem *item)
+{
+ real_engine->drawStaticTextItem(item);
+}
+
void QEmulationPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s)
{
if (state()->bgMode == Qt::OpaqueMode && pixmap.isQBitmap())
diff --git a/src/gui/painting/qemulationpaintengine_p.h b/src/gui/painting/qemulationpaintengine_p.h
index 0ed641b..5835f10 100644
--- a/src/gui/painting/qemulationpaintengine_p.h
+++ b/src/gui/painting/qemulationpaintengine_p.h
@@ -78,6 +78,7 @@ public:
virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr);
virtual void drawTextItem(const QPointF &p, const QTextItem &textItem);
+ virtual void drawStaticTextItem(QStaticTextItem *item);
virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s);
virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags);
diff --git a/src/gui/painting/qmath_p.h b/src/gui/painting/qmath_p.h
index cd9f5ea..8a5f5ab 100644
--- a/src/gui/painting/qmath_p.h
+++ b/src/gui/painting/qmath_p.h
@@ -54,6 +54,7 @@
//
#include <math.h>
+#include <qmath.h>
QT_BEGIN_NAMESPACE
@@ -61,6 +62,11 @@ static const qreal Q_PI = qreal(3.14159265358979323846); // pi
static const qreal Q_2PI = qreal(6.28318530717958647693); // 2*pi
static const qreal Q_PI2 = qreal(1.57079632679489661923); // pi/2
+inline int qIntSqrtInt(int v)
+{
+ return static_cast<int>(qSqrt(static_cast<qreal>(v)));
+}
+
QT_END_NAMESPACE
#endif // QMATH_P_H
diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp
index 2344c04..39b76c8 100644
--- a/src/gui/painting/qpaintbuffer.cpp
+++ b/src/gui/painting/qpaintbuffer.cpp
@@ -45,6 +45,8 @@
#include <private/qfontengine_p.h>
#include <private/qemulationpaintengine_p.h>
#include <private/qimage_p.h>
+#include <qstatictext.h>
+#include <private/qstatictext_p.h>
#include <QDebug>
@@ -306,6 +308,8 @@ public:
Q_Q(QPaintBufferEngine);
q->buffer->addCommand(QPaintBufferPrivate::Cmd_SystemStateChanged, QVariant(systemClip));
}
+
+ QTransform last;
};
@@ -492,6 +496,32 @@ void QPaintBufferEngine::renderHintsChanged()
void QPaintBufferEngine::transformChanged()
{
+ Q_D(QPaintBufferEngine);
+ const QTransform &transform = state()->matrix;
+
+ QTransform delta;
+
+ bool invertible = false;
+ if (transform.type() <= QTransform::TxScale && transform.type() == d->last.type())
+ delta = transform * d->last.inverted(&invertible);
+
+ d->last = transform;
+
+ if (invertible && delta.type() == QTransform::TxNone)
+ return;
+
+ if (invertible && delta.type() == QTransform::TxTranslate) {
+#ifdef QPAINTBUFFER_DEBUG_DRAW
+ qDebug() << "QPaintBufferEngine: transformChanged (translate only) " << state()->matrix;
+#endif
+ QPaintBufferCommand *cmd =
+ buffer->addCommand(QPaintBufferPrivate::Cmd_Translate);
+
+ qreal data[] = { delta.dx(), delta.dy() };
+ cmd->extra = buffer->addData((qreal *) data, 2);
+ return;
+ }
+
// ### accumulate, like in QBrush case...
if (!buffer->commands.isEmpty()
&& buffer->commands.last().id == QPaintBufferPrivate::Cmd_SetTransform) {
@@ -960,6 +990,18 @@ void QPaintBufferEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, con
buffer->updateBoundingRect(r);
}
+void QPaintBufferEngine::drawStaticTextItem(QStaticTextItem *staticTextItem)
+{
+ QString text = QString(staticTextItem->chars, staticTextItem->numChars);
+
+ QStaticText staticText(text);
+ staticText.prepare(state()->matrix, staticTextItem->font);
+
+ QVariantList variants;
+ variants << QVariant(staticTextItem->font) << QVariant::fromValue(staticText);
+ buffer->addCommand(QPaintBufferPrivate::Cmd_DrawStaticText, QVariant(variants));
+}
+
void QPaintBufferEngine::drawTextItem(const QPointF &pos, const QTextItem &ti)
{
#ifdef QPAINTBUFFER_DEBUG_DRAW
@@ -999,6 +1041,7 @@ void QPaintBufferEngine::drawTextItem(const QPointF &pos, const QTextItem &ti)
void QPaintBufferEngine::setState(QPainterState *s)
{
+ Q_D(QPaintBufferEngine);
if (m_begin_detected) {
#ifdef QPAINTBUFFER_DEBUG_DRAW
qDebug() << "QPaintBufferEngine: setState: begin, ignoring.";
@@ -1017,6 +1060,8 @@ void QPaintBufferEngine::setState(QPainterState *s)
buffer->addCommand(QPaintBufferPrivate::Cmd_Restore);
}
+ d->last = s->matrix;
+
QPaintEngineEx::setState(s);
}
@@ -1138,6 +1183,15 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd)
painter->setTransform(xform * m_world_matrix);
break; }
+ case QPaintBufferPrivate::Cmd_Translate: {
+ QPointF delta(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1));
+#ifdef QPAINTBUFFER_DEBUG_DRAW
+ qDebug() << " -> Cmd_Translate, offset: " << cmd.offset << delta;
+#endif
+ painter->translate(delta.x(), delta.y());
+ return;
+ }
+
case QPaintBufferPrivate::Cmd_SetCompositionMode: {
QPainter::CompositionMode mode = (QPainter::CompositionMode) cmd.extra;
#ifdef QPAINTBUFFER_DEBUG_DRAW
@@ -1425,6 +1479,19 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd)
#endif
painter->setClipRegion(region, Qt::ClipOperation(cmd.extra));
break; }
+
+ case QPaintBufferPrivate::Cmd_DrawStaticText: {
+
+ QVariantList variants(d->variants.at(cmd.offset).value<QVariantList>());
+
+ QFont font(variants.at(0).value<QFont>());
+ QStaticText text(variants.at(0).value<QStaticText>());
+
+ painter->setFont(font);
+ painter->drawStaticText(QPointF(0, 0), text);
+
+ break;
+ }
case QPaintBufferPrivate::Cmd_DrawText: {
QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1));
@@ -1770,8 +1837,28 @@ struct QPaintBufferCacheEntry
QVariant::Type type;
quint64 cacheKey;
};
+
+struct QPaintBufferCacheEntryV2
+{
+ enum Type {
+ ImageKey,
+ PixmapKey
+ };
+
+ struct Flags {
+ uint type : 8;
+ uint key : 24;
+ };
+
+ union {
+ Flags flags;
+ uint bits;
+ };
+};
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QPaintBufferCacheEntry)
+Q_DECLARE_METATYPE(QPaintBufferCacheEntryV2)
QT_BEGIN_NAMESPACE
QDataStream &operator<<(QDataStream &stream, const QPaintBufferCacheEntry &entry)
@@ -1784,10 +1871,22 @@ QDataStream &operator>>(QDataStream &stream, QPaintBufferCacheEntry &entry)
return stream >> entry.type >> entry.cacheKey;
}
+QDataStream &operator<<(QDataStream &stream, const QPaintBufferCacheEntryV2 &entry)
+{
+ return stream << entry.bits;
+}
+
+QDataStream &operator>>(QDataStream &stream, QPaintBufferCacheEntryV2 &entry)
+{
+ return stream >> entry.bits;
+}
+
static int qRegisterPaintBufferMetaTypes()
{
qRegisterMetaType<QPaintBufferCacheEntry>();
qRegisterMetaTypeStreamOperators<QPaintBufferCacheEntry>("QPaintBufferCacheEntry");
+ qRegisterMetaType<QPaintBufferCacheEntryV2>();
+ qRegisterMetaTypeStreamOperators<QPaintBufferCacheEntryV2>("QPaintBufferCacheEntryV2");
return 0; // something
}
@@ -1796,6 +1895,9 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterPaintBufferMetaTypes)
QDataStream &operator<<(QDataStream &stream, const QPaintBuffer &buffer)
{
+ QHash<qint64, uint> pixmapKeys;
+ QHash<qint64, uint> imageKeys;
+
QHash<qint64, QPixmap> pixmaps;
QHash<qint64, QImage> images;
@@ -1804,19 +1906,33 @@ QDataStream &operator<<(QDataStream &stream, const QPaintBuffer &buffer)
const QVariant &v = variants.at(i);
if (v.type() == QVariant::Image) {
const QImage image(v.value<QImage>());
- images[image.cacheKey()] = image;
- QPaintBufferCacheEntry entry;
- entry.type = QVariant::Image;
- entry.cacheKey = image.cacheKey();
+ QPaintBufferCacheEntryV2 entry;
+ entry.flags.type = QPaintBufferCacheEntryV2::ImageKey;
+
+ QHash<qint64, uint>::iterator it = imageKeys.find(image.cacheKey());
+ if (it != imageKeys.end()) {
+ entry.flags.key = *it;
+ } else {
+ imageKeys[image.cacheKey()] = entry.flags.key = images.size();
+ images[images.size()] = image;
+ }
+
variants[i] = QVariant::fromValue(entry);
} else if (v.type() == QVariant::Pixmap) {
const QPixmap pixmap(v.value<QPixmap>());
- pixmaps[pixmap.cacheKey()] = pixmap;
- QPaintBufferCacheEntry entry;
- entry.type = QVariant::Pixmap;
- entry.cacheKey = pixmap.cacheKey();
+ QPaintBufferCacheEntryV2 entry;
+ entry.flags.type = QPaintBufferCacheEntryV2::PixmapKey;
+
+ QHash<qint64, uint>::iterator it = pixmapKeys.find(pixmap.cacheKey());
+ if (it != pixmapKeys.end()) {
+ entry.flags.key = *it;
+ } else {
+ pixmapKeys[pixmap.cacheKey()] = entry.flags.key = pixmaps.size();
+ pixmaps[pixmaps.size()] = pixmap;
+ }
+
variants[i] = QVariant::fromValue(entry);
}
}
@@ -1858,6 +1974,15 @@ QDataStream &operator>>(QDataStream &stream, QPaintBuffer &buffer)
variants[i] = QVariant(images.value(entry.cacheKey));
else
variants[i] = QVariant(pixmaps.value(entry.cacheKey));
+ } else if (v.canConvert<QPaintBufferCacheEntryV2>()) {
+ QPaintBufferCacheEntryV2 entry = v.value<QPaintBufferCacheEntryV2>();
+
+ if (entry.flags.type == QPaintBufferCacheEntryV2::ImageKey)
+ variants[i] = QVariant(images.value(entry.flags.key));
+ else if (entry.flags.type == QPaintBufferCacheEntryV2::PixmapKey)
+ variants[i] = QVariant(pixmaps.value(entry.flags.key));
+ else
+ qWarning() << "operator<<(QDataStream &stream, QPaintBuffer &buffer): unrecognized cache entry type:" << entry.flags.type;
}
}
diff --git a/src/gui/painting/qpaintbuffer_p.h b/src/gui/painting/qpaintbuffer_p.h
index 79d7b35..0fde290 100644
--- a/src/gui/painting/qpaintbuffer_p.h
+++ b/src/gui/painting/qpaintbuffer_p.h
@@ -183,6 +183,10 @@ public:
Cmd_DrawTiledPixmap,
Cmd_SystemStateChanged,
+ Cmd_Translate,
+ Cmd_DrawStaticText,
+
+ // new commands must be added above this line
Cmd_LastCommand
};
@@ -394,6 +398,7 @@ public:
virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s);
virtual void drawTextItem(const QPointF &pos, const QTextItem &ti);
+ virtual void drawStaticTextItem(QStaticTextItem *staticTextItem);
virtual void setState(QPainterState *s);
virtual uint flags() const {return QPaintEngineEx::DoNotEmulate;}
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index bc56ed0..60265c5 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -67,6 +67,7 @@
// #include <private/qpolygonclipper_p.h>
// #include <private/qrasterizer_p.h>
#include <private/qimage_p.h>
+#include <private/qstatictext_p.h>
#include "qpaintengine_raster_p.h"
// #include "qbezier_p.h"
@@ -100,10 +101,6 @@
#endif
#include <limits.h>
-#if defined(QT_NO_FPU) || (_MSC_VER >= 1300 && _MSC_VER < 1400)
-# define FLOATING_POINT_BUGGY_OR_NO_FPU
-#endif
-
QT_BEGIN_NAMESPACE
extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
@@ -3006,27 +3003,22 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx
blend(current, spans, &s->penData);
}
-void QRasterPaintEngine::drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti)
+void QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
+ const QFixedPoint *positions, QFontEngine *fontEngine)
{
Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
- QVarLengthArray<QFixedPoint> positions;
- QVarLengthArray<glyph_t> glyphs;
- QTransform matrix = s->matrix;
- matrix.translate(p.x(), p.y());
- ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
-
- QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) : d->glyphCacheType;
+ QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType;
QImageTextureGlyphCache *cache =
- (QImageTextureGlyphCache *) ti.fontEngine->glyphCache(0, glyphType, s->matrix);
+ static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix));
if (!cache) {
cache = new QImageTextureGlyphCache(glyphType, s->matrix);
- ti.fontEngine->setGlyphCache(0, cache);
+ fontEngine->setGlyphCache(0, cache);
}
- cache->populate(ti, glyphs, positions);
+ cache->populate(fontEngine, numGlyphs, glyphs, positions);
const QImage &image = cache->image();
int bpl = image.bytesPerLine();
@@ -3044,7 +3036,7 @@ void QRasterPaintEngine::drawCachedGlyphs(const QPointF &p, const QTextItemInt &
const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
const uchar *bits = image.bits();
- for (int i=0; i<glyphs.size(); ++i) {
+ for (int i=0; i<numGlyphs; ++i) {
const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]);
int x = qFloor(positions[i].x + offs) + c.baseLineX - margin;
int y = qFloor(positions[i].y + offs) - c.baseLineY - margin;
@@ -3221,6 +3213,15 @@ QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
}
+void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
+{
+ ensurePen();
+ ensureState();
+
+ drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
+ textItem->fontEngine);
+}
+
/*!
\reimp
*/
@@ -3269,7 +3270,17 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
drawCached = false;
#endif
if (drawCached) {
- drawCachedGlyphs(p, ti);
+ QRasterPaintEngineState *s = state();
+
+ QVarLengthArray<QFixedPoint> positions;
+ QVarLengthArray<glyph_t> glyphs;
+
+ QTransform matrix = s->matrix;
+ matrix.translate(p.x(), p.y());
+
+ ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
+
+ drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
return;
}
@@ -3679,9 +3690,6 @@ void QRasterPaintEngine::drawEllipse(const QRectF &rect)
if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
|| (qpen_style(s->lastPen) == Qt::NoPen && !s->flags.antialiased))
&& qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
-#ifdef FLOATING_POINT_BUGGY_OR_NO_FPU
- && qMax(rect.width(), rect.height()) < 128 // integer math breakdown
-#endif
&& s->matrix.type() <= QTransform::TxScale) // no shear
{
ensureBrush();
@@ -6054,15 +6062,9 @@ static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
ProcessSpans pen_func, ProcessSpans brush_func,
QSpanData *pen_data, QSpanData *brush_data)
{
-#ifdef FLOATING_POINT_BUGGY_OR_NO_FPU // no fpu, so use fixed point
- const QFixed a = QFixed(rect.width()) >> 1;
- const QFixed b = QFixed(rect.height()) >> 1;
- QFixed d = b*b - (a*a*b) + ((a*a) >> 2);
-#else
const qreal a = qreal(rect.width()) / 2;
const qreal b = qreal(rect.height()) / 2;
qreal d = b*b - (a*a*b) + 0.25*a*a;
-#endif
int x = 0;
int y = (rect.height() + 1) / 2;
@@ -6085,12 +6087,7 @@ static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
pen_func, brush_func, pen_data, brush_data);
// region 2
-#ifdef FLOATING_POINT_BUGGY_OR_NO_FPU
- d = b*b*(x + (QFixed(1) >> 1))*(x + (QFixed(1) >> 1))
- + a*a*((y - 1)*(y - 1) - b*b);
-#else
d = b*b*(x + 0.5)*(x + 0.5) + a*a*((y - 1)*(y - 1) - b*b);
-#endif
const int miny = rect.height() & 0x1;
while (y > miny) {
if (d < 0) { // select SE
diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h
index a1c73cc..55eb82e 100644
--- a/src/gui/painting/qpaintengine_raster_p.h
+++ b/src/gui/painting/qpaintengine_raster_p.h
@@ -203,6 +203,8 @@ public:
void clip(const QRect &rect, Qt::ClipOperation op);
void clip(const QRegion &region, Qt::ClipOperation op);
+ void drawStaticTextItem(QStaticTextItem *textItem);
+
enum ClipType {
RectClip,
ComplexClip
@@ -257,7 +259,8 @@ private:
void fillRect(const QRectF &rect, QSpanData *data);
void drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fill);
- void drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti);
+ void drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions,
+ QFontEngine *fontEngine);
#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
void drawGlyphsS60(const QPointF &p, const QTextItemInt &ti);
diff --git a/src/gui/painting/qpaintengine_x11.cpp b/src/gui/painting/qpaintengine_x11.cpp
index 147491e..da48fcb 100644
--- a/src/gui/painting/qpaintengine_x11.cpp
+++ b/src/gui/painting/qpaintengine_x11.cpp
@@ -1989,6 +1989,9 @@ void QX11PaintEngine::drawPixmap(const QRectF &r, const QPixmap &px, const QRect
}
XFillRectangle(d->dpy, d->hd, d->gc, x, y, sw, sh);
restore_clip = true;
+ } else if (mono_dst && !mono_src) {
+ QBitmap bitmap(pixmap);
+ XCopyArea(d->dpy, bitmap.handle(), d->hd, d->gc, sx, sy, sw, sh, x, y);
} else {
XCopyArea(d->dpy, pixmap.handle(), d->hd, d->gc, sx, sy, sw, sh, x, y);
}
diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h
index fccd1dc..90c4f9f 100644
--- a/src/gui/painting/qpaintengineex_p.h
+++ b/src/gui/painting/qpaintengineex_p.h
@@ -70,6 +70,7 @@ QT_MODULE(Gui)
class QPainterState;
class QPaintEngineExPrivate;
+class QStaticTextItem;
struct StrokeHandler;
struct QIntRect {
@@ -200,6 +201,8 @@ public:
virtual void updateState(const QPaintEngineState &state);
+ virtual void drawStaticTextItem(QStaticTextItem *) = 0;
+
virtual void setState(QPainterState *s);
inline QPainterState *state() { return static_cast<QPainterState *>(QPaintEngine::state); }
inline const QPainterState *state() const { return static_cast<const QPainterState *>(QPaintEngine::state); }
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index cde6a2d..e69512d 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -69,6 +69,8 @@
#include <private/qwidget_p.h>
#include <private/qpaintengine_raster_p.h>
#include <private/qmath_p.h>
+#include <qstatictext.h>
+#include <private/qstatictext_p.h>
QT_BEGIN_NAMESPACE
@@ -708,13 +710,14 @@ void QPainterPrivate::updateEmulationSpecifier(QPainterState *s)
bool penTextureAlpha = false;
if (penBrush.style() == Qt::TexturePattern)
penTextureAlpha = qHasPixmapTexture(penBrush)
- ? penBrush.texture().hasAlpha()
+ ? (penBrush.texture().depth() > 1) && penBrush.texture().hasAlpha()
: penBrush.textureImage().hasAlphaChannel();
bool brushTextureAlpha = false;
- if (s->brush.style() == Qt::TexturePattern)
+ if (s->brush.style() == Qt::TexturePattern) {
brushTextureAlpha = qHasPixmapTexture(s->brush)
- ? s->brush.texture().hasAlpha()
+ ? (s->brush.texture().depth() > 1) && s->brush.texture().hasAlpha()
: s->brush.textureImage().hasAlphaChannel();
+ }
if (((penBrush.style() == Qt::TexturePattern && penTextureAlpha)
|| (s->brush.style() == Qt::TexturePattern && brushTextureAlpha))
&& !engine->hasFeature(QPaintEngine::MaskedBrush))
@@ -1986,12 +1989,25 @@ QPaintEngine *QPainter::paintEngine() const
endNativePainting().
Note that only the states the underlying paint engine changes will be reset
- to their respective default states. If, for example, the OpenGL polygon
- mode is changed by the user inside a beginNativePaint()/endNativePainting()
- block, it will not be reset to the default state by endNativePainting().
+ to their respective default states. The states we reset may change from
+ release to release. The following states are currently reset in the OpenGL
+ 2 engine:
+
+ \list
+ \i blending is disabled
+ \i the depth, stencil and scissor tests are disabled
+ \i the active texture unit is reset to 0
+ \i the depth mask, depth function and the clear depth are reset to their
+ default values
+ \i the stencil mask, stencil operation and stencil function are reset to
+ their default values
+ \i the current color is reset to solid white
+ \endlist
- Here is an example that shows intermixing of painter commands
- and raw OpenGL commands:
+ If, for example, the OpenGL polygon mode is changed by the user inside a
+ beginNativePaint()/endNativePainting() block, it will not be reset to the
+ default state by endNativePainting(). Here is an example that shows
+ intermixing of painter commands and raw OpenGL commands:
\snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 21
@@ -5684,6 +5700,23 @@ void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QR
}
/*!
+
+ \fn void QPainter::drawStaticText(const QPoint &position, const QStaticText &staticText)
+
+ \since 4.7
+
+ \overload
+*/
+
+/*!
+ \fn void QPainter::drawStaticText(int x, int y, const QStaticText &staticText)
+
+ \since 4.7
+
+ \overload
+*/
+
+/*!
\fn void QPainter::drawText(const QPointF &position, const QString &text)
Draws the given \a text with the currently defined text direction,
@@ -5706,6 +5739,124 @@ void QPainter::drawText(const QPointF &p, const QString &str)
}
/*!
+ \since 4.7
+
+ Draws the given \a staticText at the given \a position.
+
+ The text will be drawn using the font and the transformation set on the painter. If the
+ font and/or transformation set on the painter are different from the ones used to initialize
+ the layout of the QStaticText, then the layout will have to be recalculated. Use
+ QStaticText::prepare() to initialize \a staticText with the font and transformation with which
+ it will later be drawn.
+
+ If \a position is not the same as when \a staticText was initialized, or when it was last drawn,
+ then there will be a slight overhead when translating the text to its new position.
+
+ \note If the painter's transformation is not affine, then \a staticText will be drawn using regular
+ calls to drawText(), losing any potential performance improvement.
+
+ \sa QStaticText
+*/
+void QPainter::drawStaticText(const QPointF &position, const QStaticText &staticText)
+{
+ Q_D(QPainter);
+ if (!d->engine || staticText.text().isEmpty() || pen().style() == Qt::NoPen)
+ return;
+
+ QStaticTextPrivate *staticText_d =
+ const_cast<QStaticTextPrivate *>(QStaticTextPrivate::get(&staticText));
+
+ // If we don't have an extended paint engine, or if the painter is projected,
+ // we go through standard code path
+ if (d->extended == 0 || !d->state->matrix.isAffine()) {
+ staticText_d->paintText(position, this);
+ return;
+ }
+
+ // Don't recalculate entire layout because of translation, rather add the dx and dy
+ // into the position to move each text item the correct distance.
+ QPointF transformedPosition = position * d->state->matrix;
+ QTransform matrix = d->state->matrix;
+
+ // The translation has been applied to transformedPosition. Remove translation
+ // component from matrix.
+ if (d->state->matrix.isTranslating()) {
+ qreal m11 = d->state->matrix.m11();
+ qreal m12 = d->state->matrix.m12();
+ qreal m13 = d->state->matrix.m13();
+ qreal m21 = d->state->matrix.m21();
+ qreal m22 = d->state->matrix.m22();
+ qreal m23 = d->state->matrix.m23();
+ qreal m33 = d->state->matrix.m33();
+
+ d->state->matrix.setMatrix(m11, m12, m13,
+ m21, m22, m23,
+ 0.0, 0.0, m33);
+ }
+
+ // If the transform is not identical to the text transform,
+ // we have to relayout the text (for other transformations than plain translation)
+ bool staticTextNeedsReinit = false;
+ if (staticText_d->matrix != d->state->matrix) {
+ staticText_d->matrix = d->state->matrix;
+ staticTextNeedsReinit = true;
+ }
+
+ bool restoreWhenFinished = false;
+ if (staticText_d->needsClipRect) {
+ save();
+ setClipRect(QRectF(position, staticText_d->maximumSize));
+
+ restoreWhenFinished = true;
+ }
+
+ if (font() != staticText_d->font) {
+ staticText_d->font = font();
+ staticTextNeedsReinit = true;
+ }
+
+ // Recreate the layout of the static text because the matrix or font has changed
+ if (staticTextNeedsReinit)
+ staticText_d->init();
+
+ if (transformedPosition != staticText_d->position) { // Translate to actual position
+ QFixed fx = QFixed::fromReal(transformedPosition.x());
+ QFixed fy = QFixed::fromReal(transformedPosition.y());
+ QFixed oldX = QFixed::fromReal(staticText_d->position.x());
+ QFixed oldY = QFixed::fromReal(staticText_d->position.y());
+ for (int item=0; item<staticText_d->itemCount;++item) {
+ QStaticTextItem *textItem = staticText_d->items + item;
+ for (int i=0; i<textItem->numGlyphs; ++i) {
+ textItem->glyphPositions[i].x += fx - oldX;
+ textItem->glyphPositions[i].y += fy - oldY;
+ }
+ textItem->userDataNeedsUpdate = true;
+ }
+
+ staticText_d->position = transformedPosition;
+ }
+
+ QPen oldPen = d->state->pen;
+ QColor currentColor = oldPen.color();
+ for (int i=0; i<staticText_d->itemCount; ++i) {
+ QStaticTextItem *item = staticText_d->items + i;
+ if (currentColor != item->color) {
+ setPen(item->color);
+ currentColor = item->color;
+ }
+ d->extended->drawStaticTextItem(item);
+ }
+ if (currentColor != oldPen.color())
+ setPen(oldPen);
+
+ if (restoreWhenFinished)
+ restore();
+
+ if (matrix.isTranslating())
+ d->state->matrix = matrix;
+}
+
+/*!
\internal
*/
void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justificationPadding)
@@ -7509,7 +7660,7 @@ QPaintDevice *QPainter::redirected(const QPaintDevice *device, QPoint *offset)
return widgetPrivate->redirected(offset);
}
- if (*globalRedirectionAtomic() == 0)
+ if (!globalRedirectionAtomic() || *globalRedirectionAtomic() == 0)
return 0;
QMutexLocker locker(globalRedirectionsMutex());
@@ -7529,7 +7680,7 @@ QPaintDevice *QPainter::redirected(const QPaintDevice *device, QPoint *offset)
void qt_painter_removePaintDevice(QPaintDevice *dev)
{
- if (*globalRedirectionAtomic() == 0)
+ if (!globalRedirectionAtomic() || *globalRedirectionAtomic() == 0)
return;
QMutex *mutex = 0;
diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h
index ffddcba..e9fd532 100644
--- a/src/gui/painting/qpainter.h
+++ b/src/gui/painting/qpainter.h
@@ -78,6 +78,7 @@ class QPolygon;
class QTextItem;
class QMatrix;
class QTransform;
+class QStaticText;
class QPainterPrivateDeleter;
@@ -369,6 +370,10 @@ public:
void setLayoutDirection(Qt::LayoutDirection direction);
Qt::LayoutDirection layoutDirection() const;
+ void drawStaticText(const QPointF &p, const QStaticText &staticText);
+ inline void drawStaticText(const QPoint &p, const QStaticText &staticText);
+ inline void drawStaticText(int x, int y, const QStaticText &staticText);
+
void drawText(const QPointF &p, const QString &s);
inline void drawText(const QPoint &p, const QString &s);
inline void drawText(int x, int y, const QString &s);
@@ -896,6 +901,16 @@ inline void QPainter::drawImage(int x, int y, const QImage &image, int sx, int s
drawImage(QRectF(x, y, -1, -1), image, QRectF(sx, sy, sw, sh), flags);
}
+inline void QPainter::drawStaticText(const QPoint &p, const QStaticText &staticText)
+{
+ drawStaticText(QPointF(p), staticText);
+}
+
+inline void QPainter::drawStaticText(int x, int y, const QStaticText &staticText)
+{
+ drawStaticText(QPointF(x, y), staticText);
+}
+
inline void QPainter::drawTextItem(const QPoint &p, const QTextItem &ti)
{
drawTextItem(QPointF(p), ti);
diff --git a/src/gui/painting/qpathclipper.cpp b/src/gui/painting/qpathclipper.cpp
index 7997e77..949a820 100644
--- a/src/gui/painting/qpathclipper.cpp
+++ b/src/gui/painting/qpathclipper.cpp
@@ -90,8 +90,6 @@ static QPointF normalize(const QPointF &p)
return p / qSqrt(p.x() * p.x() + p.y() * p.y());
}
-static bool pathToRect(const QPainterPath &path, QRectF *rect = 0);
-
struct QIntersection
{
qreal alphaA;
@@ -1660,7 +1658,7 @@ static bool fuzzyCompare(qreal a, qreal b)
return qFuzzyCompare(a, b);
}
-static bool pathToRect(const QPainterPath &path, QRectF *rect)
+bool QPathClipper::pathToRect(const QPainterPath &path, QRectF *rect)
{
if (path.elementCount() != 5)
return false;
@@ -1693,7 +1691,7 @@ static bool pathToRect(const QPainterPath &path, QRectF *rect)
return false;
if (rect)
- *rect = QRectF(QPointF(x1, y1), QPointF(x2, y2));
+ rect->setCoords(x1, y1, x2, y2);
return true;
}
@@ -1707,6 +1705,9 @@ QPainterPath QPathClipper::clip(Operation operation)
if (subjectPath == clipPath)
return op == BoolSub ? QPainterPath() : subjectPath;
+ bool subjectIsRect = pathToRect(subjectPath, 0);
+ bool clipIsRect = pathToRect(clipPath, 0);
+
const QRectF clipBounds = clipPath.boundingRect();
const QRectF subjectBounds = subjectPath.boundingRect();
@@ -1734,8 +1735,7 @@ QPainterPath QPathClipper::clip(Operation operation)
}
if (clipBounds.contains(subjectBounds)) {
- QRectF clipRect;
- if (pathToRect(clipPath, &clipRect) && clipRect.contains(subjectBounds)) {
+ if (clipIsRect) {
switch (op) {
case BoolSub:
return QPainterPath();
@@ -1748,17 +1748,16 @@ QPainterPath QPathClipper::clip(Operation operation)
}
}
} else if (subjectBounds.contains(clipBounds)) {
- QRectF subjectRect;
- if (pathToRect(subjectPath, &subjectRect) && subjectRect.contains(clipBounds)) {
+ if (subjectIsRect) {
switch (op) {
case BoolSub:
if (clipPath.fillRule() == Qt::OddEvenFill) {
QPainterPath result = clipPath;
- result.addRect(subjectRect);
+ result.addRect(subjectBounds);
return result;
} else {
QPainterPath result = clipPath.simplified();
- result.addRect(subjectRect);
+ result.addRect(subjectBounds);
return result;
}
break;
@@ -1771,6 +1770,13 @@ QPainterPath QPathClipper::clip(Operation operation)
}
}
}
+
+ if (op == BoolAnd) {
+ if (subjectIsRect)
+ return intersect(clipPath, subjectBounds);
+ else if (clipIsRect)
+ return intersect(subjectPath, clipBounds);
+ }
}
QWingedEdge list(subjectPath, clipPath);
@@ -2054,4 +2060,243 @@ bool QPathClipper::handleCrossingEdges(QWingedEdge &list, qreal y, ClipperMode m
return false;
}
+namespace {
+
+QList<QPainterPath> toSubpaths(const QPainterPath &path)
+{
+
+ QList<QPainterPath> subpaths;
+ if (path.isEmpty())
+ return subpaths;
+
+ QPainterPath current;
+ for (int i = 0; i < path.elementCount(); ++i) {
+ const QPainterPath::Element &e = path.elementAt(i);
+ switch (e.type) {
+ case QPainterPath::MoveToElement:
+ if (current.elementCount() > 1)
+ subpaths += current;
+ current = QPainterPath();
+ current.moveTo(e);
+ break;
+ case QPainterPath::LineToElement:
+ current.lineTo(e);
+ break;
+ case QPainterPath::CurveToElement: {
+ current.cubicTo(e, path.elementAt(i + 1), path.elementAt(i + 2));
+ i+=2;
+ break;
+ }
+ case QPainterPath::CurveToDataElement:
+ Q_ASSERT(!"toSubpaths(), bad element type");
+ break;
+ }
+ }
+
+ if (current.elementCount() > 1)
+ subpaths << current;
+
+ return subpaths;
+}
+
+enum Edge
+{
+ Left, Top, Right, Bottom
+};
+
+static bool isVertical(Edge edge)
+{
+ return edge == Left || edge == Right;
+}
+
+template <Edge edge>
+bool compare(const QPointF &p, qreal t)
+{
+ switch (edge)
+ {
+ case Left:
+ return p.x() < t;
+ case Right:
+ return p.x() > t;
+ case Top:
+ return p.y() < t;
+ default:
+ return p.y() > t;
+ }
+}
+
+template <Edge edge>
+QPointF intersectLine(const QPointF &a, const QPointF &b, qreal t)
+{
+ QLineF line(a, b);
+ switch (edge) {
+ case Left: // fall-through
+ case Right:
+ return line.pointAt((t - a.x()) / (b.x() - a.x()));
+ default:
+ return line.pointAt((t - a.y()) / (b.y() - a.y()));
+ }
+}
+
+void addLine(QPainterPath &path, const QLineF &line)
+{
+ if (path.elementCount() > 0)
+ path.lineTo(line.p1());
+ else
+ path.moveTo(line.p1());
+
+ path.lineTo(line.p2());
+}
+
+template <Edge edge>
+void clipLine(const QPointF &a, const QPointF &b, qreal t, QPainterPath &result)
+{
+ bool outA = compare<edge>(a, t);
+ bool outB = compare<edge>(b, t);
+ if (outA && outB)
+ return;
+
+ if (outA)
+ addLine(result, QLineF(intersectLine<edge>(a, b, t), b));
+ else if(outB)
+ addLine(result, QLineF(a, intersectLine<edge>(a, b, t)));
+ else
+ addLine(result, QLineF(a, b));
+}
+
+void addBezier(QPainterPath &path, const QBezier &bezier)
+{
+ if (path.elementCount() > 0)
+ path.lineTo(bezier.pt1());
+ else
+ path.moveTo(bezier.pt1());
+
+ path.cubicTo(bezier.pt2(), bezier.pt3(), bezier.pt4());
+}
+
+template <Edge edge>
+void clipBezier(const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d, qreal t, QPainterPath &result)
+{
+ QBezier bezier = QBezier::fromPoints(a, b, c, d);
+
+ bool outA = compare<edge>(a, t);
+ bool outB = compare<edge>(b, t);
+ bool outC = compare<edge>(c, t);
+ bool outD = compare<edge>(d, t);
+
+ int outCount = int(outA) + int(outB) + int(outC) + int(outD);
+
+ if (outCount == 4)
+ return;
+
+ if (outCount == 0) {
+ addBezier(result, bezier);
+ return;
+ }
+
+ QTransform flip = isVertical(edge) ? QTransform(0, 1, 1, 0, 0, 0) : QTransform();
+ QBezier unflipped = bezier;
+ QBezier flipped = bezier.mapBy(flip);
+
+ qreal t0 = 0, t1 = 1;
+ int stationary = flipped.stationaryYPoints(t0, t1);
+
+ qreal segments[4];
+ QPointF points[4];
+ points[0] = unflipped.pt1();
+ segments[0] = 0;
+
+ int segmentCount = 0;
+ if (stationary > 0) {
+ ++segmentCount;
+ segments[segmentCount] = t0;
+ points[segmentCount] = unflipped.pointAt(t0);
+ }
+ if (stationary > 1) {
+ ++segmentCount;
+ segments[segmentCount] = t1;
+ points[segmentCount] = unflipped.pointAt(t1);
+ }
+ ++segmentCount;
+ segments[segmentCount] = 1;
+ points[segmentCount] = unflipped.pt4();
+
+ qreal lastIntersection = 0;
+ for (int i = 0; i < segmentCount; ++i) {
+ outA = compare<edge>(points[i], t);
+ outB = compare<edge>(points[i+1], t);
+
+ if (outA != outB) {
+ qreal intersection = flipped.tForY(segments[i], segments[i+1], t);
+
+ if (outB)
+ addBezier(result, unflipped.getSubRange(lastIntersection, intersection));
+
+ lastIntersection = intersection;
+ }
+ }
+
+ if (!outB)
+ addBezier(result, unflipped.getSubRange(lastIntersection, 1));
+}
+
+// clips a single subpath against a single edge
+template <Edge edge>
+QPainterPath clip(const QPainterPath &path, qreal t)
+{
+ QPainterPath result;
+ for (int i = 1; i < path.elementCount(); ++i) {
+ const QPainterPath::Element &element = path.elementAt(i);
+ Q_ASSERT(!element.isMoveTo());
+ if (element.isLineTo()) {
+ clipLine<edge>(path.elementAt(i-1), path.elementAt(i), t, result);
+ } else {
+ clipBezier<edge>(path.elementAt(i-1), path.elementAt(i), path.elementAt(i+1), path.elementAt(i+2), t, result);
+ i += 2;
+ }
+ }
+
+ int last = path.elementCount() - 1;
+ if (QPointF(path.elementAt(last)) != QPointF(path.elementAt(0)))
+ clipLine<edge>(path.elementAt(last), path.elementAt(0), t, result);
+
+ return result;
+}
+
+QPainterPath intersectPath(const QPainterPath &path, const QRectF &rect)
+{
+ QList<QPainterPath> subpaths = toSubpaths(path);
+
+ QPainterPath result;
+ result.setFillRule(path.fillRule());
+ for (int i = 0; i < subpaths.size(); ++i) {
+ QPainterPath subPath = subpaths.at(i);
+ QRectF bounds = subPath.boundingRect();
+ if (bounds.intersects(rect)) {
+ if (bounds.left() < rect.left())
+ subPath = clip<Left>(subPath, rect.left());
+ if (bounds.right() > rect.right())
+ subPath = clip<Right>(subPath, rect.right());
+
+ bounds = subPath.boundingRect();
+
+ if (bounds.top() < rect.top())
+ subPath = clip<Top>(subPath, rect.top());
+ if (bounds.bottom() > rect.bottom())
+ subPath = clip<Bottom>(subPath, rect.bottom());
+
+ if (subPath.elementCount() > 1)
+ result.addPath(subPath);
+ }
+ }
+ return result;
+}
+
+}
+
+QPainterPath QPathClipper::intersect(const QPainterPath &path, const QRectF &rect)
+{
+ return intersectPath(path, rect);
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpathclipper_p.h b/src/gui/painting/qpathclipper_p.h
index 0d2c049..b42dc1d 100644
--- a/src/gui/painting/qpathclipper_p.h
+++ b/src/gui/painting/qpathclipper_p.h
@@ -86,6 +86,9 @@ public:
bool intersect();
bool contains();
+ static bool pathToRect(const QPainterPath &path, QRectF *rect = 0);
+ static QPainterPath intersect(const QPainterPath &path, const QRectF &rect);
+
private:
Q_DISABLE_COPY(QPathClipper)
diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp
index dd516b1..dcf745f 100644
--- a/src/gui/painting/qpdf.cpp
+++ b/src/gui/painting/qpdf.cpp
@@ -1415,6 +1415,7 @@ void QPdfBaseEngine::setProperty(PrintEnginePropertyKey key, const QVariant &val
case PPK_FullPage:
d->fullPage = value.toBool();
break;
+ case PPK_CopyCount: // fallthrough
case PPK_NumberOfCopies:
d->copies = value.toInt();
break;
@@ -1504,6 +1505,17 @@ QVariant QPdfBaseEngine::property(PrintEnginePropertyKey key) const
case PPK_FullPage:
ret = d->fullPage;
break;
+ case PPK_CopyCount:
+ ret = d->copies;
+ break;
+ case PPK_SupportsMultipleCopies:
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ if (QCUPSSupport::isAvailable())
+ ret = true;
+ else
+#endif
+ ret = false;
+ break;
case PPK_NumberOfCopies:
#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
if (QCUPSSupport::isAvailable())
diff --git a/src/gui/painting/qpdf_p.h b/src/gui/painting/qpdf_p.h
index f79c5cc..9c4d05d 100644
--- a/src/gui/painting/qpdf_p.h
+++ b/src/gui/painting/qpdf_p.h
@@ -216,8 +216,6 @@ public:
private:
void updateClipPath(const QPainterPath & path, Qt::ClipOperation op);
-
- friend int qt_printerRealNumCopies(QPaintEngine *);
};
class QPdfBaseEnginePrivate : public QAlphaPaintEnginePrivate
diff --git a/src/gui/painting/qprintengine.h b/src/gui/painting/qprintengine.h
index 35715fb..71ff954 100644
--- a/src/gui/painting/qprintengine.h
+++ b/src/gui/painting/qprintengine.h
@@ -86,6 +86,8 @@ public:
PPK_PaperSources,
PPK_CustomPaperSize,
PPK_PageMargins,
+ PPK_CopyCount,
+ PPK_SupportsMultipleCopies,
PPK_PaperSize = PPK_PageSize,
PPK_CustomBase = 0xff00
diff --git a/src/gui/painting/qprintengine_mac.mm b/src/gui/painting/qprintengine_mac.mm
index 7195c63..3d5d1d5 100644
--- a/src/gui/painting/qprintengine_mac.mm
+++ b/src/gui/painting/qprintengine_mac.mm
@@ -685,6 +685,7 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
case PPK_FullPage:
d->fullPage = value.toBool();
break;
+ case PPK_CopyCount: // fallthrough
case PPK_NumberOfCopies:
PMSetCopies(d->settings, value.toInt(), false);
break;
@@ -787,6 +788,15 @@ QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const
case PPK_NumberOfCopies:
ret = 1;
break;
+ case PPK_CopyCount: {
+ UInt32 copies = 1;
+ PMGetCopies(d->settings, &copies);
+ ret = (uint) copies;
+ break;
+ }
+ case PPK_SupportsMultipleCopies:
+ ret = true;
+ break;
case PPK_Orientation:
PMOrientation orientation;
PMGetOrientation(d->format, &orientation);
diff --git a/src/gui/painting/qprintengine_qws.cpp b/src/gui/painting/qprintengine_qws.cpp
index 2d355b8..396d712 100644
--- a/src/gui/painting/qprintengine_qws.cpp
+++ b/src/gui/painting/qprintengine_qws.cpp
@@ -268,9 +268,13 @@ QVariant QtopiaPrintEngine::property(PrintEnginePropertyKey key) const
case PPK_FullPage:
ret = d->fullPage;
break;
+ case PPK_CopyCount: // fallthrough
case PPK_NumberOfCopies:
ret = d->numCopies;
break;
+ case PPK_SupportsMultipleCopies:
+ ret = false;
+ break;
case PPK_Orientation:
ret = d->orientation;
break;
@@ -329,6 +333,7 @@ void QtopiaPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
case PPK_FullPage:
d->fullPage = value.toBool();
break;
+ case PPK_CopyCount: // fallthrough
case PPK_NumberOfCopies:
d->numCopies = value.toInt();
break;
diff --git a/src/gui/painting/qprintengine_win.cpp b/src/gui/painting/qprintengine_win.cpp
index 374bfa0..d029b1e 100644
--- a/src/gui/painting/qprintengine_win.cpp
+++ b/src/gui/painting/qprintengine_win.cpp
@@ -1240,6 +1240,7 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
d->updateOrigin();
break;
+ case PPK_CopyCount: // fallthrough
case PPK_NumberOfCopies:
if (!d->devMode)
break;
@@ -1406,6 +1407,14 @@ QVariant QWin32PrintEngine::property(PrintEnginePropertyKey key) const
value = d->fullPage;
break;
+ case PPK_CopyCount:
+ value = d->num_copies;
+ break;
+
+ case PPK_SupportsMultipleCopies:
+ value = true;
+ break;
+
case PPK_NumberOfCopies:
value = 1;
break;
diff --git a/src/gui/painting/qprintengine_win_p.h b/src/gui/painting/qprintengine_win_p.h
index a3271cb..d435831 100644
--- a/src/gui/painting/qprintengine_win_p.h
+++ b/src/gui/painting/qprintengine_win_p.h
@@ -108,7 +108,6 @@ public:
private:
friend class QPrintDialog;
friend class QPageSetupDialog;
- friend int qt_printerRealNumCopies(QPaintEngine *);
};
class QWin32PrintEnginePrivate : public QAlphaPaintEnginePrivate
diff --git a/src/gui/painting/qprinter.cpp b/src/gui/painting/qprinter.cpp
index 4d2b50a..edf224d 100644
--- a/src/gui/painting/qprinter.cpp
+++ b/src/gui/painting/qprinter.cpp
@@ -158,27 +158,6 @@ QSizeF qt_printerPaperSize(QPrinter::Orientation orientation,
(qt_paperSizes[paperSize][height_index] * 72 / 25.4) / multiplier);
}
-
-// returns the actual num copies set on a printer, not
-// the number that is documented in QPrinter::numCopies()
-int qt_printerRealNumCopies(QPaintEngine *engine)
-{
- int numCopies = 1;
- if (engine->type() == QPaintEngine::PostScript
- || engine->type() == QPaintEngine::Pdf)
- {
- QPdfBaseEngine *base = static_cast<QPdfBaseEngine *>(engine);
- numCopies = base->d_func()->copies;
- }
-#ifdef Q_WS_WIN
- else if (engine->type() == QPaintEngine::Windows) {
- QWin32PrintEngine *base = static_cast<QWin32PrintEngine *>(engine);
- numCopies = base->d_func()->num_copies;
- }
-#endif
- return numCopies;
-}
-
void QPrinterPrivate::createDefaultEngines()
{
QPrinter::OutputFormat realOutputFormat = outputFormat;
@@ -302,7 +281,7 @@ void QPrinterPrivate::addToManualSetList(QPrintEngine::PrintEnginePropertyKey ke
printer to provide, in dots per inch (DPI).
\i setFullPage() tells QPrinter whether you want to deal with the
full page or just with the part the printer can draw on.
- \i setNumCopies() tells QPrinter how many copies of the document
+ \i setCopyCount() tells QPrinter how many copies of the document
it should print.
\endlist
@@ -748,7 +727,6 @@ void QPrinter::setOutputFormat(OutputFormat format)
d->outputFormat = format;
QPrintEngine *oldPrintEngine = d->printEngine;
- QPaintEngine *oldPaintEngine = d->paintEngine; // same as the above - shouldn't be deleted
const bool def_engine = d->use_default_engine;
d->printEngine = 0;
@@ -761,7 +739,7 @@ void QPrinter::setOutputFormat(OutputFormat format)
// PPK_NumberOfCopies need special treatmeant since it in most cases
// will return 1, disregarding the actual value that was set
if (key == QPrintEngine::PPK_NumberOfCopies)
- prop = QVariant(qt_printerRealNumCopies(oldPaintEngine));
+ prop = QVariant(copyCount());
else
prop = oldPrintEngine->property(key);
if (prop.isValid())
@@ -1263,6 +1241,7 @@ QPrinter::ColorMode QPrinter::colorMode() const
/*!
+ \obsolete
Returns the number of copies to be printed. The default value is 1.
On Windows, Mac OS X and X11 systems that support CUPS, this will always
@@ -1275,6 +1254,8 @@ QPrinter::ColorMode QPrinter::colorMode() const
buffering up the copies and in those cases the application must make an
explicit call to the print code for each copy.
+ Use copyCount() in conjunction with supportsMultipleCopies() instead.
+
\sa setNumCopies(), actualNumCopies()
*/
@@ -1286,6 +1267,7 @@ int QPrinter::numCopies() const
/*!
+ \obsolete
\since 4.6
Returns the number of copies that will be printed. The default
@@ -1294,22 +1276,26 @@ int QPrinter::numCopies() const
This function always returns the actual value specified in the print
dialog or using setNumCopies().
+ Use copyCount() instead.
+
\sa setNumCopies(), numCopies()
*/
int QPrinter::actualNumCopies() const
{
- Q_D(const QPrinter);
- return qt_printerRealNumCopies(d->paintEngine);
+ return copyCount();
}
/*!
+ \obsolete
Sets the number of copies to be printed to \a numCopies.
The printer driver reads this setting and prints the specified
number of copies.
+ Use setCopyCount() instead.
+
\sa numCopies()
*/
@@ -1321,6 +1307,58 @@ void QPrinter::setNumCopies(int numCopies)
d->addToManualSetList(QPrintEngine::PPK_NumberOfCopies);
}
+/*!
+ \since 4.7
+
+ Sets the number of copies to be printed to \a count.
+
+ The printer driver reads this setting and prints the specified number of
+ copies.
+
+ \sa copyCount(), supportsMultipleCopies()
+*/
+
+void QPrinter::setCopyCount(int count)
+{
+ Q_D(QPrinter);
+ ABORT_IF_ACTIVE("QPrinter::setCopyCount;");
+ d->printEngine->setProperty(QPrintEngine::PPK_CopyCount, count);
+ d->addToManualSetList(QPrintEngine::PPK_CopyCount);
+}
+
+/*!
+ \since 4.7
+
+ Returns the number of copies that will be printed. The default value is 1.
+
+ \sa setCopyCount(), supportsMultipleCopies()
+*/
+
+int QPrinter::copyCount() const
+{
+ Q_D(const QPrinter);
+ return d->printEngine->property(QPrintEngine::PPK_CopyCount).toInt();
+}
+
+/*!
+ \since 4.7
+
+ Returns true if the printer supports printing multiple copies of the same
+ document in one job; otherwise false is returned.
+
+ On most systems this function will return true. However, on X11 systems
+ that do not support CUPS, this function will return false. That means the
+ application has to handle the number of copies by printing the same
+ document the required number of times.
+
+ \sa setCopyCount(), copyCount()
+*/
+
+bool QPrinter::supportsMultipleCopies() const
+{
+ Q_D(const QPrinter);
+ return d->printEngine->property(QPrintEngine::PPK_SupportsMultipleCopies).toBool();
+}
/*!
\since 4.1
@@ -2262,8 +2300,8 @@ bool QPrinter::isOptionEnabled( PrinterOption option ) const
\value PPK_FullPage A boolean describing if the printer should be
full page or not.
- \value PPK_NumberOfCopies An integer specifying the number of
- copies
+ \value PPK_NumberOfCopies Obsolete. An integer specifying the number of
+ copies. Use PPK_CopyCount instead.
\value PPK_Orientation Specifies a QPrinter::Orientation value.
@@ -2310,6 +2348,11 @@ bool QPrinter::isOptionEnabled( PrinterOption option ) const
\value PPK_PageMargins A QList<QVariant> containing the left, top,
right and bottom margin values.
+ \value PPK_CopyCount An integer specifying the number of copies to print.
+
+ \value PPK_SupportsMultipleCopies A boolean value indicating whether or not
+ the printer supports printing multiple copies in one job.
+
\value PPK_CustomBase Basis for extension.
*/
diff --git a/src/gui/painting/qprinter.h b/src/gui/painting/qprinter.h
index 5aa891e..6636179 100644
--- a/src/gui/painting/qprinter.h
+++ b/src/gui/painting/qprinter.h
@@ -199,6 +199,10 @@ public:
int actualNumCopies() const;
+ void setCopyCount(int);
+ int copyCount() const;
+ bool supportsMultipleCopies() const;
+
void setPaperSource(PaperSource);
PaperSource paperSource() const;
diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp
index 7b7f325..cf3957b 100644
--- a/src/gui/painting/qtextureglyphcache.cpp
+++ b/src/gui/painting/qtextureglyphcache.cpp
@@ -55,29 +55,42 @@ QT_BEGIN_NAMESPACE
// #define CACHE_DEBUG
-void QTextureGlyphCache::populate(const QTextItemInt &ti,
- const QVarLengthArray<glyph_t> &glyphs,
- const QVarLengthArray<QFixedPoint> &)
+// returns the highest number closest to v, which is a power of 2
+// NB! assumes 32 bit ints
+int qt_next_power_of_two(int v)
+{
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ ++v;
+ return v;
+}
+
+void QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs,
+ const QFixedPoint *)
{
#ifdef CACHE_DEBUG
printf("Populating with '%s'\n", QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data());
qDebug() << " -> current transformation: " << m_transform;
#endif
- m_current_textitem = &ti;
+ m_current_fontengine = fontEngine;
const int margin = glyphMargin();
QHash<glyph_t, Coord> listItemCoordinates;
int rowHeight = 0;
// check each glyph for its metrics and get the required rowHeight.
- for (int i=0; i < glyphs.size(); ++i) {
+ for (int i=0; i < numGlyphs; ++i) {
const glyph_t glyph = glyphs[i];
if (coords.contains(glyph))
continue;
if (listItemCoordinates.contains(glyph))
continue;
- glyph_metrics_t metrics = ti.fontEngine->boundingBox(glyph, m_transform);
+ glyph_metrics_t metrics = fontEngine->boundingBox(glyph, m_transform);
#ifdef CACHE_DEBUG
printf("'%c' (%4x): w=%.2f, h=%.2f, xoff=%.2f, yoff=%.2f, x=%.2f, y=%.2f, ti.ascent=%.2f, ti.descent=%.2f\n",
@@ -116,7 +129,7 @@ void QTextureGlyphCache::populate(const QTextItemInt &ti,
rowHeight += margin * 2;
if (isNull())
- createCache(QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH, rowHeight);
+ createCache(QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH, qt_next_power_of_two(rowHeight));
// now actually use the coords and paint the wanted glyps into cache.
QHash<glyph_t, Coord>::iterator iter = listItemCoordinates.begin();
@@ -129,13 +142,9 @@ void QTextureGlyphCache::populate(const QTextItemInt &ti,
m_cy = m_h;
}
if (m_cy + c.h > m_h) {
- int new_height;
- if (m_cx == 0) { // add a whole row
- new_height = m_h + rowHeight;
- m_cy = m_h;
- } else { // just extend row
- new_height = m_cy + rowHeight;
- }
+ int new_height = m_h*2;
+ while (new_height < m_cy + c.h)
+ new_height *= 2;
// if no room in the current texture - realloc a larger texture
resizeTextureData(m_w, new_height);
m_h = new_height;
@@ -182,7 +191,7 @@ QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const
break;
};
- QFontEngineFT *ft = static_cast<QFontEngineFT*> (m_current_textitem->fontEngine);
+ QFontEngineFT *ft = static_cast<QFontEngineFT*> (m_current_fontengine);
QFontEngineFT::QGlyphSet *gset = ft->loadTransformedGlyphSet(m_transform);
if (gset && ft->loadGlyphs(gset, &g, 1, format)) {
@@ -194,9 +203,9 @@ QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const
} else
#endif
if (m_type == QFontEngineGlyphCache::Raster_RGBMask)
- return m_current_textitem->fontEngine->alphaRGBMapForGlyph(g, glyphMargin(), m_transform);
+ return m_current_fontengine->alphaRGBMapForGlyph(g, glyphMargin(), m_transform);
else
- return m_current_textitem->fontEngine->alphaMapForGlyph(g, m_transform);
+ return m_current_fontengine->alphaMapForGlyph(g, m_transform);
return QImage();
}
diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h
index d347e61..803e71b 100644
--- a/src/gui/painting/qtextureglyphcache_p.h
+++ b/src/gui/painting/qtextureglyphcache_p.h
@@ -76,7 +76,9 @@ class Q_GUI_EXPORT QTextureGlyphCache : public QFontEngineGlyphCache
{
public:
QTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix)
- : QFontEngineGlyphCache(matrix, type), m_w(0), m_h(0), m_cx(0), m_cy(0) { }
+ : QFontEngineGlyphCache(matrix, type), m_current_fontengine(0),
+ m_w(0), m_h(0), m_cx(0), m_cy(0)
+ { }
virtual ~QTextureGlyphCache() { }
@@ -90,9 +92,8 @@ public:
int baseLineY;
};
- void populate(const QTextItemInt &ti,
- const QVarLengthArray<glyph_t> &glyphs,
- const QVarLengthArray<QFixedPoint> &positions);
+ void populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs,
+ const QFixedPoint *positions);
virtual void createTextureData(int width, int height) = 0;
virtual void resizeTextureData(int width, int height) = 0;
@@ -113,7 +114,7 @@ public:
QImage textureMapForGlyph(glyph_t g) const;
protected:
- const QTextItemInt *m_current_textitem;
+ QFontEngine *m_current_fontengine;
int m_w; // image width
int m_h; // image height
diff --git a/src/gui/painting/qwindowsurface_raster.cpp b/src/gui/painting/qwindowsurface_raster.cpp
index a0d2b9b..eee6bef 100644
--- a/src/gui/painting/qwindowsurface_raster.cpp
+++ b/src/gui/painting/qwindowsurface_raster.cpp
@@ -295,10 +295,8 @@ void QRasterWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoi
CGContextRestoreGState(context);
#ifndef QT_MAC_USE_COCOA
QDEndCGContext(port, &context);
-#else
- CGContextFlush(context);
-#endif
#endif
+#endif // Q_WS_MAC
#ifdef Q_OS_SYMBIAN
Q_UNUSED(widget);
diff --git a/src/gui/painting/qwindowsurface_s60.cpp b/src/gui/painting/qwindowsurface_s60.cpp
index b41dc2c..028ec48 100644
--- a/src/gui/painting/qwindowsurface_s60.cpp
+++ b/src/gui/painting/qwindowsurface_s60.cpp
@@ -145,12 +145,23 @@ QImage* QS60WindowSurface::buffer(const QWidget *widget)
void QS60WindowSurface::flush(QWidget *widget, const QRegion &region, const QPoint &)
{
- QWExtra *extra = widget->d_func()->extraData();
- if (extra && !extra->inExpose) {
- extra->inExpose = true; // Prevent DrawNow() from calling syncBackingStore() again
- TRect tr = qt_QRect2TRect(region.boundingRect());
+ QWidget *window = widget->window();
+ Q_ASSERT(window);
+ QTLWExtra *topExtra = window->d_func()->maybeTopData();
+ Q_ASSERT(topExtra);
+ QRect qr = region.boundingRect();
+ if (!topExtra->inExpose) {
+ topExtra->inExpose = true; // Prevent DrawNow() from calling syncBackingStore() again
+ TRect tr = qt_QRect2TRect(qr);
widget->winId()->DrawNow(tr);
- extra->inExpose = false;
+ topExtra->inExpose = false;
+ } else {
+ // This handles the case when syncBackingStore updates content outside of the
+ // original drawing rectangle. This might happen if there are pending update()
+ // events at the same time as we get a Draw() from Symbian.
+ QRect drawRect = qt_TRect2QRect(widget->winId()->DrawableWindow()->GetDrawRect());
+ if (!drawRect.contains(qr))
+ widget->winId()->DrawDeferred();
}
}