diff options
author | Jani Hautakangas <ext-jani.hautakangas@nokia.com> | 2010-05-20 10:04:34 (GMT) |
---|---|---|
committer | Jani Hautakangas <ext-jani.hautakangas@nokia.com> | 2010-05-20 10:04:34 (GMT) |
commit | 6fb92f77f6d6b5b685b8748a1a35ffbd7df8b76b (patch) | |
tree | ba9ec7bc61be5ae87bd93fa055c6fb628b3d8404 /src/gui/painting | |
parent | 98972c1b271de1292b4e46484fe689d62a8b8e62 (diff) | |
parent | e6557220bccbdbbc218dc9eab0eb426ba774435e (diff) | |
download | Qt-6fb92f77f6d6b5b685b8748a1a35ffbd7df8b76b.zip Qt-6fb92f77f6d6b5b685b8748a1a35ffbd7df8b76b.tar.gz Qt-6fb92f77f6d6b5b685b8748a1a35ffbd7df8b76b.tar.bz2 |
Merge branch '4.7' of scm.dev.troll.no:qt/qt-s60-public into 4.7
Diffstat (limited to 'src/gui/painting')
-rw-r--r-- | src/gui/painting/qbezier.cpp | 228 | ||||
-rw-r--r-- | src/gui/painting/qbezier_p.h | 7 | ||||
-rw-r--r-- | src/gui/painting/qpaintengine_mac.cpp | 6 | ||||
-rw-r--r-- | src/gui/painting/qpaintengine_mac_p.h | 3 | ||||
-rw-r--r-- | src/gui/painting/qpaintengine_x11.cpp | 2 | ||||
-rw-r--r-- | src/gui/painting/qpaintengineex.cpp | 2 | ||||
-rw-r--r-- | src/gui/painting/qpainter.cpp | 9 | ||||
-rw-r--r-- | src/gui/painting/qpdf.cpp | 9 | ||||
-rw-r--r-- | src/gui/painting/qprintengine_pdf.cpp | 46 | ||||
-rw-r--r-- | src/gui/painting/qprintengine_pdf_p.h | 1 | ||||
-rw-r--r-- | src/gui/painting/qstroker.cpp | 23 | ||||
-rw-r--r-- | src/gui/painting/qstroker_p.h | 18 | ||||
-rw-r--r-- | src/gui/painting/qtextureglyphcache_p.h | 2 | ||||
-rw-r--r-- | src/gui/painting/qtransform.cpp | 9 |
14 files changed, 98 insertions, 267 deletions
diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp index 7ff2a37..2a9b31a 100644 --- a/src/gui/painting/qbezier.cpp +++ b/src/gui/painting/qbezier.cpp @@ -93,7 +93,7 @@ QBezier QBezier::fromPoints(const QPointF &p1, const QPointF &p2, /*! \internal */ -QPolygonF QBezier::toPolygon() const +QPolygonF QBezier::toPolygon(qreal bezier_flattening_threshold) const { // flattening is done by splitting the bezier until we can replace the segment by a straight // line. We split further until the control points are close enough to the line connecting the @@ -108,7 +108,7 @@ QPolygonF QBezier::toPolygon() const QPolygonF polygon; polygon.append(QPointF(x1, y1)); - addToPolygon(&polygon); + addToPolygon(&polygon, bezier_flattening_threshold); return polygon; } @@ -117,34 +117,6 @@ QBezier QBezier::mapBy(const QTransform &transform) const return QBezier::fromPoints(transform.map(pt1()), transform.map(pt2()), transform.map(pt3()), transform.map(pt4())); } -//0.05 is really low, but required for scaled-up beziers... -static const qreal flatness = 0.05; - -//based on "Fast, precise flattening of cubic Bezier path and offset curves" -// by T. F. Hain, A. L. Ahmad, S. V. R. Racherla and D. D. Langan -static inline void flattenBezierWithoutInflections(QBezier &bez, - QPolygonF *&p) -{ - QBezier left; - - while (1) { - qreal dx = bez.x2 - bez.x1; - qreal dy = bez.y2 - bez.y1; - - qreal normalized = qSqrt(dx * dx + dy * dy); - if (qFuzzyIsNull(normalized)) - break; - - qreal d = qAbs(dx * (bez.y3 - bez.y2) - dy * (bez.x3 - bez.x2)); - - qreal t = qSqrt(4. / 3. * normalized * flatness / d); - if (t > 1 || qFuzzyIsNull(t - (qreal)1.)) - break; - bez.parameterSplitLeft(t, &left); - p->append(bez.pt1()); - } -} - QBezier QBezier::getSubRange(qreal t0, qreal t1) const { QBezier result; @@ -223,7 +195,7 @@ static inline bool findInflections(qreal a, qreal b, qreal c, } -void QBezier::addToPolygon(QPolygonF *polygon) const +void QBezier::addToPolygon(QPolygonF *polygon, qreal bezier_flattening_threshold) const { QBezier beziers[32]; beziers[0] = *this; @@ -243,7 +215,7 @@ void QBezier::addToPolygon(QPolygonF *polygon) const qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3); l = 1.; } - if (d < flatness*l || b == beziers + 31) { + if (d < bezier_flattening_threshold*l || b == beziers + 31) { // good enough, we pop it off and add the endpoint polygon->append(QPointF(b->x4, b->y4)); --b; @@ -255,55 +227,6 @@ void QBezier::addToPolygon(QPolygonF *polygon) const } } -void QBezier::addToPolygonMixed(QPolygonF *polygon) const -{ - qreal ax = -x1 + 3*x2 - 3*x3 + x4; - qreal ay = -y1 + 3*y2 - 3*y3 + y4; - qreal bx = 3*x1 - 6*x2 + 3*x3; - qreal by = 3*y1 - 6*y2 + 3*y3; - qreal cx = -3*x1 + 3*x2; - qreal cy = -3*y1 + 2*y2; - qreal a = 6 * (ay * bx - ax * by); - qreal b = 6 * (ay * cx - ax * cy); - qreal c = 2 * (by * cx - bx * cy); - - if ((qFuzzyIsNull(a) && qFuzzyIsNull(b)) || - (b * b - 4 * a *c) < 0) { - QBezier bez(*this); - flattenBezierWithoutInflections(bez, polygon); - polygon->append(QPointF(x4, y4)); - } else { - QBezier beziers[32]; - beziers[0] = *this; - QBezier *b = beziers; - - while (b >= beziers) { - // check if we can pop the top bezier curve from the stack - qreal y4y1 = b->y4 - b->y1; - qreal x4x1 = b->x4 - b->x1; - qreal l = qAbs(x4x1) + qAbs(y4y1); - qreal d; - if (l > 1.) { - d = qAbs( (x4x1)*(b->y1 - b->y2) - (y4y1)*(b->x1 - b->x2) ) - + qAbs( (x4x1)*(b->y1 - b->y3) - (y4y1)*(b->x1 - b->x3) ); - } else { - d = qAbs(b->x1 - b->x2) + qAbs(b->y1 - b->y2) + - qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3); - l = 1.; - } - if (d < .5*l || b == beziers + 31) { - // good enough, we pop it off and add the endpoint - polygon->append(QPointF(b->x4, b->y4)); - --b; - } else { - // split, second half of the polygon goes lower into the stack - b->split(b+1, b); - ++b; - } - } - } -} - QRectF QBezier::bounds() const { qreal xmin = x1; @@ -824,147 +747,4 @@ QBezier QBezier::bezierOnInterval(qreal t0, qreal t1) const return result; } - -static inline void bindInflectionPoint(const QBezier &bez, const qreal t, - qreal *tMinus , qreal *tPlus) -{ - if (t <= 0) { - *tMinus = *tPlus = -1; - return; - } else if (t >= 1) { - *tMinus = *tPlus = 2; - return; - } - - QBezier left, right; - splitBezierAt(bez, t, &left, &right); - - qreal ax = -right.x1 + 3*right.x2 - 3*right.x3 + right.x4; - qreal ay = -right.y1 + 3*right.y2 - 3*right.y3 + right.y4; - qreal ex = 3 * (right.x2 - right.x3); - qreal ey = 3 * (right.y2 - right.y3); - - qreal s4 = qAbs(6 * (ey * ax - ex * ay) / qSqrt(ex * ex + ey * ey)) + 0.00001f; - qreal tf = qPow(qreal(9 * flatness / s4), qreal(1./3.)); - *tMinus = t - (1 - t) * tf; - *tPlus = t + (1 - t) * tf; -} - -void QBezier::addToPolygonIterative(QPolygonF *p) const -{ - qreal t1, t2, tcusp; - qreal t1min, t1plus, t2min, t2plus; - - qreal ax = -x1 + 3*x2 - 3*x3 + x4; - qreal ay = -y1 + 3*y2 - 3*y3 + y4; - qreal bx = 3*x1 - 6*x2 + 3*x3; - qreal by = 3*y1 - 6*y2 + 3*y3; - qreal cx = -3*x1 + 3*x2; - qreal cy = -3*y1 + 2*y2; - - if (findInflections(6 * (ay * bx - ax * by), - 6 * (ay * cx - ax * cy), - 2 * (by * cx - bx * cy), - &t1, &t2, &tcusp)) { - bindInflectionPoint(*this, t1, &t1min, &t1plus); - bindInflectionPoint(*this, t2, &t2min, &t2plus); - - QBezier tmpBez = *this; - QBezier left, right, bez1, bez2, bez3; - if (t1min > 0) { - if (t1min >= 1) { - flattenBezierWithoutInflections(tmpBez, p); - } else { - splitBezierAt(tmpBez, t1min, &left, &right); - flattenBezierWithoutInflections(left, p); - p->append(tmpBez.pointAt(t1min)); - - if (t2min < t1plus) { - if (tcusp < 1) { - p->append(tmpBez.pointAt(tcusp)); - } - if (t2plus < 1) { - splitBezierAt(tmpBez, t2plus, &left, &right); - flattenBezierWithoutInflections(right, p); - } - } else if (t1plus < 1) { - if (t2min < 1) { - splitBezierAt(tmpBez, t2min, &bez3, &right); - splitBezierAt(bez3, t1plus, &left, &bez2); - - flattenBezierWithoutInflections(bez2, p); - p->append(tmpBez.pointAt(t2min)); - - if (t2plus < 1) { - splitBezierAt(tmpBez, t2plus, &left, &bez2); - flattenBezierWithoutInflections(bez2, p); - } - } else { - splitBezierAt(tmpBez, t1plus, &left, &bez2); - flattenBezierWithoutInflections(bez2, p); - } - } - } - } else if (t1plus > 0) { - p->append(QPointF(x1, y1)); - if (t2min < t1plus) { - if (tcusp < 1) { - p->append(tmpBez.pointAt(tcusp)); - } - if (t2plus < 1) { - splitBezierAt(tmpBez, t2plus, &left, &bez2); - flattenBezierWithoutInflections(bez2, p); - } - } else if (t1plus < 1) { - if (t2min < 1) { - splitBezierAt(tmpBez, t2min, &bez3, &right); - splitBezierAt(bez3, t1plus, &left, &bez2); - - flattenBezierWithoutInflections(bez2, p); - - p->append(tmpBez.pointAt(t2min)); - if (t2plus < 1) { - splitBezierAt(tmpBez, t2plus, &left, &bez2); - flattenBezierWithoutInflections(bez2, p); - } - } else { - splitBezierAt(tmpBez, t1plus, &left, &bez2); - flattenBezierWithoutInflections(bez2, p); - } - } - } else if (t2min > 0) { - if (t2min < 1) { - splitBezierAt(tmpBez, t2min, &bez1, &right); - flattenBezierWithoutInflections(bez1, p); - p->append(tmpBez.pointAt(t2min)); - - if (t2plus < 1) { - splitBezierAt(tmpBez, t2plus, &left, &bez2); - flattenBezierWithoutInflections(bez2, p); - } - } else { - //### in here we should check whether the area of the - // triangle formed between pt1/pt2/pt3 is smaller - // or equal to 0 and then do iterative flattening - // if not we should fallback and do the recursive - // flattening. - flattenBezierWithoutInflections(tmpBez, p); - } - } else if (t2plus > 0) { - p->append(QPointF(x1, y1)); - if (t2plus < 1) { - splitBezierAt(tmpBez, t2plus, &left, &bez2); - flattenBezierWithoutInflections(bez2, p); - } - } else { - flattenBezierWithoutInflections(tmpBez, p); - } - } else { - QBezier bez = *this; - flattenBezierWithoutInflections(bez, p); - } - - p->append(QPointF(x4, y4)); -} - QT_END_NAMESPACE diff --git a/src/gui/painting/qbezier_p.h b/src/gui/painting/qbezier_p.h index 846635f..18ec116 100644 --- a/src/gui/painting/qbezier_p.h +++ b/src/gui/painting/qbezier_p.h @@ -79,10 +79,9 @@ public: inline QPointF derivedAt(qreal t) const; inline QPointF secondDerivedAt(qreal t) const; - QPolygonF toPolygon() const; - void addToPolygon(QPolygonF *p) const; - void addToPolygonIterative(QPolygonF *p) const; - void addToPolygonMixed(QPolygonF *p) const; + QPolygonF toPolygon(qreal bezier_flattening_threshold = 0.5) const; + void addToPolygon(QPolygonF *p, qreal bezier_flattening_threshold = 0.5) const; + QRectF bounds() const; qreal length(qreal error = 0.01) const; void addIfClose(qreal *length, qreal error) const; diff --git a/src/gui/painting/qpaintengine_mac.cpp b/src/gui/painting/qpaintengine_mac.cpp index 14ba94e..e5323d8 100644 --- a/src/gui/painting/qpaintengine_mac.cpp +++ b/src/gui/painting/qpaintengine_mac.cpp @@ -1390,7 +1390,11 @@ QCoreGraphicsPaintEngine::updateRenderHints(QPainter::RenderHints hints) CGContextSetInterpolationQuality(d->hd, (hints & QPainter::SmoothPixmapTransform) ? kCGInterpolationHigh : kCGInterpolationNone); } - CGContextSetShouldSmoothFonts(d->hd, hints & QPainter::TextAntialiasing); + bool textAntialiasing = (hints & QPainter::TextAntialiasing) == QPainter::TextAntialiasing; + if (!textAntialiasing || d->disabledSmoothFonts) { + d->disabledSmoothFonts = !textAntialiasing; + CGContextSetShouldSmoothFonts(d->hd, textAntialiasing); + } } /* diff --git a/src/gui/painting/qpaintengine_mac_p.h b/src/gui/painting/qpaintengine_mac_p.h index c9ab419..940b2bc 100644 --- a/src/gui/painting/qpaintengine_mac_p.h +++ b/src/gui/painting/qpaintengine_mac_p.h @@ -148,7 +148,7 @@ class QCoreGraphicsPaintEnginePrivate : public QPaintEnginePrivate Q_DECLARE_PUBLIC(QCoreGraphicsPaintEngine) public: QCoreGraphicsPaintEnginePrivate() - : hd(0), shading(0), stackCount(0), complexXForm(false) + : hd(0), shading(0), stackCount(0), complexXForm(false), disabledSmoothFonts(false) { } @@ -168,6 +168,7 @@ public: CGShadingRef shading; int stackCount; bool complexXForm; + bool disabledSmoothFonts; enum { CosmeticNone, CosmeticTransformPath, CosmeticSetPenWidth } cosmeticPen; // pixel and cosmetic pen size in user coordinates. diff --git a/src/gui/painting/qpaintengine_x11.cpp b/src/gui/painting/qpaintengine_x11.cpp index da48fcb..aef8b80 100644 --- a/src/gui/painting/qpaintengine_x11.cpp +++ b/src/gui/painting/qpaintengine_x11.cpp @@ -315,7 +315,7 @@ static Picture getPatternFill(int screen, const QBrush &b) return X11->pattern_fills[i].picture; } // none found, replace one - int i = rand() % 16; + int i = qrand() % 16; if (X11->pattern_fills[i].screen != screen && X11->pattern_fills[i].picture) { XRenderFreePicture (X11->display, X11->pattern_fills[i].picture); diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index fda937e..ff82d59 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -461,6 +461,7 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) // change the current transform. Normal transformed, // non-cosmetic pens will be transformed as part of fill // later, so they are also covered here.. + d->activeStroker->setCurveThresholdFromTransform(state()->matrix); d->activeStroker->begin(d->strokeHandler); if (types) { while (points < lastPoint) { @@ -518,6 +519,7 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) QPainterPath painterPath = state()->matrix.map(path.convertToPainterPath()); d->activeStroker->strokePath(painterPath, d->strokeHandler, QTransform()); } else { + d->activeStroker->setCurveThresholdFromTransform(state()->matrix); d->activeStroker->begin(d->strokeHandler); if (types) { while (points < lastPoint) { diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 898a996..596649e 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5977,12 +5977,17 @@ void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justif gf.glyphs = engine.shapedGlyphs(&si); gf.chars = engine.layoutData->string.unicode() + si.position; gf.num_chars = engine.length(item); - gf.width = si.width; + if (engine.forceJustification) { + for (int j=0; j<gf.glyphs.numGlyphs; ++j) + gf.width += gf.glyphs.effectiveAdvance(j); + } else { + gf.width = si.width; + } gf.logClusters = engine.logClusters(&si); drawTextItem(QPointF(x.toReal(), p.y()), gf); - x += si.width; + x += gf.width; } } diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index 44049c0..6e02435 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -971,12 +971,17 @@ void QPdfBaseEngine::drawPoints (const QPointF *points, int pointCount) if (!points) return; + Q_D(QPdfBaseEngine); QPainterPath p; for (int i=0; i!=pointCount;++i) { p.moveTo(points[i]); p.lineTo(points[i] + QPointF(0, 0.001)); } + + bool hadBrush = d->hasBrush; + d->hasBrush = false; drawPath(p); + d->hasBrush = hadBrush; } void QPdfBaseEngine::drawLines (const QLineF *lines, int lineCount) @@ -984,12 +989,16 @@ void QPdfBaseEngine::drawLines (const QLineF *lines, int lineCount) if (!lines) return; + Q_D(QPdfBaseEngine); QPainterPath p; for (int i=0; i!=lineCount;++i) { p.moveTo(lines[i].p1()); p.lineTo(lines[i].p2()); } + bool hadBrush = d->hasBrush; + d->hasBrush = false; drawPath(p); + d->hasBrush = hadBrush; } void QPdfBaseEngine::drawRects (const QRectF *rects, int rectCount) diff --git a/src/gui/painting/qprintengine_pdf.cpp b/src/gui/painting/qprintengine_pdf.cpp index b8bf15e..2955e39 100644 --- a/src/gui/painting/qprintengine_pdf.cpp +++ b/src/gui/painting/qprintengine_pdf.cpp @@ -931,29 +931,16 @@ void QPdfEnginePrivate::writeHeader() void QPdfEnginePrivate::writeInfo() { info = addXrefEntry(-1); - - // The 'text string' type in PDF is encoded either as PDFDocEncoding, or - // Unicode UTF-16 with a Unicode byte order mark as the first character - // (0xfeff), with the high-order byte first. - QByteArray array("<<\n/Title (\xfe\xff"); - const ushort *utf16Title = title.utf16(); - for (int i=0; i < title.size(); ++i) { - array.append((*(utf16Title + i)) >> 8); - array.append((*(utf16Title + i)) & 0xff); - } - array.append(")\n/Creator (\xfe\xff"); - const ushort *utf16Creator = creator.utf16(); - for (int i=0; i < creator.size(); ++i) { - array.append((*(utf16Creator + i)) >> 8); - array.append((*(utf16Creator + i)) & 0xff); - } - array.append(")\n/Producer (Qt " QT_VERSION_STR " (C) 2010 Nokia Corporation and/or its subsidiary(-ies))\n"); - write(array); - + xprintf("<<\n/Title "); + printString(title); + xprintf("\n/Creator "); + printString(creator); + xprintf("\n/Producer "); + printString(QString::fromLatin1("Qt " QT_VERSION_STR " (C) 2010 Nokia Corporation and/or its subsidiary(-ies)")); QDateTime now = QDateTime::currentDateTime().toUTC(); QTime t = now.time(); QDate d = now.date(); - xprintf("/CreationDate (D:%d%02d%02d%02d%02d%02d)\n", + xprintf("\n/CreationDate (D:%d%02d%02d%02d%02d%02d)\n", d.year(), d.month(), d.day(), @@ -1230,6 +1217,25 @@ int QPdfEnginePrivate::addXrefEntry(int object, bool printostr) return object; } +void QPdfEnginePrivate::printString(const QString &string) { + // The 'text string' type in PDF is encoded either as PDFDocEncoding, or + // Unicode UTF-16 with a Unicode byte order mark as the first character + // (0xfeff), with the high-order byte first. + QByteArray array("(\xfe\xff"); + const ushort *utf16 = string.utf16(); + + for (int i=0; i < string.size(); ++i) { + char part[2] = {char((*(utf16 + i)) >> 8), char((*(utf16 + i)) & 0xff)}; + for(int j=0; j < 2; ++j) { + if (part[j] == '(' || part[j] == ')' || part[j] == '\\') + array.append('\\'); + array.append(part[j]); + } + } + array.append(")"); + write(array); +} + QT_END_NAMESPACE #endif // QT_NO_PRINTER diff --git a/src/gui/painting/qprintengine_pdf_p.h b/src/gui/painting/qprintengine_pdf_p.h index cb6c59d..e0ca56f 100644 --- a/src/gui/painting/qprintengine_pdf_p.h +++ b/src/gui/painting/qprintengine_pdf_p.h @@ -170,6 +170,7 @@ private: void writePage(); int addXrefEntry(int object, bool printostr = true); + void printString(const QString &string); void xprintf(const char* fmt, ...); inline void write(const QByteArray &data) { stream->writeRawData(data.constData(), data.size()); diff --git a/src/gui/painting/qstroker.cpp b/src/gui/painting/qstroker.cpp index 9b8e099..eabbd8a 100644 --- a/src/gui/painting/qstroker.cpp +++ b/src/gui/painting/qstroker.cpp @@ -120,8 +120,8 @@ private: class QSubpathFlatIterator { public: - QSubpathFlatIterator(const QDataBuffer<QStrokerOps::Element> *path) - : m_path(path), m_pos(0), m_curve_index(-1) { } + QSubpathFlatIterator(const QDataBuffer<QStrokerOps::Element> *path, qreal threshold) + : m_path(path), m_pos(0), m_curve_index(-1), m_curve_threshold(threshold) { } inline bool hasNext() const { return m_curve_index >= 0 || m_pos < m_path->size(); } @@ -152,7 +152,7 @@ public: QPointF(qt_fixed_to_real(m_path->at(m_pos+1).x), qt_fixed_to_real(m_path->at(m_pos+1).y)), QPointF(qt_fixed_to_real(m_path->at(m_pos+2).x), - qt_fixed_to_real(m_path->at(m_pos+2).y))).toPolygon(); + qt_fixed_to_real(m_path->at(m_pos+2).y))).toPolygon(m_curve_threshold); m_curve_index = 1; e.type = QPainterPath::LineToElement; e.x = m_curve.at(0).x(); @@ -169,6 +169,7 @@ private: int m_pos; QPolygonF m_curve; int m_curve_index; + qreal m_curve_threshold; }; template <class Iterator> bool qt_stroke_side(Iterator *it, QStroker *stroker, @@ -187,7 +188,12 @@ static inline qreal adapted_angle_on_x(const QLineF &line) } QStrokerOps::QStrokerOps() - : m_elements(0), m_customData(0), m_moveTo(0), m_lineTo(0), m_cubicTo(0) + : m_elements(0) + , m_curveThreshold(qt_real_to_fixed(0.25)) + , m_customData(0) + , m_moveTo(0) + , m_lineTo(0) + , m_cubicTo(0) { } @@ -195,7 +201,6 @@ QStrokerOps::~QStrokerOps() { } - /*! Prepares the stroker. Call this function once before starting a stroke by calling moveTo, lineTo or cubicTo. @@ -238,6 +243,7 @@ void QStrokerOps::strokePath(const QPainterPath &path, void *customData, const Q if (path.isEmpty()) return; + setCurveThresholdFromTransform(matrix); begin(customData); int count = path.elementCount(); if (matrix.isIdentity()) { @@ -308,6 +314,8 @@ void QStrokerOps::strokePolygon(const QPointF *points, int pointCount, bool impl { if (!pointCount) return; + + setCurveThresholdFromTransform(matrix); begin(data); if (matrix.isIdentity()) { moveTo(qt_real_to_fixed(points[0].x()), qt_real_to_fixed(points[0].y())); @@ -348,6 +356,7 @@ void QStrokerOps::strokeEllipse(const QRectF &rect, void *data, const QTransform } } + setCurveThresholdFromTransform(matrix); begin(data); moveTo(qt_real_to_fixed(start.x()), qt_real_to_fixed(start.y())); for (int i=0; i<12; i+=3) { @@ -366,12 +375,10 @@ QStroker::QStroker() { m_strokeWidth = qt_real_to_fixed(1); m_miterLimit = qt_real_to_fixed(2); - m_curveThreshold = qt_real_to_fixed(0.25); } QStroker::~QStroker() { - } Qt::PenCapStyle QStroker::capForJoinMode(LineJoinMode mode) @@ -1135,7 +1142,7 @@ void QDashStroker::processCurrentSubpath() QPainterPath dashPath; - QSubpathFlatIterator it(&m_elements); + QSubpathFlatIterator it(&m_elements, m_curveThreshold); qfixed2d prev = it.next(); bool clipping = !m_clip_rect.isEmpty(); diff --git a/src/gui/painting/qstroker_p.h b/src/gui/painting/qstroker_p.h index 3e622a8..d646135 100644 --- a/src/gui/painting/qstroker_p.h +++ b/src/gui/painting/qstroker_p.h @@ -124,6 +124,9 @@ typedef void (*qStrokerCubicToHook)(qfixed c1x, qfixed c1y, qfixed ex, qfixed ey, void *data); +// qtransform.cpp +Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale); + class Q_GUI_EXPORT QStrokerOps { public: @@ -161,6 +164,16 @@ public: QRectF clipRect() const { return m_clip_rect; } void setClipRect(const QRectF &clip) { m_clip_rect = clip; } + void setCurveThresholdFromTransform(const QTransform &transform) + { + qreal scale; + qt_scaleForTransform(transform, &scale); + setCurveThreshold(scale == 0 ? qreal(0.5) : (qreal(0.5) / scale)); + } + + void setCurveThreshold(qfixed threshold) { m_curveThreshold = threshold; } + qfixed curveThreshold() const { return m_curveThreshold; } + protected: inline void emitMoveTo(qfixed x, qfixed y); inline void emitLineTo(qfixed x, qfixed y); @@ -170,6 +183,7 @@ protected: QDataBuffer<Element> m_elements; QRectF m_clip_rect; + qfixed m_curveThreshold; void *m_customData; qStrokerMoveToHook m_moveTo; @@ -208,9 +222,6 @@ public: void setMiterLimit(qfixed length) { m_miterLimit = length; } qfixed miterLimit() const { return m_miterLimit; } - void setCurveThreshold(qfixed threshold) { m_curveThreshold = threshold; } - qfixed curveThreshold() const { return m_curveThreshold; } - void joinPoints(qfixed x, qfixed y, const QLineF &nextLine, LineJoinMode join); inline void emitMoveTo(qfixed x, qfixed y); inline void emitLineTo(qfixed x, qfixed y); @@ -227,7 +238,6 @@ protected: qfixed m_strokeWidth; qfixed m_miterLimit; - qfixed m_curveThreshold; LineJoinMode m_capStyle; LineJoinMode m_joinStyle; diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h index 390fe51..a818978 100644 --- a/src/gui/painting/qtextureglyphcache_p.h +++ b/src/gui/painting/qtextureglyphcache_p.h @@ -125,7 +125,7 @@ protected: }; -class QImageTextureGlyphCache : public QTextureGlyphCache +class Q_GUI_EXPORT QImageTextureGlyphCache : public QTextureGlyphCache { public: QImageTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix) diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index 80b7520..aaa241f 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -1545,12 +1545,19 @@ static inline bool lineTo_clipped(QPainterPath &path, const QTransform &transfor return true; } +Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale); static inline bool cubicTo_clipped(QPainterPath &path, const QTransform &transform, const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d, bool needsMoveTo) { // Convert projective xformed curves to line // segments so they can be transformed more accurately - QPolygonF segment = QBezier::fromPoints(a, b, c, d).toPolygon(); + + qreal scale; + qt_scaleForTransform(transform, &scale); + + qreal curveThreshold = scale == 0 ? qreal(0.25) : (qreal(0.25) / scale); + + QPolygonF segment = QBezier::fromPoints(a, b, c, d).toPolygon(curveThreshold); for (int i = 0; i < segment.size() - 1; ++i) if (lineTo_clipped(path, transform, segment.at(i), segment.at(i+1), needsMoveTo)) |