TextStream& SVGPaintServerPattern::externalRepresentation(TextStream& ts) const { // Gradients/patterns aren't setup, until they are used for painting. Work around that fact. m_ownerElement->buildPattern(FloatRect(0.0f, 0.0f, 1.0f, 1.0f)); ts << "[type=PATTERN]" << " [bbox=" << patternBoundaries() << "]"; if (!patternTransform().isIdentity()) ts << " [pattern transform=" << patternTransform() << "]"; return ts; }
bool SVGPaintServerPattern::setup(GraphicsContext*& context, const RenderObject* object, SVGPaintTargetType type, bool isPaintingText) const { FloatRect targetRect = object->objectBoundingBox(); const SVGRenderStyle* style = object->style()->svgStyle(); bool isFilled = (type & ApplyToFillTargetType) && style->hasFill(); bool isStroked = (type & ApplyToStrokeTargetType) && style->hasStroke(); ASSERT(isFilled && !isStroked || !isFilled && isStroked); m_ownerElement->buildPattern(targetRect); if (!tile()) return false; context->save(); ASSERT(!m_pattern); IntRect tileRect = tile()->image()->rect(); if (tileRect.width() > patternBoundaries().width() || tileRect.height() > patternBoundaries().height()) { // Draw the first cell of the pattern manually to support overflow="visible" on all platforms. int tileWidth = static_cast<int>(patternBoundaries().width() + 0.5f); int tileHeight = static_cast<int>(patternBoundaries().height() + 0.5f); OwnPtr<ImageBuffer> tileImage = ImageBuffer::create(IntSize(tileWidth, tileHeight)); GraphicsContext* tileImageContext = tileImage->context(); int numY = static_cast<int>(ceilf(tileRect.height() / tileHeight)) + 1; int numX = static_cast<int>(ceilf(tileRect.width() / tileWidth)) + 1; tileImageContext->save(); tileImageContext->translate(-patternBoundaries().width() * numX, -patternBoundaries().height() * numY); for (int i = numY; i > 0; i--) { tileImageContext->translate(0, patternBoundaries().height()); for (int j = numX; j > 0; j--) { tileImageContext->translate(patternBoundaries().width(), 0); tileImageContext->drawImage(tile()->image(), object->style()->colorSpace(), tileRect, tileRect); } tileImageContext->translate(-patternBoundaries().width() * numX, 0); } tileImageContext->restore(); m_pattern = Pattern::create(tileImage->image(), true, true); } else m_pattern = Pattern::create(tile()->image(), true, true); if (isFilled) { context->setAlpha(style->fillOpacity()); context->setFillPattern(m_pattern); context->setFillRule(style->fillRule()); } if (isStroked) { context->setAlpha(style->strokeOpacity()); context->setStrokePattern(m_pattern); applyStrokeStyleToContext(context, object->style(), object); } TransformationMatrix matrix; matrix.translate(patternBoundaries().x(), patternBoundaries().y()); matrix.multiply(patternTransform()); m_pattern->setPatternSpaceTransform(matrix); if (isPaintingText) { context->setTextDrawingMode(isFilled ? cTextFill : cTextStroke); #if PLATFORM(CG) if (isFilled) context->applyFillPattern(); else context->applyStrokePattern(); #endif } return true; }
bool SVGPaintServerPattern::setup(GraphicsContext*& context, const RenderObject* object, SVGPaintTargetType type, bool isPaintingText) const { CGContextRef contextRef = context->platformContext(); // Build pattern tile, passing destination object bounding box FloatRect targetRect; if (isPaintingText) { IntRect textBoundary = const_cast<RenderObject*>(object)->absoluteBoundingBoxRect(); targetRect = object->absoluteTransform().inverse().mapRect(textBoundary); } else targetRect = CGContextGetPathBoundingBox(contextRef); m_ownerElement->buildPattern(targetRect); if (!tile()) return false; CGSize cellSize = CGSize(tile()->size()); CGFloat alpha = 1; // canvasStyle->opacity(); //which? context->save(); // Repesct local pattern transformations CGContextConcatCTM(contextRef, patternTransform()); // Pattern space seems to start in the lower-left, so we flip the Y here. CGSize phase = CGSizeMake(patternBoundaries().x(), -patternBoundaries().y()); CGContextSetPatternPhase(contextRef, phase); RenderStyle* style = object->style(); CGContextSetAlpha(contextRef, style->opacity()); // or do I set the alpha above? ASSERT(!m_pattern); CGPatternCallbacks callbacks = {0, patternCallback, NULL}; m_pattern = CGPatternCreate(tile(), CGRectMake(0, 0, cellSize.width, cellSize.height), CGContextGetCTM(contextRef), patternBoundaries().width(), patternBoundaries().height(), kCGPatternTilingConstantSpacing, // FIXME: should ask CG guys. true, // has color &callbacks); if (!m_patternSpace) m_patternSpace = CGColorSpaceCreatePattern(0); if ((type & ApplyToFillTargetType) && style->svgStyle()->hasFill()) { CGContextSetFillColorSpace(contextRef, m_patternSpace); CGContextSetFillPattern(contextRef, m_pattern, &alpha); if (isPaintingText) context->setTextDrawingMode(cTextFill); } if ((type & ApplyToStrokeTargetType) && style->svgStyle()->hasStroke()) { CGContextSetStrokeColorSpace(contextRef, m_patternSpace); CGContextSetStrokePattern(contextRef, m_pattern, &alpha); applyStrokeStyleToContext(contextRef, style, object); if (isPaintingText) context->setTextDrawingMode(cTextStroke); } return true; }