diff -r dee5afe5301f -r 3f74d0d4af4c src/openvg/qpaintengine_vg.cpp --- a/src/openvg/qpaintengine_vg.cpp Mon Mar 15 12:43:09 2010 +0200 +++ b/src/openvg/qpaintengine_vg.cpp Thu Apr 08 14:19:33 2010 +0300 @@ -183,11 +183,13 @@ qreal penScale; // Pen scaling factor from "transform". QTransform pathTransform; // Calculated VG path transformation. + QTransform glyphTransform; // Calculated VG glyph transformation. QTransform imageTransform; // Calculated VG image transformation. bool pathTransformSet; // True if path transform set in the VG context. bool maskValid; // True if vgMask() contains valid data. bool maskIsSet; // True if mask would be fully set if it was valid. + bool scissorMask; // True if scissor is used in place of the mask. bool rawVG; // True if processing a raw VG escape. QRect maskRect; // Rectangle version of mask if it is simple. @@ -355,6 +357,7 @@ maskValid = false; maskIsSet = false; + scissorMask = false; rawVG = false; scissorActive = false; @@ -498,42 +501,49 @@ void QVGPaintEnginePrivate::updateTransform(QPaintDevice *pdev) { - VGfloat devh = pdev->height() - 1; + VGfloat devh = pdev->height(); // Construct the VG transform by combining the Qt transform with // the following viewport transformation: - // | 1 0 0 | | 1 0 0.5 | | 1 0 0.5 | - // | 0 -1 devh | * | 0 1 -0.5 | = | 0 -1 (0.5 + devh) | - // | 0 0 1 | | 0 0 1 | | 0 0 1 | + // | 1 0 0 | + // | 0 -1 devh | + // | 0 0 1 | + // The glyph transform uses a slightly different transformation: + // | 1 0 0 | | 1 0 0.5 | | 1 0 0.5 | + // | 0 -1 devh - 1 | * | 0 1 -0.5 | = | 0 -1 (devh - 0.5) | + // | 0 0 1 | | 0 0 1 | | 0 0 1 | // The full VG transform is effectively: // 1. Apply the user's transformation matrix. - // 2. Translate by (0.5, -0.5) to correct for Qt and VG putting - // the centre of the pixel at different positions. + // 2. Translate glyphs by an extra (0.5, -0.5). // 3. Flip the co-ordinate system upside down. QTransform viewport(1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, - 0.5f, devh + 0.5f, 1.0f); - - // The image transform is always the full transformation, - // because it can be projective. - imageTransform = transform * viewport; - - // Determine if the transformation is projective. - bool projective = (imageTransform.m13() != 0.0f || - imageTransform.m23() != 0.0f || - imageTransform.m33() != 1.0f); + 0.0f, devh, 1.0f); + QTransform gviewport(1.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.5f, devh - 0.5f, 1.0f); + + // Compute the path transform and determine if it is projective. + pathTransform = transform * viewport; + glyphTransform = transform * gviewport; + bool projective = (pathTransform.m13() != 0.0f || + pathTransform.m23() != 0.0f || + pathTransform.m33() != 1.0f); if (projective) { // The engine cannot do projective path transforms for us, // so we will have to convert the co-ordinates ourselves. // Change the matrix to just the viewport transformation. pathTransform = viewport; + glyphTransform = gviewport; simpleTransform = false; } else { - pathTransform = imageTransform; simpleTransform = true; } pathTransformSet = false; + // The image transform is always the full transformation, + imageTransform = transform * viewport; + // Calculate the scaling factor to use for turning cosmetic pens // into ordinary non-cosmetic pens. qt_scaleForTransform(transform, &penScale); @@ -1542,7 +1552,28 @@ static inline bool clipTransformIsSimple(const QTransform& transform) { QTransform::TransformationType type = transform.type(); - return (type == QTransform::TxNone || type == QTransform::TxTranslate); + if (type == QTransform::TxNone || type == QTransform::TxTranslate) + return true; + if (type == QTransform::TxRotate) { + // Check for 0, 90, 180, and 270 degree rotations. + // (0 might happen after 4 rotations of 90 degrees). + qreal m11 = transform.m11(); + qreal m12 = transform.m12(); + qreal m21 = transform.m21(); + qreal m22 = transform.m22(); + if (m11 == 0.0f && m22 == 0.0f) { + if (m12 == 1.0f && m21 == -1.0f) + return true; // 90 degrees. + else if (m12 == -1.0f && m21 == 1.0f) + return true; // 270 degrees. + } else if (m12 == 0.0f && m21 == 0.0f) { + if (m11 == -1.0f && m22 == -1.0f) + return true; // 180 degrees. + else if (m11 == 1.0f && m22 == 1.0f) + return true; // 0 degrees. + } + } + return false; } #if defined(QVG_SCISSOR_CLIP) @@ -1664,12 +1695,12 @@ if (op == Qt::NoClip) { d->maskValid = false; d->maskIsSet = true; + d->scissorMask = false; d->maskRect = QRect(); vgSeti(VG_MASKING, VG_FALSE); return; } -#if defined(QVG_NO_RENDER_TO_MASK) // We don't have vgRenderToMask(), so handle simple QRectF's only. if (path.shape() == QVectorPath::RectangleHint && path.elementCount() == 4 && clipTransformIsSimple(d->transform)) { @@ -1679,8 +1710,10 @@ QRectF rect(points[0], points[1], points[2] - points[0], points[5] - points[1]); clip(rect.toRect(), op); + return; } -#else + +#if !defined(QVG_NO_RENDER_TO_MASK) QPaintDevice *pdev = paintDevice(); int width = pdev->width(); int height = pdev->height(); @@ -1711,6 +1744,7 @@ vgSeti(VG_MASKING, VG_TRUE); d->maskValid = true; d->maskIsSet = false; + d->scissorMask = false; #endif } @@ -1731,6 +1765,7 @@ { d->maskValid = false; d->maskIsSet = true; + d->scissorMask = false; d->maskRect = QRect(); vgSeti(VG_MASKING, VG_FALSE); } @@ -1746,6 +1781,7 @@ vgSeti(VG_MASKING, VG_FALSE); d->maskValid = false; d->maskIsSet = true; + d->scissorMask = false; d->maskRect = QRect(); } else { // Special case: if the intersection of the system @@ -1763,6 +1799,7 @@ if (clip.rectCount() != 1) { d->maskValid = false; d->maskIsSet = false; + d->scissorMask = false; d->maskRect = QRect(); d->modifyMask(this, VG_FILL_MASK, r); break; @@ -1771,6 +1808,7 @@ } d->maskValid = false; d->maskIsSet = false; + d->scissorMask = true; d->maskRect = clipRect; vgSeti(VG_MASKING, VG_FALSE); updateScissor(); @@ -1781,13 +1819,30 @@ case Qt::IntersectClip: { QRect r = d->transform.mapRect(rect); - if (d->maskIsSet && isDefaultClipRect(r)) { + if (!d->maskValid) { + // Mask has not been used yet, so intersect with + // the previous scissor-based region in maskRect. + if (d->scissorMask) + r = r.intersect(d->maskRect); + if (isDefaultClipRect(r)) { + // The clip is the full window, so turn off clipping. + d->maskIsSet = true; + d->maskRect = QRect(); + } else { + // Activate the scissor on a smaller maskRect. + d->maskIsSet = false; + d->maskRect = r; + } + d->scissorMask = true; + updateScissor(); + } else if (d->maskIsSet && isDefaultClipRect(r)) { // Intersecting a full-window clip with a full-window // region is the same as turning off clipping. if (d->maskValid) vgSeti(VG_MASKING, VG_FALSE); d->maskValid = false; d->maskIsSet = true; + d->scissorMask = false; d->maskRect = QRect(); } else { d->modifyMask(this, VG_INTERSECT_MASK, r); @@ -1829,6 +1884,7 @@ { d->maskValid = false; d->maskIsSet = true; + d->scissorMask = false; d->maskRect = QRect(); vgSeti(VG_MASKING, VG_FALSE); } @@ -1844,6 +1900,7 @@ vgSeti(VG_MASKING, VG_FALSE); d->maskValid = false; d->maskIsSet = true; + d->scissorMask = false; d->maskRect = QRect(); } else { // Special case: if the intersection of the system @@ -1857,12 +1914,14 @@ if (clip.rectCount() == 1) { d->maskValid = false; d->maskIsSet = false; + d->scissorMask = true; d->maskRect = clip.boundingRect(); vgSeti(VG_MASKING, VG_FALSE); updateScissor(); } else { d->maskValid = false; d->maskIsSet = false; + d->scissorMask = false; d->maskRect = QRect(); d->modifyMask(this, VG_FILL_MASK, r); } @@ -1887,6 +1946,7 @@ vgSeti(VG_MASKING, VG_FALSE); d->maskValid = false; d->maskIsSet = true; + d->scissorMask = false; d->maskRect = QRect(); } else { d->modifyMask(this, VG_INTERSECT_MASK, r); @@ -1965,6 +2025,7 @@ if (op == Qt::NoClip) { d->maskValid = false; d->maskIsSet = true; + d->scissorMask = false; d->maskRect = QRect(); vgSeti(VG_MASKING, VG_FALSE); return; @@ -2000,6 +2061,7 @@ vgSeti(VG_MASKING, VG_TRUE); d->maskValid = true; d->maskIsSet = false; + d->scissorMask = false; #else QPaintEngineEx::clip(path, op); #endif @@ -2008,6 +2070,7 @@ void QVGPaintEnginePrivate::ensureMask (QVGPaintEngine *engine, int width, int height) { + scissorMask = false; if (maskIsSet) { vgMask(VG_INVALID_HANDLE, VG_FILL_MASK, 0, 0, width, height); maskRect = QRect(); @@ -2043,6 +2106,7 @@ vgSeti(VG_MASKING, VG_TRUE); maskValid = true; maskIsSet = false; + scissorMask = false; } void QVGPaintEnginePrivate::modifyMask @@ -2064,6 +2128,7 @@ vgSeti(VG_MASKING, VG_TRUE); maskValid = true; maskIsSet = false; + scissorMask = false; } #endif // !QVG_SCISSOR_CLIP @@ -2096,7 +2161,7 @@ { #if !defined(QVG_SCISSOR_CLIP) // Combine the system clip with the simple mask rectangle. - if (!d->maskRect.isNull()) { + if (d->scissorMask) { if (region.isEmpty()) region = d->maskRect; else @@ -2187,6 +2252,7 @@ // Replay the entire clip stack to put the mask into the right state. d->maskValid = false; d->maskIsSet = true; + d->scissorMask = false; d->maskRect = QRect(); s->clipRegion = defaultClipRegion(); d->replayClipOperations(); @@ -2196,6 +2262,7 @@ vgSeti(VG_MASKING, VG_FALSE); d->maskValid = false; d->maskIsSet = false; + d->scissorMask = false; d->maskRect = QRect(); } #endif @@ -2314,12 +2381,7 @@ Q_D(QVGPaintEngine); QVGPainterState *s = state(); if (!s->clipEnabled || s->clipOperation == Qt::NoClip) { - // The transform will either be identity or a simple translation, - // so do a simpler version of "r = d->transform.map(rect).toRect()". - QRect r = QRect(qRound(rect.x() + d->transform.dx()), - qRound(rect.y() + d->transform.dy()), - qRound(rect.width()), - qRound(rect.height())); + QRect r = d->transform.mapRect(rect).toRect(); int height = paintDevice()->height(); if (d->clearColor != color || d->clearOpacity != s->opacity) { VGfloat values[4]; @@ -2346,7 +2408,7 @@ return; // Check to see if we can use vgClear() for faster filling. - if (brush.style() == Qt::SolidPattern && + if (brush.style() == Qt::SolidPattern && brush.isOpaque() && clipTransformIsSimple(d->transform) && d->opacity == 1.0f && clearRect(rect, brush.color())) { return; @@ -2389,7 +2451,7 @@ Q_D(QVGPaintEngine); // Check to see if we can use vgClear() for faster filling. - if (clipTransformIsSimple(d->transform) && d->opacity == 1.0f && + if (clipTransformIsSimple(d->transform) && d->opacity == 1.0f && color.alpha() == 255 && clearRect(rect, color)) { return; } @@ -3258,7 +3320,7 @@ } // Set the transformation to use for drawing the current glyphs. - QTransform glyphTransform(d->pathTransform); + QTransform glyphTransform(d->glyphTransform); glyphTransform.translate(p.x(), p.y()); #if defined(QVG_NO_IMAGE_GLYPHS) glyphTransform.scale(glyphCache->scaleX, glyphCache->scaleY); @@ -3398,6 +3460,7 @@ QPaintEngine::DirtyClipEnabled)) != 0) { d->maskValid = false; d->maskIsSet = false; + d->scissorMask = false; d->maskRect = QRect(); clipEnabledChanged(); } @@ -3590,10 +3653,10 @@ } else { // Set the path transform to the default viewport transformation. - VGfloat devh = screenSize.height() - 1; + VGfloat devh = screenSize.height(); QTransform viewport(1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, - -0.5f, devh + 0.5f, 1.0f); + 0.0f, devh, 1.0f); d->setTransform(VG_MATRIX_PATH_USER_TO_SURFACE, viewport); // Set the brush to use to fill the background. @@ -3629,10 +3692,10 @@ } // Set the image transformation and modes. - VGfloat devh = screenSize.height() - 1; + VGfloat devh = screenSize.height(); QTransform transform(1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, - -0.5f, devh + 0.5f, 1.0f); + 0.0f, devh, 1.0f); transform.translate(offset.x(), offset.y()); d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform); d->setImageMode(VG_DRAW_IMAGE_NORMAL);