void BitmapImage::drawPattern(GraphicsContext& ctxt, const FloatRect& tileRect, const AffineTransform& transform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, const FloatRect& destRect, BlendMode blendMode) { if (tileRect.isEmpty()) return; if (!ctxt.drawLuminanceMask()) { Image::drawPattern(ctxt, tileRect, transform, phase, spacing, op, destRect, blendMode); return; } if (!m_cachedImage) { auto buffer = ImageBuffer::createCompatibleBuffer(expandedIntSize(tileRect.size()), ctxt); if (!buffer) return; ImageObserver* observer = imageObserver(); ASSERT(observer); // Temporarily reset image observer, we don't want to receive any changeInRect() calls due to this relayout. setImageObserver(nullptr); draw(buffer->context(), tileRect, tileRect, op, blendMode, ImageOrientationDescription()); setImageObserver(observer); buffer->convertToLuminanceMask(); m_cachedImage = buffer->copyImage(DontCopyBackingStore, Unscaled); if (!m_cachedImage) return; } ctxt.setDrawLuminanceMask(false); m_cachedImage->drawPattern(ctxt, tileRect, transform, phase, spacing, op, destRect, blendMode); }
void SVGImage::drawForContainer(GraphicsContext& context, const FloatSize containerSize, float zoom, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp, BlendMode blendMode) { if (!m_page) return; ImageObserver* observer = imageObserver(); ASSERT(observer); // Temporarily reset image observer, we don't want to receive any changeInRect() calls due to this relayout. setImageObserver(nullptr); IntSize roundedContainerSize = roundedIntSize(containerSize); setContainerSize(roundedContainerSize); FloatRect scaledSrc = srcRect; scaledSrc.scale(1 / zoom); // Compensate for the container size rounding by adjusting the source rect. FloatSize adjustedSrcSize = scaledSrc.size(); adjustedSrcSize.scale(roundedContainerSize.width() / containerSize.width(), roundedContainerSize.height() / containerSize.height()); scaledSrc.setSize(adjustedSrcSize); draw(context, dstRect, scaledSrc, compositeOp, blendMode, ImageOrientationDescription()); setImageObserver(observer); }
void BitmapImage::updateSize() const { if (!m_sizeAvailable || m_haveSize) return; m_size = m_source.size(); m_sizeRespectingOrientation = m_source.size(ImageOrientationDescription(RespectImageOrientation)); m_haveSize = true; didDecodeProperties(); }
// Passes ownership of the native image to the caller so NativeImagePtr needs // to be a smart pointer type. NativeImagePtr SVGImage::nativeImageForCurrentFrame() { if (!m_page) return nullptr; // Cairo does not use the accelerated drawing flag, so it's OK to make an unconditionally unaccelerated buffer. std::unique_ptr<ImageBuffer> buffer = ImageBuffer::create(size(), Unaccelerated); if (!buffer) // failed to allocate image return nullptr; draw(buffer->context(), rect(), rect(), CompositeSourceOver, BlendModeNormal, ImageOrientationDescription()); // FIXME: WK(Bug 113657): We should use DontCopyBackingStore here. return buffer->copyImage(CopyBackingStore)->nativeImageForCurrentFrame(); }
DragImageRef DataTransfer::createDragImage(IntPoint& location) const { location = m_dragLocation; if (m_dragImage) return createDragImageFromImage(m_dragImage->image(), ImageOrientationDescription()); if (m_dragImageElement) { if (Frame* frame = m_dragImageElement->document().frame()) return createDragImageForNode(*frame, *m_dragImageElement); } // We do not have enough information to create a drag image, use the default icon. return nullptr; }
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(); }
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 MediaPlayerPrivateGStreamerBase::paint(GraphicsContext* context, const IntRect& rect) { #if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER_GL) && !USE(COORDINATED_GRAPHICS) if (client()) return; #endif if (context->paintingDisabled()) return; if (!m_player->visible()) return; g_mutex_lock(m_bufferMutex); if (!m_buffer) { g_mutex_unlock(m_bufferMutex); return; } #ifdef GST_API_VERSION_1 GRefPtr<GstCaps> caps = currentVideoSinkCaps(); #else GRefPtr<GstCaps> caps = GST_BUFFER_CAPS(m_buffer); #endif if (!caps) { g_mutex_unlock(m_bufferMutex); return; } RefPtr<ImageGStreamer> gstImage = ImageGStreamer::createImage(m_buffer, caps.get()); if (!gstImage) { g_mutex_unlock(m_bufferMutex); return; } context->drawImage(reinterpret_cast<Image*>(gstImage->image().get()), ColorSpaceSRGB, rect, gstImage->rect(), CompositeCopy, ImageOrientationDescription(), false); g_mutex_unlock(m_bufferMutex); }
NativeImagePtr SVGImage::nativeImage(const GraphicsContext* targetContext) { ASSERT(targetContext); if (!m_page || !targetContext) return nullptr; auto platformContext = targetContext->platformContext(); ASSERT(platformContext); // Draw the SVG into a bitmap. COMPtr<ID2D1BitmapRenderTarget> nativeImageTarget; HRESULT hr = platformContext->CreateCompatibleRenderTarget(IntSize(rect().size()), &nativeImageTarget); ASSERT(SUCCEEDED(hr)); GraphicsContext localContext(nativeImageTarget.get()); draw(localContext, rect(), rect(), CompositeSourceOver, BlendModeNormal, ImageOrientationDescription()); COMPtr<ID2D1Bitmap> nativeImage; hr = nativeImageTarget->GetBitmap(&nativeImage); ASSERT(SUCCEEDED(hr)); return nativeImage; }
void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op, BlendMode blendMode) { draw(context, dst, src, styleColorSpace, op, blendMode, ImageOrientationDescription()); }
void BitmapTextureImageBuffer::updateContents(Image* image, const IntRect& targetRect, const IntPoint& offset, UpdateContentsFlag) { m_image->context()->drawImage(image, ColorSpaceDeviceRGB, targetRect, IntRect(offset, targetRect.size()), CompositeCopy, ImageOrientationDescription()); }
bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, const IntSize* size) { ASSERT(bmp); BITMAP bmpInfo; GetObject(bmp, sizeof(BITMAP), &bmpInfo); ASSERT(bmpInfo.bmBitsPixel == 32); int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight; CGContextRef cgContext = CGBitmapContextCreate(bmpInfo.bmBits, bmpInfo.bmWidth, bmpInfo.bmHeight, 8, bmpInfo.bmWidthBytes, deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); GraphicsContext gc(cgContext); FloatSize imageSize = BitmapImage::size(); if (size) drawFrameMatchingSourceSize(gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), *size, ColorSpaceDeviceRGB, CompositeCopy); else draw(gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), ColorSpaceDeviceRGB, CompositeCopy, BlendModeNormal, ImageOrientationDescription()); // Do cleanup CGContextRelease(cgContext); return true; }
// Passes ownership of the native image to the caller so PassNativeImagePtr needs // to be a smart pointer type. PassNativeImagePtr SVGImage::nativeImageForCurrentFrame() { if (!m_page) return 0; std::unique_ptr<ImageBuffer> buffer = ImageBuffer::create(size(), 1); if (!buffer) // failed to allocate image return 0; draw(buffer->context(), rect(), rect(), ColorSpaceDeviceRGB, CompositeSourceOver, BlendModeNormal, ImageOrientationDescription()); // FIXME: WK(Bug 113657): We should use DontCopyBackingStore here. return buffer->copyImage(CopyBackingStore)->nativeImageForCurrentFrame(); }
void Image::drawTiled(GraphicsContext& ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, const FloatSize& spacing, CompositeOperator op, BlendMode blendMode) { if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), op); return; } ASSERT(!isBitmapImage() || notSolidColor()); #if PLATFORM(IOS) FloatSize intrinsicTileSize = originalSize(); #else FloatSize intrinsicTileSize = size(); #endif 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() + spacing.width(), scaledTileSize.height() + spacing.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, op, blendMode, ImageOrientationDescription()); return; } #if PLATFORM(IOS) // When using accelerated drawing on iOS, it's faster to stretch an image than to tile it. if (ctxt.isAcceleratedContext()) { if (size().width() == 1 && intersection(oneTileRect, destRect).height() == destRect.height()) { FloatRect visibleSrcRect; visibleSrcRect.setX(0); visibleSrcRect.setY((destRect.y() - oneTileRect.y()) / scale.height()); visibleSrcRect.setWidth(1); visibleSrcRect.setHeight(destRect.height() / scale.height()); draw(ctxt, destRect, visibleSrcRect, op, BlendModeNormal, ImageOrientationDescription()); return; } if (size().height() == 1 && intersection(oneTileRect, destRect).width() == destRect.width()) { FloatRect visibleSrcRect; visibleSrcRect.setX((destRect.x() - oneTileRect.x()) / scale.width()); visibleSrcRect.setY(0); visibleSrcRect.setWidth(destRect.width() / scale.width()); visibleSrcRect.setHeight(1); draw(ctxt, destRect, visibleSrcRect, op, BlendModeNormal, ImageOrientationDescription()); return; } } #endif // Patterned images and gradients can use lots of memory for caching when the // tile size is large (<rdar://problem/4691859>, <rdar://problem/6239505>). // Memory consumption depends on the transformed tile size which can get // larger than the original tile if user zooms in enough. #if PLATFORM(IOS) const float maxPatternTilePixels = 512 * 512; #else const float maxPatternTilePixels = 2048 * 2048; #endif FloatRect transformedTileSize = ctxt.getCTM().mapRect(FloatRect(FloatPoint(), scaledTileSize)); float transformedTileSizePixels = transformedTileSize.width() * transformedTileSize.height(); FloatRect currentTileRect = oneTileRect; if (transformedTileSizePixels > maxPatternTilePixels) { GraphicsContextStateSaver stateSaver(ctxt); ctxt.clip(destRect); currentTileRect.shiftYEdgeTo(destRect.y()); float toY = currentTileRect.y(); while (toY < destRect.maxY()) { currentTileRect.shiftXEdgeTo(destRect.x()); float toX = currentTileRect.x(); while (toX < destRect.maxX()) { FloatRect toRect(toX, toY, currentTileRect.width(), currentTileRect.height()); FloatRect fromRect(toFloatPoint(currentTileRect.location() - oneTileRect.location()), currentTileRect.size()); fromRect.scale(1 / scale.width(), 1 / scale.height()); draw(ctxt, toRect, fromRect, op, BlendModeNormal, ImageOrientationDescription()); toX += currentTileRect.width(); currentTileRect.shiftXEdgeTo(oneTileRect.x()); } toY += currentTileRect.height(); currentTileRect.shiftYEdgeTo(oneTileRect.y()); } return; } AffineTransform patternTransform = AffineTransform().scaleNonUniform(scale.width(), scale.height()); FloatRect tileRect(FloatPoint(), intrinsicTileSize); drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), spacing, op, destRect, blendMode); #if PLATFORM(IOS) startAnimation(DoNotCatchUp); #else startAnimation(); #endif }
unsigned ImageSource::frameBytesAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const { IntSize frameSize = frameSizeAtIndex(index, subsamplingLevel, ImageOrientationDescription(RespectImageOrientation)); return frameSize.width() * frameSize.height() * 4; }
void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator compositeOp) { size_t frames = frameCount(); for (size_t i = 0; i < frames; ++i) { RefPtr<cairo_surface_t> surface = frameAtIndex(i); if (!surface) continue; if (cairo_image_surface_get_height(surface.get()) == static_cast<size_t>(srcSize.height()) && cairo_image_surface_get_width(surface.get()) == 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()), ColorSpaceDeviceRGB, compositeOp, BlendModeNormal, ImageOrientationDescription()); m_currentFrame = currentFrame; return; } } // No image of the correct size was found, fallback to drawing the current frame IntSize imageSize = BitmapImage::size(); draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), ColorSpaceDeviceRGB, compositeOp, BlendModeNormal, ImageOrientationDescription()); }
bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, const IntSize* size) { ASSERT(bmp); BITMAP bmpInfo; GetObject(bmp, sizeof(BITMAP), &bmpInfo); // If this is a 32bpp bitmap, which it always should be, we'll clear it so alpha-wise it will be visible if (bmpInfo.bmBitsPixel == 32 && bmpInfo.bmBits) { int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight; memset(bmpInfo.bmBits, 255, bufferSize); } unsigned char* bmpdata = (unsigned char*)bmpInfo.bmBits + bmpInfo.bmWidthBytes*(bmpInfo.bmHeight-1); cairo_surface_t* image = cairo_image_surface_create_for_data(bmpdata, CAIRO_FORMAT_ARGB32, bmpInfo.bmWidth, bmpInfo.bmHeight, -bmpInfo.bmWidthBytes); cairo_t* targetRef = cairo_create(image); cairo_surface_destroy(image); GraphicsContext gc(targetRef); IntSize imageSize = BitmapImage::size(); if (size) drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), *size, ColorSpaceDeviceRGB, CompositeCopy); else draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), ColorSpaceDeviceRGB, CompositeCopy, BlendModeNormal, ImageOrientationDescription()); // Do cleanup cairo_destroy(targetRef); return true; }
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) { auto image = frameImageAtIndex(i).get(); auto imageSize = image->GetSize(); if (image && clampTo<size_t>(imageSize.height) == static_cast<size_t>(srcSize.height()) && clampTo<size_t>(imageSize.width) == 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()); }