Title: [207681] trunk/Source/WebCore
Revision
207681
Author
bfulg...@apple.com
Date
2016-10-21 10:10:31 -0700 (Fri, 21 Oct 2016)

Log Message

[Win][Direct2D] Correct some memory leaks and other minor bugs
https://bugs.webkit.org/show_bug.cgi?id=163769

Reviewed by Alex Christensen.

Several D2D handles were being leaked.
 
Direct2D sometimes returns an infinite rect containing { -inf, -inf, FloatMax, FloatMax },
sometimes { -FloatMax, -FloatMax, inf, inf }, and various combinations thereof. This caused
most SVG drawing to decide no screen rect was contained in the "infinite rect" so nothing
would be drawn.
        
Tested by existing layout tests. 

* platform/graphics/GraphicsContext.h:
* platform/graphics/win/FloatRectDirect2D.cpp:
(WebCore::isInfiniteRect): Recognize various infinite rects in Windows.
(WebCore::FloatRect::FloatRect): Convert a Windows infinite rect to the style
we use inside WebKit.
* platform/graphics/win/FontCascadeDirect2D.cpp:
(WebCore::FontCascade::drawGlyphs): Use cached brushes if possible.
* platform/graphics/win/GlyphPageTreeNodeDirect2D.cpp:
(WebCore::GlyphPage::fill): Don't terminate on this error case.
* platform/graphics/win/GradientDirect2D.cpp:
(WebCore::Gradient::generateGradient): Don't leak gradients.
* platform/graphics/win/GraphicsContextDirect2D.cpp:
(WebCore::GraphicsContextPlatformPrivate::brushWithColor): Added.
(WebCore::GraphicsContext::brushWithColor): Added.
(WebCore::GraphicsContextPlatformPrivate::concatCTM): Perform transform multiplication
in the right order (hint: it's not distributive).
(WebCore::GraphicsContext::drawWithShadow): Use convenience method.
(WebCore::GraphicsContext::fillRect): Ditto.
(WebCore::GraphicsContext::platformFillRoundedRect): Ditto.
(WebCore::GraphicsContext::clearRect): Ditto.
(WebCore::GraphicsContext::setPlatformStrokeColor): Ditto.
(WebCore::GraphicsContext::setPlatformFillColor): Ditto.
* platform/graphics/win/PathDirect2D.cpp:
(WebCore::Path::polygonPathFromPoints): No need to convert manually.
(WebCore::Path::~Path): Don't leak ID2D1Geometry entities.
(WebCore::Path::appendGeometry): Ditto.
(WebCore::Path::createGeometryWithFillMode): Ditto.
(WebCore::Path::Path): Ditto.
(WebCore::Path::operator=): Ditto.
(WebCore::Path::strokeBoundingRect): Provide an implementation.
(WebCore::Path::addRect): No need for manual casting here.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (207680 => 207681)


--- trunk/Source/WebCore/ChangeLog	2016-10-21 17:08:19 UTC (rev 207680)
+++ trunk/Source/WebCore/ChangeLog	2016-10-21 17:10:31 UTC (rev 207681)
@@ -1,3 +1,51 @@
+2016-10-20  Brent Fulgham  <bfulg...@apple.com>
+
+        [Win][Direct2D] Correct some memory leaks and other minor bugs
+        https://bugs.webkit.org/show_bug.cgi?id=163769
+
+        Reviewed by Alex Christensen.
+
+        Several D2D handles were being leaked.
+ 
+        Direct2D sometimes returns an infinite rect containing { -inf, -inf, FloatMax, FloatMax },
+        sometimes { -FloatMax, -FloatMax, inf, inf }, and various combinations thereof. This caused
+        most SVG drawing to decide no screen rect was contained in the "infinite rect" so nothing
+        would be drawn.
+        
+        Tested by existing layout tests. 
+
+        * platform/graphics/GraphicsContext.h:
+        * platform/graphics/win/FloatRectDirect2D.cpp:
+        (WebCore::isInfiniteRect): Recognize various infinite rects in Windows.
+        (WebCore::FloatRect::FloatRect): Convert a Windows infinite rect to the style
+        we use inside WebKit.
+        * platform/graphics/win/FontCascadeDirect2D.cpp:
+        (WebCore::FontCascade::drawGlyphs): Use cached brushes if possible.
+        * platform/graphics/win/GlyphPageTreeNodeDirect2D.cpp:
+        (WebCore::GlyphPage::fill): Don't terminate on this error case.
+        * platform/graphics/win/GradientDirect2D.cpp:
+        (WebCore::Gradient::generateGradient): Don't leak gradients.
+        * platform/graphics/win/GraphicsContextDirect2D.cpp:
+        (WebCore::GraphicsContextPlatformPrivate::brushWithColor): Added.
+        (WebCore::GraphicsContext::brushWithColor): Added.
+        (WebCore::GraphicsContextPlatformPrivate::concatCTM): Perform transform multiplication
+        in the right order (hint: it's not distributive).
+        (WebCore::GraphicsContext::drawWithShadow): Use convenience method.
+        (WebCore::GraphicsContext::fillRect): Ditto.
+        (WebCore::GraphicsContext::platformFillRoundedRect): Ditto.
+        (WebCore::GraphicsContext::clearRect): Ditto.
+        (WebCore::GraphicsContext::setPlatformStrokeColor): Ditto.
+        (WebCore::GraphicsContext::setPlatformFillColor): Ditto.
+        * platform/graphics/win/PathDirect2D.cpp:
+        (WebCore::Path::polygonPathFromPoints): No need to convert manually.
+        (WebCore::Path::~Path): Don't leak ID2D1Geometry entities.
+        (WebCore::Path::appendGeometry): Ditto.
+        (WebCore::Path::createGeometryWithFillMode): Ditto.
+        (WebCore::Path::Path): Ditto.
+        (WebCore::Path::operator=): Ditto.
+        (WebCore::Path::strokeBoundingRect): Provide an implementation.
+        (WebCore::Path::addRect): No need for manual casting here.
+
 2016-10-21  Wenson Hsieh  <wenson_hs...@apple.com>
 
         Fix minor style issue in the signature of StaticRange::create

Modified: trunk/Source/WebCore/platform/graphics/GraphicsContext.h (207680 => 207681)


--- trunk/Source/WebCore/platform/graphics/GraphicsContext.h	2016-10-21 17:08:19 UTC (rev 207680)
+++ trunk/Source/WebCore/platform/graphics/GraphicsContext.h	2016-10-21 17:10:31 UTC (rev 207681)
@@ -42,6 +42,7 @@
 interface ID2D1DCRenderTarget;
 interface ID2D1RenderTarget;
 interface ID2D1Factory;
+interface ID2D1SolidColorBrush;
 typedef ID2D1RenderTarget PlatformGraphicsContext;
 #elif USE(CAIRO)
 namespace WebCore {
@@ -559,6 +560,8 @@
     ID2D1Brush* solidFillBrush() const;
     ID2D1Brush* patternStrokeBrush() const;
     ID2D1Brush* patternFillBrush() const;
+
+    ID2D1SolidColorBrush* brushWithColor(const Color&);
 #endif
 #else // PLATFORM(WIN)
     bool shouldIncludeChildWindows() const { return false; }

Modified: trunk/Source/WebCore/platform/graphics/win/FloatRectDirect2D.cpp (207680 => 207681)


--- trunk/Source/WebCore/platform/graphics/win/FloatRectDirect2D.cpp	2016-10-21 17:08:19 UTC (rev 207680)
+++ trunk/Source/WebCore/platform/graphics/win/FloatRectDirect2D.cpp	2016-10-21 17:10:31 UTC (rev 207681)
@@ -33,10 +33,33 @@
 
 namespace WebCore {
 
+static bool isInfiniteRect(const D2D1_RECT_F& rect)
+{
+    if (!std::isinf(rect.top) && rect.top != -std::numeric_limits<float>::max())
+        return false;
+
+    if (!std::isinf(rect.left) && rect.left != -std::numeric_limits<float>::max())
+        return false;
+
+    if (!std::isinf(rect.bottom) && rect.bottom != std::numeric_limits<float>::max())
+        return false;
+
+    if (!std::isinf(rect.right) && rect.right != std::numeric_limits<float>::max())
+        return false;
+
+    return true;
+}
+
 FloatRect::FloatRect(const D2D1_RECT_F& r)
-    : m_location(FloatPoint(r.left, r.top))
-    , m_size(FloatSize(r.right - r.left, r.bottom - r.top))
 {
+    // Infinite Rect case:
+    if (isInfiniteRect(r)) {
+        *this = infiniteRect();
+        return;
+    }
+
+    m_location = FloatPoint(r.left, r.top);
+    m_size = FloatSize(r.right - r.left, r.bottom - r.top);
 }
 
 FloatRect::operator D2D1_RECT_F() const

Modified: trunk/Source/WebCore/platform/graphics/win/FontCascadeDirect2D.cpp (207680 => 207681)


--- trunk/Source/WebCore/platform/graphics/win/FontCascadeDirect2D.cpp	2016-10-21 17:08:19 UTC (rev 207680)
+++ trunk/Source/WebCore/platform/graphics/win/FontCascadeDirect2D.cpp	2016-10-21 17:10:31 UTC (rev 207681)
@@ -129,13 +129,10 @@
         // If shadows are ignoring transforms, then we haven't applied the Y coordinate flip yet, so down is negative.
         float shadowTextY = point.y() + translation.height() + shadowOffset.height() * (graphicsContext.shadowsIgnoreTransforms() ? -1 : 1);
 
-        COMPtr<ID2D1SolidColorBrush> shadowBrush;
-        if (!SUCCEEDED(context->CreateSolidColorBrush(graphicsContext.colorWithGlobalAlpha(shadowFillColor), &shadowBrush)))
-            return;
-
-        context->DrawGlyphRun(D2D1::Point2F(shadowTextX, shadowTextY), &glyphRun, shadowBrush.get());
+        auto shadowBrush = graphicsContext.brushWithColor(shadowFillColor);
+        context->DrawGlyphRun(D2D1::Point2F(shadowTextX, shadowTextY), &glyphRun, shadowBrush);
         if (font.syntheticBoldOffset())
-            context->DrawGlyphRun(D2D1::Point2F(shadowTextX + font.syntheticBoldOffset(), shadowTextY), &glyphRun, shadowBrush.get());
+            context->DrawGlyphRun(D2D1::Point2F(shadowTextX + font.syntheticBoldOffset(), shadowTextY), &glyphRun, shadowBrush);
     }
 
     context->DrawGlyphRun(D2D1::Point2F(point.x() + translation.width(), point.y() + translation.height()), &glyphRun, graphicsContext.solidFillBrush());

Modified: trunk/Source/WebCore/platform/graphics/win/GlyphPageTreeNodeDirect2D.cpp (207680 => 207681)


--- trunk/Source/WebCore/platform/graphics/win/GlyphPageTreeNodeDirect2D.cpp	2016-10-21 17:08:19 UTC (rev 207680)
+++ trunk/Source/WebCore/platform/graphics/win/GlyphPageTreeNodeDirect2D.cpp	2016-10-21 17:10:31 UTC (rev 207681)
@@ -67,7 +67,8 @@
     hr = analyzer->GetGlyphs(buffer, bufferLength, fontPlatformData.dwFontFace(), fontPlatformData.orientation() == Vertical, false,
         &helper.m_analysis, nullptr, nullptr, nullptr, nullptr, 0, GlyphPage::size, clusterMap, textProperties.data(),
         localGlyphBuffer, glyphProperties.data(), &returnedCount);
-    RELEASE_ASSERT(SUCCEEDED(hr));
+    if (!SUCCEEDED(hr))
+        return false;
 
     for (unsigned i = 0; i < GlyphPage::size; i++) {
         Glyph glyph = localGlyphBuffer[i];

Modified: trunk/Source/WebCore/platform/graphics/win/GradientDirect2D.cpp (207680 => 207681)


--- trunk/Source/WebCore/platform/graphics/win/GradientDirect2D.cpp	2016-10-21 17:08:19 UTC (rev 207680)
+++ trunk/Source/WebCore/platform/graphics/win/GradientDirect2D.cpp	2016-10-21 17:10:31 UTC (rev 207681)
@@ -66,6 +66,11 @@
     HRESULT hr = renderTarget->CreateGradientStopCollection(gradientStops.data(), gradientStops.size(), &gradientStopCollection);
     RELEASE_ASSERT(SUCCEEDED(hr));
 
+    if (m_gradient) {
+        m_gradient->Release();
+        m_gradient = nullptr;
+    }
+
     if (m_radial) {
         FloatSize offset = p1() - p0();
         ID2D1RadialGradientBrush* radialGradient = nullptr;

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


--- trunk/Source/WebCore/platform/graphics/win/GraphicsContextDirect2D.cpp	2016-10-21 17:08:19 UTC (rev 207680)
+++ trunk/Source/WebCore/platform/graphics/win/GraphicsContextDirect2D.cpp	2016-10-21 17:10:31 UTC (rev 207681)
@@ -274,7 +274,7 @@
     }
 
     auto existingBrush = m_solidColoredBrushCache.ensure(colorKey, [this, color] {
-        ID2D1SolidColorBrush* colorBrush = nullptr;
+        COMPtr<ID2D1SolidColorBrush> colorBrush;
         m_renderTarget->CreateSolidColorBrush(color, &colorBrush);
         return colorBrush;
     });
@@ -282,6 +282,11 @@
     return existingBrush.iterator->value;
 }
 
+ID2D1SolidColorBrush* GraphicsContext::brushWithColor(const Color& color)
+{
+    return m_data->brushWithColor(colorWithGlobalAlpha(color)).get();
+}
+
 void GraphicsContextPlatformPrivate::clip(const FloatRect& rect)
 {
     if (m_renderStates.isEmpty())
@@ -320,7 +325,8 @@
     D2D1_MATRIX_3X2_F currentTransform;
     m_renderTarget->GetTransform(&currentTransform);
 
-    m_renderTarget->SetTransform(affineTransform * AffineTransform(currentTransform));
+    D2D1_MATRIX_3X2_F transformToConcat = affineTransform;
+    m_renderTarget->SetTransform(transformToConcat * currentTransform);
 }
 
 void GraphicsContextPlatformPrivate::flush()
@@ -882,7 +888,8 @@
 
     deviceContext->BeginDraw();
     deviceContext->DrawImage(compositor.get(), D2D1_INTERPOLATION_MODE_LINEAR);
-    deviceContext->EndDraw();
+    hr = deviceContext->EndDraw();
+    ASSERT(SUCCEEDED(hr));
 }
 
 void GraphicsContext::fillPath(const Path& path)
@@ -1051,7 +1058,7 @@
 
     drawWithoutShadow(rect, [this, rect, color](ID2D1RenderTarget* renderTarget) {
         const D2D1_RECT_F d2dRect = rect;
-        renderTarget->FillRectangle(&d2dRect, m_data->brushWithColor(colorWithGlobalAlpha(color)).get());
+        renderTarget->FillRectangle(&d2dRect, brushWithColor(color));
     });
 }
 
@@ -1085,8 +1092,7 @@
     bool hasCustomFill = m_state.fillGradient || m_state.fillPattern;
     if (!hasCustomFill && equalWidths && equalHeights && radii.topLeft().width() * 2 == r.width() && radii.topLeft().height() * 2 == r.height()) {
         auto roundedRect = D2D1::RoundedRect(r, radii.topLeft().width(), radii.topLeft().height());
-        COMPtr<ID2D1SolidColorBrush> fillBrush = m_data->brushWithColor(colorWithGlobalAlpha(color));
-        context->FillRoundedRectangle(roundedRect, fillBrush.get());
+        context->FillRoundedRectangle(roundedRect, brushWithColor(color));
     } else {
         D2DContextStateSaver stateSaver(*m_data);
         setFillColor(color);
@@ -1345,7 +1351,7 @@
 
         renderTarget->SetTags(1, __LINE__);
         rectToClear.intersect(renderTargetRect);
-        renderTarget->FillRectangle(rectToClear, m_data->brushWithColor(colorWithGlobalAlpha(fillColor())).get());
+        renderTarget->FillRectangle(rectToClear, solidFillBrush());
     });
 }
 
