void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRectIn, ColorSpace styleColorSpace, CompositeOperator compositeOp, BlendMode blendMode, ImageOrientationDescription) { if (!m_source.initialized()) return; if (mayFillWithSolidColor()) fillWithSolidColor(ctxt, dstRect, solidColor(), styleColorSpace, compositeOp); else { IntRect intSrcRect(srcRectIn); RefPtr<SharedBitmap> bmp = frameAtIndex(m_currentFrame); if (bmp) { if (bmp->width() != m_source.size().width()) { double scaleFactor = static_cast<double>(bmp->width()) / m_source.size().width(); intSrcRect.setX(stableRound(srcRectIn.x() * scaleFactor)); intSrcRect.setWidth(stableRound(srcRectIn.width() * scaleFactor)); intSrcRect.setY(stableRound(srcRectIn.y() * scaleFactor)); intSrcRect.setHeight(stableRound(srcRectIn.height() * scaleFactor)); } bmp->draw(ctxt, enclosingIntRect(dstRect), intSrcRect, styleColorSpace, compositeOp, blendMode); } } startAnimation(); }
// Drawing Routines void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, CompositeOperator op) { startAnimation(); QPixmap* image = nativeImageForCurrentFrame(); if (!image) return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, dst, solidColor(), op); return; } IntSize selfSize = size(); ctxt->save(); // Set the compositing operation. ctxt->setCompositeOperation(op); QPainter* painter(ctxt->platformContext()); if (!image->hasAlpha() && painter->compositionMode() == QPainter::CompositionMode_SourceOver) painter->setCompositionMode(QPainter::CompositionMode_Source); // Test using example site at // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html painter->drawPixmap(dst, *image, src); ctxt->restore(); if (imageObserver()) imageObserver()->didDraw(this); }
// FIXME: Merge with the other drawTiled eventually, since we need a combination of both for some things. void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, const FloatSize& tileScaleFactor, TileRule hRule, TileRule vRule, ColorSpace styleColorSpace, CompositeOperator op) { if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, dstRect, solidColor(), styleColorSpace, op); return; } // FIXME: We do not support 'round' or 'space' yet. For now just map them to 'repeat'. if (hRule == RoundTile || hRule == SpaceTile) hRule = RepeatTile; if (vRule == RoundTile || vRule == SpaceTile) vRule = RepeatTile; AffineTransform patternTransform = AffineTransform().scaleNonUniform(tileScaleFactor.width(), tileScaleFactor.height()); // We want to construct the phase such that the pattern is centered (when stretch is not // set for a particular rule). float hPhase = tileScaleFactor.width() * srcRect.x(); float vPhase = tileScaleFactor.height() * srcRect.y(); float scaledTileWidth = tileScaleFactor.width() * srcRect.width(); float scaledTileHeight = tileScaleFactor.height() * srcRect.height(); if (hRule == Image::RepeatTile) hPhase -= (dstRect.width() - scaledTileWidth) / 2; if (vRule == Image::RepeatTile) vPhase -= (dstRect.height() - scaledTileHeight) / 2; FloatPoint patternPhase(dstRect.x() - hPhase, dstRect.y() - vPhase); drawPattern(ctxt, srcRect, patternTransform, patternPhase, styleColorSpace, op, dstRect); startAnimation(); }
void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { FloatRect srcRect(src); FloatRect dstRect(dst); if (dstRect.width() == 0.0f || dstRect.height() == 0.0f || srcRect.width() == 0.0f || srcRect.height() == 0.0f) return; startAnimation(); cairo_surface_t* image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(context, dstRect, solidColor(), styleColorSpace, op); return; } context->save(); // Set the compositing operation. if (op == CompositeSourceOver && !frameHasAlphaAtIndex(m_currentFrame)) context->setCompositeOperation(CompositeCopy); else context->setCompositeOperation(op); context->platformContext()->drawSurfaceToContext(image, dstRect, srcRect, context); context->restore(); if (imageObserver()) imageObserver()->didDraw(this); }
// FIXME: Merge with the other drawTiled eventually, since we need a combination of both for some things. void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, CompositeOperator op) { if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, dstRect, solidColor(), op); return; } // FIXME: We do not support 'round' yet. For now just map it to 'repeat'. if (hRule == RoundTile) hRule = RepeatTile; if (vRule == RoundTile) vRule = RepeatTile; FloatSize scale = calculatePatternScale(dstRect, srcRect, hRule, vRule); AffineTransform patternTransform = AffineTransform().scale(scale.width(), scale.height()); // We want to construct the phase such that the pattern is centered (when stretch is not // set for a particular rule). float hPhase = scale.width() * srcRect.x(); float vPhase = scale.height() * srcRect.y(); if (hRule == Image::RepeatTile) hPhase -= fmodf(dstRect.width(), scale.width() * srcRect.width()) / 2.0f; if (vRule == Image::RepeatTile) vPhase -= fmodf(dstRect.height(), scale.height() * srcRect.height()) / 2.0f; FloatPoint patternPhase(dstRect.x() - hPhase, dstRect.y() - vPhase); drawPattern(ctxt, srcRect, patternTransform, patternPhase, op, dstRect); startAnimation(); }
void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, CompositeOperator op) { FloatRect srcRect(src); FloatRect dstRect(dst); if (dstRect.width() == 0.0f || dstRect.height() == 0.0f || srcRect.width() == 0.0f || srcRect.height() == 0.0f) return; startAnimation(); cairo_surface_t* image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(context, dstRect, solidColor(), op); return; } IntSize selfSize = size(); cairo_t* cr = context->platformContext(); cairo_save(cr); // Set the compositing operation. if (op == CompositeSourceOver && !frameHasAlphaAtIndex(m_currentFrame)) context->setCompositeOperation(CompositeCopy); else context->setCompositeOperation(op); // If we're drawing a sub portion of the image or scaling then create // a pattern transformation on the image and draw the transformed pattern. // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image); // To avoid the unwanted gradient effect (#14017) we use // CAIRO_FILTER_NEAREST now, but the real fix will be to have // CAIRO_EXTEND_PAD implemented for surfaces in Cairo allowing us to still // use bilinear filtering cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST); float scaleX = srcRect.width() / dstRect.width(); float scaleY = srcRect.height() / dstRect.height(); cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, srcRect.x(), srcRect.y() }; cairo_pattern_set_matrix(pattern, &matrix); // Draw the image. cairo_translate(cr, dstRect.x(), dstRect.y()); cairo_set_source(cr, pattern); cairo_pattern_destroy(pattern); cairo_rectangle(cr, 0, 0, dstRect.width(), dstRect.height()); cairo_clip(cr); cairo_paint_with_alpha(cr, context->getAlpha()); cairo_restore(cr); if (imageObserver()) imageObserver()->didDraw(this); }
// Drawing Routines void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, CompositeOperator op) { QPixmap* image = nativeImageForCurrentFrame(); if (!image) return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, dst, solidColor(), op); return; } IntSize selfSize = size(); FloatRect srcRect(src); FloatRect dstRect(dst); ctxt->save(); // Set the compositing operation. ctxt->setCompositeOperation(op); QPainter* painter(ctxt->platformContext()); // Test using example site at // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html painter->drawPixmap(dst, *image, src); ctxt->restore(); startAnimation(); }
void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { FloatRect srcRect(src); FloatRect dstRect(dst); if (dstRect.width() == 0.0f || dstRect.height() == 0.0f || srcRect.width() == 0.0f || srcRect.height() == 0.0f) return; startAnimation(); cairo_surface_t* image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; //+EAWebKitChange //5/30/2012 #if ENABLE(IMAGE_COMPRESSION) // Check if this is a compressed surface. const void* pCompressedSurfaceUserData = cairo_surface_get_user_data (image, (cairo_user_data_key_t*) ImageCompressionGetUserDataKey()); #endif //-EAWebKitChange if (mayFillWithSolidColor()) { fillWithSolidColor(context, dstRect, solidColor(), styleColorSpace, op); //+EAWebKitChange //5/30/2012 #if ENABLE(IMAGE_COMPRESSION) if (pCompressedSurfaceUserData) cairo_surface_destroy(image); #endif //-EAWebKitChange return; } context->save(); // Set the compositing operation. if (op == CompositeSourceOver && !frameHasAlphaAtIndex(m_currentFrame)) context->setCompositeOperation(CompositeCopy); else context->setCompositeOperation(op); context->platformContext()->drawSurfaceToContext(image, dstRect, srcRect, context); context->restore(); if (imageObserver()) imageObserver()->didDraw(this); //+EAWebKitChange //5/30/2012 #if ENABLE(IMAGE_COMPRESSION) if (pCompressedSurfaceUserData) cairo_surface_destroy(image); #endif //-EAWebKitChange }
void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op, BlendMode, RespectImageOrientationEnum shouldRespectImageOrientation) { if (!dst.width() || !dst.height() || !src.width() || !src.height()) return; startAnimation(); NativeImageCairo* nativeImage = frameAtIndex(m_currentFrame); if (!nativeImage) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(context, dst, solidColor(), styleColorSpace, op); return; } context->save(); // Set the compositing operation. if (op == CompositeSourceOver && !frameHasAlphaAtIndex(m_currentFrame)) context->setCompositeOperation(CompositeCopy); else context->setCompositeOperation(op); #if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) cairo_surface_t* surface = nativeImage->surface(); IntSize scaledSize(cairo_image_surface_get_width(surface), cairo_image_surface_get_height(surface)); FloatRect adjustedSrcRect = adjustSourceRectForDownSampling(src, scaledSize); #else FloatRect adjustedSrcRect(src); #endif ImageOrientation orientation = DefaultImageOrientation; if (shouldRespectImageOrientation == RespectImageOrientation) orientation = frameOrientationAtIndex(m_currentFrame); FloatRect dstRect = dst; if (orientation != DefaultImageOrientation) { // ImageOrientation expects the origin to be at (0, 0). context->translate(dstRect.x(), dstRect.y()); dstRect.setLocation(FloatPoint()); context->concatCTM(orientation.transformFromDefault(dstRect.size())); if (orientation.usesWidthAsHeight()) { // The destination rectangle will have it's width and height already reversed for the orientation of // the image, as it was needed for page layout, so we need to reverse it back here. dstRect = FloatRect(dstRect.x(), dstRect.y(), dstRect.height(), dstRect.width()); } } context->platformContext()->drawSurfaceToContext(nativeImage->surface(), dstRect, adjustedSrcRect, context); context->restore(); if (imageObserver()) imageObserver()->didDraw(this); }
// FIXME: Merge with the other drawTiled eventually, since we need a combination of both for some things. void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, const FloatSize& providedTileScaleFactor, TileRule hRule, TileRule vRule, CompositeOperator op) { if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, dstRect, solidColor(), op); return; } // FIXME: We do not support 'space' yet. For now just map it to 'repeat'. if (hRule == SpaceTile) hRule = RepeatTile; if (vRule == SpaceTile) vRule = RepeatTile; // FIXME: if this code is used for background-repeat: round (in addition to // border-image-repeat), then add logic to deal with the background-size: auto // special case. The aspect ratio should be maintained in this case. FloatSize tileScaleFactor = providedTileScaleFactor; bool useLowInterpolationQuality = false; if (hRule == RoundTile) { float hRepetitions = std::max(1.0f, roundf(dstRect.width() / (tileScaleFactor.width() * srcRect.width()))); tileScaleFactor.setWidth(dstRect.width() / (srcRect.width() * hRepetitions)); } if (vRule == RoundTile) { float vRepetitions = std::max(1.0f, roundf(dstRect.height() / (tileScaleFactor.height() * srcRect.height()))); tileScaleFactor.setHeight(dstRect.height() / (srcRect.height() * vRepetitions)); } if (hRule == RoundTile || vRule == RoundTile) { // High interpolation quality rounds the scaled tile to an integer size (see Image::drawPattern). // To avoid causing a visual problem, linear interpolation must be used instead. // FIXME: Allow using high-quality interpolation in this case, too. useLowInterpolationQuality = true; } // We want to construct the phase such that the pattern is centered (when stretch is not // set for a particular rule). float hPhase = tileScaleFactor.width() * srcRect.x(); float vPhase = tileScaleFactor.height() * srcRect.y(); float scaledTileWidth = tileScaleFactor.width() * srcRect.width(); float scaledTileHeight = tileScaleFactor.height() * srcRect.height(); if (hRule == Image::RepeatTile) hPhase -= (dstRect.width() - scaledTileWidth) / 2; if (vRule == Image::RepeatTile) vPhase -= (dstRect.height() - scaledTileHeight) / 2; FloatPoint patternPhase(dstRect.x() - hPhase, dstRect.y() - vPhase); if (useLowInterpolationQuality) { InterpolationQuality previousInterpolationQuality = ctxt->imageInterpolationQuality(); ctxt->setImageInterpolationQuality(InterpolationLow); drawPattern(ctxt, srcRect, tileScaleFactor, patternPhase, op, dstRect); ctxt->setImageInterpolationQuality(previousInterpolationQuality); } else { drawPattern(ctxt, srcRect, tileScaleFactor, patternPhase, op, dstRect); } startAnimation(); }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator compositeOp) { CGImageRef image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), compositeOp); return; } CGContextRef context = ctxt->platformContext(); ctxt->save(); // If the source rect is a subportion of the image, then we compute an inflated destination rect that will hold the entire image // and then set a clip to the portion that we want to display. CGSize selfSize = size(); FloatRect adjustedDestRect = destRect; if (srcRect.width() != selfSize.width || srcRect.height() != selfSize.height) { // A subportion of the image is drawing. Adjust the destination rect to // account for this. float xScale = srcRect.width() / destRect.width(); float yScale = srcRect.height() / destRect.height(); adjustedDestRect.setLocation(FloatPoint(destRect.x() - srcRect.x() / xScale, destRect.y() - srcRect.y() / yScale)); adjustedDestRect.setSize(FloatSize(size().width() / xScale, size().height() / yScale)); CGContextClipToRect(context, destRect); } // If the image is only partially loaded, then shrink the destination rect that we're drawing into accordingly. float currHeight = CGImageGetHeight(image); if (currHeight < selfSize.height) adjustedDestRect.setHeight(adjustedDestRect.height() * currHeight / selfSize.height); // Flip the coords. ctxt->setCompositeOperation(compositeOp); CGContextTranslateCTM(context, adjustedDestRect.x(), adjustedDestRect.bottom()); CGContextScaleCTM(context, 1, -1); adjustedDestRect.setLocation(FloatPoint()); // Draw the image. CGContextDrawImage(context, adjustedDestRect, image); ctxt->restore(); startAnimation(); if (imageObserver()) imageObserver()->didDraw(this); }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp, BlendMode blendMode, ImageOrientationDescription description) { #if PLATFORM(IOS) startAnimation(DoNotCatchUp); #else startAnimation(); #endif RetainPtr<CGImageRef> image; // Never use subsampled images for drawing into PDF contexts. if (wkCGContextIsPDFContext(ctxt->platformContext())) image = adoptCF(copyUnscaledFrameAtIndex(m_currentFrame)); else { CGRect transformedDestinationRect = CGRectApplyAffineTransform(destRect, CGContextGetCTM(ctxt->platformContext())); float subsamplingScale = std::min<float>(1, std::max(transformedDestinationRect.size.width / srcRect.width(), transformedDestinationRect.size.height / srcRect.height())); image = frameAtIndex(m_currentFrame, subsamplingScale); } if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, compositeOp); return; } // Subsampling may have given us an image that is smaller than size(). IntSize imageSize(CGImageGetWidth(image.get()), CGImageGetHeight(image.get())); // srcRect is in the coordinates of the unsubsampled image, so we have to map it to the subsampled image. FloatRect scaledSrcRect = srcRect; if (imageSize != m_size) { FloatRect originalImageBounds(FloatPoint(), m_size); FloatRect subsampledImageBounds(FloatPoint(), imageSize); scaledSrcRect = mapRect(srcRect, originalImageBounds, subsampledImageBounds); } ImageOrientation orientation; if (description.respectImageOrientation() == RespectImageOrientation) orientation = frameOrientationAtIndex(m_currentFrame); ctxt->drawNativeImage(image.get(), imageSize, styleColorSpace, destRect, scaledSrcRect, compositeOp, blendMode, orientation); if (imageObserver()) imageObserver()->didDraw(this); }
// Drawing Routines void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, CompositeOperator op) { os::Bitmap* image = nativeImageForCurrentFrame(); if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, dst, solidColor(), op); return; } //DEBUG( "Image::draw() %f %f\n", image->GetBounds().Width(), image->GetBounds().Height() ); IntSize selfSize = size(); FloatRect srcRect(src); FloatRect dstRect(dst); ctxt->save(); // Set the compositing operation. ctxt->setCompositeOperation(op); os::View* view = ctxt->platformContext(); os::Rect cSrc = srcRect; os::Rect cDst = dstRect; cSrc.Resize( 0, 0, -1, -1 ); cDst.Resize( 0, 0, -1, -1 ); if( !image->GetBounds().Includes( cSrc ) ) DEBUG( "Error: Image::draw(): Source size larger than bitmap\n" ); view->DrawBitmap( image, cSrc & image->GetBounds(), cDst ); #if 0 QPainter* painter(ctxt->platformContext()); // Test using example site at // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html painter->drawImage(dst, *image, src); #endif ctxt->restore(); startAnimation(); }
// Drawing Routines void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { QRectF normalizedDst = dst.normalized(); QRectF normalizedSrc = src.normalized(); startAnimation(); if (normalizedSrc.isEmpty() || normalizedDst.isEmpty()) return; QPixmap* image = nativeImageForCurrentFrame(); if (!image) return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, normalizedDst, solidColor(), styleColorSpace, op); return; } #if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) normalizedSrc = adjustSourceRectForDownSampling(normalizedSrc, image->size()); #endif CompositeOperator previousOperator = ctxt->compositeOperation(); ctxt->setCompositeOperation(!image->hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op); if (ctxt->hasShadow()) { ShadowBlur* shadow = ctxt->shadowBlur(); GraphicsContext* shadowContext = shadow->beginShadowLayer(ctxt, normalizedDst); if (shadowContext) { QPainter* shadowPainter = shadowContext->platformContext(); shadowPainter->drawPixmap(normalizedDst, *image, normalizedSrc); shadow->endShadowLayer(ctxt); } } ctxt->platformContext()->drawPixmap(normalizedDst, *image, normalizedSrc); ctxt->setCompositeOperation(previousOperator); if (imageObserver()) imageObserver()->didDraw(this); }
void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, ColorSpace styleColorSpace, CompositeOperator op) { if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, op); return; } // See <https://webkit.org/b/59043>. #if !PLATFORM(WX) ASSERT(!isBitmapImage() || notSolidColor()); #endif FloatSize intrinsicTileSize = size(); if (hasRelativeWidth()) intrinsicTileSize.setWidth(scaledTileSize.width()); if (hasRelativeHeight()) intrinsicTileSize.setHeight(scaledTileSize.height()); FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(), scaledTileSize.height() / intrinsicTileSize.height()); FloatRect oneTileRect; oneTileRect.setX(destRect.x() + fmodf(fmodf(-srcPoint.x(), scaledTileSize.width()) - scaledTileSize.width(), scaledTileSize.width())); oneTileRect.setY(destRect.y() + fmodf(fmodf(-srcPoint.y(), scaledTileSize.height()) - scaledTileSize.height(), scaledTileSize.height())); oneTileRect.setSize(scaledTileSize); // Check and see if a single draw of the image can cover the entire area we are supposed to tile. if (oneTileRect.contains(destRect)) { FloatRect visibleSrcRect; visibleSrcRect.setX((destRect.x() - oneTileRect.x()) / scale.width()); visibleSrcRect.setY((destRect.y() - oneTileRect.y()) / scale.height()); visibleSrcRect.setWidth(destRect.width() / scale.width()); visibleSrcRect.setHeight(destRect.height() / scale.height()); draw(ctxt, destRect, visibleSrcRect, styleColorSpace, op); return; } AffineTransform patternTransform = AffineTransform().scaleNonUniform(scale.width(), scale.height()); FloatRect tileRect(FloatPoint(), intrinsicTileSize); drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), styleColorSpace, op, destRect); startAnimation(); }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp, BlendMode blendMode, ImageOrientationDescription description) { CGImageRef image; #if !PLATFORM(IOS) startAnimation(); image = frameAtIndex(m_currentFrame); #else startAnimation(DoNotCatchUp); CGRect transformedDestinationRect = CGRectApplyAffineTransform(destRect, CGContextGetCTM(ctxt->platformContext())); RetainPtr<CGImageRef> imagePossiblyCopied; // Never use subsampled images for drawing into PDF contexts. if (CGContextGetType(ctxt->platformContext()) == kCGContextTypePDF) imagePossiblyCopied = adoptCF(copyUnscaledFrameAtIndex(m_currentFrame)); else imagePossiblyCopied = frameAtIndex(m_currentFrame, std::min<float>(1.0f, std::max(transformedDestinationRect.size.width / srcRect.width(), transformedDestinationRect.size.height / srcRect.height()))); image = imagePossiblyCopied.get(); #endif if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, compositeOp); return; } float scale = 1; #if PLATFORM(IOS) scale = m_frames[m_currentFrame].m_scale; #endif FloatSize selfSize = currentFrameSize(); ImageOrientation orientation; if (description.respectImageOrientation() == RespectImageOrientation) orientation = frameOrientationAtIndex(m_currentFrame); ctxt->drawNativeImage(image, selfSize, styleColorSpace, destRect, srcRect, scale, compositeOp, blendMode, orientation); if (imageObserver()) imageObserver()->didDraw(this); }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp) { startAnimation(); RetainPtr<CGImageRef> image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, compositeOp); return; } FloatSize selfSize = currentFrameSize(); ctxt->drawNativeImage(image.get(), selfSize, styleColorSpace, destRect, srcRect, compositeOp); if (imageObserver()) imageObserver()->didDraw(this); }
void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, ColorSpace styleColorSpace, CompositeOperator op, BlendMode blendMode) { if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, op); return; } ASSERT(!isBitmapImage() || notSolidColor()); FloatSize intrinsicTileSize = size(); if (hasRelativeWidth()) intrinsicTileSize.setWidth(scaledTileSize.width()); if (hasRelativeHeight()) intrinsicTileSize.setHeight(scaledTileSize.height()); FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(), scaledTileSize.height() / intrinsicTileSize.height()); FloatRect oneTileRect; FloatSize actualTileSize(scaledTileSize.width() + spaceSize().width(), scaledTileSize.height() + spaceSize().height()); oneTileRect.setX(destRect.x() + fmodf(fmodf(-srcPoint.x(), actualTileSize.width()) - actualTileSize.width(), actualTileSize.width())); oneTileRect.setY(destRect.y() + fmodf(fmodf(-srcPoint.y(), actualTileSize.height()) - actualTileSize.height(), actualTileSize.height())); oneTileRect.setSize(scaledTileSize); // Check and see if a single draw of the image can cover the entire area we are supposed to tile. if (oneTileRect.contains(destRect) && !ctxt->drawLuminanceMask()) { FloatRect visibleSrcRect; visibleSrcRect.setX((destRect.x() - oneTileRect.x()) / scale.width()); visibleSrcRect.setY((destRect.y() - oneTileRect.y()) / scale.height()); visibleSrcRect.setWidth(destRect.width() / scale.width()); visibleSrcRect.setHeight(destRect.height() / scale.height()); draw(ctxt, destRect, visibleSrcRect, styleColorSpace, op, blendMode, ImageOrientationDescription()); return; } AffineTransform patternTransform = AffineTransform().scaleNonUniform(scale.width(), scale.height()); FloatRect tileRect(FloatPoint(), intrinsicTileSize); drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), styleColorSpace, op, destRect, blendMode); startAnimation(); }
void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, CompositeOperator op, WebBlendMode blendMode, const IntSize& repeatSpacing) { if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), op); return; } // See <https://webkit.org/b/59043>. ASSERT(!isBitmapImage() || notSolidColor()); FloatSize intrinsicTileSize = size(); if (hasRelativeWidth()) intrinsicTileSize.setWidth(scaledTileSize.width()); if (hasRelativeHeight()) intrinsicTileSize.setHeight(scaledTileSize.height()); FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(), scaledTileSize.height() / intrinsicTileSize.height()); FloatSize actualTileSize(scaledTileSize.width() + repeatSpacing.width(), scaledTileSize.height() + repeatSpacing.height()); FloatRect oneTileRect; oneTileRect.setX(destRect.x() + fmodf(fmodf(-srcPoint.x(), actualTileSize.width()) - actualTileSize.width(), actualTileSize.width())); oneTileRect.setY(destRect.y() + fmodf(fmodf(-srcPoint.y(), actualTileSize.height()) - actualTileSize.height(), actualTileSize.height())); oneTileRect.setSize(scaledTileSize); // Check and see if a single draw of the image can cover the entire area we are supposed to tile. if (oneTileRect.contains(destRect)) { FloatRect visibleSrcRect; visibleSrcRect.setX((destRect.x() - oneTileRect.x()) / scale.width()); visibleSrcRect.setY((destRect.y() - oneTileRect.y()) / scale.height()); visibleSrcRect.setWidth(destRect.width() / scale.width()); visibleSrcRect.setHeight(destRect.height() / scale.height()); draw(ctxt, destRect, visibleSrcRect, op, blendMode); return; } FloatRect tileRect(FloatPoint(), intrinsicTileSize); drawPattern(ctxt, tileRect, scale, oneTileRect.location(), op, destRect, blendMode, repeatSpacing); startAnimation(); }
void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, CompositeOperator op) { if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), op); return; } FloatSize intrinsicTileSize = size(); if (hasRelativeWidth()) intrinsicTileSize.setWidth(scaledTileSize.width()); if (hasRelativeHeight()) intrinsicTileSize.setHeight(scaledTileSize.height()); FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(), scaledTileSize.height() / intrinsicTileSize.height()); AffineTransform patternTransform = AffineTransform().scale(scale.width(), scale.height()); FloatRect oneTileRect; oneTileRect.setX(destRect.x() + fmodf(fmodf(-srcPoint.x(), scaledTileSize.width()) - scaledTileSize.width(), scaledTileSize.width())); oneTileRect.setY(destRect.y() + fmodf(fmodf(-srcPoint.y(), scaledTileSize.height()) - scaledTileSize.height(), scaledTileSize.height())); oneTileRect.setSize(scaledTileSize); // Check and see if a single draw of the image can cover the entire area we are supposed to tile. if (oneTileRect.contains(destRect)) { FloatRect visibleSrcRect; visibleSrcRect.setX((destRect.x() - oneTileRect.x()) / scale.width()); visibleSrcRect.setY((destRect.y() - oneTileRect.y()) / scale.height()); visibleSrcRect.setWidth(destRect.width() / scale.width()); visibleSrcRect.setHeight(destRect.height() / scale.height()); draw(ctxt, destRect, visibleSrcRect, op); return; } FloatRect tileRect(FloatPoint(), intrinsicTileSize); drawPatternCounter.startCounting(); drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), op, destRect); drawPatternCounter.stopCounting(); startAnimation(); }
// Drawing Routines void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { QRectF normalizedDst = dst.normalized(); QRectF normalizedSrc = src.normalized(); startAnimation(); if (normalizedSrc.isEmpty() || normalizedDst.isEmpty()) return; QPixmap* image = nativeImageForCurrentFrame(); if (!image) return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, normalizedDst, solidColor(), styleColorSpace, op); return; } CompositeOperator previousOperator = ctxt->compositeOperation(); ctxt->setCompositeOperation(!image->hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op); ContextShadow* shadow = ctxt->contextShadow(); if (shadow->m_type != ContextShadow::NoShadow) { QPainter* shadowPainter = shadow->beginShadowLayer(ctxt, normalizedDst); if (shadowPainter) { shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255); shadowPainter->drawPixmap(normalizedDst, *image, normalizedSrc); shadow->endShadowLayer(ctxt); } } ctxt->platformContext()->drawPixmap(normalizedDst, *image, normalizedSrc); ctxt->setCompositeOperation(previousOperator); if (imageObserver()) imageObserver()->didDraw(this); }
// Drawing Routines void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { if (!m_source.initialized()) return; // Spin the animation to the correct frame before we try to draw it, so we // don't draw an old frame and then immediately need to draw a newer one, // causing flicker and wasting CPU. startAnimation(); BBitmap* image = nativeImageForCurrentFrame(); if (!image || !image->IsValid()) // If the image hasn't fully loaded. return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, dst, solidColor(), styleColorSpace, op); return; } ctxt->save(); ctxt->setCompositeOperation(op); BRect srcRect(src); BRect dstRect(dst); // Test using example site at // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html ctxt->platformContext()->SetDrawingMode(B_OP_ALPHA); uint32 options = 0; if (ctxt->imageInterpolationQuality() == InterpolationDefault || ctxt->imageInterpolationQuality() > InterpolationLow) { options |= B_FILTER_BITMAP_BILINEAR; } ctxt->platformContext()->DrawBitmapAsync(image, srcRect, dstRect, options); ctxt->restore(); if (imageObserver()) imageObserver()->didDraw(this); }
void Image::drawPattern(GraphicsContext* context, const FloatRect& src, const AffineTransform& patternTransformation, const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& dst) { if (dst.isEmpty() || src.isEmpty()) return; NativeImagePtr image = nativeImageForCurrentFrame(); if (!image) return; startAnimation(); if (mayFillWithSolidColor()) { fillWithSolidColor(context, dst, solidColor(), styleColorSpace, op); return; } notImplemented(); if (imageObserver()) imageObserver()->didDraw(this); }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp, BlendMode blendMode, RespectImageOrientationEnum shouldRespectImageOrientation) { startAnimation(); CGImageRef image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, compositeOp); return; } FloatSize selfSize = currentFrameSize(); ImageOrientation orientation = DefaultImageOrientation; if (shouldRespectImageOrientation == RespectImageOrientation) orientation = frameOrientationAtIndex(m_currentFrame); ctxt->drawNativeImage(image, selfSize, styleColorSpace, destRect, srcRect, compositeOp, blendMode, orientation); if (imageObserver()) imageObserver()->didDraw(this); }
void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { if (dst.isEmpty() || src.isEmpty()) return; NativeImagePtr image = nativeImageForCurrentFrame(); if (!image) return; startAnimation(); if (mayFillWithSolidColor()) { fillWithSolidColor(context, dst, solidColor(), styleColorSpace, op); return; } context->save(); // Set the compositing operation. if (op == CompositeSourceOver && !frameHasAlphaAtIndex(m_currentFrame)) context->setCompositeOperation(CompositeCopy); else context->setCompositeOperation(op); #if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) FloatRect srcRectLocal = adjustSourceRectForDownSampling(src, image->size()); #else FloatRect srcRectLocal(src); #endif context->platformContext()->activePainter()->drawImage(image, dst, srcRectLocal); context->restore(); if (imageObserver()) imageObserver()->didDraw(this); }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, CompositeOperator op) { if (!m_source.initialized()) return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, dst, solidColor(), op); return; } #if USE(WXGC) wxGCDC* context = (wxGCDC*)ctxt->platformContext(); wxGraphicsContext* gc = context->GetGraphicsContext(); #else wxWindowDC* context = ctxt->platformContext(); #endif startAnimation(); wxBitmap* bitmap = frameAtIndex(m_currentFrame); if (!bitmap) // If it's too early we won't have an image yet. return; // If we're drawing a sub portion of the image or scaling then create // a pattern transformation on the image and draw the transformed pattern. // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html // FIXME: NYI ctxt->save(); // Set the compositing operation. ctxt->setCompositeOperation(op); #if USE(WXGC) float scaleX = src.width() / dst.width(); float scaleY = src.height() / dst.height(); FloatRect adjustedDestRect = dst; FloatSize selfSize = currentFrameSize(); if (src.size() != selfSize) { adjustedDestRect.setLocation(FloatPoint(dst.x() - src.x() / scaleX, dst.y() - src.y() / scaleY)); adjustedDestRect.setSize(FloatSize(selfSize.width() / scaleX, selfSize.height() / scaleY)); } // If the image is only partially loaded, then shrink the destination rect that we're drawing into accordingly. int currHeight = bitmap->GetHeight(); if (currHeight < selfSize.height()) adjustedDestRect.setHeight(adjustedDestRect.height() * currHeight / selfSize.height()); gc->DrawBitmap(*bitmap, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height()); #else IntRect srcIntRect(src); IntRect dstIntRect(dst); bool rescaling = false; if ((dstIntRect.width() != srcIntRect.width()) || (dstIntRect.height() != srcIntRect.height())) { rescaling = true; wxImage img = bitmap->ConvertToImage(); img.Rescale(dstIntRect.width(), dstIntRect.height()); bitmap = new wxBitmap(img); } wxMemoryDC mydc; ASSERT(bitmap->GetRefData()); mydc.SelectObject(*bitmap); context->Blit((wxCoord)dstIntRect.x(),(wxCoord)dstIntRect.y(), (wxCoord)dstIntRect.width(), (wxCoord)dstIntRect.height(), &mydc, (wxCoord)srcIntRect.x(), (wxCoord)srcIntRect.y(), wxCOPY, true); mydc.SelectObject(wxNullBitmap); // NB: delete is causing crashes during page load, but not during the deletion // itself. It occurs later on when a valid bitmap created in frameAtIndex // suddenly becomes invalid after returning. It's possible these errors deal // with reentrancy and threding problems. //delete bitmap; if (rescaling) { delete bitmap; bitmap = NULL; } #endif ctxt->restore(); }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp) { startAnimation(); RetainPtr<CGImageRef> image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, compositeOp); return; } float currHeight = CGImageGetHeight(image.get()); if (currHeight <= srcRect.y()) return; CGContextRef context = ctxt->platformContext(); ctxt->save(); bool shouldUseSubimage = false; // If the source rect is a subportion of the image, then we compute an inflated destination rect that will hold the entire image // and then set a clip to the portion that we want to display. FloatRect adjustedDestRect = destRect; FloatSize selfSize = currentFrameSize(); if (srcRect.size() != selfSize) { CGInterpolationQuality interpolationQuality = CGContextGetInterpolationQuality(context); // When the image is scaled using high-quality interpolation, we create a temporary CGImage // containing only the portion we want to display. We need to do this because high-quality // interpolation smoothes sharp edges, causing pixels from outside the source rect to bleed // into the destination rect. See <rdar://problem/6112909>. shouldUseSubimage = (interpolationQuality == kCGInterpolationHigh || interpolationQuality == kCGInterpolationDefault) && (srcRect.size() != destRect.size() || !ctxt->getCTM().isIdentityOrTranslationOrFlipped()); float xScale = srcRect.width() / destRect.width(); float yScale = srcRect.height() / destRect.height(); if (shouldUseSubimage) { FloatRect subimageRect = srcRect; float leftPadding = srcRect.x() - floorf(srcRect.x()); float topPadding = srcRect.y() - floorf(srcRect.y()); subimageRect.move(-leftPadding, -topPadding); adjustedDestRect.move(-leftPadding / xScale, -topPadding / yScale); subimageRect.setWidth(ceilf(subimageRect.width() + leftPadding)); adjustedDestRect.setWidth(subimageRect.width() / xScale); subimageRect.setHeight(ceilf(subimageRect.height() + topPadding)); adjustedDestRect.setHeight(subimageRect.height() / yScale); image.adoptCF(CGImageCreateWithImageInRect(image.get(), subimageRect)); if (currHeight < srcRect.bottom()) { ASSERT(CGImageGetHeight(image.get()) == currHeight - CGRectIntegral(srcRect).origin.y); adjustedDestRect.setHeight(CGImageGetHeight(image.get()) / yScale); } } else { adjustedDestRect.setLocation(FloatPoint(destRect.x() - srcRect.x() / xScale, destRect.y() - srcRect.y() / yScale)); adjustedDestRect.setSize(FloatSize(selfSize.width() / xScale, selfSize.height() / yScale)); } CGContextClipToRect(context, destRect); } // If the image is only partially loaded, then shrink the destination rect that we're drawing into accordingly. if (!shouldUseSubimage && currHeight < selfSize.height()) adjustedDestRect.setHeight(adjustedDestRect.height() * currHeight / selfSize.height()); ctxt->setCompositeOperation(compositeOp); // Flip the coords. CGContextScaleCTM(context, 1, -1); adjustedDestRect.setY(-adjustedDestRect.bottom()); // Adjust the color space. image = imageWithColorSpace(image.get(), styleColorSpace); // Draw the image. CGContextDrawImage(context, adjustedDestRect, image.get()); ctxt->restore(); if (imageObserver()) imageObserver()->didDraw(this); }
void BitmapImage::readyWRATHWidgets(PaintedWidgetsOfWRATHHandleT<Image>& handle, ContextOfWRATH *ctx, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { BitmapImage_readyWRATHWidgets *d(BitmapImage_readyWRATHWidgets::object(this, handle)); ContextOfWRATH::AutoPushNode autoPushRoot(ctx, d->m_root_node); d->m_solid_color.visible(false); if (d->m_image_rect_item.widget()) d->m_image_rect_item.widget()->visible(false); FloatRect normalizedDst = dst.normalized(); FloatRect normalizedSrc = src.normalized(); startAnimation(); if (normalizedSrc.isEmpty() || normalizedDst.isEmpty()) return; NativeImagePtr nativeImage = nativeImageForCurrentFrame(); if (!nativeImage) return; // "Hardcode" the requirement for the underlying wrath image type to WRATHImage. // The reason is support for setting texture coordinates, which isn't possible for WRATHCompoundImage WRATHImage* image = nativeImage->getWrathImage(); if (!image) return; if (mayFillWithSolidColor()) { d->m_solid_color.visible(true); readyWRATHWidgetSolidColor(d->m_solid_color, ctx, this, normalizedDst, solidColor(), styleColorSpace, op); return; } // ImageRectOfWRATH methods handle changing the op with respect to composite operator /* CompositeOperator previousOperator = ctxt->compositeOperation(); ctxt->setCompositeOperation(!image->hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op); */ if(!nativeImage->hasAlpha() && op == CompositeSourceOver) { op=CompositeCopy; } /* [WRATH-DANGER]: No shadows ContextShadow* shadow = ctxt->contextShadow(); if (shadow->m_type != ContextShadow::NoShadow) { QPainter* shadowPainter = shadow->beginShadowLayer(ctxt, normalizedDst); if (shadowPainter) { shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255); shadowPainter->drawPixmap(normalizedDst, *image, normalizedSrc); shadow->endShadowLayer(ctxt); } } */ /* [WRATH-DANGER]: Possible rounding errors from converting to IntRect */ d->m_image_rect_item.update(ctx, nativeImage, normalizedDst, IntRect(normalizedSrc), op); if (d->m_image_rect_item.widget()) d->m_image_rect_item.widget()->visible(true); /* ctxt->platformContext()->drawPixmap(normalizedDst, *image, normalizedSrc); */ /* ctxt->setCompositeOperation(previousOperator); */ if (imageObserver()) imageObserver()->didDraw(this); }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { if (!m_source.initialized()) return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, dst, solidColor(), styleColorSpace, op); return; } #if USE(WXGC) wxGCDC* context = (wxGCDC*)ctxt->platformContext(); wxGraphicsContext* gc = context->GetGraphicsContext(); wxGraphicsBitmap* bitmap = frameAtIndex(m_currentFrame); #else wxDC* context = ctxt->platformContext(); wxBitmap* bitmap = frameAtIndex(m_currentFrame); #endif startAnimation(); if (!bitmap) // If it's too early we won't have an image yet. return; // If we're drawing a sub portion of the image or scaling then create // a pattern transformation on the image and draw the transformed pattern. // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html // FIXME: NYI ctxt->save(); // Set the compositing operation. ctxt->setCompositeOperation(op); #if USE(WXGC) float scaleX = src.width() / dst.width(); float scaleY = src.height() / dst.height(); FloatRect adjustedDestRect = dst; FloatSize selfSize = currentFrameSize(); if (src.size() != selfSize) { adjustedDestRect.setLocation(FloatPoint(dst.x() - src.x() / scaleX, dst.y() - src.y() / scaleY)); adjustedDestRect.setSize(FloatSize(selfSize.width() / scaleX, selfSize.height() / scaleY)); } gc->Clip(dst.x(), dst.y(), dst.width(), dst.height()); #if wxCHECK_VERSION(2,9,0) gc->DrawBitmap(*bitmap, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height()); #else gc->DrawGraphicsBitmap(*bitmap, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height()); #endif #else // USE(WXGC) bitmap = getCachedResizedBitmap(bitmap, dst.size(), src); context->DrawBitmap(*bitmap, dst.x(), dst.y(), true); #endif ctxt->restore(); if (ImageObserver* observer = imageObserver()) observer->didDraw(this); }
void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { FloatRect srcRect(src); FloatRect dstRect(dst); if (dstRect.width() == 0.0f || dstRect.height() == 0.0f || srcRect.width() == 0.0f || srcRect.height() == 0.0f) return; startAnimation(); cairo_surface_t* image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(context, dstRect, solidColor(), styleColorSpace, op); return; } IntSize selfSize = size(); cairo_t* cr = context->platformContext(); context->save(); // Set the compositing operation. if (op == CompositeSourceOver && !frameHasAlphaAtIndex(m_currentFrame)) context->setCompositeOperation(CompositeCopy); else context->setCompositeOperation(op); // If we're drawing a sub portion of the image or scaling then create // a pattern transformation on the image and draw the transformed pattern. // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD); float scaleX = srcRect.width() / dstRect.width(); float scaleY = srcRect.height() / dstRect.height(); cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, srcRect.x(), srcRect.y() }; cairo_pattern_set_matrix(pattern, &matrix); // Draw the shadow #if ENABLE(FILTERS) FloatSize shadowOffset; float shadowBlur; Color shadowColor; if (context->getShadow(shadowOffset, shadowBlur, shadowColor)) { IntSize shadowBufferSize; FloatRect shadowRect; float radius = 0; context->calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, dstRect, shadowOffset, shadowBlur); shadowColor = colorWithOverrideAlpha(shadowColor.rgb(), (shadowColor.alpha() * context->getAlpha()) / 255.f); //draw shadow into a new ImageBuffer OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); cairo_t* shadowContext = shadowBuffer->context()->platformContext(); cairo_set_source(shadowContext, pattern); cairo_translate(shadowContext, -dstRect.x(), -dstRect.y()); cairo_rectangle(shadowContext, 0, 0, dstRect.width(), dstRect.height()); cairo_fill(shadowContext); context->applyPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius); } #endif // Draw the image. cairo_translate(cr, dstRect.x(), dstRect.y()); cairo_set_source(cr, pattern); cairo_pattern_destroy(pattern); cairo_rectangle(cr, 0, 0, dstRect.width(), dstRect.height()); cairo_clip(cr); cairo_paint_with_alpha(cr, context->getAlpha()); context->restore(); if (imageObserver()) imageObserver()->didDraw(this); }