Title: [207020] trunk/Source/WebCore
Revision
207020
Author
bfulg...@apple.com
Date
2016-10-10 13:59:48 -0700 (Mon, 10 Oct 2016)

Log Message

[Win][Direct2D] Implement dashed and dotted border line drawing
https://bugs.webkit.org/show_bug.cgi?id=163235

Reviewed by Alex Christensen.

Covered by existing fast/border tests.

* platform/graphics/GraphicsContext.cpp: Use custom 'setPlatformStrokeStyle' for D2D.
* platform/graphics/Path.cpp:
(WebCore::Path::length): Don't use default implementation for Direct2D.
* platform/graphics/win/GraphicsContextDirect2D.cpp:
(WebCore::GraphicsContextPlatformPrivate::brushWithColor): Initialize pointer to nullptr.
(WebCore::GraphicsContext::drawRect): Use proper stroke style.
(WebCore::GraphicsContextPlatformPrivate::setLineCap): Added.
(WebCore::GraphicsContextPlatformPrivate::setLineJoin): Added.
(WebCore::GraphicsContextPlatformPrivate::setStrokeStyle): Added.
(WebCore::GraphicsContextPlatformPrivate::setMiterLimit): Added.
(WebCore::GraphicsContextPlatformPrivate::setDashOffset): Added.
(WebCore::GraphicsContextPlatformPrivate::setPatternWidth): Added.
(WebCore::GraphicsContextPlatformPrivate::setPatternOffset): Added.
(WebCore::GraphicsContextPlatformPrivate::setStrokeThickness): Added.
(WebCore::GraphicsContextPlatformPrivate::setDashes): Added.
(WebCore::GraphicsContextPlatformPrivate::recomputeStrokeStyle): Added.
(WebCore::GraphicsContextPlatformPrivate::strokeStyle): Added.
(WebCore::GraphicsContext::drawLine): Use proper stroke style.
(WebCore::GraphicsContext::drawEllipse): Ditto.
(WebCore::GraphicsContext::drawPath): Ditto.
(WebCore::GraphicsContext::strokePath): Ditto.
(WebCore::GraphicsContext::setPlatformStrokeStyle): Added.
(WebCore::GraphicsContext::setMiterLimit): Tell D2D context about miter limit.
(WebCore::GraphicsContext::setLineCap): Ditto for line cap.
(WebCore::GraphicsContext::setLineDash): Ditto for dashes.
(WebCore::GraphicsContext::setLineJoin): Ditto for join style.
(WebCore::GraphicsContext::setPlatformStrokeThickness): Ditto for stroke thickness.
(WebCore::GraphicsContext::platformStrokeEllipse): Use proper stroke style.
* platform/graphics/win/GraphicsContextPlatformPrivateDirect2D.h:
* platform/graphics/win/PathDirect2D.cpp:
(WebCore::Path::currentPoint): Zero-initialize a value.
(WebCore::Path::length): Added.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (207019 => 207020)


