Skip to content

Commit

Permalink
Cherry-pick 271354@main (a8f57b1). rdar://119334889
Browse files Browse the repository at this point in the history
    GraphicsContextCG should clip the paths via CGContext in GPUP mode
    https://bugs.webkit.org/show_bug.cgi?id=252833
    rdar://105835901

    Reviewed by Said Abou-Hallawa.

    Construct the clipped path directly into the CGContext.
    Instead of creating a CGPath object, add the path info upon need to
    the CGContext.

    Removes some of CG work in GPUP receive side where time is spent
    just copying the CGPath objects.

    The implementation has now duplicated logic:
     - Add path segments to CGPath via PathCG
     - Add path segments to CGContext path

    The implementation of both are stored next to each other so that
    they keep in sync.

    * Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp:
    (WebCore::setCGContextPath):
    (WebCore::drawPathWithCGContext):
    (WebCore::GraphicsContextCG::drawNativeImageInternal):
    (WebCore::GraphicsContextCG::drawPattern):
    (WebCore::GraphicsContextCG::drawPath):
    (WebCore::GraphicsContextCG::fillPath):
    (WebCore::GraphicsContextCG::strokePath):
    (WebCore::GraphicsContextCG::fillRect):
    (WebCore::GraphicsContextCG::fillRectWithRoundedHole):
    (WebCore::GraphicsContextCG::clipOut):
    (WebCore::GraphicsContextCG::clipPath):
    (WebCore::GraphicsContextCG::beginTransparencyLayer):
    (WebCore::GraphicsContextCG::drawLinesForText):
    * Source/WebCore/platform/graphics/cg/PathCG.cpp:
    (WebCore::addToContextPath):
    (WebCore::copyClosingSubpathsApplierFunction):
    (WebCore::addToCGContextPath):
    * Source/WebCore/platform/graphics/cg/PathCG.h:

    Canonical link: https://commits.webkit.org/271354@main

Canonical link: https://commits.webkit.org/267815.633@safari-7617-branch
  • Loading branch information
kkinnunen-apple committed Dec 14, 2023
1 parent b4db56f commit c10cd41
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 58 deletions.
103 changes: 48 additions & 55 deletions Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "config.h"
Expand All @@ -38,6 +38,7 @@
#include "ImageOrientation.h"
#include "Logging.h"
#include "Path.h"
#include "PathCG.h"
#include "Pattern.h"
#include "ShadowBlur.h"
#include "Timer.h"
Expand Down Expand Up @@ -183,6 +184,22 @@ static void setCGBlendMode(CGContextRef context, CompositeOperator op, BlendMode
CGContextSetBlendMode(context, selectCGBlendMode(op, blendMode));
}

static void setCGContextPath(CGContextRef context, const Path& path)
{
CGContextBeginPath(context);
addToCGContextPath(context, path);
}

static void drawPathWithCGContext(CGContextRef context, CGPathDrawingMode drawingMode, const Path& path)
{
#if HAVE(CG_CONTEXT_DRAW_PATH_DIRECT)
CGContextDrawPathDirect(context, drawingMode, path.platformPath(), nullptr);
#else
setCGContextPath(context, path);
CGContextDrawPath(context, drawingMode);
#endif
}

