SVGPaintServerPattern::~SVGPaintServerPattern() { #if PLATFORM(CG) CGPatternRelease(m_pattern); CGColorSpaceRelease(m_patternSpace); #endif }
void CanvasRenderingContext2D::applyFillPattern() { GraphicsContext* c = drawingContext(); if (!c) return; #if PLATFORM(CG) // Check for case where the pattern is already set. CGAffineTransform m = CGContextGetCTM(c->platformContext()); if (state().m_appliedFillPattern && CGAffineTransformEqualToTransform(m, state().m_fillStylePatternTransform)) return; CanvasPattern* pattern = state().m_fillStyle->pattern(); if (!pattern) return; CGPatternRef platformPattern = pattern->createPattern(m); if (!platformPattern) return; CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(0); CGContextSetFillColorSpace(c->platformContext(), patternSpace); CGColorSpaceRelease(patternSpace); const CGFloat patternAlpha = 1; CGContextSetFillPattern(c->platformContext(), platformPattern, &patternAlpha); CGPatternRelease(platformPattern); state().m_fillStylePatternTransform = m; #elif PLATFORM(QT) fprintf(stderr, "FIXME: CanvasRenderingContext2D::applyFillPattern\n"); #endif state().m_appliedFillPattern = true; }
void SVGPaintServerPattern::teardown(GraphicsContext*& context, const RenderObject*, SVGPaintTargetType, bool) const { CGPatternRelease(m_pattern); m_pattern = 0; context->restore(); }
void CanvasRenderingContext2D::applyFillPattern() { GraphicsContext* c = drawingContext(); if (!c) return; #if PLATFORM(CG) // Check for case where the pattern is already set. CGAffineTransform m = CGContextGetCTM(c->platformContext()); if (state().m_appliedFillPattern && CGAffineTransformEqualToTransform(m, state().m_fillStylePatternTransform)) return; CanvasPattern* pattern = state().m_fillStyle->pattern(); if (!pattern) return; CGPatternRef platformPattern = pattern->createPattern(m); if (!platformPattern) return; CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(0); CGContextSetFillColorSpace(c->platformContext(), patternSpace); CGColorSpaceRelease(patternSpace); const CGFloat patternAlpha = 1; CGContextSetFillPattern(c->platformContext(), platformPattern, &patternAlpha); CGPatternRelease(platformPattern); state().m_fillStylePatternTransform = m; #elif PLATFORM(QT) notImplemented(); #elif PLATFORM(CAIRO) && !PLATFORM(BAL) CanvasPattern* pattern = state().m_fillStyle->pattern(); if (!pattern) return; cairo_t* cr = c->platformContext(); cairo_matrix_t m; cairo_get_matrix(cr, &m); cairo_pattern_t* platformPattern = pattern->createPattern(m); if (!platformPattern) return; cairo_set_source(cr, platformPattern); cairo_pattern_destroy(platformPattern); #elif PLATFORM(BAL) notImplemented(); #endif state().m_appliedFillPattern = true; }
void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) { if (!nativeImageForCurrentFrame()) return; ASSERT(patternTransform.isInvertible()); if (!patternTransform.isInvertible()) // Avoid a hang under CGContextDrawTiledImage on release builds. return; CGContextRef context = ctxt->platformContext(); ctxt->save(); CGContextClipToRect(context, destRect); ctxt->setCompositeOperation(op); 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. float adjustedY = destRect.height() - (phase.y() - destRect.y() + tileRect.y() * narrowPrecisionToFloat(patternTransform.d()) + scaledTileHeight); CGImageRef tileImage = nativeImageForCurrentFrame(); float h = CGImageGetHeight(tileImage); CGImageRef subImage; if (tileRect.size() == size()) subImage = tileImage; else { // Copying a sub-image out of a partially-decoded image stops the decoding of the original image. It should never happen // because sub-images are only used for border-image, which only renders when the image is fully decoded. ASSERT(h == height()); subImage = CGImageCreateWithImageInRect(tileImage, tileRect); } #ifndef BUILDING_ON_TIGER // Leopard has an optimized call for the tiling of image patterns, but we can only use it if the image has been decoded enough that // its buffer is the same size as the overall image. Because a partially decoded CGImageRef with a smaller width or height than the // overall image buffer needs to tile with "gaps", we can't use the optimized tiling call in that case. // FIXME: Could create WebKitSystemInterface SPI for CGCreatePatternWithImage2 and probably make Tiger tile faster as well. // FIXME: We cannot use CGContextDrawTiledImage with scaled tiles on Leopard, because it suffers from rounding errors. Snow Leopard is ok. float scaledTileWidth = tileRect.width() * narrowPrecisionToFloat(patternTransform.a()); float w = CGImageGetWidth(tileImage); #ifdef BUILDING_ON_LEOPARD if (w == size().width() && h == size().height() && scaledTileWidth == tileRect.width() && scaledTileHeight == tileRect.height()) #else if (w == size().width() && h == size().height()) #endif CGContextDrawTiledImage(context, FloatRect(adjustedX, adjustedY, scaledTileWidth, scaledTileHeight), subImage); else { #endif // On Leopard, this code now only runs for partially decoded images whose buffers do not yet match the overall size of the image. // On Tiger this code runs all the time. This code is suboptimal because the pattern does not reference the image directly, and the // pattern is destroyed before exiting the function. This means any decoding the pattern does doesn't end up cached anywhere, so we // redecode every time we paint. static const CGPatternCallbacks patternCallbacks = { 0, drawPatternCallback, NULL }; CGAffineTransform matrix = CGAffineTransformMake(narrowPrecisionToCGFloat(patternTransform.a()), 0, 0, narrowPrecisionToCGFloat(patternTransform.d()), adjustedX, adjustedY); matrix = CGAffineTransformConcat(matrix, CGContextGetCTM(context)); // The top of a partially-decoded image is drawn at the bottom of the tile. Map it to the top. matrix = CGAffineTransformTranslate(matrix, 0, size().height() - h); CGPatternRef pattern = CGPatternCreate(subImage, CGRectMake(0, 0, tileRect.width(), tileRect.height()), matrix, tileRect.width(), tileRect.height(), kCGPatternTilingConstantSpacing, true, &patternCallbacks); if (pattern == NULL) { if (subImage != tileImage) CGImageRelease(subImage); ctxt->restore(); return; } CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL); CGFloat alpha = 1; CGColorRef color = CGColorCreateWithPattern(patternSpace, pattern, &alpha); CGContextSetFillColorSpace(context, patternSpace); CGColorSpaceRelease(patternSpace); CGPatternRelease(pattern); // FIXME: Really want a public API for this. It is just CGContextSetBaseCTM(context, CGAffineTransformIdentiy). wkSetPatternBaseCTM(context, CGAffineTransformIdentity); CGContextSetPatternPhase(context, CGSizeZero); CGContextSetFillColorWithColor(context, color); CGContextFillRect(context, CGContextGetClipBoundingBox(context)); CGColorRelease(color); #ifndef BUILDING_ON_TIGER } #endif if (subImage != tileImage) CGImageRelease(subImage); ctxt->restore(); if (imageObserver()) imageObserver()->didDraw(this); }