@@ -1668,7 +1674,7 @@
 
     m_data->m_solidStrokeBrush = nullptr;
 
-    m_data->m_solidStrokeBrush = m_data->brushWithColor(colorWithGlobalAlpha(strokeColor()));
+    m_data->m_solidStrokeBrush = brushWithColor(strokeColor());
 }
 
 void GraphicsContext::setPlatformStrokeThickness(float thickness)
@@ -1683,7 +1689,7 @@
 
     m_data->m_solidFillBrush = nullptr;
 
-    m_data->m_solidFillBrush = m_data->brushWithColor(colorWithGlobalAlpha(fillColor()));
+    m_data->m_solidFillBrush = brushWithColor(fillColor());
 }
 
 void GraphicsContext::setPlatformShouldAntialias(bool enable)

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


--- trunk/Source/WebCore/platform/graphics/win/PathDirect2D.cpp	2016-10-21 17:08:19 UTC (rev 207680)
+++ trunk/Source/WebCore/platform/graphics/win/PathDirect2D.cpp	2016-10-21 17:10:31 UTC (rev 207681)
@@ -52,7 +52,7 @@
     Vector<D2D1_POINT_2F, 32> d2dPoints;
     d2dPoints.reserveInitialCapacity(points.size() - 1);
     for (auto point : points)
