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;
}