--- trunk/Source/WebCore/ChangeLog	2016-10-10 20:57:37 UTC (rev 207019)
+++ trunk/Source/WebCore/ChangeLog	2016-10-10 20:59:48 UTC (rev 207020)
@@ -1,3 +1,45 @@
+2016-10-10  Brent Fulgham  <bfulg...@apple.com>
+
+        [Win][Direct2D] Implement dashed and dotted border line drawing
+        https://bugs.webkit.org/show_bug.cgi?id=163235
+
+        Reviewed by Alex Christensen.
+
+        Covered by existing fast/border tests.
+
+        * platform/graphics/GraphicsContext.cpp: Use custom 'setPlatformStrokeStyle' for D2D.
+        * platform/graphics/Path.cpp:
+        (WebCore::Path::length): Don't use default implementation for Direct2D.
+        * platform/graphics/win/GraphicsContextDirect2D.cpp:
+        (WebCore::GraphicsContextPlatformPrivate::brushWithColor): Initialize pointer to nullptr.
+        (WebCore::GraphicsContext::drawRect): Use proper stroke style.
+        (WebCore::GraphicsContextPlatformPrivate::setLineCap): Added.
+        (WebCore::GraphicsContextPlatformPrivate::setLineJoin): Added.
+        (WebCore::GraphicsContextPlatformPrivate::setStrokeStyle): Added.
+        (WebCore::GraphicsContextPlatformPrivate::setMiterLimit): Added.
+        (WebCore::GraphicsContextPlatformPrivate::setDashOffset): Added.
+        (WebCore::GraphicsContextPlatformPrivate::setPatternWidth): Added.
+        (WebCore::GraphicsContextPlatformPrivate::setPatternOffset): Added.
+        (WebCore::GraphicsContextPlatformPrivate::setStrokeThickness): Added.
+        (WebCore::GraphicsContextPlatformPrivate::setDashes): Added.
+        (WebCore::GraphicsContextPlatformPrivate::recomputeStrokeStyle): Added.
+        (WebCore::GraphicsContextPlatformPrivate::strokeStyle): Added.
+        (WebCore::GraphicsContext::drawLine): Use proper stroke style.
+        (WebCore::GraphicsContext::drawEllipse): Ditto.
+        (WebCore::GraphicsContext::drawPath): Ditto.
+        (WebCore::GraphicsContext::strokePath): Ditto.
+        (WebCore::GraphicsContext::setPlatformStrokeStyle): Added.
+        (WebCore::GraphicsContext::setMiterLimit): Tell D2D context about miter limit.
+        (WebCore::GraphicsContext::setLineCap): Ditto for line cap.
+        (WebCore::GraphicsContext::setLineDash): Ditto for dashes.
+        (WebCore::GraphicsContext::setLineJoin): Ditto for join style.
+        (WebCore::GraphicsContext::setPlatformStrokeThickness): Ditto for stroke thickness.
+        (WebCore::GraphicsContext::platformStrokeEllipse): Use proper stroke style.
+        * platform/graphics/win/GraphicsContextPlatformPrivateDirect2D.h:
+        * platform/graphics/win/PathDirect2D.cpp:
+        (WebCore::Path::currentPoint): Zero-initialize a value.
+        (WebCore::Path::length): Added.
+
 2016-10-10  Chris Dumez  <cdu...@apple.com>
 
         Update ProgressEvent to stop using legacy [ConstructorTemplate=Event]

Modified: trunk/Source/WebCore/platform/graphics/GraphicsContext.cpp (207019 => 207020)


--- trunk/Source/WebCore/platform/graphics/GraphicsContext.cpp	2016-10-10 20:57:37 UTC (rev 207019)
+++ trunk/Source/WebCore/platform/graphics/GraphicsContext.cpp	2016-10-10 20:59:48 UTC (rev 207020)
@@ -964,7 +964,7 @@
 }
 #endif
 
-#if !USE(CAIRO)
+#if !USE(CAIRO) && !USE(DIRECT2D)
 void GraphicsContext::setPlatformStrokeStyle(StrokeStyle)
 {
 }

Modified: trunk/Source/WebCore/platform/graphics/Path.cpp (207019 => 207020)


--- trunk/Source/WebCore/platform/graphics/Path.cpp	2016-10-10 20:57:37 UTC (rev 207019)
+++ trunk/Source/WebCore/platform/graphics/Path.cpp	2016-10-10 20:59:48 UTC (rev 207020)
@@ -40,6 +40,7 @@
 
 namespace WebCore {
 
+#if !USE(DIRECT2D)
 float Path::length() const
 {
     PathTraversalState traversalState(PathTraversalState::Action::TotalLength);
@@ -50,6 +51,7 @@
 
     return traversalState.totalLength();
 }
+#endif
 
 PathTraversalState Path::traversalStateAtLength(float length, bool& success) const
 {
@@ -116,7 +118,7 @@
     }
 
     if (strategy == PreferNativeRoundedRect) {
-#if USE(CG)
+#if USE(CG) || USE(DIRECT2D)
         platformAddPathForRoundedRect(rect, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight());
         return;
 #endif

Modified: trunk/Source/WebCore/platform/graphics/win/GraphicsContextDirect2D.cpp (207019 => 207020)


--- trunk/Source/WebCore/platform/graphics/win/GraphicsContextDirect2D.cpp	2016-10-10 20:57:37 UTC (rev 207019)
+++ trunk/Source/WebCore/platform/graphics/win/GraphicsContextDirect2D.cpp	2016-10-10 20:59:48 UTC (rev 207020)
@@ -274,7 +274,7 @@
     }
 
     auto existingBrush = m_solidColoredBrushCache.ensure(colorKey, [this, color] {
-        ID2D1SolidColorBrush* colorBrush;
+        ID2D1SolidColorBrush* colorBrush = nullptr;
         m_renderTarget->CreateSolidColorBrush(color, &colorBrush);
         return colorBrush;
     });
@@ -467,11 +467,149 @@
 
     drawWithoutShadow(rect, [this, rect](ID2D1RenderTarget* renderTarget) {
         const D2D1_RECT_F d2dRect = rect;
-        renderTarget->DrawRectangle(&d2dRect, solidStrokeBrush(), strokeThickness());
         renderTarget->FillRectangle(&d2dRect, solidFillBrush());
+        renderTarget->DrawRectangle(&d2dRect, solidStrokeBrush(), strokeThickness(), m_data->strokeStyle());
     });
 }
 