-        d2dPoints.uncheckedAppend(D2D1::Point2F(point.x(), point.y()));
+        d2dPoints.uncheckedAppend(point);
 
     path.moveTo(points.first());
 
@@ -70,6 +70,8 @@
 
 Path::~Path()
 {
+    if (m_path)
+        m_path->Release();
 }
 
 PlatformPathPtr Path::ensurePlatformPath()
@@ -89,18 +91,24 @@
     unsigned geometryCount = m_path ? m_path->GetSourceGeometryCount() : 0;
     Vector<ID2D1Geometry*> geometries(geometryCount, nullptr);
 
+    // Note: 'GetSourceGeometries' returns geometries that have a +1 ref count.
+    // so they must be released before we return.
     if (geometryCount)
         m_path->GetSourceGeometries(geometries.data(), geometryCount);
 
+    geometry->AddRef();
     geometries.append(geometry);
 
     auto fillMode = m_path ? m_path->GetFillMode() : D2D1_FILL_MODE_WINDING;
 
-    COMPtr<ID2D1GeometryGroup> protectedPath = m_path;
+    COMPtr<ID2D1GeometryGroup> protectedPath = adoptCOM(m_path);
     m_path = nullptr;
 
     HRESULT hr = GraphicsContext::systemFactory()->CreateGeometryGroup(fillMode, geometries.data(), geometries.size(), &m_path);
     RELEASE_ASSERT(SUCCEEDED(hr));
