diff options
author | Frederik Gladhorn <frederik.gladhorn@theqtcompany.com> | 2015-02-24 17:19:40 +0100 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@theqtcompany.com> | 2015-02-24 21:02:08 +0100 |
commit | 34b14a8472f44f8517577756e033b92ebd4c5912 (patch) | |
tree | 66a0575156d0a17a835430137e218e2b3f04cc65 /src/plugins/platforms/direct2d | |
parent | d34353a065c443aac20376cbd88323480d769183 (diff) | |
parent | edd555425a08f9e074f0a4d9333862636ccaae8d (diff) |
Merge remote-tracking branch 'origin/5.4' into 5.5
Conflicts:
examples/xml/htmlinfo/simpleexample.html
examples/xml/rsslisting/rsslisting.cpp
qmake/generators/win32/msbuild_objectmodel.cpp
src/3rdparty/harfbuzz-ng/src/hb-private.hh
src/corelib/global/qlogging.cpp
src/corelib/io/qstorageinfo_unix.cpp
src/corelib/thread/qwaitcondition_unix.cpp
src/gui/kernel/qguiapplication.cpp
src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
src/testlib/doc/src/qt-webpages.qdoc
tests/auto/other/qaccessibility/tst_qaccessibility.cpp
Change-Id: Ib272ff0bc30a1a5d51275eb3cd2f201dc82c11ff
Diffstat (limited to 'src/plugins/platforms/direct2d')
-rw-r--r-- | src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp | 248 | ||||
-rw-r--r-- | src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h | 3 |
2 files changed, 119 insertions, 132 deletions
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index aedb8f7b88..36cfff43f5 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -68,8 +68,6 @@ enum { D2DDebugFillRectTag, D2DDebugDrawRectsTag, D2DDebugDrawRectFsTag, - D2DDebugDrawLinesTag, - D2DDebugDrawLineFsTag, D2DDebugDrawEllipseTag, D2DDebugDrawEllipseFTag, D2DDebugDrawImageTag, @@ -102,22 +100,28 @@ static inline ID2D1Factory1 *factory() return QWindowsDirect2DContext::instance()->d2dFactory(); } -static inline D2D1_MATRIX_3X2_F transformFromLine(const QLineF &line, qreal penWidth) +static inline D2D1_MATRIX_3X2_F transformFromLine(const QLineF &line, qreal penWidth, qreal dashOffset) { const qreal halfWidth = penWidth / 2; const qreal angle = -qDegreesToRadians(line.angle()); - QTransform transform = QTransform::fromTranslate(line.p1().x() + qSin(angle) * halfWidth, - line.p1().y() - qCos(angle) * halfWidth); + const qreal sinA = qSin(angle); + const qreal cosA = qCos(angle); + QTransform transform = QTransform::fromTranslate(line.p1().x() + dashOffset * cosA + sinA * halfWidth, + line.p1().y() + dashOffset * sinA - cosA * halfWidth); transform.rotateRadians(angle); return to_d2d_matrix_3x2_f(transform); } +static void adjustLine(QPointF *p1, QPointF *p2); +static bool isLinePositivelySloped(const QPointF &p1, const QPointF &p2); + class Direct2DPathGeometryWriter { public: Direct2DPathGeometryWriter() : m_inFigure(false) , m_roundCoordinates(false) + , m_adjustPositivelySlopedLines(false) { } @@ -152,6 +156,11 @@ public: m_roundCoordinates = enable; } + void setPositiveSlopeAdjustmentEnabled(bool enable) + { + m_adjustPositivelySlopedLines = enable; + } + bool isInFigure() const { return m_inFigure; @@ -164,11 +173,20 @@ public: m_sink->BeginFigure(adjusted(point), D2D1_FIGURE_BEGIN_FILLED); m_inFigure = true; + m_previousPoint = point; } void lineTo(const QPointF &point) { - m_sink->AddLine(adjusted(point)); + QPointF pt = point; + if (m_adjustPositivelySlopedLines && isLinePositivelySloped(m_previousPoint, point)) { + moveTo(m_previousPoint - QPointF(0, 1)); + pt -= QPointF(0, 1); + } + m_sink->AddLine(adjusted(pt)); + if (pt != point) + moveTo(point); + m_previousPoint = point; } void curveTo(const QPointF &p1, const QPointF &p2, const QPointF &p3) @@ -180,6 +198,7 @@ public: }; m_sink->AddBezier(segment); + m_previousPoint = p3; } void close() @@ -212,6 +231,8 @@ private: bool m_inFigure; bool m_roundCoordinates; + bool m_adjustPositivelySlopedLines; + QPointF m_previousPoint; }; struct D2DVectorPathCache { @@ -257,6 +278,7 @@ public: ComPtr<ID2D1Brush> brush; ComPtr<ID2D1StrokeStyle1> strokeStyle; ComPtr<ID2D1BitmapBrush1> dashBrush; + int dashLength; inline void reset() { emulate = false; @@ -264,6 +286,7 @@ public: brush.Reset(); strokeStyle.Reset(); dashBrush.Reset(); + dashLength = 0; } } pen; @@ -566,6 +589,7 @@ public: D2D1_BITMAP_BRUSH_PROPERTIES1 bitmapBrushProperties = D2D1::BitmapBrushProperties1( D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_CLAMP, D2D1_INTERPOLATION_MODE_LINEAR); hr = dc()->CreateBitmapBrush(bitmap.bitmap(), bitmapBrushProperties, &pen.dashBrush); + pen.dashLength = bitmap.size().width(); } else { hr = factory()->CreateStrokeStyle(props, NULL, 0, &pen.strokeStyle); } @@ -795,6 +819,8 @@ public: writer.setWindingFillEnabled(path.hasWindingFill()); writer.setAliasingEnabled(alias); + writer.setPositiveSlopeAdjustmentEnabled(path.shape() == QVectorPath::LinesHint + || path.shape() == QVectorPath::PolygonHint); const QPainterPath::ElementType *types = path.elements(); const int count = path.elementCount(); @@ -910,6 +936,90 @@ public: DWRITE_MEASURING_MODE_GDI_CLASSIC); } + void stroke(const QVectorPath &path) + { + Q_Q(QWindowsDirect2DPaintEngine); + + // Default path (no optimization) + if (!(path.shape() == QVectorPath::LinesHint || path.shape() == QVectorPath::PolygonHint) + || !pen.dashBrush || q->state()->renderHints.testFlag(QPainter::HighQualityAntialiasing)) { + ComPtr<ID2D1Geometry> geometry = vectorPathToID2D1PathGeometry(path); + if (!geometry) { + qWarning("%s: Could not convert path to d2d geometry", __FUNCTION__); + return; + } + dc()->DrawGeometry(geometry.Get(), pen.brush.Get(), pen.qpen.widthF(), pen.strokeStyle.Get()); + return; + } + + // Optimized dash line drawing + const bool isPolygon = path.shape() == QVectorPath::PolygonHint && path.elementCount() >= 3; + const bool implicitClose = isPolygon && (path.hints() & QVectorPath::ImplicitClose); + const bool skipJoin = !isPolygon // Non-polygons don't require joins + || (pen.qpen.joinStyle() == Qt::MiterJoin && qFuzzyIsNull(pen.qpen.miterLimit())); + const qreal *points = path.points(); + const int lastElement = path.elementCount() - (implicitClose ? 1 : 2); + qreal dashOffset = 0; + QPointF jointStart; + ID2D1Brush *brush = pen.dashBrush ? pen.dashBrush.Get() : pen.brush.Get(); + for (int i = 0; i <= lastElement; ++i) { + QPointF p1(points[i * 2], points[i * 2 + 1]); + QPointF p2 = implicitClose && i == lastElement ? QPointF(points[0], points[1]) + : QPointF(points[i * 2 + 2], points[i * 2 + 3]); + if (!isPolygon) // Advance the count for lines + ++i; + + // Match raster engine output + if (p1 == p2 && pen.qpen.widthF() <= 1.0) { + q->fillRect(QRectF(p1, QSizeF(pen.qpen.widthF(), pen.qpen.widthF())), pen.qpen.brush()); + continue; + } + + if (!q->antiAliasingEnabled()) + adjustLine(&p1, &p2); + + q->adjustForAliasing(&p1); + q->adjustForAliasing(&p2); + + const QLineF line(p1, p2); + const qreal lineLength = line.length(); + if (pen.dashBrush) { + pen.dashBrush->SetTransform(transformFromLine(line, pen.qpen.widthF(), dashOffset)); + dashOffset = pen.dashLength - fmod(lineLength - dashOffset, pen.dashLength); + } + dc()->DrawLine(to_d2d_point_2f(p1), to_d2d_point_2f(p2), + brush, pen.qpen.widthF(), NULL); + + if (skipJoin) + continue; + + // Patch the join with the original brush + const qreal patchSegment = pen.dashBrush ? qBound(0.0, (pen.dashLength - dashOffset) / lineLength, 1.0) + : pen.qpen.widthF(); + if (i > 0) { + Direct2DPathGeometryWriter writer; + writer.begin(); + writer.moveTo(jointStart); + writer.lineTo(p1); + writer.lineTo(line.pointAt(patchSegment)); + writer.close(); + dc()->DrawGeometry(writer.geometry().Get(), pen.brush.Get(), pen.qpen.widthF(), pen.strokeStyle.Get()); + } + // Record the start position of the next joint + jointStart = line.pointAt(1 - patchSegment); + + if (implicitClose && i == lastElement) { // Close the polygon + Direct2DPathGeometryWriter writer; + writer.begin(); + writer.moveTo(jointStart); + writer.lineTo(p2); + writer.lineTo(QLineF(p2, QPointF(points[2], points[3])).pointAt(patchSegment)); + writer.close(); + dc()->DrawGeometry(writer.geometry().Get(), pen.brush.Get(), pen.qpen.widthF(), pen.strokeStyle.Get()); + } + } + } + ComPtr<IDWriteFontFace> fontFaceFromFontEngine(QFontEngine *fe) { const QFontDef fontDef = fe->fontDef; @@ -1055,20 +1165,12 @@ void QWindowsDirect2DPaintEngine::setState(QPainterState *s) void QWindowsDirect2DPaintEngine::draw(const QVectorPath &path) { - Q_D(QWindowsDirect2DPaintEngine); - - ComPtr<ID2D1Geometry> geometry = d->vectorPathToID2D1PathGeometry(path); - if (!geometry) { - qWarning("%s: Could not convert path to d2d geometry", __FUNCTION__); - return; - } - const QBrush &brush = state()->brush; if (qbrush_style(brush) != Qt::NoBrush) { if (emulationRequired(BrushEmulation)) rasterFill(path, brush); else - fill(geometry.Get(), brush); + fill(path, brush); } const QPen &pen = state()->pen; @@ -1076,7 +1178,7 @@ void QWindowsDirect2DPaintEngine::draw(const QVectorPath &path) if (emulationRequired(PenEmulation)) QPaintEngineEx::stroke(path, pen); else - stroke(geometry.Get(), pen); + stroke(path, pen); } } @@ -1106,18 +1208,6 @@ void QWindowsDirect2DPaintEngine::fill(const QVectorPath &path, const QBrush &br d->dc()->FillGeometry(geometry.Get(), d->brush.brush.Get()); } -void QWindowsDirect2DPaintEngine::fill(ID2D1Geometry *geometry, const QBrush &brush) -{ - Q_D(QWindowsDirect2DPaintEngine); - D2D_TAG(D2DDebugFillTag); - - ensureBrush(brush); - if (!d->brush.brush) - return; - - d->dc()->FillGeometry(geometry, d->brush.brush.Get()); -} - void QWindowsDirect2DPaintEngine::stroke(const QVectorPath &path, const QPen &pen) { Q_D(QWindowsDirect2DPaintEngine); @@ -1135,25 +1225,7 @@ void QWindowsDirect2DPaintEngine::stroke(const QVectorPath &path, const QPen &pe if (!d->pen.brush) return; - ComPtr<ID2D1Geometry> geometry = d->vectorPathToID2D1PathGeometry(path); - if (!geometry) { - qWarning("%s: Could not convert path to d2d geometry", __FUNCTION__); - return; - } - - d->dc()->DrawGeometry(geometry.Get(), d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); -} - -void QWindowsDirect2DPaintEngine::stroke(ID2D1Geometry *geometry, const QPen &pen) -{ - Q_D(QWindowsDirect2DPaintEngine); - D2D_TAG(D2DDebugFillTag); - - ensurePen(pen); - if (!d->pen.brush) - return; - - d->dc()->DrawGeometry(geometry, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); + d->stroke(path); } void QWindowsDirect2DPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) @@ -1301,88 +1373,6 @@ static void adjustLine(QPointF *p1, QPointF *p2) } } -void QWindowsDirect2DPaintEngine::drawLines(const QLine *lines, int lineCount) -{ - Q_D(QWindowsDirect2DPaintEngine); - D2D_TAG(D2DDebugDrawLinesTag); - - ensurePen(); - - if (emulationRequired(PenEmulation)) { - QPaintEngineEx::drawLines(lines, lineCount); - } else if (d->pen.brush) { - for (int i = 0; i < lineCount; i++) { - QPointF p1 = lines[i].p1(); - QPointF p2 = lines[i].p2(); - - // Match raster engine output - if (p1 == p2 && d->pen.qpen.widthF() <= 1.0) { - fillRect(QRectF(p1, QSizeF(d->pen.qpen.widthF(), d->pen.qpen.widthF())), - d->pen.qpen.brush()); - continue; - } - - // Match raster engine output - if (!antiAliasingEnabled()) - adjustLine(&p1, &p2); - - adjustForAliasing(&p1); - adjustForAliasing(&p2); - - D2D1_POINT_2F d2d_p1 = to_d2d_point_2f(p1); - D2D1_POINT_2F d2d_p2 = to_d2d_point_2f(p2); - - if (!d->pen.dashBrush || state()->renderHints.testFlag(QPainter::HighQualityAntialiasing)) { - d->dc()->DrawLine(d2d_p1, d2d_p2, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); - } else { - d->pen.dashBrush->SetTransform(transformFromLine(lines[i], d->pen.qpen.widthF())); - d->dc()->DrawLine(d2d_p1, d2d_p2, d->pen.dashBrush.Get(), d->pen.qpen.widthF(), NULL); - } - } - } -} - -void QWindowsDirect2DPaintEngine::drawLines(const QLineF *lines, int lineCount) -{ - Q_D(QWindowsDirect2DPaintEngine); - D2D_TAG(D2DDebugDrawLineFsTag); - - ensurePen(); - - if (emulationRequired(PenEmulation)) { - QPaintEngineEx::drawLines(lines, lineCount); - } else if (d->pen.brush) { - for (int i = 0; i < lineCount; i++) { - QPointF p1 = lines[i].p1(); - QPointF p2 = lines[i].p2(); - - // Match raster engine output - if (p1 == p2 && d->pen.qpen.widthF() <= 1.0) { - fillRect(QRectF(p1, QSizeF(d->pen.qpen.widthF(), d->pen.qpen.widthF())), - d->pen.qpen.brush()); - continue; - } - - // Match raster engine output - if (!antiAliasingEnabled()) - adjustLine(&p1, &p2); - - adjustForAliasing(&p1); - adjustForAliasing(&p2); - - D2D1_POINT_2F d2d_p1 = to_d2d_point_2f(p1); - D2D1_POINT_2F d2d_p2 = to_d2d_point_2f(p2); - - if (!d->pen.dashBrush || state()->renderHints.testFlag(QPainter::HighQualityAntialiasing)) { - d->dc()->DrawLine(d2d_p1, d2d_p2, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); - } else { - d->pen.dashBrush->SetTransform(transformFromLine(lines[i], d->pen.qpen.widthF())); - d->dc()->DrawLine(d2d_p1, d2d_p2, d->pen.dashBrush.Get(), d->pen.qpen.widthF(), NULL); - } - } - } -} - void QWindowsDirect2DPaintEngine::drawEllipse(const QRectF &r) { Q_D(QWindowsDirect2DPaintEngine); diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h index f9fd6eb591..a75c0b6cc7 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h @@ -92,9 +92,6 @@ public: void drawRects(const QRect *rects, int rectCount) Q_DECL_OVERRIDE; void drawRects(const QRectF *rects, int rectCount) Q_DECL_OVERRIDE; - void drawLines(const QLine *lines, int lineCount) Q_DECL_OVERRIDE; - void drawLines(const QLineF *lines, int lineCount) Q_DECL_OVERRIDE; - void drawEllipse(const QRectF &r) Q_DECL_OVERRIDE; void drawEllipse(const QRect &r) Q_DECL_OVERRIDE; |