+void GraphicsContextPlatformPrivate::setLineCap(LineCap cap)
+{
+    if (m_lineCap == cap)
+        return;
+
+    D2D1_CAP_STYLE capStyle = D2D1_CAP_STYLE_FLAT;
+    switch (cap) {
+    case RoundCap:
+        capStyle = D2D1_CAP_STYLE_ROUND;
+        break;
+    case SquareCap:
+        capStyle = D2D1_CAP_STYLE_SQUARE;
+        break;
+    case ButtCap:
+    default:
+        capStyle = D2D1_CAP_STYLE_FLAT;
+        break;
+    }
+
+    m_lineCap = capStyle;
+    m_strokeSyleIsDirty = true;
+}
+
+void GraphicsContextPlatformPrivate::setLineJoin(LineJoin join)
+{
+    if (m_lineJoin == join)
+        return;
+
+    D2D1_LINE_JOIN joinStyle = D2D1_LINE_JOIN_MITER;
+    switch (join) {
+    case RoundJoin:
+        joinStyle = D2D1_LINE_JOIN_ROUND;
+        break;
+    case BevelJoin:
+        joinStyle = D2D1_LINE_JOIN_BEVEL;
+        break;
+    case MiterJoin:
+    default:
+        joinStyle = D2D1_LINE_JOIN_MITER;
+        break;
+    }
+
+    m_lineJoin = joinStyle;
+    m_strokeSyleIsDirty = true;
+}
+
+void GraphicsContextPlatformPrivate::setStrokeStyle(StrokeStyle strokeStyle)
+{
+    if (m_strokeStyle == strokeStyle)
+        return;
+
+    m_strokeStyle = strokeStyle;
+    m_strokeSyleIsDirty = true;
+}
+
+void GraphicsContextPlatformPrivate::setMiterLimit(float miterLimit)
+{
+    if (WTF::areEssentiallyEqual(miterLimit, m_miterLimit))
+        return;
+
+    m_miterLimit = miterLimit;
+    m_strokeSyleIsDirty = true;
+}
+
+void GraphicsContextPlatformPrivate::setDashOffset(float dashOffset)
+{
+    if (WTF::areEssentiallyEqual(dashOffset, m_dashOffset))
+        return;
+
+    m_dashOffset = dashOffset;
+    m_strokeSyleIsDirty = true;
+}
+
+void GraphicsContextPlatformPrivate::setPatternWidth(float patternWidth)
+{
+    if (WTF::areEssentiallyEqual(patternWidth, m_patternWidth))
+        return;
+
+    m_patternWidth = patternWidth;
+    m_strokeSyleIsDirty = true;
+}
+
+void GraphicsContextPlatformPrivate::setPatternOffset(float patternOffset)
+{
+    if (WTF::areEssentiallyEqual(patternOffset, m_patternOffset))
+        return;
+
+    m_patternOffset = patternOffset;
+    m_strokeSyleIsDirty = true;
+}
+
+void GraphicsContextPlatformPrivate::setStrokeThickness(float thickness)
+{
+    if (WTF::areEssentiallyEqual(thickness, m_strokeThickness))
+        return;
+
+    m_strokeThickness = thickness;
+    m_strokeSyleIsDirty = true;
+}
+
+void GraphicsContextPlatformPrivate::setDashes(const DashArray& dashes)
+{
+    if (m_dashes == dashes)
+        return;
+
+    m_dashes = dashes;
+    m_strokeSyleIsDirty = true;
+}
+
+void GraphicsContextPlatformPrivate::recomputeStrokeStyle()
+{
+    if (!m_strokeSyleIsDirty)
+        return;
+
+    m_d2dStrokeStyle = nullptr;
+
+    if ((m_strokeStyle != SolidStroke) && (m_strokeStyle != NoStroke)) {
+        float patternOffset = m_patternOffset / m_strokeThickness;
+
+        DashArray dashes = m_dashes;
+
+        // In Direct2D, dashes and dots are defined in terms of the ratio of the dash length to the line thickness.
+        for (auto& dash : dashes)
+            dash /= m_strokeThickness;
+
+        auto strokeStyleProperties = D2D1::StrokeStyleProperties(m_lineCap, m_lineCap, m_lineCap, m_lineJoin, m_strokeThickness, D2D1_DASH_STYLE_CUSTOM, patternOffset);
+        GraphicsContext::systemFactory()->CreateStrokeStyle(&strokeStyleProperties, dashes.data(), dashes.size(), &m_d2dStrokeStyle);
+    }
+
+    m_strokeSyleIsDirty = false;
+}
+
+ID2D1StrokeStyle* GraphicsContextPlatformPrivate::strokeStyle()
+{
+    recomputeStrokeStyle();
+    return m_d2dStrokeStyle.get();
+}
+
 // This is only used to draw borders.
 void GraphicsContext::drawLine(const FloatPoint& point1, const FloatPoint& point2)
 {
@@ -513,6 +651,12 @@
         const float dashes[2] = { patternWidth, patternWidth };
         auto strokeStyleProperties = D2D1::StrokeStyleProperties();
         GraphicsContext::systemFactory()->CreateStrokeStyle(&strokeStyleProperties, dashes, ARRAYSIZE(dashes), &d2dStrokeStyle);
+
+        m_data->setPatternWidth(patternWidth);
+        m_data->setPatternOffset(patternOffset);
+        m_data->setDashes(DashArray(2, patternWidth));
+
+        d2dStrokeStyle = m_data->strokeStyle();
     }
 
     auto centeredPoints = centerLineAndCutOffCorners(isVerticalLine, cornerWidth, point1, point2);