static RenderingMode renderingModeForCGContext(CGContextRef cgContext, GraphicsContextCG::CGContextSource source)
{
if (!cgContext)
Expand Down Expand Up @@ -312,7 +329,7 @@ void GraphicsContextCG::drawNativeImageInternal(NativeImage& nativeImage, const
FloatSize size = FloatSize(CGImageGetWidth(image), CGImageGetHeight(image));
return options.orientation().usesWidthAsHeight() ? size.transposedSize() : size;
};

auto context = platformContext();
CGContextStateSaver stateSaver(context, false);
auto transform = CGContextGetCTM(context);
Expand Down Expand Up @@ -387,7 +404,7 @@ void GraphicsContextCG::drawNativeImageInternal(NativeImage& nativeImage, const
if (options.orientation().usesWidthAsHeight())
adjustedDestRect = adjustedDestRect.transposedRect();
}

// Flip the coords.
CGContextTranslateCTM(context, 0, adjustedDestRect.height());
CGContextScaleCTM(context, 1, -1);
Expand Down Expand Up @@ -446,10 +463,10 @@ void GraphicsContextCG::drawPattern(NativeImage& nativeImage, const FloatRect& d

CGContextTranslateCTM(context, destRect.x(), destRect.y() + destRect.height());
CGContextScaleCTM(context, 1, -1);

// Compute the scaled tile size.
float scaledTileHeight = tileRect.height() * narrowPrecisionToFloat(patternTransform.d());

// We have to adjust the phase to deal with the fact we're in Cartesian space now (with the bottom left corner of destRect being
// the origin).
float adjustedX = phase.x() - destRect.x() + tileRect.x() * narrowPrecisionToFloat(patternTransform.a()); // We translated the context so that destRect.x() is the origin, so subtract it out.
Expand Down Expand Up @@ -486,7 +503,7 @@ void GraphicsContextCG::drawPattern(NativeImage& nativeImage, const FloatRect& d
tileRect.width() + spacing.width() * (1 / narrowPrecisionToFloat(patternTransform.a())),
tileRect.height() + spacing.height() * (1 / narrowPrecisionToFloat(patternTransform.d())),
kCGPatternTilingConstantSpacing, true, &patternCallbacks));

if (!pattern)
return;

Expand Down Expand Up @@ -685,15 +702,8 @@ void GraphicsContextCG::drawPath(const Path& path)
applyStrokePattern();

CGPathDrawingMode drawingMode;
if (calculateDrawingMode(*this, drawingMode)) {
#if HAVE(CG_CONTEXT_DRAW_PATH_DIRECT)
CGContextDrawPathDirect(context, drawingMode, path.platformPath(), nullptr);
#else
CGContextBeginPath(context);
CGContextAddPath(context, path.platformPath());
CGContextDrawPath(context, drawingMode);
#endif
}
if (calculateDrawingMode(*this, drawingMode))
drawPathWithCGContext(context, drawingMode, path);
}

void GraphicsContextCG::fillPath(const Path& path)
Expand All @@ -713,8 +723,7 @@ void GraphicsContextCG::fillPath(const Path& path)

CGContextScaleCTM(layerContext, layerSize.width() / rect.width(), layerSize.height() / rect.height());
CGContextTranslateCTM(layerContext, -rect.x(), -rect.y());
CGContextBeginPath(layerContext);
CGContextAddPath(layerContext, path.platformPath());
setCGContextPath(layerContext, path);
CGContextConcatCTM(layerContext, fillGradientSpaceTransform());

if (fillRule() == WindRule::EvenOdd)
Expand All @@ -725,8 +734,7 @@ void GraphicsContextCG::fillPath(const Path& path)
fillGradient->paint(layerContext);
CGContextDrawLayerInRect(context, rect, layer.get());
} else {
CGContextBeginPath(context);
CGContextAddPath(context, path.platformPath());
setCGContextPath(context, path);
CGContextStateSaver stateSaver(context);
CGContextConcatCTM(context, fillGradientSpaceTransform());

Expand All @@ -743,16 +751,8 @@ void GraphicsContextCG::fillPath(const Path& path)

if (fillPattern())
applyFillPattern();
#if HAVE(CG_CONTEXT_DRAW_PATH_DIRECT)
CGContextDrawPathDirect(context, fillRule() == WindRule::EvenOdd ? kCGPathEOFill : kCGPathFill, path.platformPath(), nullptr);
#else
CGContextBeginPath(context);
CGContextAddPath(context, path.platformPath());
if (fillRule() == WindRule::EvenOdd)
CGContextEOFillPath(context);
else
CGContextFillPath(context);
#endif

drawPathWithCGContext(context, fillRule() == WindRule::EvenOdd ? kCGPathEOFill : kCGPathFill, path);
}

void GraphicsContextCG::strokePath(const Path& path)
Expand Down Expand Up @@ -784,7 +784,7 @@ void GraphicsContextCG::strokePath(const Path& path)
CGContextScaleCTM(layerContext, layerSize.width() / adjustedWidth, layerSize.height() / adjustedHeight);
CGContextTranslateCTM(layerContext, translationX, translationY);

CGContextAddPath(layerContext, path.platformPath());
setCGContextPath(layerContext, path);
CGContextReplacePathWithStrokedPath(layerContext);
CGContextClip(layerContext);
CGContextConcatCTM(layerContext, strokeGradientSpaceTransform());
Expand All @@ -795,8 +795,7 @@ void GraphicsContextCG::strokePath(const Path& path)
CGContextDrawLayerInRect(context, CGRectMake(destinationX, destinationY, adjustedWidth, adjustedHeight), layer.get());
} else {
CGContextStateSaver stateSaver(context);
CGContextBeginPath(context);
CGContextAddPath(context, path.platformPath());
setCGContextPath(context, path);
CGContextReplacePathWithStrokedPath(context);
CGContextClip(context);
CGContextConcatCTM(context, strokeGradientSpaceTransform());
Expand All @@ -816,13 +815,7 @@ void GraphicsContextCG::strokePath(const Path& path)
}
#endif

