void BitmapImage::draw(GraphicsContext& context, const FloatRect& dst, const FloatRect& src, CompositeOperator op, BlendMode blendMode, ImageOrientationDescription description) { if (!dst.width() || !dst.height() || !src.width() || !src.height()) return; startAnimation(); auto surface = frameImageAtIndex(m_currentFrame); if (!surface) // If it's too early we won't have an image yet. return; Color color = singlePixelSolidColor(); if (color.isValid()) { fillWithSolidColor(context, dst, color, op); return; } context.save(); // Set the compositing operation. if (op == CompositeSourceOver && blendMode == BlendModeNormal && !frameHasAlphaAtIndex(m_currentFrame)) context.setCompositeOperation(CompositeCopy); else context.setCompositeOperation(op, blendMode); #if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) IntSize scaledSize = cairoSurfaceSize(surface.get()); FloatRect adjustedSrcRect = adjustSourceRectForDownSampling(src, scaledSize); #else FloatRect adjustedSrcRect(src); #endif ImageOrientation frameOrientation(description.imageOrientation()); if (description.respectImageOrientation() == RespectImageOrientation) frameOrientation = frameOrientationAtIndex(m_currentFrame); FloatRect dstRect = dst; if (frameOrientation != DefaultImageOrientation) { // ImageOrientation expects the origin to be at (0, 0). context.translate(dstRect.x(), dstRect.y()); dstRect.setLocation(FloatPoint()); context.concatCTM(frameOrientation.transformFromDefault(dstRect.size())); if (frameOrientation.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(surface.get(), dstRect, adjustedSrcRect, context); context.restore(); if (imageObserver()) imageObserver()->didDraw(this); }
CGImageRef BitmapImage::getFirstCGImageRefOfSize(const IntSize& size) { size_t count = frameCount(); for (size_t i = 0; i < count; ++i) { CGImageRef cgImage = frameImageAtIndex(i).get(); if (cgImage && IntSize(CGImageGetWidth(cgImage), CGImageGetHeight(cgImage)) == size) return cgImage; } // Fallback to the default CGImageRef if we can't find the right size return getCGImageRef(); }
RetainPtr<CFArrayRef> BitmapImage::getCGImageArray() { size_t count = frameCount(); if (!count) return nullptr; CFMutableArrayRef array = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks); for (size_t i = 0; i < count; ++i) { if (CGImageRef currFrame = frameImageAtIndex(i).get()) CFArrayAppendValue(array, currFrame); } return adoptCF(array); }
void BitmapImage::draw(GraphicsContext& ctxt, const FloatRect& destRect, const FloatRect& srcRect, 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 = copyUnscaledFrameImageAtIndex(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 = frameImageAtIndex(m_currentFrame, subsamplingScale); } if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), 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, imageSize, destRect, scaledSrcRect, compositeOp, blendMode, orientation); if (imageObserver()) imageObserver()->didDraw(this); }
void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext& ctxt, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator compositeOp) { size_t frames = frameCount(); for (size_t i = 0; i < frames; ++i) { CGImageRef image = frameImageAtIndex(i).get(); if (image && CGImageGetHeight(image) == static_cast<size_t>(srcSize.height()) && CGImageGetWidth(image) == static_cast<size_t>(srcSize.width())) { size_t currentFrame = m_currentFrame; m_currentFrame = i; draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), compositeOp, BlendModeNormal, ImageOrientationDescription()); m_currentFrame = currentFrame; return; } } // No image of the correct size was found, fallback to drawing the current frame FloatSize imageSize = BitmapImage::size(); draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), compositeOp, BlendModeNormal, ImageOrientationDescription()); }
NativeImagePtr BitmapImage::nativeImageForCurrentFrame() { return frameImageAtIndex(currentFrame()); }
CGImageRef BitmapImage::getCGImageRef() { return frameImageAtIndex(0).get(); }