void HTMLCanvasElement::paint(GraphicsContext* context, const LayoutRect& r, bool useLowQualityScale) { // Clear the dirty rect m_dirtyRect = FloatRect(); if (context->paintingDisabled()) return; if (m_context) { if (!paintsIntoCanvasBuffer() && !document().printing()) return; m_context->paintRenderingResultsToCanvas(); } if (hasCreatedImageBuffer()) { ImageBuffer* imageBuffer = buffer(); if (imageBuffer) { if (m_presentedImage) { ImageOrientationDescription orientationDescription; #if ENABLE(CSS_IMAGE_ORIENTATION) orientationDescription.setImageOrientationEnum(renderer()->style().imageOrientation()); #endif context->drawImage(m_presentedImage.get(), ColorSpaceDeviceRGB, pixelSnappedIntRect(r), ImagePaintingOptions(orientationDescription, useLowQualityScale)); } else context->drawImageBuffer(imageBuffer, ColorSpaceDeviceRGB, pixelSnappedIntRect(r), useLowQualityScale); } } #if ENABLE(WEBGL) if (is3D()) static_cast<WebGLRenderingContext*>(m_context.get())->markLayerComposited(); #endif }
void RenderSnapshottedPlugIn::paintSnapshot(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { Image* image = m_snapshotResource->image().get(); if (!image || image->isNull()) return; LayoutUnit cWidth = contentWidth(); LayoutUnit cHeight = contentHeight(); if (!cWidth || !cHeight) return; GraphicsContext* context = paintInfo.context; #if PLATFORM(MAC) if (style()->highlight() != nullAtom && !context->paintingDisabled()) paintCustomHighlight(toPoint(paintOffset - location()), style()->highlight(), true); #endif LayoutSize contentSize(cWidth, cHeight); LayoutPoint contentLocation = location() + paintOffset; contentLocation.move(borderLeft() + paddingLeft(), borderTop() + paddingTop()); LayoutRect rect(contentLocation, contentSize); IntRect alignedRect = pixelSnappedIntRect(rect); if (alignedRect.width() <= 0 || alignedRect.height() <= 0) return; bool useLowQualityScaling = shouldPaintAtLowQuality(context, image, image, alignedRect.size()); ImageOrientationDescription orientationDescription; #if ENABLE(CSS_IMAGE_ORIENTATION) orientationDescription.setImageOrientationEnum(style()->imageOrientation()); #endif context->drawImage(image, style()->colorSpace(), alignedRect, CompositeSourceOver, orientationDescription, useLowQualityScaling); }
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); }
IntSize ImageSource::frameSizeAtIndex(size_t index, ImageOrientationDescription description) const { RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata))); if (!properties) return IntSize(); int w = 0, h = 0; CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth); if (num) CFNumberGetValue(num, kCFNumberIntType, &w); num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight); if (num) CFNumberGetValue(num, kCFNumberIntType, &h); #if PLATFORM(IOS) if (!m_isProgressive) { CFDictionaryRef jfifProperties = static_cast<CFDictionaryRef>(CFDictionaryGetValue(properties.get(), kCGImagePropertyJFIFDictionary)); if (jfifProperties) { CFBooleanRef isProgCFBool = static_cast<CFBooleanRef>(CFDictionaryGetValue(jfifProperties, kCGImagePropertyJFIFIsProgressive)); if (isProgCFBool) m_isProgressive = CFBooleanGetValue(isProgCFBool); // Workaround for <rdar://problem/5184655> - Hang rendering very large progressive JPEG. Decoding progressive // images hangs for a very long time right now. Until this is fixed, don't sub-sample progressive images. This // will cause them to fail our large image check and they won't be decoded. // FIXME: Remove once underlying issue is fixed (<rdar://problem/5191418>) } } if ((m_baseSubsampling == 0) && !m_isProgressive) { IntSize subsampledSize(w, h); const int cMaximumImageSizeBeforeSubsampling = 5 * 1024 * 1024; while ((m_baseSubsampling < 3) && subsampledSize.width() * subsampledSize.height() > cMaximumImageSizeBeforeSubsampling) { // We know the size, but the actual image is very large and should be sub-sampled. // Increase the base subsampling and ask for the size again. If the image can be subsampled, the size will be // greatly reduced. 4x sub-sampling will make us support up to 320MP (5MP * 4^3) images, which should be plenty. // There's no callback from ImageIO when the size is available, so we do the check when we happen // to check the size and its non - zero. // Note: Some clients of this class don't call isSizeAvailable() so we can't rely on that. ++m_baseSubsampling; subsampledSize = frameSizeAtIndex(index, description.respectImageOrientation()); } w = subsampledSize.width(); h = subsampledSize.height(); } #endif if ((description.respectImageOrientation() == RespectImageOrientation) && orientationFromProperties(properties.get()).usesWidthAsHeight()) return IntSize(h, w); return IntSize(w, h); }
void BitmapImage::updateSize(ImageOrientationDescription description) const { if (!m_sizeAvailable || m_haveSize) return; m_size = m_source.size(description); m_sizeRespectingOrientation = m_source.size(ImageOrientationDescription(RespectImageOrientation, description.imageOrientation())); m_imageOrientation = static_cast<unsigned>(description.imageOrientation()); m_shouldRespectImageOrientation = static_cast<unsigned>(description.respectImageOrientation()); m_haveSize = true; determineMinimumSubsamplingLevel(); didDecodeProperties(); }
static DragImageRef createDragImageFromSnapshot(std::unique_ptr<ImageBuffer> snapshot, Node* node) { if (!snapshot) return nullptr; ImageOrientationDescription orientation; #if ENABLE(CSS_IMAGE_ORIENTATION) if (node) { RenderObject* renderer = node->renderer(); if (!renderer) return nullptr; orientation.setRespectImageOrientation(renderer->shouldRespectImageOrientation()); orientation.setImageOrientationEnum(renderer->style().imageOrientation()); } #else UNUSED_PARAM(node); #endif RefPtr<Image> image = snapshot->copyImage(ImageBuffer::fastCopyImageMode()); if (!image) return nullptr; return createDragImageFromImage(image.get(), orientation); }
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); }
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); }
IntSize ImageSource::frameSizeAtIndex(size_t index, SubsamplingLevel subsamplingLevel, ImageOrientationDescription description) const { RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions(subsamplingLevel).get())); if (!properties) return IntSize(); int width = 0; int height = 0; CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth); if (num) CFNumberGetValue(num, kCFNumberIntType, &width); num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight); if (num) CFNumberGetValue(num, kCFNumberIntType, &height); if ((description.respectImageOrientation() == RespectImageOrientation) && orientationFromProperties(properties.get()).usesWidthAsHeight()) return IntSize(height, width); return IntSize(width, height); }