#if HAVE(CG_CONTEXT_DRAW_PATH_DIRECT)
CGContextDrawPathDirect(context, kCGPathStroke, path.platformPath(), nullptr);
#else
CGContextBeginPath(context);
CGContextAddPath(context, path.platformPath());
CGContextStrokePath(context);
#endif
drawPathWithCGContext(context, kCGPathStroke, path);
}

void GraphicsContextCG::fillRect(const FloatRect& rect)
Expand Down Expand Up @@ -892,7 +885,7 @@ void GraphicsContextCG::fillRect(const FloatRect& rect, const Color& color)
}

CGContextFillRect(context, rect);

if (drawOwnShadow)
stateSaver.restore();

Expand Down Expand Up @@ -975,7 +968,7 @@ void GraphicsContextCG::fillRectWithRoundedHole(const FloatRect& rect, const Flo

if (drawOwnShadow)
stateSaver.restore();

setFillRule(oldFillRule);
setFillColor(oldFillColor);
}
Expand All @@ -996,21 +989,23 @@ void GraphicsContextCG::clipOut(const FloatRect& rect)
// to <rdar://problem/12584492>, CGRectInfinite can't be used with an accelerated context that
// has certain transforms that aren't just a translation or a scale. And due to <rdar://problem/14634453>
// we cannot use it in for a printing context either.
CGContextRef context = platformContext();
const AffineTransform& ctm = getCTM();
bool canUseCGRectInfinite = CGContextGetType(platformContext()) != kCGContextTypePDF && (renderingMode() == RenderingMode::Unaccelerated || (!ctm.b() && !ctm.c()));
CGRect rects[2] = { canUseCGRectInfinite ? CGRectInfinite : CGContextGetClipBoundingBox(platformContext()), rect };
CGContextBeginPath(platformContext());
CGContextAddRects(platformContext(), rects, 2);
CGContextEOClip(platformContext());
bool canUseCGRectInfinite = CGContextGetType(context) != kCGContextTypePDF && (renderingMode() == RenderingMode::Unaccelerated || (!ctm.b() && !ctm.c()));
CGRect rects[2] = { canUseCGRectInfinite ? CGRectInfinite : CGContextGetClipBoundingBox(context), rect };
CGContextBeginPath(context);
CGContextAddRects(context, rects, 2);
CGContextEOClip(context);
}

void GraphicsContextCG::clipOut(const Path& path)
{
CGContextBeginPath(platformContext());
CGContextAddRect(platformContext(), CGContextGetClipBoundingBox(platformContext()));
CGContextRef context = platformContext();
CGContextBeginPath(context);
CGContextAddRect(context, CGContextGetClipBoundingBox(context));
if (!path.isEmpty())
CGContextAddPath(platformContext(), path.platformPath());
CGContextEOClip(platformContext());
addToCGContextPath(context, path);
CGContextEOClip(context);
}

void GraphicsContextCG::clipPath(const Path& path, WindRule clipRule)
Expand All @@ -1019,9 +1014,7 @@ void GraphicsContextCG::clipPath(const Path& path, WindRule clipRule)
if (path.isEmpty())
CGContextClipToRect(context, CGRectZero);
else {
CGContextBeginPath(platformContext());
CGContextAddPath(platformContext(), path.platformPath());

setCGContextPath(context, path);
if (clipRule == WindRule::EvenOdd)
CGContextEOClip(context);
else
Expand Down Expand Up @@ -1059,7 +1052,7 @@ void GraphicsContextCG::beginTransparencyLayer(float opacity)
CGContextRef context = platformContext();
CGContextSetAlpha(context, opacity);
CGContextBeginTransparencyLayer(context, 0);

m_userToDeviceTransformKnownToBeIdentity = false;
}

Expand Down Expand Up @@ -1467,7 +1460,7 @@ void GraphicsContextCG::drawLinesForText(const FloatPoint& point, float thicknes
return;

bool fillColorIsNotEqualToStrokeColor = fillColor() != localStrokeColor;

Vector<CGRect, 4> dashBounds;
ASSERT(!(widths.size() % 2));
dashBounds.reserveInitialCapacity(dashBounds.size() / 2);
Expand Down
Loading

0 comments on commit c10cd41

Please sign in to comment.