+
+    for (auto entry : geometries)
+        entry->Release();
 }
 
 void Path::createGeometryWithFillMode(WindRule webkitFillMode, COMPtr<ID2D1GeometryGroup>& path) const
@@ -118,10 +126,16 @@
 
     Vector<ID2D1Geometry*> geometries(geometryCount, nullptr);
     ASSERT(geometryCount);
+
+    // Note: 'GetSourceGeometries' returns geometries that have a +1 ref count.
+    // so they must be released before we return.
     m_path->GetSourceGeometries(geometries.data(), geometryCount);
 
     HRESULT hr = GraphicsContext::systemFactory()->CreateGeometryGroup(fillMode, geometries.data(), geometries.size(), &path);
     RELEASE_ASSERT(SUCCEEDED(hr));
+
+    for (auto entry : geometries)
+        entry->Release();
 }
 
 Path::Path(const Path& other)
@@ -133,15 +147,24 @@
 
         Vector<ID2D1Geometry*> geometries(geometryCount, nullptr);
         ASSERT(geometryCount);
+
+        // Note: 'GetSourceGeometries' returns geometries that have a +1 ref count.
+        // so they must be released before we return.
         otherPath->GetSourceGeometries(geometries.data(), geometryCount);
 
         HRESULT hr = GraphicsContext::systemFactory()->CreateGeometryGroup(other.m_path->GetFillMode(), geometries.data(), geometryCount, &m_path);
         RELEASE_ASSERT(SUCCEEDED(hr));
