Beispiel #1
0
cairo_surface_t *cairo_quartz_surface_create(CGContextRef context,
        int width,
        int height,
        cairo_bool_t y_grows_down)
{
    cairo_quartz_surface_t *surface;
    CGRect clip_box;

    surface = malloc(sizeof(cairo_quartz_surface_t));
    if (surface == NULL) {
        _cairo_error (CAIRO_STATUS_NO_MEMORY);
        return (cairo_surface_t*) &_cairo_surface_nil;
    }

    /* XXX: The content value here might be totally wrong. */
    _cairo_surface_init(&surface->base, &cairo_quartz_surface_backend,
                        CAIRO_CONTENT_COLOR_ALPHA);

    surface->context = context;
    surface->clip_region = NULL;
    surface->y_grows_down = y_grows_down;

    clip_box = CGContextGetClipBoundingBox (context);
    surface->extents.x = clip_box.origin.x;
    surface->extents.y = clip_box.origin.y;
    surface->extents.width = clip_box.size.width;
    surface->extents.height = clip_box.size.height;

    return (cairo_surface_t *) surface;
}
Beispiel #2
0
bool GiCanvasIos::beginPaint(CGContextRef context, bool fast, bool buffered)
{
    if (m_draw->getContext() || !context)
        return false;

    if (gs()) {
        CGRect rc = CGContextGetClipBoundingBox(context);
        RECT_2D clipBox = { rc.origin.x, rc.origin.y, 
            rc.origin.x + rc.size.width, rc.origin.y + rc.size.height };
        owner()->_beginPaint(clipBox);
    }

    m_draw->_context = context;
    m_draw->_fast = fast;
    m_draw->_ctxused[0] = false;
    m_draw->_ctxused[1] = false;
    
    if (buffered && gs()) {
        m_draw->createBufferBitmap(m_draw->width(), m_draw->height(), m_draw->_scale);
        context = m_draw->getContext();
    }

    bool antiAlias = !fast && (!gs() || gs()->isAntiAliasMode());
    CGContextSetAllowsAntialiasing(context, antiAlias);
    CGContextSetShouldAntialias(context, antiAlias);
    CGContextSetFlatness(context, fast ? 20 : 1);

    CGContextSetLineCap(context, kCGLineCapRound);
    CGContextSetLineJoin(context, kCGLineJoinRound);
    if (owner())        // 设置最小线宽为0.5像素,使用屏幕放大倍数以便得到实际像素值
        owner()->setMaxPenWidth(-1, 0.5f / m_draw->_scale);

    return true;
}
Beispiel #3
0
FX_BOOL CFX_QuartzDeviceDriver::GetDIBits(CFX_DIBitmap*     bitmap,
        FX_INT32            left,
        FX_INT32            top,
        void* pIccTransform,
        FX_BOOL bDEdge)
{
    if (FXDC_PRINTER == _deviceClass) {
        return FALSE;
    }
    if (bitmap->GetBPP() < 32) {
        return FALSE;
    }
    if (!(_renderCaps | FXRC_GET_BITS)) {
        return FALSE;
    }
    CGPoint pt = CGPointMake(left, top);
    pt = CGPointApplyAffineTransform(pt, _foxitDevice2User);
    CGAffineTransform ctm = CGContextGetCTM(_context);
    pt.x *= FXSYS_fabs(ctm.a);
    pt.y *= FXSYS_fabs(ctm.d);
    CGImageRef image = CGBitmapContextCreateImage(_context);
    if (NULL == image) {
        return FALSE;
    }
    CGFloat width	= (CGFloat) bitmap->GetWidth();
    CGFloat height	= (CGFloat) bitmap->GetHeight();
    if (width + pt.x > _width) {
        width -= (width + pt.x - _width);
    }
    if (height + pt.y > _height) {
        height -= (height + pt.y - _height);
    }
    CGImageRef subImage = CGImageCreateWithImageInRect(image,
                          CGRectMake(pt.x,
                                     pt.y,
                                     width,
                                     height));
    CGContextRef context = createContextWithBitmap(bitmap);
    CGRect rect = CGContextGetClipBoundingBox(context);
    CGContextClearRect(context, rect);
    CGContextDrawImage(context, rect, subImage);
    CGContextRelease(context);
    CGImageRelease(subImage);
    CGImageRelease(image);
    if (bitmap->HasAlpha()) {
        for (int row = 0; row < bitmap->GetHeight(); row ++) {
            FX_LPBYTE pScanline = (FX_LPBYTE)bitmap->GetScanline(row);
            for (int col = 0; col < bitmap->GetWidth(); col ++) {
                if (pScanline[3] > 0) {
                    pScanline[0] = (pScanline[0] * 255.f / pScanline[3] + .5f);
                    pScanline[1] = (pScanline[1] * 255.f / pScanline[3] + .5f);
                    pScanline[2] = (pScanline[2] * 255.f / pScanline[3] + .5f);
                }
                pScanline += 4;
            }
        }
    }
    return TRUE;
}
Beispiel #4
0
void WKCACFLayer::display(PlatformGraphicsContext* context)
{
    if (!m_owner)
        return;

    CGContextSaveGState(context);

    CGRect layerBounds = bounds();
    if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) {
        CGContextScaleCTM(context, 1, -1);
        CGContextTranslateCTM(context, 0, -layerBounds.size.height);
    }

    if (m_owner->client()) {
        GraphicsContext graphicsContext(context);

        // It's important to get the clip from the context, because it may be significantly
        // smaller than the layer bounds (e.g. tiled layers)
        CGRect clipBounds = CGContextGetClipBoundingBox(context);
        IntRect clip(enclosingIntRect(clipBounds));
        m_owner->paintGraphicsLayerContents(graphicsContext, clip);
    }
