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;
}
示例#2
0
void wxMemoryDCImpl::DoSelect( const wxBitmap& bitmap )
{
    if ( m_selected.IsOk() )
    {
        m_selected.EndRawAccess() ;
        wxDELETE(m_graphicContext);
    }

    m_selected = bitmap;
    if (m_selected.IsOk())
    {
        if ( m_selected.GetDepth() != 1 )
            m_selected.UseAlpha() ;
        m_selected.BeginRawAccess() ;
        m_width = bitmap.GetScaledWidth();
        m_height = bitmap.GetScaledHeight();
        m_contentScaleFactor = bitmap.GetScaleFactor();
        CGColorSpaceRef genericColorSpace  = wxMacGetGenericRGBColorSpace();
        CGContextRef bmCtx = (CGContextRef) m_selected.GetHBITMAP();

        if ( bmCtx )
        {
            CGContextSetFillColorSpace( bmCtx, genericColorSpace );
            CGContextSetStrokeColorSpace( bmCtx, genericColorSpace );
            SetGraphicsContext( wxGraphicsContext::CreateFromNative( bmCtx ) );
        }
        m_ok = (m_graphicContext != NULL) ;
    }
    else
    {
        m_ok = false;
    }
}
示例#3
0
wxMetafileRefData::wxMetafileRefData( int width, int height)
{
    Init();

    m_width = width;
    m_height = height;

    CGRect r = CGRectMake( 0 , 0 , width  , height );

    CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
    m_data.reset(data);
    CGDataConsumerRef dataConsumer = wxMacCGDataConsumerCreateWithCFData(data);
    m_context = CGPDFContextCreate( dataConsumer, (width != 0 && height != 0) ? &r : NULL , NULL );
    CGDataConsumerRelease( dataConsumer );
    if ( m_context )
    {
        CGPDFContextBeginPage(m_context, NULL);

        CGColorSpaceRef genericColorSpace  = wxMacGetGenericRGBColorSpace();

        CGContextSetFillColorSpace( m_context, genericColorSpace );
        CGContextSetStrokeColorSpace( m_context, genericColorSpace );

        CGContextTranslateCTM( m_context , 0 ,  height ) ;
        CGContextScaleCTM( m_context , 1 , -1 ) ;
    }
}
void drawWithColorBlendMode(CGContextRef context, CFURLRef url)
{
    // A pleasant green color.
    float green[4] = { 0.584, 0.871, 0.318, 1.0 }; 
    CGRect insetRect, pdfRect;
    
    // Create a CGPDFDocument object from the URL.
    CGPDFDocumentRef pdfDoc = CGPDFDocumentCreateWithURL(url);
    if(pdfDoc == NULL){
		fprintf(stderr, "Couldn't create CGPDFDocument from URL!\n");
		return;
    }
    // Obtain the media box for page 1 of the PDF document.
    pdfRect = CGPDFDocumentGetMediaBox(pdfDoc, 1);
    // Set the origin of the rectangle to (0,0).
    pdfRect.origin.x = pdfRect.origin.y = 0;
    
    // Graphic 1, the left portion of the figure.
    CGContextTranslateCTM(context, 20, 10 + CGRectGetHeight(pdfRect)/2);
    
    // Draw the PDF document.
    CGContextDrawPDFDocument(context, pdfRect, pdfDoc, 1);
    
    // Set the fill color space to that returned by getTheCalibratedRGBColorSpace.
    CGContextSetFillColorSpace(context, getTheCalibratedRGBColorSpace());
    // Set the fill color to green.
    CGContextSetFillColor(context, green);
    
    // Graphic 2, the top-right portion of the figure.
    CGContextTranslateCTM(context, CGRectGetWidth(pdfRect) + 10, 
				    CGRectGetHeight(pdfRect)/2 + 10);

    // Draw the PDF document again.
    CGContextDrawPDFDocument(context, pdfRect, pdfDoc, 1);

    // Make a fill rectangle that is the same size as the PDF document
    // but inset each side by 80 units in x and 20 units in y.
    insetRect = CGRectInset(pdfRect, 80, 20);
    // Fill the rectangle with green. Because the fill color is opaque and
    // the blend mode is Normal, this obscures the drawing underneath. 
    CGContextFillRect(context, insetRect);
    
    // Graphic 3, the bottom-right portion of the figure.
    CGContextTranslateCTM(context, 0, -(10 + CGRectGetHeight(pdfRect)));

    // Draw the PDF document again.
    CGContextDrawPDFDocument(context, pdfRect, pdfDoc, 1);
    
    // Set the blend mode to kCGBlendModeColor which will
    // colorize the destination with subsequent drawing.
    CGContextSetBlendMode(context, kCGBlendModeColor);
    // Draw the rectangle on top of the PDF document. The portion of the
    // background that is covered by the rectangle is colorized
    // with the fill color.
    CGContextFillRect(context, insetRect);

    // Release the CGPDFDocumentRef the code created.
    CGPDFDocumentRelease(pdfDoc);
}
示例#5
0
//-----------------------------------------------------------------------------
void CGDrawContext::init ()
{
	CGContextSaveGState (cgContext);
	CGContextSetShouldAntialias (cgContext, false);
	CGContextSetFillColorSpace (cgContext, GetCGColorSpace ());
	CGContextSetStrokeColorSpace (cgContext, GetCGColorSpace ()); 
	CGContextSaveGState (cgContext);
	CGAffineTransform cgCTM = CGAffineTransformMake (1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
	CGContextSetTextMatrix (cgContext, cgCTM);

	CDrawContext::init ();
}
void doIndexedColorDrawGraphics(CGContextRef context)
{
	CGColorSpaceRef theBaseRGBSpace = getTheCalibratedRGBColorSpace();
	CGColorSpaceRef theIndexedSpace = NULL;
	unsigned char lookupTable[6];
	float opaqueRed[] = { 0, 1 }; // index, alpha
	float aBlue[] = { 1, 1 };   // index, alpha
	
	// Set the first 3 values in the lookup table to a red of
	// 169/255 = 0.663, no green, and blue = 8/255 = 0.031. This makes  
	// the first entry in the lookup table a shade of red.
	lookupTable[0] = 169; lookupTable[1] = 0; lookupTable[2] = 8;
	
	// Set the second 3 values in the lookup table to a red value
	// of 123/255 = 0.482, a green value of 158/255 = 0.62, and
	// a blue value of 222/255 = 0.871. This makes the second entry
	// in the lookup table a shade of blue.
	lookupTable[3] = 123; lookupTable[4] = 158; lookupTable[5] = 222;
	
	// Create the indexed color space with this color lookup table,
	// using the RGB color space as the base color space and a 2 element
	// color lookup table to characterize the indexed color space.
	theIndexedSpace = CGColorSpaceCreateIndexed(theBaseRGBSpace, 1, lookupTable);
	if(theIndexedSpace != NULL){
	    CGContextSetStrokeColorSpace(context, theIndexedSpace);
	    CGContextSetFillColorSpace(context, theIndexedSpace);
	    // Release the color space this code created since it is no
		// longer needed in this routine.
	    CGColorSpaceRelease(theIndexedSpace);

	    // Set the stroke color to an opaque blue.
	    CGContextSetStrokeColor(context, aBlue);
	    // Set the fill color to an opaque red.
	    CGContextSetFillColor(context, opaqueRed);

	    CGContextSetLineWidth(context, 8.);
	 	// Draw the first rectangle.
	    CGContextBeginPath(context);
	    CGContextAddRect(context, CGRectMake(20., 20., 100., 100.));
	    CGContextDrawPath(context, kCGPathFillStroke);

	    // Continue to use the stroke colorspace already set
	    // but change the stroke alpha value to a semitransparent value
	    // while leaving the index value unchanged.
	    aBlue[1] = 0.5;
	    CGContextSetStrokeColor(context, aBlue);
	    // Draw another rectangle to the right of the first one.
	    CGContextBeginPath(context);
	    CGContextAddRect(context, CGRectMake(140., 20., 100., 100.));
	    CGContextDrawPath(context, kCGPathFillStroke);
	}else
	    fprintf(stderr, "Couldn't make the indexed color space!\n");
}
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;
}
示例#8
0
void GraphicsContext::applyFillPattern()
{
    CGContextRef cgContext = platformContext();

    RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_state.fillPattern->createPlatformPattern(getCTM()));
    if (!platformPattern)
        return;

    RetainPtr<CGColorSpaceRef> patternSpace(AdoptCF, CGColorSpaceCreatePattern(0));
    CGContextSetFillColorSpace(cgContext, patternSpace.get());

    const CGFloat patternAlpha = 1;
    CGContextSetFillPattern(cgContext, platformPattern.get(), &patternAlpha);
}
示例#9
0
void wxMemoryDC::DoSelect( const wxBitmap& bitmap )
{
    if ( m_selected.Ok() )
    {
#if wxMAC_USE_CORE_GRAPHICS
        m_selected.EndRawAccess() ;
        delete m_graphicContext ;
        m_graphicContext = NULL ;
#else
// TODO: UnlockPixels( GetGWorldPixMap(MAC_WXHBITMAP(m_selected.GetHBITMAP())) );
#endif
    }

    m_selected = bitmap;
    if (m_selected.Ok())
    { 
#if wxMAC_USE_CORE_GRAPHICS
        if ( m_selected.GetDepth() != 1 )
            m_selected.UseAlpha() ;
        m_selected.BeginRawAccess() ;
		m_width = bitmap.GetWidth();
		m_height = bitmap.GetHeight();
        CGColorSpaceRef genericColorSpace  = wxMacGetGenericRGBColorSpace();
        CGContextRef bmCtx = (CGContextRef) m_selected.GetHBITMAP();

        if ( bmCtx )
        {
            CGContextSetFillColorSpace( bmCtx, genericColorSpace );
            CGContextSetStrokeColorSpace( bmCtx, genericColorSpace );
			SetGraphicsContext( wxGraphicsContext::CreateFromNative( bmCtx ) );
        }
        m_ok = (m_graphicContext != NULL) ;

#else
        m_macPort = m_selected.GetHBITMAP( &m_macMask ) ;
        m_ok = (m_macPort != NULL) ;
        if (m_ok)
        {
            LockPixels( GetGWorldPixMap( (CGrafPtr) m_macPort ) ) ;
            SetRectRgn( (RgnHandle) m_macBoundaryClipRgn , 0 , 0 , m_selected.GetWidth() , m_selected.GetHeight() ) ;
            CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
        }
#endif
    }
    else
    {
        m_ok = false;
    }
}
示例#10
0
//-----------------------------------------------------------------------------
void CGDrawContext::init ()
{
    CGContextSaveGState (cgContext);
    CGContextSetAllowsAntialiasing (cgContext, true);
    CGContextSetAllowsFontSmoothing (cgContext, true);
    CGContextSetAllowsFontSubpixelPositioning (cgContext, true);
    CGContextSetAllowsFontSubpixelQuantization (cgContext, true);
    CGContextSetShouldAntialias (cgContext, false);
    CGContextSetFillColorSpace (cgContext, GetCGColorSpace ());
    CGContextSetStrokeColorSpace (cgContext, GetCGColorSpace ());
    CGContextSaveGState (cgContext);
    CGAffineTransform cgCTM = CGAffineTransformMake (1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
    CGContextSetTextMatrix (cgContext, cgCTM);

    CDrawContext::init ();
}
void doAlphaOnlyContext(CGContextRef context)
{
    CGImageRef mask = NULL;
    // This code is going to capture the alpha coverage
    // of the drawing done by the doAlphaRects routine.
    // The value passed here as the width and height is
    // the size of the bounding rectangle of that drawing.
    size_t width = 520, height = 400;
    CGContextRef alphaContext = createAlphaOnlyContext(width, height);
    if(context == NULL){
		fprintf(stderr, "Couldn't create the alpha-only context!\n");
		return;
    }

    // Draw the content to the alpha-only context, capturing
    // the alpha coverage. The doAlphaRects routine paints
    // a series of translucent red rectangles.
    doAlphaRects(alphaContext);

    // Finished drawing to the context and now the raster contains
    // the alpha data captured from the drawing. Create
    // the mask from the data in the context.
    mask = createMaskFromAlphaOnlyContext(alphaContext);
    // This code is now finshed with the context so it can
    // release it.
    CGContextRelease(alphaContext);
    
    if(mask == NULL){
		return;
    }

    // Set the fill color space.
    CGContextSetFillColorSpace(context, getTheCalibratedRGBColorSpace());
    float opaqueBlue[] = { 0.11, 0.208, 0.451, 1.0 };
    // Set the painting color to opaque blue.
    CGContextSetFillColor(context, opaqueBlue);
    // Draw the mask, painting the mask with blue. This colorizes
    // the image to blue and it is as if we painted the
    // alpha rects with blue instead of red.
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), mask);

    // Releasing the mask will cause Quartz to release the data provider 
    // and therefore the raster memory used to create the context.
    CGImageRelease(mask);
}
void drawWithGlobalAlpha(CGContextRef context)
{
	int i;
	CGRect rect = CGRectMake(40., 210., 100., 100.);
	float color[4] = { 1.0, 0.0, 0.0, 1.0 }; // opaque red
	// Set the fill color space to that returned by getTheCalibratedRGBColorSpace.
	CGContextSetFillColorSpace(context, getTheCalibratedRGBColorSpace());
	
	CGContextSetFillColor(context, color);
	for(i = 0; i < 2 ; i++){
		CGContextSaveGState(context);
			// Paint the leftmost rect on this row with 100% opaque red.
			CGContextFillRect(context, rect);
	    
			CGContextTranslateCTM(context, rect.size.width + 70., 0.);
			// Set the alpha value of this rgba color to 0.5.
			color[3] = 0.5;
			// Use the new color as the fill color in the graphics state.
			CGContextSetFillColor(context, color);
			// Paint the center rect on this row with 50% opaque red.
			CGContextFillRect(context, rect);

			CGContextTranslateCTM(context, rect.size.width + 70., 0.);
			// Set the alpha value of this rgba color to 0.25.
			color[3] = 0.25;
			// Use the new color as the fill color in the graphics state.
			CGContextSetFillColor(context, color);
			// Paint the rightmost rect on this row with 25% opaque red.
			CGContextFillRect(context, rect);
		CGContextRestoreGState(context);
		// After restoring the graphics state, the fill color is set to
		// that prior to calling CGContextSaveGState, that is, opaque
		// red. The coordinate system is also restored.
		
		// Now set the context global alpha value to 50% opaque.
		CGContextSetAlpha(context, 0.5);
		// Translate down for a second row of rectangles.
		CGContextTranslateCTM(context, 0., -(rect.size.height + 70.));
		// Reset the alpha value of the color array to fully opaque.
		color[3] = 1.0;
	}
}
void doColorSpaceFillAndStroke(CGContextRef context)
{
	CGColorSpaceRef theColorSpace = getTheCalibratedRGBColorSpace();
	float opaqueRed[] = { 0.663, 0.0, 0.031, 1.0 }; // red,green,blue,alpha
	float aBlue[] = { 0.482, 0.62, 0.871, 1.0 };	// red,green,blue,alpha
	
	// Set the fill color space to be the generic calibrated RGB color space.
	CGContextSetFillColorSpace(context, theColorSpace);
	// Set the fill color to opaque red. The number of elements in the
	// array passed to this function must be the number of color
	// components in the current fill color space plus 1 for alpha.
	CGContextSetFillColor(context, opaqueRed);
	
	// Set the stroke color space to be the generic calibrated RGB color space.
	CGContextSetStrokeColorSpace(context, theColorSpace);
	// Set the stroke color to opaque blue. The number of elements
	// in the array passed to this function must be the number of color
	// components in the current stroke color space plus 1 for alpha.
	CGContextSetStrokeColor(context, aBlue);
	
	CGContextSetLineWidth(context, 8.);
 	// Rectangle 1.
	CGContextBeginPath(context);
	CGContextAddRect(context, CGRectMake(20., 20., 100., 100.));
	CGContextDrawPath(context, kCGPathFillStroke);
    
	// Continue to use the stroke colorspace already set
	// but change the stroke alpha value to a semitransparent blue.
	aBlue[3] = 0.5;
	CGContextSetStrokeColor(context, aBlue);
 	// Rectangle 2.
	CGContextBeginPath(context);
	CGContextAddRect(context, CGRectMake(140., 20., 100., 100.));
	CGContextDrawPath(context, kCGPathFillStroke);
    
	// Don't release the color space since this routine 
	// didn't create it.
}
示例#14
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);
}
示例#15
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);
}
示例#16
0
bool FBVLC_Mac::onCoreGraphicsDraw(FB::CoreGraphicsDraw *evt, FB::PluginWindowMacCG*)
{
    boost::lock_guard<boost::mutex> lock( m_frameGuard );

    FB::Rect bounds(evt->bounds);
    //FB::Rect clip(evt->clip);
    short width = bounds.right - bounds.left, height = bounds.bottom - bounds.top;

    CGContextRef cgContext(evt->context);

    CGContextSaveGState(cgContext);

    CGContextTranslateCTM(cgContext, 0.0, height);
    CGContextScaleCTM(cgContext, 1.0, -1.0);

    CGColorSpaceRef cSpace = CGColorSpaceCreateDeviceRGB();
    CGContextSetFillColorSpace(cgContext, cSpace);

    CGColorRef bgColor = CGColorCreate(cSpace, m_bgComponents);
    CGContextSetFillColorWithColor(cgContext, bgColor);

    if ( 0 != m_media_width && 0 != m_media_height ) {
        CGRect imgRect = {
            { (width - m_media_width) / 2, (height - m_media_height) / 2 },
            { m_media_width, m_media_height }
        };

        const std::vector<char>& fb = vlc::vmem::frame_buf();
        CGContextRef frameBmpCtx =
            CGBitmapContextCreate( (void*)&fb[0], m_media_width, m_media_height, 8,
                                   m_media_width * vlc::DEF_PIXEL_BYTES, cSpace,
                                   kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little );
        CGImageRef frameImage = CGBitmapContextCreateImage( frameBmpCtx );

        CGContextDrawImage( cgContext, imgRect, frameImage );

        CGImageRelease( frameImage );
        CGContextRelease( frameBmpCtx );

        if( m_media_width < width ) {
            CGRect bgLeft = {
                { 0, 0 },
                { imgRect.origin.x, height }
            };
            CGContextFillRect(cgContext, bgLeft);

            CGRect bgRight = {
                { imgRect.origin.x + imgRect.size.width, 0 },
                { width - (imgRect.origin.x + imgRect.size.width), height }
            };
            CGContextFillRect(cgContext, bgRight);

        } else if( m_media_height < height ){
            CGRect bgTop = {
                { 0, 0 },
                { width, imgRect.origin.y }
            };
            CGContextFillRect(cgContext, bgTop);

            CGRect bgBottom = {
                { 0, imgRect.origin.y + imgRect.size.height },
                { width, height - (imgRect.origin.y + imgRect.size.height) }
            };
            CGContextFillRect(cgContext, bgBottom);
        }
    } else {
        CGRect cgBounds = {
            { 0, 0 },
            { width, height }
        };
        CGContextFillRect(cgContext, cgBounds);
    }

    CGColorRelease(bgColor);
    CGColorSpaceRelease(cSpace);
    CGContextRestoreGState(cgContext);

    return true; // This is handled
}
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;
}