+
+        for (auto entry : geometries)
+            entry->Release();
     }
 }
 
 Path& Path::operator=(const Path& other)
 {
+    if (m_path)
+        m_path->Release();
+
     m_path = other.m_path;
     if (m_path)
         m_path->AddRef();
@@ -264,7 +287,7 @@
     if (!SUCCEEDED(m_path->GetBounds(nullptr, &bounds)))
         return FloatRect();
 
-    return FloatRect(bounds.left, bounds.bottom, bounds.right - bounds.left, bounds.top - bounds.bottom);
+    return bounds;
 }
 
 FloatRect Path::fastBoundingRect() const
@@ -276,7 +299,7 @@
     if (!SUCCEEDED(m_path->GetBounds(nullptr, &bounds)))
         return FloatRect();
 
-    return FloatRect(bounds.left, bounds.bottom, bounds.right - bounds.left, bounds.top - bounds.bottom);
+    return bounds;
 }
 
 FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const
@@ -284,9 +307,14 @@
     if (isNull())
         return FloatRect();
 
+    if (!applier)
+        return boundingRect();
+
     UNUSED_PARAM(applier);
     notImplemented();
-    return FloatRect();
+
+    // Just return regular bounding rect for now.
+    return boundingRect();
 }
 
 void Path::moveTo(const FloatPoint& point)