#ifndef NDEBUG
    else {
        ASSERT_NOT_REACHED();

        // FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color,
        // so CA never makes backing store for it (which is what -setNeedsDisplay will do above).
        CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f);
        CGContextFillRect(context, layerBounds);
    }
#endif

    if (m_owner->showRepaintCounter()) {
        char text[16]; // that's a lot of repaints
        _snprintf(text, sizeof(text), "%d", m_owner->incrementRepaintCount());

        CGContextSaveGState(context);
        CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f);
        
        CGRect aBounds = layerBounds;

        aBounds.size.width = 10 + 12 * strlen(text);
        aBounds.size.height = 25;
        CGContextFillRect(context, aBounds);
        
        CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 1.0f);

        CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, -1.0f));
        CGContextSelectFont(context, "Helvetica", 25, kCGEncodingMacRoman);
        CGContextShowTextAtPoint(context, aBounds.origin.x + 3.0f, aBounds.origin.y + 20.0f, text, strlen(text));
        
        CGContextRestoreGState(context);        
    }

    CGContextRestoreGState(context);
}
void GraphicsContext::clipOutEllipseInRect(const IntRect& rect)
{
    if (paintingDisabled())
        return;
        
    CGContextBeginPath(platformContext());
    CGContextAddRect(platformContext(), CGContextGetClipBoundingBox(platformContext()));
    CGContextAddEllipseInRect(platformContext(), rect);
    CGContextEOClip(platformContext());
}
Beispiel #6
0
FX_BOOL CFX_QuartzDeviceDriver::GetClipBox(FX_RECT* rect)
{
    CGRect r = CGContextGetClipBoundingBox(_context);
    r = CGRectApplyAffineTransform(r, _user2FoxitDevice);
    rect->left		= FXSYS_floor(r.origin.x);
    rect->top		= FXSYS_floor(r.origin.y);
    rect->right		= FXSYS_ceil(r.origin.x + r.size.width);
    rect->bottom	= FXSYS_ceil(r.origin.y + r.size.height);
    return TRUE;
}
Beispiel #7
0
void GraphicsContext::clipOut(const IntRect& rect)
{
    if (paintingDisabled())
        return;

    CGRect rects[2] = { CGContextGetClipBoundingBox(platformContext()), rect };
    CGContextBeginPath(platformContext());
    CGContextAddRects(platformContext(), rects, 2);
    CGContextEOClip(platformContext());
}
Beispiel #8
0
void GraphicsContext::clipOut(const Path& path)
{
    if (paintingDisabled())
        return;

    CGContextBeginPath(platformContext());
    CGContextAddRect(platformContext(), CGContextGetClipBoundingBox(platformContext()));
    CGContextAddPath(platformContext(), path.platformPath());
    CGContextEOClip(platformContext());
}
Beispiel #9
0
CFX_QuartzDeviceDriver::CFX_QuartzDeviceDriver(CGContextRef context, FX_INT32 deviceClass)
{
    m_saveCount = 0;
    _context		= context;
    _deviceClass	= deviceClass;
    CGContextRetain(_context);
    CGRect r = CGContextGetClipBoundingBox(context);
    _width	= FXSYS_round(r.size.width);
    _height	= FXSYS_round(r.size.height);
    _renderCaps = FXRC_SOFT_CLIP | FXRC_BLEND_MODE |
                  FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE |
                  FXRC_BIT_MASK | FXRC_ALPHA_MASK;
    if (_deviceClass != FXDC_DISPLAY) {
    } else {
        CGImageRef image = CGBitmapContextCreateImage(_context);
        if (image) {
            _renderCaps |= FXRC_GET_BITS;
            _width = CGImageGetWidth(image);
            _height = CGImageGetHeight(image);
            CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(image);
            if (kCGImageAlphaPremultipliedFirst == alphaInfo ||
                    kCGImageAlphaPremultipliedLast == alphaInfo ||
                    kCGImageAlphaOnly == alphaInfo) {
                _renderCaps |= FXRC_ALPHA_OUTPUT;
            }
        }
        CGImageRelease(image);
    }
    CGAffineTransform ctm = CGContextGetCTM(_context);
    CGContextSaveGState(_context);
    m_saveCount++;
    if (ctm.d >= 0) {
        CGFloat offset_x, offset_y;
        offset_x = ctm.tx;
        offset_y = ctm.ty;
        CGContextTranslateCTM(_context, -offset_x, -offset_y);
        CGContextConcatCTM(_context, CGAffineTransformMake(1, 0, 0, -1, offset_x, _height + offset_y));
    }
    _foxitDevice2User = CGAffineTransformIdentity;
    _user2FoxitDevice = CGAffineTransformInvert(_foxitDevice2User);
}
Beispiel #10
0
void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
{
    if (paintingDisabled())
        return;

    RetainPtr<CFURLRef> urlRef(AdoptCF, link.createCFURL());
    if (!urlRef)
        return;

    CGContextRef context = platformContext();

    // Get the bounding box to handle clipping.
    CGRect box = CGContextGetClipBoundingBox(context);

    IntRect intBox((int)box.origin.x, (int)box.origin.y, (int)box.size.width, (int)box.size.height);
    IntRect rect = destRect;
    rect.intersect(intBox);

    CGPDFContextSetURLForRect(context, urlRef.get(),
        CGRectApplyAffineTransform(rect, CGContextGetCTM(context)));
}
Beispiel #11
0
void GraphicsContext::clipOut(const IntRect& rect)
{
    if (paintingDisabled())
        return;

#if USE(WXGC)
    wxGraphicsContext* gc = m_data->context->GetGraphicsContext();

#if wxUSE_CAIRO
    double x1, y1, x2, y2;
    cairo_t* cr = (cairo_t*)gc->GetNativeContext();
    cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
    cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1);
    cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
    cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
    cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
    cairo_clip(cr);
    cairo_set_fill_rule(cr, savedFillRule);

