DRAW_TEST_P(CGContextFillMode, OverlappedEllipses) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); bounds = CGRectInset(bounds, 16.f, 16.f); CGFloat width = bounds.size.width; CGFloat height = bounds.size.height; CGFloat xstart = bounds.origin.x; CGFloat ystart = bounds.origin.y; CGPathDrawingMode fillMode = GetParam(); CGMutablePathRef leftCircles = CGPathCreateMutable(); CGPathMoveToPoint(leftCircles, NULL, xstart + .25 * width + .4 * height, ystart + .5 * height); CGPathAddArc(leftCircles, NULL, xstart + .25 * width, ystart + .5 * height, .4 * height, 0, M_PI, true); CGPathAddArc(leftCircles, NULL, xstart + .25 * width, ystart + .5 * height, .4 * height, M_PI, 0, true); CGPathMoveToPoint(leftCircles, NULL, xstart + .25 * width + .3 * height, ystart + .5 * height); CGPathAddArc(leftCircles, NULL, xstart + .25 * width, ystart + .5 * height, .3 * height, 0, M_PI, true); CGPathAddArc(leftCircles, NULL, xstart + .25 * width, ystart + .5 * height, .3 * height, M_PI, 0, true); CGPathMoveToPoint(leftCircles, NULL, xstart + .25 * width + .2 * height, ystart + .5 * height); CGPathAddArc(leftCircles, NULL, xstart + .25 * width, ystart + .5 * height, .2 * height, 0, M_PI, true); CGPathAddArc(leftCircles, NULL, xstart + .25 * width, ystart + .5 * height, .2 * height, M_PI, 0, true); CGPathMoveToPoint(leftCircles, NULL, xstart + .25 * width + .1 * height, ystart + .5 * height); CGPathAddArc(leftCircles, NULL, xstart + .25 * width, ystart + .5 * height, .1 * height, 0, M_PI, true); CGPathAddArc(leftCircles, NULL, xstart + .25 * width, ystart + .5 * height, .1 * height, M_PI, 0, true); CGPathCloseSubpath(leftCircles); CGMutablePathRef rightCircles = CGPathCreateMutable(); CGPathMoveToPoint(rightCircles, NULL, xstart + .75 * width + .4 * height, ystart + .5 * height); CGPathAddArc(rightCircles, NULL, xstart + .75 * width, ystart + .5 * height, .4 * height, 0, M_PI, false); CGPathAddArc(rightCircles, NULL, xstart + .75 * width, ystart + .5 * height, .4 * height, M_PI, 0, false); CGPathMoveToPoint(rightCircles, NULL, xstart + .75 * width + .3 * height, ystart + .5 * height); CGPathAddArc(rightCircles, NULL, xstart + .75 * width, ystart + .5 * height, .3 * height, 0, M_PI, true); CGPathAddArc(rightCircles, NULL, xstart + .75 * width, ystart + .5 * height, .3 * height, M_PI, 0, true); CGPathMoveToPoint(rightCircles, NULL, xstart + .75 * width + .2 * height, ystart + .5 * height); CGPathAddArc(rightCircles, NULL, xstart + .75 * width, ystart + .5 * height, .2 * height, 0, M_PI, false); CGPathAddArc(rightCircles, NULL, xstart + .75 * width, ystart + .5 * height, .2 * height, M_PI, 0, false); CGPathMoveToPoint(rightCircles, NULL, xstart + .75 * width + .1 * height, ystart + .5 * height); CGPathAddArc(rightCircles, NULL, xstart + .75 * width, ystart + .5 * height, .1 * height, 0, M_PI, true); CGPathAddArc(rightCircles, NULL, xstart + .75 * width, ystart + .5 * height, .1 * height, M_PI, 0, true); CGPathCloseSubpath(rightCircles); CGContextAddPath(context, leftCircles); CGContextAddPath(context, rightCircles); CGContextSetRGBFillColor(context, 0, 0, 1, 1); CGContextSetRGBStrokeColor(context, 1, 0, 0, 1); CGContextDrawPath(context, fillMode); CGPathRelease(leftCircles); CGPathRelease(rightCircles); }
void JBGStrokePathByLines(CGContextRef ctx, CGPathRef path, CGColorRef color_1, CGFloat width_1, CGColorRef color_2, CGFloat width_2, CGColorRef color_3, CGFloat width_3) { if (width_1 > 0.0f) { CGContextSetLineWidth(ctx, width_1); CGContextAddPath(ctx, path); CGContextSetStrokeColorWithColor(ctx, color_1); CGContextStrokePath(ctx); } if (width_2 > 0.0f) { CGContextAddPath(ctx, path); CGContextSetStrokeColorWithColor(ctx, color_2); CGContextSetLineWidth(ctx, width_2); CGContextStrokePath(ctx); } if (width_3 > 0.0f) { CGContextAddPath(ctx, path); CGContextSetStrokeColorWithColor(ctx, color_3); CGContextSetLineWidth(ctx, width_3); CGContextStrokePath(ctx); } }
//----------------------------------------------------------------------------- void CGDrawContext::fillLinearGradient (CGraphicsPath* _path, const CGradient& gradient, const CPoint& startPoint, const CPoint& endPoint, bool evenOdd, CGraphicsTransform* t) { QuartzGraphicsPath* path = dynamic_cast<QuartzGraphicsPath*> (_path); if (path == 0) return; const QuartzGradient* cgGradient = dynamic_cast<const QuartzGradient*> (&gradient); if (cgGradient == 0) return; CGContextRef cgContext = beginCGContext (true, currentState.drawMode.integralMode ()); if (cgContext) { if (t) { CGContextSaveGState (cgContext); CGAffineTransform transform = QuartzGraphicsPath::createCGAfflineTransform (*t); CGContextConcatCTM (cgContext, transform); CGContextAddPath (cgContext, path->getCGPathRef ()); CGContextRestoreGState (cgContext); } else CGContextAddPath (cgContext, path->getCGPathRef ()); if (evenOdd) CGContextEOClip (cgContext); else CGContextClip (cgContext); CGContextDrawLinearGradient (cgContext, *cgGradient, CGPointMake (startPoint.x, startPoint.y), CGPointMake (endPoint.x, endPoint.y), kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); releaseCGContext (cgContext); } }
//----------------------------------------------------------------------------- void CGDrawContext::drawGraphicsPath (CGraphicsPath* _path, PathDrawMode mode, CGraphicsTransform* t) { QuartzGraphicsPath* path = dynamic_cast<QuartzGraphicsPath*> (_path); if (path == 0) return; CGContextRef context = beginCGContext (true, getDrawMode ().integralMode ()); if (context) { CGPathDrawingMode cgMode; switch (mode) { case kPathFilledEvenOdd: { cgMode = kCGPathEOFill; break; } case kPathStroked: { cgMode = kCGPathStroke; applyLineStyle (context); break; } default: { cgMode = kCGPathFill; break; } } if (getDrawMode ().integralMode ()) { applyLineWidthCTM (context); path->pixelAlign (this, t); CGContextAddPath (context, path->getCGPathRef ()); } else if (t) { CGContextSaveGState (context); CGAffineTransform transform = QuartzGraphicsPath::createCGAffineTransform (*t); CGContextConcatCTM (context, transform); CGContextAddPath (context, path->getCGPathRef ()); CGContextRestoreGState (context); } else CGContextAddPath (context, path->getCGPathRef ()); CGContextDrawPath (context, cgMode); releaseCGContext (context); } }
bool PathCG::StrokeContainsPoint(const StrokeOptions &aStrokeOptions, const Point &aPoint, const Matrix &aTransform) const { Matrix inverse = aTransform; inverse.Invert(); Point transformedPoint = inverse*aPoint; // We could probably drop the input transform and just transform the point at the caller? CGPoint point = {transformedPoint.x, transformedPoint.y}; CGContextRef cg = ScratchContext(); CGContextSaveGState(cg); CGContextBeginPath(cg); CGContextAddPath(cg, mPath); SetStrokeOptions(cg, aStrokeOptions); CGContextReplacePathWithStrokedPath(cg); CGContextRestoreGState(cg); CGPathRef sPath = CGContextCopyPath(cg); bool inStroke = CGPathContainsPoint(sPath, nullptr, point, false); CGPathRelease(sPath); return inStroke; }
Rect PathCG::GetStrokedBounds(const StrokeOptions &aStrokeOptions, const Matrix &aTransform) const { // 10.7 has CGPathCreateCopyByStrokingPath which we could use // instead of this scratch context business CGContextRef cg = ScratchContext(); CGContextSaveGState(cg); CGContextBeginPath(cg); CGContextAddPath(cg, mPath); SetStrokeOptions(cg, aStrokeOptions); CGContextReplacePathWithStrokedPath(cg); Rect bounds = CGRectToRect(CGContextGetPathBoundingBox(cg)); CGContextRestoreGState(cg); if (!bounds.IsFinite()) { return Rect(); } return aTransform.TransformBounds(bounds); }
void GraphicsContext::drawFocusRing(const Color& color) { if (paintingDisabled()) return; float radius = (focusRingWidth() - 1) / 2.0f; int offset = radius + focusRingOffset(); CGColorRef colorRef = color.isValid() ? cgColor(color) : 0; CGMutablePathRef focusRingPath = CGPathCreateMutable(); const Vector<IntRect>& rects = focusRingRects(); unsigned rectCount = rects.size(); for (unsigned i = 0; i < rectCount; i++) CGPathAddRect(focusRingPath, 0, CGRectInset(rects[i], -offset, -offset)); CGContextRef context = platformContext(); CGContextSaveGState(context); CGContextBeginPath(context); CGContextAddPath(context, focusRingPath); wkDrawFocusRing(context, colorRef, radius); CGColorRelease(colorRef); CGPathRelease(focusRingPath); CGContextRestoreGState(context); }
void GraphicsContext::drawPath(const Path& path) { if (paintingDisabled()) return; CGContextRef context = platformContext(); const GraphicsContextState& state = m_state; if (state.fillGradient || state.strokeGradient) { // We don't have any optimized way to fill & stroke a path using gradients // FIXME: Be smarter about this. fillPath(path); strokePath(path); return; } CGContextBeginPath(context); CGContextAddPath(context, path.platformPath()); if (state.fillPattern) applyFillPattern(); if (state.strokePattern) applyStrokePattern(); CGPathDrawingMode drawingMode; if (calculateDrawingMode(state, drawingMode)) CGContextDrawPath(context, drawingMode); }
void GraphicsContext::fillPath(const Path& path) { if (paintingDisabled()) return; CGContextRef context = platformContext(); CGContextBeginPath(context); CGContextAddPath(context, path.platformPath()); if (m_state.fillGradient) { CGContextSaveGState(context); if (fillRule() == RULE_EVENODD) CGContextEOClip(context); else CGContextClip(context); CGContextConcatCTM(context, m_state.fillGradient->gradientSpaceTransform()); m_state.fillGradient->paint(this); CGContextRestoreGState(context); return; } if (m_state.fillPattern) applyFillPattern(); fillPathWithFillRule(context, fillRule()); }
FloatRect strokeBoundingBox(const Path& path, RenderStyle* style, const RenderObject* object) { // the bbox might grow if the path is stroked. // and CGPathGetBoundingBox doesn't support that, so we'll have // to make an alternative call... // FIXME: since this is mainly used to decide what to repaint, // perhaps it would be sufficient to just outset the fill bbox by // the stroke width - that should be way cheaper and simpler than // what we do here. CGPathRef cgPath = path.platformPath(); CGContextRef context = scratchContext(); CGContextSaveGState(context); CGContextBeginPath(context); CGContextAddPath(context, cgPath); GraphicsContext gc(context); applyStrokeStyleToContext(&gc, style, object); CGContextReplacePathWithStrokedPath(context); if (CGContextIsPathEmpty(context)) { // CGContextReplacePathWithStrokedPath seems to fail to create a path sometimes, this is not well understood. // returning here prevents CG from logging to the console from CGContextGetPathBoundingBox CGContextRestoreGState(context); return FloatRect(); } CGRect box = CGContextGetPathBoundingBox(context); CGContextRestoreGState(context); return FloatRect(box); }
//----------------------------------------------------------------------------- void CGDrawContext::fillLinearGradient (CGraphicsPath* _path, const CGradient& gradient, const CPoint& startPoint, const CPoint& endPoint, bool evenOdd, CGraphicsTransform* t) { QuartzGraphicsPath* path = dynamic_cast<QuartzGraphicsPath*> (_path); if (path == 0) return; const QuartzGradient* cgGradient = dynamic_cast<const QuartzGradient*> (&gradient); if (cgGradient == 0) return; CGContextRef context = beginCGContext (true, getDrawMode ().integralMode ()); if (context) { CGPoint start = CGPointFromCPoint (startPoint); CGPoint end = CGPointFromCPoint (endPoint); if (getDrawMode ().integralMode ()) { path->pixelAlign (this, t); applyLineWidthCTM (context); CGContextAddPath (context, path->getCGPathRef ()); start = pixelAlligned (start); end = pixelAlligned (end); } else if (t) { CGContextSaveGState (context); CGAffineTransform transform = QuartzGraphicsPath::createCGAffineTransform (*t); CGContextConcatCTM (context, transform); CGContextAddPath (context, path->getCGPathRef ()); CGContextRestoreGState (context); } else CGContextAddPath (context, path->getCGPathRef ()); if (evenOdd) CGContextEOClip (context); else CGContextClip (context); CGContextDrawLinearGradient (context, *cgGradient, start, end, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); releaseCGContext (context); } }
void GraphicsContext::clipOut(const Path& path) { if (paintingDisabled()) return; CGContextBeginPath(platformContext()); CGContextAddRect(platformContext(), CGContextGetClipBoundingBox(platformContext())); CGContextAddPath(platformContext(), path.platformPath()); CGContextEOClip(platformContext()); }
void GraphicsContext::clip(const Path& path) { if (paintingDisabled()) return; CGContextRef context = platformContext(); CGContextBeginPath(context); CGContextAddPath(context, path.platformPath()); CGContextClip(context); m_data->clip(path); }
void CanvasRenderingContext2D::fill() { GraphicsContext* c = drawingContext(); if (!c) return; // FIXME: Do this through platform-independent GraphicsContext API. #if PLATFORM(CG) CGContextBeginPath(c->platformContext()); CGContextAddPath(c->platformContext(), state().m_path.platformPath()); if (!state().m_path.isEmpty()) willDraw(CGContextGetPathBoundingBox(c->platformContext())); if (state().m_fillStyle->gradient()) { // Shading works on the entire clip region, so convert the current path to a clip. c->save(); CGContextClip(c->platformContext()); CGContextDrawShading(c->platformContext(), state().m_fillStyle->gradient()->platformShading()); c->restore(); } else { if (state().m_fillStyle->pattern()) applyFillPattern(); CGContextFillPath(c->platformContext()); } #elif PLATFORM(QT) QPainterPath* path = state().m_path.platformPath(); QPainter* p = static_cast<QPainter*>(c->platformContext()); willDraw(path->controlPointRect()); if (state().m_fillStyle->gradient()) { p->fillPath(*path, QBrush(*(state().m_fillStyle->gradient()->platformShading()))); } else { if (state().m_fillStyle->pattern()) applyFillPattern(); p->fillPath(*path, p->brush()); } #elif PLATFORM(CAIRO) cairo_t* pathCr = state().m_path.platformPath()->m_cr; cairo_t* cr = c->platformContext(); cairo_save(cr); willDraw(state().m_path.boundingRect()); if (state().m_fillStyle->gradient()) { cairo_set_source(cr, state().m_fillStyle->gradient()->platformShading()); c->addPath(state().m_path); cairo_fill(cr); } else { if (state().m_fillStyle->pattern()) applyFillPattern(); c->addPath(state().m_path); cairo_fill(cr); } cairo_restore(cr); #endif clearPathForDashboardBackwardCompatibilityMode(); }
DRAW_TEST_F(CGContextFlush, FillFlush, WhiteBackgroundTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); _CGContextPushBeginDraw(context); CGContextSetRGBFillColor(context, 1, 0, 0, 1); CGContextFillRect(context, bounds); // Flush the red fill rect CGContextFlush(context); CGContextSetRGBFillColor(context, 0, 0, 1, 1); CGContextFillRect(context, CGRectMake(0, 0, 300, 300)); // We should still have red & blue rectangle should not show up. unsigned char* dataPtr = static_cast<unsigned char*>(CGBitmapContextGetData(context)); ASSERT_NE(dataPtr, nullptr); // Validate only the red fill rect is executed. EXPECT_EQ(dataPtr[0], 0x00); EXPECT_EQ(dataPtr[1], 0x00); EXPECT_EQ(dataPtr[2], 0xff); EXPECT_EQ(dataPtr[3], 0xff); CGContextFlush(context); // We should now see the blue fill rect EXPECT_EQ(dataPtr[0], 0xff); EXPECT_EQ(dataPtr[1], 0x00); EXPECT_EQ(dataPtr[2], 0x00); EXPECT_EQ(dataPtr[3], 0xff); // Add some extra drawings CGContextClearRect(context, CGRectMake(100, 100, 200, 300)); CGPoint center = _CGRectGetCenter(bounds); CGMutablePathRef concentricCirclesPath = CGPathCreateMutable(); CGPathAddEllipseInRect(concentricCirclesPath, nullptr, _CGRectCenteredOnPoint({ 50, 50 }, center)); CGPathAddEllipseInRect(concentricCirclesPath, nullptr, _CGRectCenteredOnPoint({ 100, 100 }, center)); CGPathAddEllipseInRect(concentricCirclesPath, nullptr, _CGRectCenteredOnPoint({ 150, 150 }, center)); CGPathAddEllipseInRect(concentricCirclesPath, nullptr, _CGRectCenteredOnPoint({ 200, 200 }, center)); CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 0.5); CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0); CGContextAddPath(context, concentricCirclesPath); CGContextDrawPath(context, kCGPathFillStroke); CGPathRelease(concentricCirclesPath); _CGContextPopEndDraw(context); }
//----------------------------------------------------------------------------- void CGDrawContext::fillRadialGradient (CGraphicsPath* _path, const CGradient& gradient, const CPoint& center, CCoord radius, const CPoint& originOffset, bool evenOdd, CGraphicsTransform* t) { QuartzGraphicsPath* path = dynamic_cast<QuartzGraphicsPath*> (_path); if (path == 0) return; const QuartzGradient* cgGradient = dynamic_cast<const QuartzGradient*> (&gradient); if (cgGradient == 0) return; CGContextRef context = beginCGContext (true, getDrawMode ().integralMode ()); if (context) { if (getDrawMode ().integralMode ()) { path->pixelAlign (this, t); CGContextAddPath (context, path->getCGPathRef ()); } else if (t) { CGContextSaveGState (context); CGAffineTransform transform = QuartzGraphicsPath::createCGAffineTransform (*t); CGContextConcatCTM (context, transform); CGContextAddPath (context, path->getCGPathRef ()); CGContextRestoreGState (context); } else CGContextAddPath (context, path->getCGPathRef ()); if (evenOdd) CGContextEOClip (context); else CGContextClip (context); CPoint startCenter = center + originOffset; CGContextDrawRadialGradient (context, *cgGradient, CGPointFromCPoint (startCenter), 0, CGPointFromCPoint (center), static_cast<CGFloat> (radius), kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); releaseCGContext (context); } }
void PlatformCALayer::drawRepaintIndicator(CGContextRef context, PlatformCALayer* platformCALayer, int repaintCount, CGColorRef customBackgroundColor) { char text[16]; // that's a lot of repaints snprintf(text, sizeof(text), "%d", repaintCount); FloatRect indicatorBox = platformCALayer->bounds();\ indicatorBox.setLocation( { 1, 1 } ); indicatorBox.setSize(FloatSize(12 + 10 * strlen(text), 27)); CGContextStateSaver stateSaver(context); CGContextSetAlpha(context, 0.5f); CGContextBeginTransparencyLayerWithRect(context, indicatorBox, 0); if (customBackgroundColor) CGContextSetFillColorWithColor(context, customBackgroundColor); else CGContextSetRGBFillColor(context, 0, 0.5f, 0.25f, 1); if (platformCALayer->isOpaque()) CGContextFillRect(context, indicatorBox); else { Path boundsPath; boundsPath.moveTo(indicatorBox.maxXMinYCorner()); boundsPath.addLineTo(indicatorBox.maxXMaxYCorner()); boundsPath.addLineTo(indicatorBox.minXMaxYCorner()); const float cornerChunk = 8; boundsPath.addLineTo(FloatPoint(indicatorBox.x(), indicatorBox.y() + cornerChunk)); boundsPath.addLineTo(FloatPoint(indicatorBox.x() + cornerChunk, indicatorBox.y())); boundsPath.closeSubpath(); CGContextAddPath(context, boundsPath.platformPath()); CGContextFillPath(context); } if (platformCALayer->owner()->isUsingDisplayListDrawing(platformCALayer)) { CGContextSetRGBStrokeColor(context, 0, 0, 0, 0.65); CGContextSetLineWidth(context, 2); CGContextStrokeRect(context, indicatorBox); } if (platformCALayer->acceleratesDrawing()) CGContextSetRGBFillColor(context, 1, 0, 0, 1); else CGContextSetRGBFillColor(context, 1, 1, 1, 1); platformCALayer->drawTextAtPoint(context, indicatorBox.x() + 5, indicatorBox.y() + 22, CGSizeMake(1, -1), 22, text, strlen(text)); CGContextEndTransparencyLayer(context); }
void CanvasRenderingContext2D::stroke() { GraphicsContext* c = drawingContext(); if (!c) return; // FIXME: Do this through platform-independent GraphicsContext API. #if PLATFORM(CG) CGContextBeginPath(c->platformContext()); CGContextAddPath(c->platformContext(), state().m_path.platformPath()); if (!state().m_path.isEmpty()) { float lineWidth = state().m_lineWidth; float inset = -lineWidth / 2; CGRect boundingRect = CGRectInset(CGContextGetPathBoundingBox(c->platformContext()), inset, inset); willDraw(boundingRect); } if (state().m_strokeStyle->gradient()) { // Shading works on the entire clip region, so convert the current path to a clip. c->save(); CGContextReplacePathWithStrokedPath(c->platformContext()); CGContextClip(c->platformContext()); CGContextDrawShading(c->platformContext(), state().m_strokeStyle->gradient()->platformShading()); c->restore(); } else { if (state().m_strokeStyle->pattern()) applyStrokePattern(); CGContextStrokePath(c->platformContext()); } #elif PLATFORM(QT) QPainterPath* path = state().m_path.platformPath(); QPainter* p = static_cast<QPainter*>(c->platformContext()); willDraw(path->controlPointRect()); if (state().m_strokeStyle->gradient()) { p->save(); p->setBrush(*(state().m_strokeStyle->gradient()->platformShading())); p->strokePath(*path, p->pen()); p->restore(); } else { if (state().m_strokeStyle->pattern()) applyStrokePattern(); p->strokePath(*path, p->pen()); } #endif clearPathForDashboardBackwardCompatibilityMode(); }
bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const { ASSERT(applier); CGContextRef context = scratchContext(); CGContextSaveGState(context); CGContextBeginPath(context); CGContextAddPath(context, platformPath()); GraphicsContext gc(context); applier->strokeStyle(&gc); bool hitSuccess = CGContextPathContainsPoint(context, point, kCGPathStroke); CGContextRestoreGState(context); return hitSuccess; }
void GraphicsContext::clipPath(const Path& path, WindRule clipRule) { if (paintingDisabled()) return; if (path.isEmpty()) return; CGContextRef context = platformContext(); CGContextBeginPath(platformContext()); CGContextAddPath(platformContext(), path.platformPath()); if (clipRule == RULE_EVENODD) CGContextEOClip(context); else CGContextClip(context); }
void GraphicsContext::clip(const Path& path) { if (paintingDisabled()) return; CGContextRef context = platformContext(); // CGContextClip does nothing if the path is empty, so in this case, we // instead clip against a zero rect to reduce the clipping region to // nothing - which is the intended behavior of clip() if the path is empty. if (path.isEmpty()) CGContextClipToRect(context, CGRectZero); else { CGContextBeginPath(context); CGContextAddPath(context, path.platformPath()); CGContextClip(context); } m_data->clip(path); }
FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const { CGContextRef context = scratchContext(); CGContextSaveGState(context); CGContextBeginPath(context); CGContextAddPath(context, platformPath()); if (applier) { GraphicsContext graphicsContext(context); applier->strokeStyle(&graphicsContext); } CGContextReplacePathWithStrokedPath(context); CGRect box = CGContextIsPathEmpty(context) ? CGRectZero : CGContextGetPathBoundingBox(context); CGContextRestoreGState(context); return box; }
void TIPGradientAxialFillPath( CGContextRef theContext, TIPGradientRef theGradient, CGPathRef thePath, float angle) { CGRect boundingRect = CGPathGetBoundingBox(thePath); CGPoint startPoint; CGPoint endPoint; TIPGradientFindEndpointsForRotation(boundingRect,angle,&startPoint,&endPoint); // CoreGraphics Calls CGContextSaveGState(theContext); CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); CGShadingRef myCGShading = CGShadingCreateAxial(colorSpace,startPoint,endPoint,theGradient->gradientFunction,FALSE,FALSE); CGContextAddPath(theContext,thePath); CGContextClip(theContext); CGContextDrawShading(theContext,myCGShading); CGShadingRelease(myCGShading); CGColorSpaceRelease(colorSpace); CGContextRestoreGState(theContext); }
void doRotatedEllipsesWithCGPath(CGContextRef context) { int i, totreps = 144.; CGMutablePathRef path = NULL; float tint = 1., tintIncrement = 1./totreps; // Create a new transform consisting of a 45 degree rotation. CGAffineTransform theTransform = CGAffineTransformMakeRotation(M_PI/4); // Apply a scaling transformation to the transform just created. theTransform = CGAffineTransformScale(theTransform, 1, 2); // Create a mutable CGPath object. path = CGPathCreateMutable(); if(!path){ fprintf(stderr, "Couldn't create path!\n"); return; } // Add a circular arc to the CGPath object, transformed // by an affine transform. CGPathAddArc(path, &theTransform, 0., 0., 45., 0., 2*M_PI, false); // Close the CGPath object. CGPathCloseSubpath(path); // Place the first ellipse at a good location. CGContextTranslateCTM(context, 100., 100.); for (i = 0 ; i < totreps ; i++){ CGContextBeginPath(context); // Add the CGPath object to the current path in the context. CGContextAddPath(context, path); // Set the fill color for this instance of the ellipse. CGContextSetRGBFillColor(context, tint, 0., 0., 1.); // Filling the path implicitly closes it. CGContextFillPath(context); // Compute the next tint color. tint -= tintIncrement; // Move over for the next ellipse. CGContextTranslateCTM(context, 1, 0.); } // Release the path when done with it. CGPathRelease(path); }
void GraphicsContext::clipPath(const Path& path, WindRule clipRule) { if (paintingDisabled()) return; // FIXME: Why does this method ignore empty paths? if (path.isEmpty()) return; wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); #if wxUSE_CAIRO cairo_t* cr = (cairo_t*)gc->GetNativeContext(); cairo_path_t* nativePath = (cairo_path_t*)path.platformPath()->GetNativePath(); cairo_new_path(cr); cairo_append_path(cr, nativePath); cairo_set_fill_rule(cr, clipRule == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); cairo_clip(cr); #elif __WXMAC__ CGContextRef context = (CGContextRef)gc->GetNativeContext(); CGPathRef nativePath = (CGPathRef)path.platformPath()->GetNativePath(); CGContextBeginPath(context); CGContextAddPath(context, nativePath); if (clipRule == RULE_EVENODD) CGContextEOClip(context); else CGContextClip(context); #elif __WXMSW__ Gdiplus::Graphics* g = (Gdiplus::Graphics*)gc->GetNativeContext(); Gdiplus::GraphicsPath* nativePath = (Gdiplus::GraphicsPath*)path.platformPath()->GetNativePath(); if (clipRule == RULE_EVENODD) nativePath->SetFillMode(Gdiplus::FillModeAlternate); else nativePath->SetFillMode(Gdiplus::FillModeWinding); g->SetClip(nativePath); #endif }
CGContextRef BitLockerSkia::cgContext() { SkDevice* device = m_canvas->getDevice(); ASSERT(device); if (!device) return 0; releaseIfNeeded(); const SkBitmap& bitmap = device->accessBitmap(true); bitmap.lockPixels(); void* pixels = bitmap.getPixels(); m_cgContext = CGBitmapContextCreate(pixels, device->width(), device->height(), 8, bitmap.rowBytes(), CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst); // Apply device matrix. CGAffineTransform contentsTransform = CGAffineTransformMakeScale(1, -1); contentsTransform = CGAffineTransformTranslate(contentsTransform, 0, -device->height()); CGContextConcatCTM(m_cgContext, contentsTransform); // Apply clip in device coordinates. CGMutablePathRef clipPath = CGPathCreateMutable(); SkRegion::Iterator iter(m_canvas->getTotalClip()); for (; !iter.done(); iter.next()) { IntRect rect = iter.rect(); CGPathAddRect(clipPath, 0, rect); } CGContextAddPath(m_cgContext, clipPath); CGContextClip(m_cgContext); CGPathRelease(clipPath); // Apply content matrix. const SkMatrix& skMatrix = m_canvas->getTotalMatrix(); CGAffineTransform affine = SkMatrixToCGAffineTransform(skMatrix); CGContextConcatCTM(m_cgContext, affine); return m_cgContext; }
bool RenderPath::strokeContains(const FloatPoint& point, bool requiresStroke) const { if (path().isEmpty()) return false; if (requiresStroke && !SVGPaintServer::strokePaintServer(style(), this)) return false; CGMutablePathRef cgPath = path().platformPath(); CGContextRef context = scratchContext(); CGContextSaveGState(context); CGContextBeginPath(context); CGContextAddPath(context, cgPath); GraphicsContext gc(context); applyStrokeStyleToContext(&gc, style(), this); bool hitSuccess = CGContextPathContainsPoint(context, point, kCGPathStroke); CGContextRestoreGState(context); return hitSuccess; }
void GraphicsContext::strokePath(const Path& path) { if (paintingDisabled()) return; CGContextRef context = platformContext(); CGContextBeginPath(context); CGContextAddPath(context, path.platformPath()); if (m_state.strokeGradient) { CGContextSaveGState(context); CGContextReplacePathWithStrokedPath(context); CGContextClip(context); CGContextConcatCTM(context, m_state.strokeGradient->gradientSpaceTransform()); m_state.strokeGradient->paint(this); CGContextRestoreGState(context); return; } if (m_state.strokePattern) applyStrokePattern(); CGContextStrokePath(context); }
static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) { Color fillColor = graphicsContext->fillColor(); bool drawIntoBitmap = false; TextDrawingModeFlags drawingMode = graphicsContext->textDrawingMode(); if (drawingMode == TextModeFill) { if (!fillColor.alpha()) return; drawIntoBitmap = fillColor.alpha() != 255 || graphicsContext->inTransparencyLayer(); if (!drawIntoBitmap) { FloatSize offset; float blur; Color color; ColorSpace shadowColorSpace; graphicsContext->getShadow(offset, blur, color, shadowColorSpace); drawIntoBitmap = offset.width() || offset.height() || blur; } } // We have to convert CG's two-dimensional floating point advances to just horizontal integer advances. Vector<int, 2048> gdiAdvances; int totalWidth = 0; for (int i = 0; i < numGlyphs; i++) { gdiAdvances.append(lroundf(glyphBuffer.advanceAt(from + i))); totalWidth += gdiAdvances[i]; } HDC hdc = 0; OwnPtr<GraphicsContext::WindowsBitmap> bitmap; IntRect textRect; if (!drawIntoBitmap) hdc = graphicsContext->getWindowsContext(textRect, true, false); if (!hdc) { drawIntoBitmap = true; // We put slop into this rect, since glyphs can overflow the ascent/descent bounds and the left/right edges. // FIXME: Can get glyphs' optical bounds (even from CG) to get this right. const FontMetrics& fontMetrics = font->fontMetrics(); int lineGap = fontMetrics.lineGap(); textRect = IntRect(point.x() - (fontMetrics.ascent() + fontMetrics.descent()) / 2, point.y() - fontMetrics.ascent() - lineGap, totalWidth + fontMetrics.ascent() + fontMetrics.descent(), fontMetrics.lineSpacing()); bitmap = graphicsContext->createWindowsBitmap(textRect.size()); memset(bitmap->buffer(), 255, bitmap->bufferLength()); hdc = bitmap->hdc(); XFORM xform; xform.eM11 = 1.0f; xform.eM12 = 0.0f; xform.eM21 = 0.0f; xform.eM22 = 1.0f; xform.eDx = -textRect.x(); xform.eDy = -textRect.y(); SetWorldTransform(hdc, &xform); } SelectObject(hdc, font->platformData().hfont()); // Set the correct color. if (drawIntoBitmap) SetTextColor(hdc, RGB(0, 0, 0)); else SetTextColor(hdc, RGB(fillColor.red(), fillColor.green(), fillColor.blue())); SetBkMode(hdc, TRANSPARENT); SetTextAlign(hdc, TA_LEFT | TA_BASELINE); // Uniscribe gives us offsets to help refine the positioning of combining glyphs. FloatSize translation = glyphBuffer.offsetAt(from); if (translation.width() || translation.height()) { XFORM xform; xform.eM11 = 1.0; xform.eM12 = 0; xform.eM21 = 0; xform.eM22 = 1.0; xform.eDx = translation.width(); xform.eDy = translation.height(); ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); } if (drawingMode == TextModeFill) { XFORM xform; xform.eM11 = 1.0; xform.eM12 = 0; xform.eM21 = font->platformData().syntheticOblique() ? -tanf(syntheticObliqueAngle * piFloat / 180.0f) : 0; xform.eM22 = 1.0; xform.eDx = point.x(); xform.eDy = point.y(); ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); if (font->syntheticBoldOffset()) { xform.eM21 = 0; xform.eDx = font->syntheticBoldOffset(); xform.eDy = 0; ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); } } else { XFORM xform; GetWorldTransform(hdc, &xform); AffineTransform hdcTransform(xform.eM11, xform.eM21, xform.eM12, xform.eM22, xform.eDx, xform.eDy); CGAffineTransform initialGlyphTransform = hdcTransform.isInvertible() ? hdcTransform.inverse() : CGAffineTransformIdentity; if (font->platformData().syntheticOblique()) initialGlyphTransform = CGAffineTransformConcat(initialGlyphTransform, CGAffineTransformMake(1, 0, tanf(syntheticObliqueAngle * piFloat / 180.0f), 1, 0, 0)); initialGlyphTransform.tx = 0; initialGlyphTransform.ty = 0; CGContextRef cgContext = graphicsContext->platformContext(); CGContextSaveGState(cgContext); BOOL fontSmoothingEnabled = false; SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0); CGContextSetShouldAntialias(cgContext, fontSmoothingEnabled); CGContextScaleCTM(cgContext, 1.0, -1.0); CGContextTranslateCTM(cgContext, point.x() + glyphBuffer.offsetAt(from).width(), -(point.y() + glyphBuffer.offsetAt(from).height())); for (unsigned i = 0; i < numGlyphs; ++i) { RetainPtr<CGPathRef> glyphPath(AdoptCF, createPathForGlyph(hdc, glyphBuffer.glyphAt(from + i))); CGContextSaveGState(cgContext); CGContextConcatCTM(cgContext, initialGlyphTransform); if (drawingMode & TextModeFill) { CGContextAddPath(cgContext, glyphPath.get()); CGContextFillPath(cgContext); if (font->syntheticBoldOffset()) { CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0); CGContextAddPath(cgContext, glyphPath.get()); CGContextFillPath(cgContext); CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0); } } if (drawingMode & TextModeStroke) { CGContextAddPath(cgContext, glyphPath.get()); CGContextStrokePath(cgContext); if (font->syntheticBoldOffset()) { CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0); CGContextAddPath(cgContext, glyphPath.get()); CGContextStrokePath(cgContext); CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0); } } CGContextRestoreGState(cgContext); CGContextTranslateCTM(cgContext, gdiAdvances[i], 0); } CGContextRestoreGState(cgContext); } if (drawIntoBitmap) { UInt8* buffer = bitmap->buffer(); unsigned bufferLength = bitmap->bufferLength(); for (unsigned i = 0; i < bufferLength; i += 4) { // Use green, which is always in the middle. UInt8 alpha = (255 - buffer[i + 1]) * fillColor.alpha() / 255; buffer[i] = fillColor.blue(); buffer[i + 1] = fillColor.green(); buffer[i + 2] = fillColor.red(); buffer[i + 3] = alpha; } graphicsContext->drawWindowsBitmap(bitmap.get(), textRect.location()); } else graphicsContext->releaseWindowsContext(hdc, textRect, true, false); }
void GraphicsContext::addPath(const Path& path) { CGContextAddPath(platformContext(), path.platformPath()); }