@@ -547,7 +691,7 @@
     drawWithoutShadow(rect, [this, ellipse](ID2D1RenderTarget* renderTarget) {
         renderTarget->FillEllipse(&ellipse, solidFillBrush());
 
-        renderTarget->DrawEllipse(&ellipse, solidStrokeBrush(), strokeThickness());
+        renderTarget->DrawEllipse(&ellipse, solidStrokeBrush(), strokeThickness(), m_data->strokeStyle());
     });
 }
 
@@ -603,7 +747,7 @@
 
     auto rect = path.fastBoundingRect();
     drawWithoutShadow(rect, [this, &path](ID2D1RenderTarget* renderTarget) {
-        renderTarget->DrawGeometry(path.platformPath(), solidStrokeBrush());
+        renderTarget->DrawGeometry(path.platformPath(), solidStrokeBrush(), strokeThickness(), m_data->strokeStyle());
     });
 }
 
@@ -768,7 +912,7 @@
 
     FloatRect contextRect(FloatPoint(), context->GetSize());
     drawWithoutShadow(contextRect, [this, &path](ID2D1RenderTarget* renderTarget) {
-        renderTarget->DrawGeometry(path.platformPath(), solidStrokeBrush(), strokeThickness());
+        renderTarget->DrawGeometry(path.platformPath(), solidStrokeBrush(), strokeThickness(), m_data->strokeStyle());
     });
 }
 
@@ -1089,6 +1233,14 @@
     notImplemented();
 }
 
+void GraphicsContext::setPlatformStrokeStyle(StrokeStyle style)
+{
+    if (paintingDisabled())
+        return;
+
+    m_data->setStrokeStyle(style);
+}
+
 void GraphicsContext::setMiterLimit(float limit)
 {
     if (paintingDisabled())
@@ -1100,7 +1252,7 @@
         return;
     }
 
-    notImplemented();
+    m_data->setMiterLimit(limit);
 }
 
 void GraphicsContext::clearRect(const FloatRect& rect)
@@ -1135,8 +1287,15 @@
 
 void GraphicsContext::setLineCap(LineCap cap)
 {
-    (void)cap;
-    notImplemented();
+    if (paintingDisabled())
+        return;
+
+    if (isRecording()) {
+        m_displayListRecorder->setLineCap(cap);
+        return;
+    }
+
+    m_data->setLineCap(cap);
 }
 
 void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
@@ -1157,7 +1316,8 @@
             dashOffset = fmod(dashOffset, length) + length;
     }
 
-    notImplemented();
+    m_data->setDashes(dashes);
+    m_data->setDashOffset(dashOffset);
 }
 
 void GraphicsContext::setLineJoin(LineJoin join)
@@ -1170,7 +1330,7 @@
         return;
     }
 
-    notImplemented();
+    m_data->setLineJoin(join);
 }
 
 void GraphicsContext::canvasClip(const Path& path, WindRule fillRule)
@@ -1414,8 +1574,8 @@
 
 void GraphicsContext::setPlatformStrokeThickness(float thickness)
 {
-    // This is a no-op on Windows. We fill using the GraphicsContextState::strokeThickness member.
     ASSERT(m_state.strokeThickness == thickness);
+    m_data->setStrokeThickness(thickness);
 }
 
 void GraphicsContext::setPlatformFillColor(const Color& color)