#elif __WXMAC__
    CGContextRef context = (CGContextRef)gc->GetNativeContext();

    CGRect rects[2] = { CGContextGetClipBoundingBox(context), CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()) };
    CGContextBeginPath(context);
    CGContextAddRects(context, rects, 2);
    CGContextEOClip(context);
    return;

#elif __WXMSW__
    Gdiplus::Graphics* g = (Gdiplus::Graphics*)gc->GetNativeContext();
    Gdiplus::Region excludeRegion(Gdiplus::Rect(rect.x(), rect.y(), rect.width(), rect.height()));
    g->ExcludeClip(&excludeRegion);
    return; 
#endif

#endif // USE(WXGC)

    notImplemented();
}
Beispiel #12
0
void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform,
                        const FloatPoint& phase, ColorSpace styleColorSpace, 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);

    RetainPtr<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.adoptCF(CGImageCreateWithImageInRect(tileImage, tileRect));
    }

    // Adjust the color space.
    subImage = imageWithColorSpace(subImage.get(), styleColorSpace);
    
#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.get());
    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);
    RetainPtr<CGPatternRef> pattern(AdoptCF, CGPatternCreate(subImage.get(), CGRectMake(0, 0, tileRect.width(), tileRect.height()),
                                             matrix, tileRect.width(), tileRect.height(), 
                                             kCGPatternTilingConstantSpacing, true, &patternCallbacks));
    if (!pattern) {
        ctxt->restore();
        return;
    }

    RetainPtr<CGColorSpaceRef> patternSpace(AdoptCF, CGColorSpaceCreatePattern(0));
    
    CGFloat alpha = 1;
    RetainPtr<CGColorRef> color(AdoptCF, CGColorCreateWithPattern(patternSpace.get(), pattern.get(), &alpha));
    CGContextSetFillColorSpace(context, patternSpace.get());

    // FIXME: Really want a public API for this.  It is just CGContextSetBaseCTM(context, CGAffineTransformIdentiy).
    wkSetPatternBaseCTM(context, CGAffineTransformIdentity);
    CGContextSetPatternPhase(context, CGSizeZero);

    CGContextSetFillColorWithColor(context, color.get());
    CGContextFillRect(context, CGContextGetClipBoundingBox(context));

