Diff
Modified: trunk/Source/WebCore/ChangeLog (237976 => 237977)
--- trunk/Source/WebCore/ChangeLog 2018-11-08 03:14:37 UTC (rev 237976)
+++ trunk/Source/WebCore/ChangeLog 2018-11-08 03:30:36 UTC (rev 237977)
@@ -1,3 +1,77 @@
+2018-11-07 Brent Fulgham <[email protected]>
+
+ [Windows][DirectX] Update canvas code to pass more tests
+ https://bugs.webkit.org/show_bug.cgi?id=191337
+ <rdar://problem/45878801>
+
+ Reviewed by Dean Jackson.
+
+ Update the Direct2D code paths to comply with our canvas tests, improving the
+ the test results scores to 579/770.
+
+ PathDirect2D was updated with an implementation of 'addArcTo' based on work by
+ Dirk Schulze <[email protected]> (see https://hg.mozilla.org/mozilla-central/rev/b116b49459f8).
+
+ Tests: canvas/philip/tests
+
+ * platform/graphics/ImageBuffer.cpp:
+ (WebCore::ImageBuffer::createCompatibleBuffer): Direct2D needs access to the graphics
+ context to create the buffer.
+ * platform/graphics/ImageBuffer.h:
+ * platform/graphics/Path.h:
+ * platform/graphics/win/GraphicsContextDirect2D.cpp:
+ (WebCore::GraphicsContext::drawPattern): Flush needed.
+ (WebCore::GraphicsContext::drawRect): Ditto.
+ (WebCore::GraphicsContextPlatformPrivate::setMiterLimit): Correct for Direct2D definition of miter limit.
+ (WebCore::GraphicsContextPlatformPrivate::strokeStyleProperties const): Added helper function.
+ (WebCore::GraphicsContextPlatformPrivate::recomputeStrokeStyle): Update for new helper.
+ (WebCore::GraphicsContext::drawLine): Ditto.
+ (WebCore::drawWithShadowHelper): Ditto.
+ (WebCore::GraphicsContext::fillRect): Add flush.
+ (WebCore::GraphicsContext::platformFillRoundedRect): Update for helper.
+ (WebCore::GraphicsContext::clipPath): Add flush.
+ (WebCore::GraphicsContext::strokeRect): Ditto.
+ (WebCore::GraphicsContext::drawLineForText): Update for upstream changes.
+ (WebCore::GraphicsContext::drawLinesForText): Ditto.
+ * platform/graphics/win/GraphicsContextPlatformPrivateDirect2D.h:
+ * platform/graphics/win/ImageBufferDirect2D.cpp:
+ (WebCore::createCroppedImageIfNecessary): Add missing implementations.
+ (WebCore::createBitmapImageAfterScalingIfNeeded): Ditto.
+ (WebCore::ImageBuffer::copyImage const): Ditto.
+ (WebCore::ImageBuffer::sinkIntoImage): Ditto.
+ (WebCore::ImageBuffer::fastCopyImageMode): Ditto.
+ (WebCore::ImageBuffer::sinkIntoNativeImage): Ditto.
+ (WebCore::ImageBuffer::copyNativeImage const): Ditto.
+ * platform/graphics/win/PathDirect2D.cpp:
+ (WebCore::Path::operator=):
+ (WebCore::Path::drawDidComplete): This should never have been const.
+ It manipulates the path!
+ (WebCore::Path::transform): Properly transform existing geometries.
+ (WebCore::Path::openFigureAtCurrentPointIfNecessary): Added.
+ (WebCore::Path::moveTo):
+ (WebCore::Path::addLineTo): Make sure figure starts at a valid point.
+ (WebCore::Path::addQuadCurveTo): Ditto.
+ (WebCore::Path::addBezierCurveTo): Ditto.
+ (WebCore::Path::addArcTo): Add implementation.
+ (WebCore::Path::closeSubpath):
+ (WebCore::drawArcSection):
+ (WebCore::Path::addArc): Update to build large arcs out of small arc segments. If the
+ arc is effectively a complete circle, use the ellipse drawing routines.
+ (WebCore::Path::addRect): Make sure we start at a valid starting point.
+ (WebCore::Path::addEllipse): Correct for definition of D2D ellipse.
+ (WebCore::Path::drawDidComplete const): Deleted.
+ * platform/graphics/win/SimpleFontDataDirect2D.cpp:
+ (WebCore::Font::platformWidthForGlyph const):
+ * rendering/svg/RenderSVGResourceClipper.cpp:
+ (WebCore::RenderSVGResourceClipper::applyClippingToContext):
+ * rendering/svg/RenderSVGResourceFilter.cpp:
+ (WebCore::RenderSVGResourceFilter::applyResource):
+ * rendering/svg/RenderSVGResourceMasker.cpp:
+ (WebCore::RenderSVGResourceMasker::applyResource):
+ * rendering/svg/SVGRenderingContext.cpp:
+ (WebCore::SVGRenderingContext::createImageBuffer):
+ * rendering/svg/SVGRenderingContext.h:
+
2018-11-07 Wenson Hsieh <[email protected]>
Add an editing command for creating and inserting child lists
Modified: trunk/Source/WebCore/platform/graphics/ImageBuffer.cpp (237976 => 237977)
--- trunk/Source/WebCore/platform/graphics/ImageBuffer.cpp 2018-11-08 03:14:37 UTC (rev 237976)
+++ trunk/Source/WebCore/platform/graphics/ImageBuffer.cpp 2018-11-08 03:30:36 UTC (rev 237977)
@@ -212,7 +212,11 @@
std::unique_ptr<ImageBuffer> ImageBuffer::createCompatibleBuffer(const FloatSize& size, float resolutionScale, ColorSpace colorSpace, const GraphicsContext& context)
{
+#if USE(DIRECT2D)
+ return create(size, context.renderingMode(), &context, resolutionScale, colorSpace);
+#else
return create(size, context.renderingMode(), resolutionScale, colorSpace);
+#endif
}
IntSize ImageBuffer::compatibleBufferSize(const FloatSize& size, const GraphicsContext& context)
Modified: trunk/Source/WebCore/platform/graphics/ImageBuffer.h (237976 => 237977)
--- trunk/Source/WebCore/platform/graphics/ImageBuffer.h 2018-11-08 03:14:37 UTC (rev 237976)
+++ trunk/Source/WebCore/platform/graphics/ImageBuffer.h 2018-11-08 03:30:36 UTC (rev 237977)
@@ -141,6 +141,8 @@
static RetainPtr<CGImageRef> sinkIntoNativeImage(std::unique_ptr<ImageBuffer>);
void flushContext() const;
#elif USE(DIRECT2D)
+ COMPtr<ID2D1Bitmap> copyNativeImage(BackingStoreCopy = CopyBackingStore) const;
+ static COMPtr<ID2D1Bitmap> sinkIntoNativeImage(std::unique_ptr<ImageBuffer>);
void flushContext() const;
#endif
Modified: trunk/Source/WebCore/platform/graphics/Path.h (237976 => 237977)
--- trunk/Source/WebCore/platform/graphics/Path.h 2018-11-08 03:14:37 UTC (rev 237976)
+++ trunk/Source/WebCore/platform/graphics/Path.h 2018-11-08 03:30:36 UTC (rev 237977)
@@ -197,9 +197,10 @@
ID2D1GeometrySink* activePath() const { return m_activePath.get(); }
void appendGeometry(ID2D1Geometry*);
void createGeometryWithFillMode(WindRule, COMPtr<ID2D1GeometryGroup>&) const;
- void drawDidComplete() const;
+ void drawDidComplete();
HRESULT initializePathState();
+ void openFigureAtCurrentPointIfNecessary();
#endif
#ifndef NDEBUG
@@ -211,6 +212,7 @@
COMPtr<ID2D1GeometryGroup> m_path;
COMPtr<ID2D1PathGeometry> m_activePathGeometry;
COMPtr<ID2D1GeometrySink> m_activePath;
+ bool m_doesHaveOpenFigure { false };
#else
PlatformPathPtr m_path { nullptr };
#endif
Modified: trunk/Source/WebCore/platform/graphics/win/GraphicsContextDirect2D.cpp (237976 => 237977)
--- trunk/Source/WebCore/platform/graphics/win/GraphicsContextDirect2D.cpp 2018-11-08 03:14:37 UTC (rev 237976)
+++ trunk/Source/WebCore/platform/graphics/win/GraphicsContextDirect2D.cpp 2018-11-08 03:30:36 UTC (rev 237977)
@@ -596,6 +596,9 @@
COMPtr<ID2D1BitmapBrush> patternBrush;
HRESULT hr = context->CreateBitmapBrush(tileImage.get(), &bitmapBrushProperties, &brushProperties, &patternBrush);
+ ASSERT(SUCCEEDED(hr));
+ if (!SUCCEEDED(hr))
+ return;
drawWithoutShadow(destRect, [this, destRect, patternBrush](ID2D1RenderTarget* renderTarget) {
const D2D1_RECT_F d2dRect = destRect;
@@ -692,8 +695,10 @@
m_strokeSyleIsDirty = true;
}
-void GraphicsContextPlatformPrivate::setMiterLimit(float miterLimit)
+void GraphicsContextPlatformPrivate::setMiterLimit(float canvasMiterLimit)
{
+ // Direct2D miter limit is in terms of HALF the line thickness.
+ float miterLimit = 0.5f * canvasMiterLimit;
if (WTF::areEssentiallyEqual(miterLimit, m_miterLimit))
return;
@@ -746,6 +751,11 @@
m_strokeSyleIsDirty = true;
}
+D2D1_STROKE_STYLE_PROPERTIES GraphicsContextPlatformPrivate::strokeStyleProperties() const
+{
+ return D2D1::StrokeStyleProperties(m_lineCap, m_lineCap, m_lineCap, m_lineJoin, m_miterLimit, D2D1_DASH_STYLE_SOLID, 0.0f);
+}
+
void GraphicsContextPlatformPrivate::recomputeStrokeStyle()
{
if (!m_strokeSyleIsDirty)
@@ -753,19 +763,23 @@
m_d2dStrokeStyle = nullptr;
+ DashArray dashes;
+ float patternOffset = 0;
+ auto dashStyle = D2D1_DASH_STYLE_SOLID;
+
if ((m_strokeStyle != SolidStroke) && (m_strokeStyle != NoStroke)) {
- float patternOffset = m_patternOffset / m_strokeThickness;
+ dashStyle = D2D1_DASH_STYLE_CUSTOM;
+ patternOffset = m_patternOffset / m_strokeThickness;
+ dashes = m_dashes;
- 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);
}
+ auto strokeStyleProperties = D2D1::StrokeStyleProperties(m_lineCap, m_lineCap, m_lineCap, m_lineJoin, m_miterLimit, dashStyle, patternOffset);
+ GraphicsContext::systemFactory()->CreateStrokeStyle(&strokeStyleProperties, dashes.data(), dashes.size(), &m_d2dStrokeStyle);
+
m_strokeSyleIsDirty = false;
}
@@ -819,7 +833,7 @@
float patternOffset = dashedLinePatternOffsetForPatternAndStrokeWidth(patternWidth, strokeWidth);
const float dashes[2] = { patternWidth, patternWidth };
- auto strokeStyleProperties = D2D1::StrokeStyleProperties();
+ auto strokeStyleProperties = m_data->strokeStyleProperties();
GraphicsContext::systemFactory()->CreateStrokeStyle(&strokeStyleProperties, dashes, ARRAYSIZE(dashes), &d2dStrokeStyle);
m_data->setPatternWidth(patternWidth);
@@ -926,8 +940,6 @@
auto brush = m_state.strokePattern ? patternStrokeBrush() : solidStrokeBrush();
renderTarget->DrawGeometry(path.platformPath(), brush, strokeThickness(), m_data->strokeStyle());
});
-
- flush();
}
void GraphicsContext::drawWithoutShadow(const FloatRect& /*boundingRect*/, const WTF::Function<void(ID2D1RenderTarget*)>& drawCommands)
@@ -1047,8 +1059,6 @@
auto brush = m_state.fillPattern ? patternFillBrush() : solidFillBrush();
renderTarget->FillGeometry(pathToFill.get(), brush);
});
-
- flush();
}
void GraphicsContext::strokePath(const Path& path)
@@ -1092,8 +1102,6 @@
auto brush = m_state.strokePattern ? patternStrokeBrush() : solidStrokeBrush();
renderTarget->DrawGeometry(path.platformPath(), brush, strokeThickness(), m_data->strokeStyle());
});
-
- flush();
}
void GraphicsContext::fillRect(const FloatRect& rect)
@@ -1329,6 +1337,8 @@
return;
}
+ ASSERT(!path.activePath());
+
COMPtr<ID2D1GeometryGroup> pathToClip;
path.createGeometryWithFillMode(clipRule, pathToClip);
@@ -1687,24 +1697,23 @@
return rect;
}
-void GraphicsContext::drawLineForText(const FloatPoint& point, float width, bool printing, bool doubleLines, StrokeStyle strokeStyle)
+void GraphicsContext::drawLineForText(const FloatRect& rect, bool printing, bool doubleLines, StrokeStyle strokeStyle)
{
DashArray widths;
widths.append(0);
- widths.append(width);
- drawLinesForText(point, widths, printing, doubleLines, strokeStyle);
+ widths.append(rect.width());
+ drawLinesForText(rect.location(), rect.height(), widths, printing, doubleLines, strokeStyle);
}
-void GraphicsContext::drawLinesForText(const FloatPoint& point, const DashArray& widths, bool printing, bool doubleLines, StrokeStyle strokeStyle)
+void GraphicsContext::drawLinesForText(const FloatPoint& point, float thickness, const DashArray& widths, bool printing, bool doubleLines, StrokeStyle strokeStyle)
{
if (paintingDisabled())
- return;
if (!widths.size())
return;
if (m_impl) {
- m_impl->drawLinesForText(point, widths, printing, doubleLines, strokeThickness());
+ m_impl->drawLinesForText(point, thickness, widths, printing, doubleLines);
return;
}
Modified: trunk/Source/WebCore/platform/graphics/win/GraphicsContextPlatformPrivateDirect2D.h (237976 => 237977)
--- trunk/Source/WebCore/platform/graphics/win/GraphicsContextPlatformPrivateDirect2D.h 2018-11-08 03:14:37 UTC (rev 237976)
+++ trunk/Source/WebCore/platform/graphics/win/GraphicsContextPlatformPrivateDirect2D.h 2018-11-08 03:30:36 UTC (rev 237977)
@@ -92,6 +92,8 @@
float currentGlobalAlpha() const;
+ D2D1_STROKE_STYLE_PROPERTIES strokeStyleProperties() const;
+
private:
void recomputeStrokeStyle();
@@ -124,7 +126,7 @@
StrokeStyle m_strokeStyle { SolidStroke };
DashArray m_dashes;
- float m_miterLimit { 1.0f };
+ float m_miterLimit { 10.0f };
float m_dashOffset { 0 };
float m_patternWidth { 1.0f };
float m_patternOffset { 0 };
Modified: trunk/Source/WebCore/platform/graphics/win/ImageBufferDirect2D.cpp (237976 => 237977)
--- trunk/Source/WebCore/platform/graphics/win/ImageBufferDirect2D.cpp 2018-11-08 03:14:37 UTC (rev 237976)
+++ trunk/Source/WebCore/platform/graphics/win/ImageBufferDirect2D.cpp 2018-11-08 03:30:36 UTC (rev 237977)
@@ -137,21 +137,56 @@
context().flush();
}
-RefPtr<Image> ImageBuffer::copyImage(BackingStoreCopy copyBehavior, PreserveResolution) const
+static COMPtr<ID2D1Bitmap> createCroppedImageIfNecessary(ID2D1Bitmap* image, const IntSize& bounds)
{
- notImplemented();
- return nullptr;
+ FloatSize imageSize = image ? image->GetSize() : FloatSize();
+
+ if (image && (static_cast<size_t>(imageSize.width()) != static_cast<size_t>(bounds.width()) || static_cast<size_t>(imageSize.height()) != static_cast<size_t>(bounds.height()))) {
+ D2D_POINT_2U origin = { };
+ D2D1_RECT_U croppedDimenstions = IntRect(IntPoint(), bounds);
+ COMPtr<ID2D1Bitmap> croppedImage;
+ HRESULT hr = croppedImage->CopyFromBitmap(&origin, image, &croppedDimenstions);
+ if (SUCCEEDED(hr))
+ return croppedImage;
+ }
+
+ return image;
}
-RefPtr<Image> ImageBuffer::sinkIntoImage(std::unique_ptr<ImageBuffer> imageBuffer, PreserveResolution)
+static RefPtr<Image> createBitmapImageAfterScalingIfNeeded(COMPtr<ID2D1Bitmap>&& image, IntSize internalSize, IntSize logicalSize, IntSize backingStoreSize, float resolutionScale, PreserveResolution preserveResolution)
{
+ if (resolutionScale == 1 || preserveResolution == PreserveResolution::Yes)
+ image = createCroppedImageIfNecessary(image.get(), internalSize);
+ else {
+ // FIXME: Need to implement scaled version
+ notImplemented();
+ }
+
+ if (!image)
+ return nullptr;
+
+ return BitmapImage::create(WTFMove(image));
+}
+
+RefPtr<Image> ImageBuffer::copyImage(BackingStoreCopy copyBehavior, PreserveResolution preserveResolution) const
+{
+ COMPtr<ID2D1Bitmap> image;
+ if (m_resolutionScale == 1 || preserveResolution == PreserveResolution::Yes)
+ image = copyNativeImage(copyBehavior);
+ else
+ image = copyNativeImage(DontCopyBackingStore);
+
+ return createBitmapImageAfterScalingIfNeeded(WTFMove(image), internalSize(), logicalSize(), m_data.backingStoreSize, m_resolutionScale, preserveResolution);
+}
+
+RefPtr<Image> ImageBuffer::sinkIntoImage(std::unique_ptr<ImageBuffer> imageBuffer, PreserveResolution preserveResolution)
+{
IntSize internalSize = imageBuffer->internalSize();
IntSize logicalSize = imageBuffer->logicalSize();
IntSize backingStoreSize = imageBuffer->m_data.backingStoreSize;
float resolutionScale = imageBuffer->m_resolutionScale;
- notImplemented();
- return nullptr;
+ return createBitmapImageAfterScalingIfNeeded(sinkIntoNativeImage(WTFMove(imageBuffer)), internalSize, logicalSize, backingStoreSize, resolutionScale, preserveResolution);
}
BackingStoreCopy ImageBuffer::fastCopyImageMode()
@@ -159,6 +194,41 @@
return DontCopyBackingStore;
}
+COMPtr<ID2D1Bitmap> ImageBuffer::sinkIntoNativeImage(std::unique_ptr<ImageBuffer> imageBuffer)
+{
+ // FIXME: See if we can reuse the on-hardware image.
+ return imageBuffer->copyNativeImage(DontCopyBackingStore);
+}
+
+COMPtr<ID2D1Bitmap> ImageBuffer::copyNativeImage(BackingStoreCopy copyBehavior) const
+{
+ auto bitmapTarget = reinterpret_cast<ID2D1BitmapRenderTarget*>(context().platformContext());
+
+ COMPtr<ID2D1Bitmap> image;
+ HRESULT hr = bitmapTarget->GetBitmap(&image);
+ ASSERT(SUCCEEDED(hr));
+
+ if (!context().isAcceleratedContext()) {
+ switch (copyBehavior) {
+ case DontCopyBackingStore:
+ break;
+ case CopyBackingStore:
+ D2D1_RECT_U backingStoreDimenstions = IntRect(IntPoint(), m_data.backingStoreSize);
+ image->CopyFromMemory(&backingStoreDimenstions, m_data.data, 32);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ }
+#if USE(IOSURFACE_CANVAS_BACKING_STORE)
+ else
+ image = m_data.surface->createImage();
+#endif
+
+ return image;
+}
+
void ImageBuffer::drawConsuming(std::unique_ptr<ImageBuffer> imageBuffer, GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode)
{
imageBuffer->draw(destContext, destRect, srcRect, op, blendMode);
Modified: trunk/Source/WebCore/platform/graphics/win/PathDirect2D.cpp (237976 => 237977)
--- trunk/Source/WebCore/platform/graphics/win/PathDirect2D.cpp 2018-11-08 03:14:37 UTC (rev 237976)
+++ trunk/Source/WebCore/platform/graphics/win/PathDirect2D.cpp 2018-11-08 03:30:36 UTC (rev 237977)
@@ -171,6 +171,8 @@
Path& Path::operator=(const Path& other)
{
+ if (this == &other)
+ return *this;
m_path = other.m_path;
m_activePath = other.m_activePath;
m_activePathGeometry = other.m_activePathGeometry;
@@ -208,7 +210,7 @@
return m_activePathGeometry->Open(&m_activePath);
}
-void Path::drawDidComplete() const
+void Path::drawDidComplete()
{
FloatPoint currentPoint = this->currentPoint();
@@ -222,6 +224,7 @@
m_activePath->SetFillMode(D2D1_FILL_MODE_WINDING);
m_activePath->BeginFigure(currentPoint, D2D1_FIGURE_BEGIN_FILLED);
+ m_doesHaveOpenFigure = true;
}
bool Path::contains(const FloatPoint& point, WindRule rule) const
@@ -267,8 +270,14 @@
if (transform.isIdentity() || isEmpty())
return;
+ std::optional<FloatPoint> currentPoint;
+ if (hasCurrentPoint())
+ currentPoint = this->currentPoint();
+
bool pathIsActive = false;
if (m_activePath) {
+ m_activePath->EndFigure(D2D1_FIGURE_END_OPEN);
+ m_doesHaveOpenFigure = false;
m_activePath->Close();
m_activePath = nullptr;
m_activePathGeometry = nullptr;
@@ -275,9 +284,8 @@
pathIsActive = true;
}
- const D2D1_MATRIX_3X2_F& d2dTransform = static_cast<const D2D1_MATRIX_3X2_F>(transform);
COMPtr<ID2D1TransformedGeometry> transformedPath;
- if (!SUCCEEDED(GraphicsContext::systemFactory()->CreateTransformedGeometry(m_path.get(), d2dTransform, &transformedPath)))
+ if (!SUCCEEDED(GraphicsContext::systemFactory()->CreateTransformedGeometry(m_path.get(), transform, &transformedPath)))
return;
Vector<ID2D1Geometry*> geometries;
@@ -295,6 +303,15 @@
HRESULT hr = GraphicsContext::systemFactory()->CreateGeometryGroup(fillMode, geometries.data(), geometries.size(), &m_path);
RELEASE_ASSERT(SUCCEEDED(hr));
+
+ if (!currentPoint)
+ return;
+
+ m_activePath->SetFillMode(fillMode);
+
+ auto transformedPoint = transform.mapPoint(currentPoint.value());
+ m_activePath->BeginFigure(transformedPoint, D2D1_FIGURE_BEGIN_FILLED);
+ m_doesHaveOpenFigure = true;
}
FloatRect Path::boundingRect() const
@@ -336,20 +353,35 @@
return boundingRect();
}
+void Path::openFigureAtCurrentPointIfNecessary()
+{
+ if (m_doesHaveOpenFigure)
+ return;
+
+ m_activePath->SetFillMode(D2D1_FILL_MODE_WINDING);
+ m_activePath->BeginFigure(currentPoint(), D2D1_FIGURE_BEGIN_FILLED);
+ m_doesHaveOpenFigure = true;
+}
+
void Path::moveTo(const FloatPoint& point)
{
- if (!m_activePath) {
- GraphicsContext::systemFactory()->CreatePathGeometry(&m_activePathGeometry);
+ if (m_activePath) {
+ m_activePath->Close();
+ m_activePath = nullptr;
+ m_activePathGeometry = nullptr;
+ m_doesHaveOpenFigure = false;
+ }
- appendGeometry(m_activePathGeometry.get());
+ GraphicsContext::systemFactory()->CreatePathGeometry(&m_activePathGeometry);
- if (!SUCCEEDED(m_activePathGeometry->Open(&m_activePath)))
- return;
+ appendGeometry(m_activePathGeometry.get());
- m_activePath->SetFillMode(D2D1_FILL_MODE_WINDING);
- }
+ if (!SUCCEEDED(m_activePathGeometry->Open(&m_activePath)))
+ return;
+ m_activePath->SetFillMode(D2D1_FILL_MODE_WINDING);
m_activePath->BeginFigure(point, D2D1_FIGURE_BEGIN_FILLED);
+ m_doesHaveOpenFigure = true;
}
void Path::addLineTo(const FloatPoint& point)
@@ -356,6 +388,7 @@
{
ASSERT(m_activePath.get());
+ openFigureAtCurrentPointIfNecessary();
m_activePath->AddLine(point);
}
@@ -363,6 +396,7 @@
{
ASSERT(m_activePath.get());
+ openFigureAtCurrentPointIfNecessary();
m_activePath->AddQuadraticBezier(D2D1::QuadraticBezierSegment(cp, p));
}
@@ -370,17 +404,48 @@
{
ASSERT(m_activePath.get());
- FloatPoint beforePoint = currentPoint();
-
+ openFigureAtCurrentPointIfNecessary();
m_activePath->AddBezier(D2D1::BezierSegment(cp1, cp2, p));
}
void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
{
- UNUSED_PARAM(p1);
- UNUSED_PARAM(p2);
- UNUSED_PARAM(radius);
- notImplemented();
+ ASSERT(m_activePath.get());
+
+ FloatPoint p0 = currentPoint();
+
+ if (p1 == p0 || p1 == p2 || WTF::areEssentiallyEqual(radius, 0.0f))
+ return addLineTo(p1);
+
+ float direction = (p2.x() - p1.x()) * (p0.y() - p1.y()) + (p2.y() - p1.y()) * (p1.x() - p0.x());
+ if (WTF::areEssentiallyEqual(direction, 0.0f))
+ return addLineTo(p1);
+
+ auto a2 = toFloatPoint(p0 - p1).lengthSquared();
+ auto b2 = toFloatPoint(p1 - p2).lengthSquared();
+ auto c2 = toFloatPoint(p0 - p2).lengthSquared();
+
+ double cosx = (a2 + b2 - c2) / (2.0 * std::sqrt(a2 * b2));
+ double sinx = std::sqrt(1.0 - cosx * cosx);
+ double d = radius / ((1 - cosx) / sinx);
+
+ auto an = toFloatPoint(p1 - p0).scaled(1.0 / std::sqrt(a2));
+ auto bn = toFloatPoint(p1 - p2).scaled(1.0 / std::sqrt(b2));
+
+ auto startPoint = toFloatPoint(p1 - an.scaled(d));
+ auto p4 = toFloatPoint(p1 - bn.scaled(d));
+
+ bool anticlockwise = (direction < 0);
+ an.scale(radius * (anticlockwise ? 1 : -1));
+
+ FloatPoint center(startPoint.x() + an.y(), startPoint.y() - an.x());
+
+ double angle0 = atan2(startPoint.y() - center.y(), startPoint.x() - center.x());
+ double angle1 = atan2(p4.y() - center.y(), p4.x() - center.x());
+
+ openFigureAtCurrentPointIfNecessary();
+ addLineTo(startPoint);
+ addArc(center, radius, angle0, angle1, anticlockwise);
}
static bool equalRadiusWidths(const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius)
@@ -423,8 +488,14 @@
if (isNull())
return;
- ASSERT(m_activePath.get());
- m_activePath->EndFigure(D2D1_FIGURE_END_OPEN);
+ if (m_activePath) {
+ m_activePath->EndFigure(D2D1_FIGURE_END_CLOSED);
+ m_activePath->Close();
+ m_activePath = nullptr;
+ m_activePathGeometry = nullptr;
+ }
+
+ m_doesHaveOpenFigure = false;
}
static FloatPoint arcStart(const FloatPoint& center, float radius, float startAngle)
@@ -436,21 +507,22 @@
return startingPoint;
}
-static void drawArcSection(ID2D1GeometrySink* sink, const FloatPoint& center, float radius, float startAngle, float endAngle, bool clockwise)
+const float twoPi = 2.0f * piFloat;
+
+static void drawArcSection(ID2D1GeometrySink* sink, const FloatPoint& center, float radius, float startAngle, float endAngle, bool anticlockwise)
{
// 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;
+ FloatPoint endPoint = center;
float endX = radius * std::cos(endAngle);
float endY = radius * std::sin(endAngle);
- p.move(endX, endY);
+ endPoint.move(endX, endY);
- float arcDeg = rad2deg(endAngle - startAngle);
- D2D1_SWEEP_DIRECTION direction = clockwise ? D2D1_SWEEP_DIRECTION_CLOCKWISE : D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE;
- sink->AddArc(D2D1::ArcSegment(p, D2D1::SizeF(radius, radius), arcDeg, direction, D2D1_ARC_SIZE_SMALL));
+ D2D1_SWEEP_DIRECTION direction = anticlockwise ? D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE : D2D1_SWEEP_DIRECTION_CLOCKWISE;
+ sink->AddArc(D2D1::ArcSegment(endPoint, D2D1::SizeF(radius, radius), 0, direction, D2D1_ARC_SIZE_SMALL));
}
-void Path::addArc(const FloatPoint& center, float radius, float startAngle, float endAngle, bool clockwise)
+void Path::addArc(const FloatPoint& center, float radius, float startAngle, float endAngle, bool anticlockwise)
{
auto arcStartPoint = arcStart(center, radius, startAngle);
if (!m_activePath)
@@ -461,23 +533,41 @@
addLineTo(arcStartPoint);
}
- // Direct2D has problems drawing large arcs. It gets confused if drawing a complete (or
- // nearly complete) circle in the counter-clockwise direction. So, draw any arcs larger
- // than 180 degrees in two pieces.
- float fullSweep = endAngle - startAngle;
- float negate = fullSweep < 0 ? -1.0f : 1.0f;
- float maxSweep = negate * std::min(std::abs(fullSweep), piFloat);
- float firstArcEnd = startAngle + maxSweep;
- drawArcSection(m_activePath.get(), center, radius, startAngle, firstArcEnd, clockwise);
+ if (WTF::areEssentiallyEqual(std::abs(endAngle - startAngle), twoPi))
+ return addEllipse(FloatRect(center.x() - radius, center.y() - radius, 2.0 * radius, 2.0 * radius));
- if (WTF::areEssentiallyEqual(firstArcEnd, endAngle))
- return;
+ if (anticlockwise) {
+ if (endAngle > startAngle) {
+ endAngle -= twoPi * std::ceil((endAngle - startAngle) / twoPi);
+ ASSERT(endAngle <= startAngle);
+ }
+ } else {
+ if (startAngle > endAngle) {
+ startAngle -= twoPi * std::ceil((startAngle - endAngle) / twoPi);
+ ASSERT(startAngle <= endAngle);
+ }
+ }
- drawArcSection(m_activePath.get(), center, radius, firstArcEnd, endAngle, clockwise);
+ const float delta = anticlockwise ? -piOverTwoFloat : piOverTwoFloat;
+ float remainingArcAngle = endAngle - startAngle;
+
+ while ((remainingArcAngle > 0 && remainingArcAngle > delta) || (remainingArcAngle < 0 && remainingArcAngle < delta)) {
+ const double currentEndAngle = startAngle + delta;
+ drawArcSection(m_activePath.get(), center, radius, startAngle, currentEndAngle, anticlockwise);
+ startAngle = currentEndAngle;
+ remainingArcAngle -= delta;
+ }
+
+ // Handle any remaining part of the arc:
+ if (std::abs(remainingArcAngle) > 1e-6)
+ drawArcSection(m_activePath.get(), center, radius, startAngle, startAngle + remainingArcAngle, anticlockwise);
}
void Path::addRect(const FloatRect& r)
{
+ if (!m_activePath)
+ moveTo(r.location());
+
COMPtr<ID2D1RectangleGeometry> rectangle;
HRESULT hr = GraphicsContext::systemFactory()->CreateRectangleGeometry(r, &rectangle);
RELEASE_ASSERT(SUCCEEDED(hr));
@@ -494,8 +584,12 @@
void Path::addEllipse(const FloatRect& r)
{
+ if (!m_activePath)
+ moveTo(r.location());
+
COMPtr<ID2D1EllipseGeometry> ellipse;
- HRESULT hr = GraphicsContext::systemFactory()->CreateEllipseGeometry(D2D1::Ellipse(r.center(), r.width(), r.height()), &ellipse);
+ // Note: The radii of the ellipse contained within a rectange are half the width and height of the rect.
+ HRESULT hr = GraphicsContext::systemFactory()->CreateEllipseGeometry(D2D1::Ellipse(r.center(), 0.5 * r.width(), 0.5 * r.height()), &ellipse);
RELEASE_ASSERT(SUCCEEDED(hr));
appendGeometry(ellipse.get());
}
Modified: trunk/Source/WebCore/platform/graphics/win/SimpleFontDataDirect2D.cpp (237976 => 237977)
--- trunk/Source/WebCore/platform/graphics/win/SimpleFontDataDirect2D.cpp 2018-11-08 03:14:37 UTC (rev 237976)
+++ trunk/Source/WebCore/platform/graphics/win/SimpleFontDataDirect2D.cpp 2018-11-08 03:30:36 UTC (rev 237977)
@@ -207,8 +207,6 @@
if (m_platformData.useGDI())
return widthForGDIGlyph(glyph);
- ASSERT(glyph);
-
auto font = m_platformData.dwFont();
RELEASE_ASSERT(font);
Modified: trunk/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp (237976 => 237977)
--- trunk/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp 2018-11-08 03:14:37 UTC (rev 237976)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp 2018-11-08 03:30:36 UTC (rev 237977)
@@ -142,7 +142,7 @@
if (shouldCreateClipperMaskImage && !repaintRect.isEmpty()) {
// FIXME (149469): This image buffer should not be unconditionally unaccelerated. Making it match the context breaks nested clipping, though.
- clipperMaskImage = SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, ColorSpaceSRGB, Unaccelerated);
+ clipperMaskImage = SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, ColorSpaceSRGB, Unaccelerated, &context);
if (!clipperMaskImage)
return false;
Modified: trunk/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp (237976 => 237977)
--- trunk/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp 2018-11-08 03:14:37 UTC (rev 237976)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp 2018-11-08 03:30:36 UTC (rev 237977)
@@ -191,7 +191,7 @@
effectiveTransform.multiply(filterData->shearFreeAbsoluteTransform);
RenderingMode renderingMode = renderer.settings().acceleratedFiltersEnabled() ? Accelerated : Unaccelerated;
- auto sourceGraphic = SVGRenderingContext::createImageBuffer(filterData->drawingRegion, effectiveTransform, ColorSpaceLinearRGB, renderingMode);
+ auto sourceGraphic = SVGRenderingContext::createImageBuffer(filterData->drawingRegion, effectiveTransform, ColorSpaceLinearRGB, renderingMode, context);
if (!sourceGraphic) {
ASSERT(!m_rendererFilterDataMap.contains(&renderer));
filterData->savedContext = context;
Modified: trunk/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp (237976 => 237977)
--- trunk/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp 2018-11-08 03:14:37 UTC (rev 237976)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp 2018-11-08 03:30:36 UTC (rev 237977)
@@ -71,7 +71,7 @@
const SVGRenderStyle& svgStyle = style().svgStyle();
ColorSpace colorSpace = svgStyle.colorInterpolation() == ColorInterpolation::LinearRGB ? ColorSpaceLinearRGB : ColorSpaceSRGB;
// FIXME (149470): This image buffer should not be unconditionally unaccelerated. Making it match the context breaks alpha masking, though.
- maskerData->maskImage = SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, colorSpace, Unaccelerated);
+ maskerData->maskImage = SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, colorSpace, Unaccelerated, context);
if (!maskerData->maskImage)
return false;
Modified: trunk/Source/WebCore/rendering/svg/SVGRenderingContext.cpp (237976 => 237977)
--- trunk/Source/WebCore/rendering/svg/SVGRenderingContext.cpp 2018-11-08 03:14:37 UTC (rev 237976)
+++ trunk/Source/WebCore/rendering/svg/SVGRenderingContext.cpp 2018-11-08 03:30:36 UTC (rev 237977)
@@ -235,7 +235,7 @@
return absoluteTransform;
}
-std::unique_ptr<ImageBuffer> SVGRenderingContext::createImageBuffer(const FloatRect& targetRect, const AffineTransform& absoluteTransform, ColorSpace colorSpace, RenderingMode renderingMode)
+std::unique_ptr<ImageBuffer> SVGRenderingContext::createImageBuffer(const FloatRect& targetRect, const AffineTransform& absoluteTransform, ColorSpace colorSpace, RenderingMode renderingMode, const GraphicsContext* context)
{
IntRect paintRect = calculateImageBufferRect(targetRect, absoluteTransform);
// Don't create empty ImageBuffers.
@@ -245,7 +245,12 @@
FloatSize scale;
FloatSize clampedSize = ImageBuffer::clampedSize(paintRect.size(), scale);
+#if USE(DIRECT2D)
+ auto imageBuffer = ImageBuffer::create(clampedSize, renderingMode, context, 1, colorSpace);
+#else
+ UNUSED_PARAM(context);
auto imageBuffer = ImageBuffer::create(clampedSize, renderingMode, 1, colorSpace);
+#endif
if (!imageBuffer)
return nullptr;
@@ -258,7 +263,7 @@
return imageBuffer;
}
-std::unique_ptr<ImageBuffer> SVGRenderingContext::createImageBuffer(const FloatRect& targetRect, const FloatRect& clampedRect, ColorSpace colorSpace, RenderingMode renderingMode)
+std::unique_ptr<ImageBuffer> SVGRenderingContext::createImageBuffer(const FloatRect& targetRect, const FloatRect& clampedRect, ColorSpace colorSpace, RenderingMode renderingMode, const GraphicsContext* context)
{
IntSize clampedSize = roundedIntSize(clampedRect.size());
FloatSize unclampedSize = roundedIntSize(targetRect.size());
@@ -267,7 +272,12 @@
if (clampedSize.isEmpty())
return nullptr;
+#if USE(DIRECT2D)
+ auto imageBuffer = ImageBuffer::create(clampedSize, renderingMode, context, 1, colorSpace);
+#else
+ UNUSED_PARAM(context);
auto imageBuffer = ImageBuffer::create(clampedSize, renderingMode, 1, colorSpace);
+#endif
if (!imageBuffer)
return nullptr;
Modified: trunk/Source/WebCore/rendering/svg/SVGRenderingContext.h (237976 => 237977)
--- trunk/Source/WebCore/rendering/svg/SVGRenderingContext.h 2018-11-08 03:14:37 UTC (rev 237976)
+++ trunk/Source/WebCore/rendering/svg/SVGRenderingContext.h 2018-11-08 03:30:36 UTC (rev 237977)
@@ -60,8 +60,8 @@
void prepareToRenderSVGContent(RenderElement&, PaintInfo&, NeedsGraphicsContextSave = DontSaveGraphicsContext);
bool isRenderingPrepared() const { return m_renderingFlags & RenderingPrepared; }
- static std::unique_ptr<ImageBuffer> createImageBuffer(const FloatRect& targetRect, const AffineTransform& absoluteTransform, ColorSpace, RenderingMode);
- static std::unique_ptr<ImageBuffer> createImageBuffer(const FloatRect& targetRect, const FloatRect& clampedRect, ColorSpace, RenderingMode);
+ static std::unique_ptr<ImageBuffer> createImageBuffer(const FloatRect& targetRect, const AffineTransform& absoluteTransform, ColorSpace, RenderingMode, const GraphicsContext* = nullptr);
+ static std::unique_ptr<ImageBuffer> createImageBuffer(const FloatRect& targetRect, const FloatRect& clampedRect, ColorSpace, RenderingMode, const GraphicsContext* = nullptr);
static void renderSubtreeToImageBuffer(ImageBuffer*, RenderElement&, const AffineTransform&);
static void clipToImageBuffer(GraphicsContext&, const AffineTransform& absoluteTransform, const FloatRect& targetRect, std::unique_ptr<ImageBuffer>&, bool safeToClear);