@@ -380,8 +408,17 @@
     m_activePath->EndFigure(D2D1_FIGURE_END_OPEN);
 }
 
-static void drawArcSection(ID2D1GeometrySink* sink, FloatPoint center, float radius, float startAngle, float endAngle, bool clockwise)
+static FloatPoint arcStart(const FloatPoint& center, float radius, float startAngle)
 {
+    FloatPoint startingPoint = center;
+    float startX = radius * std::cos(startAngle);
+    float startY = radius * std::sin(startAngle);
+    startingPoint.move(startX, startY);
+    return startingPoint;
+}
+
+static void drawArcSection(ID2D1GeometrySink* sink, const FloatPoint& center, float radius, float startAngle, float endAngle, bool clockwise)
+{
     // Direct2D wants us to specify the end point of the arc, not the center. It will be drawn from
     // whatever the current point in the 'm_activePath' is.
     FloatPoint p = center;
@@ -396,13 +433,13 @@
 
 void Path::addArc(const FloatPoint& center, float radius, float startAngle, float endAngle, bool clockwise)
 {
-    if (!m_activePath) {
-        float startX = radius * std::cos(startAngle);
-        float startY = radius * std::sin(startAngle);
-
-        FloatPoint start = center;
-        start.move(startX, startY);
-        moveTo(start);
+    auto arcStartPoint = arcStart(center, radius, startAngle);
+    if (!m_activePath)
+        moveTo(arcStartPoint);
+    else if (!areEssentiallyEqual(currentPoint(), arcStartPoint)) {
+        // If the arc defined by the center and radius does not intersect the current position,
+        // we need to draw a line from the current position to the starting point of the arc.
+        addLineTo(arcStartPoint);
     }
 
     // Direct2D has problems drawing large arcs. It gets confused if drawing a complete (or
@@ -423,7 +460,7 @@
 void Path::addRect(const FloatRect& r)
 {
     COMPtr<ID2D1RectangleGeometry> rectangle;
-    HRESULT hr = GraphicsContext::systemFactory()->CreateRectangleGeometry(static_cast<D2D1_RECT_F>(r), &rectangle);
+    HRESULT hr = GraphicsContext::systemFactory()->CreateRectangleGeometry(r, &rectangle);
     RELEASE_ASSERT(SUCCEEDED(hr));
     appendGeometry(rectangle.get());
 }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to