#ifndef BUILDING_ON_TIGER
    }
#endif

    ctxt->restore();

    if (imageObserver())
        imageObserver()->didDraw(this);
}
Beispiel #13
0
float GetClipBoundingBoxY_wrap(    CGContext *c) { return CGContextGetClipBoundingBox(c).origin.y; }
Beispiel #14
0
float GetClipBoundingBoxHeight_wrap(CGContext *c) { return CGContextGetClipBoundingBox(c).size.height; }
Beispiel #15
0
float GetClipBoundingBoxWidth_wrap(CGContext *c) { return CGContextGetClipBoundingBox(c).size.width; }
    virtual void drawInContext(PlatformGraphicsContext* context)
    {
        if (!m_owner)
            return;

        CGContextSaveGState(context);

        CGRect layerBounds = bounds();
        if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) {
            CGContextScaleCTM(context, 1, -1);
            CGContextTranslateCTM(context, 0, -layerBounds.size.height);
        }

        if (m_owner->client()) {
            GraphicsContext graphicsContext(context);

            // It's important to get the clip from the context, because it may be significantly
            // smaller than the layer bounds (e.g. tiled layers)
            CGRect clipBounds = CGContextGetClipBoundingBox(context);
            IntRect clip(enclosingIntRect(clipBounds));
            m_owner->paintGraphicsLayerContents(graphicsContext, clip);
        }
#ifndef NDEBUG
        else {
            ASSERT_NOT_REACHED();

            // FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color,
            // so CA never makes backing store for it (which is what -setNeedsDisplay will do above).
            CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f);
            CGContextFillRect(context, layerBounds);
        }