@@ -1616,7 +1776,7 @@
     platformContext()->SetTags(1, __LINE__);
 
     drawWithoutShadow(ellipse, [this, d2dEllipse](ID2D1RenderTarget* renderTarget) {
-        renderTarget->DrawEllipse(&d2dEllipse, solidStrokeBrush(), strokeThickness());
+        renderTarget->DrawEllipse(&d2dEllipse, solidStrokeBrush(), strokeThickness(), m_data->strokeStyle());
     });
 }
 

Modified: trunk/Source/WebCore/platform/graphics/win/GraphicsContextPlatformPrivateDirect2D.h (207019 => 207020)


--- trunk/Source/WebCore/platform/graphics/win/GraphicsContextPlatformPrivateDirect2D.h	2016-10-10 20:57:37 UTC (rev 207019)
+++ trunk/Source/WebCore/platform/graphics/win/GraphicsContextPlatformPrivateDirect2D.h	2016-10-10 20:59:48 UTC (rev 207020)
@@ -59,8 +59,19 @@
     void concatCTM(const AffineTransform&);
     void setCTM(const AffineTransform&);
 
+    void setLineCap(LineCap);
+    void setLineJoin(LineJoin);
+    void setStrokeStyle(StrokeStyle);
+    void setMiterLimit(float);
+    void setDashOffset(float);
+    void setPatternWidth(float);
+    void setPatternOffset(float);
+    void setStrokeThickness(float);
+    void setDashes(const DashArray&);
+
     ID2D1RenderTarget* renderTarget() { return m_renderTarget.get(); }
     ID2D1Layer* clipLayer() const { return m_renderStates.last().m_activeLayer.get(); }
+    ID2D1StrokeStyle* strokeStyle();
 
     COMPtr<ID2D1SolidColorBrush> brushWithColor(const D2D1_COLOR_F&);
 
@@ -69,15 +80,19 @@
     D2D1_COMPOSITE_MODE m_compositeMode { D2D1_COMPOSITE_MODE_SOURCE_OVER };
     bool m_shouldIncludeChildWindows { false };
     bool m_didBeginDraw { false };
+    bool m_strokeSyleIsDirty { false };
 
     COMPtr<ID2D1SolidColorBrush> m_solidStrokeBrush;
     COMPtr<ID2D1SolidColorBrush> m_solidFillBrush;
 
 private:
+    void recomputeStrokeStyle();
+
     COMPtr<ID2D1RenderTarget> m_renderTarget;
     HashMap<RGBA32, COMPtr<ID2D1SolidColorBrush>> m_solidColoredBrushCache;
     COMPtr<ID2D1SolidColorBrush> m_whiteBrush;
     COMPtr<ID2D1SolidColorBrush> m_zeroBrush;
+    COMPtr<ID2D1StrokeStyle> m_d2dStrokeStyle;
 
     struct RenderState {
         COMPtr<ID2D1DrawingStateBlock> m_drawingStateBlock;
@@ -86,6 +101,16 @@
     };
 
     Vector<RenderState> m_renderStates;
+
+    D2D1_CAP_STYLE m_lineCap { D2D1_CAP_STYLE_FLAT };
+    D2D1_LINE_JOIN m_lineJoin { D2D1_LINE_JOIN_MITER };
+    StrokeStyle m_strokeStyle { SolidStroke };
+    DashArray m_dashes;
+    float m_miterLimit { 1.0f };
+    float m_dashOffset { 0 };
+    float m_patternWidth { 1.0f };
+    float m_patternOffset { 0 };
+    float m_strokeThickness { 0 };
 };
 
 class D2DContextStateSaver {

Modified: trunk/Source/WebCore/platform/graphics/win/PathDirect2D.cpp (207019 => 207020)


--- trunk/Source/WebCore/platform/graphics/win/PathDirect2D.cpp	2016-10-10 20:57:37 UTC (rev 207019)
+++ trunk/Source/WebCore/platform/graphics/win/PathDirect2D.cpp	2016-10-10 20:59:48 UTC (rev 207020)
@@ -490,7 +490,7 @@
     if (isNull())
         return FloatPoint();
 
-    float length;
+    float length = 0;
     HRESULT hr = m_path->ComputeLength(nullptr, &length);
     if (!SUCCEEDED(hr))
         return FloatPoint();
@@ -504,6 +504,16 @@
     return point;
 }
 
+float Path::length() const
+{
+    float length = 0;
+    HRESULT hr = m_path->ComputeLength(nullptr, &length);
+    if (!SUCCEEDED(hr))
+        return 0;
+
+    return length;
+}
+
 void Path::apply(const PathApplierFunction& function) const
 {
     if (isNull())
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to