#endif

        if (m_owner->showRepaintCounter()) {
            String text = String::format("%d", m_owner->incrementRepaintCount());;

            CGContextSaveGState(context);
            CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f);
            
            CGRect aBounds = layerBounds;

            aBounds.size.width = 10 + 12 * text.length();
            aBounds.size.height = 25;
            CGContextFillRect(context, aBounds);
            
            FontDescription desc;

            NONCLIENTMETRICS metrics;
            metrics.cbSize = sizeof(metrics);
            SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0);
            FontFamily family;
            family.setFamily(metrics.lfSmCaptionFont.lfFaceName);
            desc.setFamily(family);

            desc.setComputedSize(22);
            
            Font font = Font(desc, 0, 0);
            font.update(0);

            GraphicsContext cg(context);
            cg.setFillColor(Color::black, DeviceColorSpace);
            cg.drawText(font, TextRun(text), IntPoint(aBounds.origin.x + 3, aBounds.origin.y + 20));

            CGContextRestoreGState(context);        
        }

        CGContextRestoreGState(context);
    }
Beispiel #17
0
void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform,
    const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, BlendMode blendMode)
{
    if (!nativeImageForCurrentFrame())
        return;

    if (!patternTransform.isInvertible())
        return;

    CGContextRef context = ctxt->platformContext();
    GraphicsContextStateSaver stateSaver(*ctxt);
    CGContextClipToRect(context, destRect);
    ctxt->setCompositeOperation(op, blendMode);
    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);

    RetainPtr<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 = adoptCF(CGImageCreateWithImageInRect(tileImage, tileRect));
    }

    // Adjust the color space.
    subImage = Image::imageWithColorSpace(subImage.get(), styleColorSpace);

    // 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: 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);
    if (w == size().width() && h == size().height() && !spaceSize().width() && !spaceSize().height())
        CGContextDrawTiledImage(context, FloatRect(adjustedX, adjustedY, scaledTileWidth, scaledTileHeight), subImage.get());
    else {
        // On Leopard and newer, this code now only runs for partially decoded images whose buffers do not yet match the overall size of the image.
        static const CGPatternCallbacks patternCallbacks = { 0, drawPatternCallback, patternReleaseCallback };
        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);
#if PLATFORM(IOS)
        matrix = CGAffineTransformScale(matrix, 1, -1);
        matrix = CGAffineTransformTranslate(matrix, 0, -h);
#endif
        CGImageRef platformImage = CGImageRetain(subImage.get());
        RetainPtr<CGPatternRef> pattern = adoptCF(CGPatternCreate(platformImage, CGRectMake(0, 0, tileRect.width(), tileRect.height()), matrix,
            tileRect.width() + spaceSize().width() * (1 / narrowPrecisionToFloat(patternTransform.a())),
            tileRect.height() + spaceSize().height() * (1 / narrowPrecisionToFloat(patternTransform.d())),
            kCGPatternTilingConstantSpacing, true, &patternCallbacks));
        
        if (!pattern)
            return;

        RetainPtr<CGColorSpaceRef> patternSpace = adoptCF(CGColorSpaceCreatePattern(0));

        CGFloat alpha = 1;
        RetainPtr<CGColorRef> color = adoptCF(CGColorCreateWithPattern(patternSpace.get(), pattern.get(), &alpha));
        CGContextSetFillColorSpace(context, patternSpace.get());

        // FIXME: Really want a public API for this. It is just CGContextSetBaseCTM(context, CGAffineTransformIdentiy).
        wkSetBaseCTM(context, CGAffineTransformIdentity);
        CGContextSetPatternPhase(context, CGSizeZero);

        CGContextSetFillColorWithColor(context, color.get());
        CGContextFillRect(context, CGContextGetClipBoundingBox(context));
    }

    stateSaver.restore();

    if (imageObserver())
        imageObserver()->didDraw(this);
}