diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp')
-rw-r--r-- | Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp | 370 |
1 files changed, 298 insertions, 72 deletions
diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index 0d97204f4..041373a01 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -13,10 +13,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -29,6 +29,8 @@ #include "config.h" #include "ImageBuffer.h" +#if USE(CAIRO) + #include "BitmapImage.h" #include "CairoUtilities.h" #include "Color.h" @@ -39,82 +41,201 @@ #include "PlatformContextCairo.h" #include "RefPtrCairo.h" #include <cairo.h> +#include <runtime/JSCInlines.h> +#include <runtime/TypedArrayInlines.h> #include <wtf/Vector.h> #include <wtf/text/Base64.h> #include <wtf/text/WTFString.h> #if ENABLE(ACCELERATED_2D_CANVAS) #include "GLContext.h" -#include "OpenGLShims.h" #include "TextureMapperGL.h" #include <cairo-gl.h> + +#if USE(OPENGL_ES_2) +#include <GLES2/gl2.h> +#else +#include "OpenGLShims.h" +#endif + +#if USE(COORDINATED_GRAPHICS_THREADED) +#include "TextureMapperPlatformLayerBuffer.h" +#include "TextureMapperPlatformLayerProxy.h" +#endif #endif using namespace std; namespace WebCore { -ImageBufferData::ImageBufferData(const IntSize& size) +ImageBufferData::ImageBufferData(const IntSize& size, RenderingMode renderingMode) : m_platformContext(0) , m_size(size) + , m_renderingMode(renderingMode) #if ENABLE(ACCELERATED_2D_CANVAS) +#if USE(COORDINATED_GRAPHICS_THREADED) + , m_compositorTexture(0) +#endif , m_texture(0) #endif { +#if ENABLE(ACCELERATED_2D_CANVAS) && USE(COORDINATED_GRAPHICS_THREADED) + if (m_renderingMode == RenderingMode::Accelerated) + m_platformLayerProxy = adoptRef(new TextureMapperPlatformLayerProxy); +#endif +} + +ImageBufferData::~ImageBufferData() +{ + if (m_renderingMode != Accelerated) + return; + +#if ENABLE(ACCELERATED_2D_CANVAS) + GLContext* previousActiveContext = GLContext::current(); + PlatformDisplay::sharedDisplayForCompositing().sharingGLContext()->makeContextCurrent(); + + if (m_texture) + glDeleteTextures(1, &m_texture); + +#if USE(COORDINATED_GRAPHICS_THREADED) + if (m_compositorTexture) + glDeleteTextures(1, &m_compositorTexture); +#endif + + if (previousActiveContext) + previousActiveContext->makeContextCurrent(); +#endif } #if ENABLE(ACCELERATED_2D_CANVAS) -PassRefPtr<cairo_surface_t> createCairoGLSurface(const IntSize& size, uint32_t& texture) +#if USE(COORDINATED_GRAPHICS_THREADED) +void ImageBufferData::createCompositorBuffer() +{ + auto* context = PlatformDisplay::sharedDisplayForCompositing().sharingGLContext(); + context->makeContextCurrent(); + + glGenTextures(1, &m_compositorTexture); + glBindTexture(GL_TEXTURE_2D, m_compositorTexture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0 , GL_RGBA, m_size.width(), m_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + + m_compositorSurface = adoptRef(cairo_gl_surface_create_for_texture(context->cairoDevice(), CAIRO_CONTENT_COLOR_ALPHA, m_compositorTexture, m_size.width(), m_size.height())); + m_compositorCr = adoptRef(cairo_create(m_compositorSurface.get())); + cairo_set_antialias(m_compositorCr.get(), CAIRO_ANTIALIAS_NONE); +} + +void ImageBufferData::swapBuffersIfNeeded() +{ + GLContext* previousActiveContext = GLContext::current(); + + if (!m_compositorTexture) { + createCompositorBuffer(); + LockHolder holder(m_platformLayerProxy->lock()); + m_platformLayerProxy->pushNextBuffer(std::make_unique<TextureMapperPlatformLayerBuffer>(m_compositorTexture, m_size, TextureMapperGL::ShouldBlend)); + } + + // It would be great if we could just swap the buffers here as we do with webgl, but that breaks the cases + // where one frame uses the content already rendered in the previous frame. So we just copy the content + // into the compositor buffer. + cairo_set_source_surface(m_compositorCr.get(), m_surface.get(), 0, 0); + cairo_set_operator(m_compositorCr.get(), CAIRO_OPERATOR_SOURCE); + cairo_paint(m_compositorCr.get()); + + if (previousActiveContext) + previousActiveContext->makeContextCurrent(); +} +#endif + +void clearSurface(cairo_surface_t* surface) +{ + if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) + return; + + RefPtr<cairo_t> cr = adoptRef(cairo_create(surface)); + cairo_set_operator(cr.get(), CAIRO_OPERATOR_CLEAR); + cairo_paint(cr.get()); +} + +void ImageBufferData::createCairoGLSurface() { - GLContext::sharingContext()->makeContextCurrent(); + auto* context = PlatformDisplay::sharedDisplayForCompositing().sharingGLContext(); + context->makeContextCurrent(); // We must generate the texture ourselves, because there is no Cairo API for extracting it // from a pre-existing surface. - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glGenTextures(1, &m_texture); + glBindTexture(GL_TEXTURE_2D, m_texture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0 /* level */, GL_RGBA8, size.width(), size.height(), 0 /* border */, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 0 /* level */, GL_RGBA, m_size.width(), m_size.height(), 0 /* border */, GL_RGBA, GL_UNSIGNED_BYTE, 0); - GLContext* context = GLContext::sharingContext(); cairo_device_t* device = context->cairoDevice(); // Thread-awareness is a huge performance hit on non-Intel drivers. cairo_gl_device_set_thread_aware(device, FALSE); - return adoptRef(cairo_gl_surface_create_for_texture(device, CAIRO_CONTENT_COLOR_ALPHA, texture, size.width(), size.height())); + m_surface = adoptRef(cairo_gl_surface_create_for_texture(device, CAIRO_CONTENT_COLOR_ALPHA, m_texture, m_size.width(), m_size.height())); + clearSurface(m_surface.get()); } #endif -ImageBuffer::ImageBuffer(const IntSize& size, float /* resolutionScale */, ColorSpace, RenderingMode renderingMode, bool& success) - : m_data(size) - , m_size(size) +ImageBuffer::ImageBuffer(const FloatSize& size, float resolutionScale, ColorSpace, RenderingMode renderingMode, bool& success) + : m_data(IntSize(size), renderingMode) , m_logicalSize(size) + , m_resolutionScale(resolutionScale) { success = false; // Make early return mean error. + + float scaledWidth = ceilf(m_resolutionScale * size.width()); + float scaledHeight = ceilf(m_resolutionScale * size.height()); + + // FIXME: Should we automatically use a lower resolution? + if (!FloatSize(scaledWidth, scaledHeight).isExpressibleAsIntSize()) + return; + + m_size = IntSize(scaledWidth, scaledHeight); + m_data.m_size = m_size; + if (m_size.isEmpty()) return; #if ENABLE(ACCELERATED_2D_CANVAS) - if (renderingMode == Accelerated) - m_data.m_surface = createCairoGLSurface(size, m_data.m_texture); - else + if (m_data.m_renderingMode == Accelerated) { + m_data.createCairoGLSurface(); + if (!m_data.m_surface || cairo_surface_status(m_data.m_surface.get()) != CAIRO_STATUS_SUCCESS) + m_data.m_renderingMode = Unaccelerated; // If allocation fails, fall back to non-accelerated path. + } + if (m_data.m_renderingMode == Unaccelerated) #else - ASSERT_UNUSED(renderingMode, renderingMode != Accelerated); + ASSERT(m_data.m_renderingMode != Accelerated); #endif - m_data.m_surface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size.width(), size.height())); + { + static cairo_user_data_key_t s_surfaceDataKey; + + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, m_size.width()); + auto* surfaceData = fastZeroedMalloc(m_size.height() * stride); + + m_data.m_surface = adoptRef(cairo_image_surface_create_for_data(static_cast<unsigned char*>(surfaceData), CAIRO_FORMAT_ARGB32, m_size.width(), m_size.height(), stride)); + cairo_surface_set_user_data(m_data.m_surface.get(), &s_surfaceDataKey, surfaceData, [](void* data) { fastFree(data); }); + } if (cairo_surface_status(m_data.m_surface.get()) != CAIRO_STATUS_SUCCESS) return; // create will notice we didn't set m_initialized and fail. + cairoSurfaceSetDeviceScale(m_data.m_surface.get(), m_resolutionScale, m_resolutionScale); + RefPtr<cairo_t> cr = adoptRef(cairo_create(m_data.m_surface.get())); m_data.m_platformContext.setCr(cr.get()); - m_context = adoptPtr(new GraphicsContext(&m_data.m_platformContext)); + m_data.m_context = std::make_unique<GraphicsContext>(&m_data.m_platformContext); success = true; } @@ -122,18 +243,29 @@ ImageBuffer::~ImageBuffer() { } -GraphicsContext* ImageBuffer::context() const +std::unique_ptr<ImageBuffer> ImageBuffer::createCompatibleBuffer(const FloatSize& size, const GraphicsContext& context) +{ + return createCompatibleBuffer(size, ColorSpaceSRGB, context); +} + +GraphicsContext& ImageBuffer::context() const +{ + return *m_data.m_context; +} + +RefPtr<Image> ImageBuffer::sinkIntoImage(std::unique_ptr<ImageBuffer> imageBuffer, ScaleBehavior scaleBehavior) { - return m_context.get(); + return imageBuffer->copyImage(DontCopyBackingStore, scaleBehavior); } -PassRefPtr<Image> ImageBuffer::copyImage(BackingStoreCopy copyBehavior, ScaleBehavior) const +RefPtr<Image> ImageBuffer::copyImage(BackingStoreCopy copyBehavior, ScaleBehavior) const { + // copyCairoImageSurface inherits surface's device scale factor. if (copyBehavior == CopyBackingStore) return BitmapImage::create(copyCairoImageSurface(m_data.m_surface.get())); // BitmapImage will release the passed in surface on destruction - return BitmapImage::create(m_data.m_surface); + return BitmapImage::create(RefPtr<cairo_surface_t>(m_data.m_surface)); } BackingStoreCopy ImageBuffer::fastCopyImageMode() @@ -141,24 +273,24 @@ BackingStoreCopy ImageBuffer::fastCopyImageMode() return DontCopyBackingStore; } -void ImageBuffer::clip(GraphicsContext* context, const FloatRect& maskRect) const +void ImageBuffer::drawConsuming(std::unique_ptr<ImageBuffer> imageBuffer, GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode) { - context->platformContext()->pushImageMask(m_data.m_surface.get(), maskRect); + imageBuffer->draw(destContext, destRect, srcRect, op, blendMode); } -void ImageBuffer::draw(GraphicsContext* destinationContext, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, - CompositeOperator op, BlendMode blendMode, bool useLowQualityScale) +void ImageBuffer::draw(GraphicsContext& destinationContext, const FloatRect& destRect, const FloatRect& srcRect, + CompositeOperator op, BlendMode blendMode) { - BackingStoreCopy copyMode = destinationContext == context() ? CopyBackingStore : DontCopyBackingStore; + BackingStoreCopy copyMode = &destinationContext == &context() ? CopyBackingStore : DontCopyBackingStore; RefPtr<Image> image = copyImage(copyMode); - destinationContext->drawImage(image.get(), styleColorSpace, destRect, srcRect, op, blendMode, ImageOrientationDescription(), useLowQualityScale); + destinationContext.drawImage(*image, destRect, srcRect, ImagePaintingOptions(op, blendMode, ImageOrientationDescription())); } -void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform, - const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, BlendMode) +void ImageBuffer::drawPattern(GraphicsContext& context, const FloatRect& destRect, const FloatRect& srcRect, const AffineTransform& patternTransform, + const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, BlendMode) { - RefPtr<Image> image = copyImage(DontCopyBackingStore); - image->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect); + if (RefPtr<Image> image = copyImage(DontCopyBackingStore)) + image->drawPattern(context, destRect, srcRect, patternTransform, phase, spacing, op); } void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) @@ -181,10 +313,10 @@ void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) *pixel = premultipliedARGBFromColor(pixelColor); } } - cairo_surface_mark_dirty_rectangle(m_data.m_surface.get(), 0, 0, m_size.width(), m_size.height()); + cairo_surface_mark_dirty_rectangle(m_data.m_surface.get(), 0, 0, m_logicalSize.width(), m_logicalSize.height()); } -PassRefPtr<cairo_surface_t> copySurfaceToImageAndAdjustRect(cairo_surface_t* surface, IntRect& rect) +RefPtr<cairo_surface_t> copySurfaceToImageAndAdjustRect(cairo_surface_t* surface, IntRect& rect) { cairo_surface_type_t surfaceType = cairo_surface_get_type(surface); @@ -199,9 +331,11 @@ PassRefPtr<cairo_surface_t> copySurfaceToImageAndAdjustRect(cairo_surface_t* sur } template <Multiply multiplied> -PassRefPtr<Uint8ClampedArray> getImageData(const IntRect& rect, const ImageBufferData& data, const IntSize& size) +RefPtr<Uint8ClampedArray> getImageData(const IntRect& rect, const IntRect& logicalRect, const ImageBufferData& data, const IntSize& size, const IntSize& logicalSize, float resolutionScale) { RefPtr<Uint8ClampedArray> result = Uint8ClampedArray::createUninitialized(rect.width() * rect.height() * 4); + if (!result) + return nullptr; if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > size.width() || (rect.y() + rect.height()) > size.height()) result->zeroFill(); @@ -228,13 +362,17 @@ PassRefPtr<Uint8ClampedArray> getImageData(const IntRect& rect, const ImageBuffe endy = size.height(); int numRows = endy - originy; + // The size of the derived surface is in BackingStoreCoordinateSystem. + // We need to set the device scale for the derived surface from this ImageBuffer. IntRect imageRect(originx, originy, numColumns, numRows); RefPtr<cairo_surface_t> imageSurface = copySurfaceToImageAndAdjustRect(data.m_surface.get(), imageRect); + cairoSurfaceSetDeviceScale(imageSurface.get(), resolutionScale, resolutionScale); originx = imageRect.x(); originy = imageRect.y(); if (imageSurface != data.m_surface.get()) { - IntRect area = intersection(rect, IntRect(0, 0, size.width(), size.height())); - copyRectFromOneSurfaceToAnother(data.m_surface.get(), imageSurface.get(), IntSize(-area.x(), -area.y()), IntRect(IntPoint(), area.size()), IntSize(), CAIRO_OPERATOR_SOURCE); + // This cairo surface operation is done in LogicalCoordinateSystem. + IntRect logicalArea = intersection(logicalRect, IntRect(0, 0, logicalSize.width(), logicalSize.height())); + copyRectFromOneSurfaceToAnother(data.m_surface.get(), imageSurface.get(), IntSize(-logicalArea.x(), -logicalArea.y()), IntRect(IntPoint(), logicalArea.size()), IntSize(), CAIRO_OPERATOR_SOURCE); } unsigned char* dataSrc = cairo_image_surface_get_data(imageSurface.get()); @@ -275,53 +413,91 @@ PassRefPtr<Uint8ClampedArray> getImageData(const IntRect& rect, const ImageBuffe return result.release(); } -PassRefPtr<Uint8ClampedArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect, CoordinateSystem) const +template<typename Unit> +inline Unit logicalUnit(const Unit& value, ImageBuffer::CoordinateSystem coordinateSystemOfValue, float resolutionScale) { - return getImageData<Unmultiplied>(rect, m_data, m_size); + if (coordinateSystemOfValue == ImageBuffer::LogicalCoordinateSystem || resolutionScale == 1.0) + return value; + Unit result(value); + result.scale(1.0 / resolutionScale); + return result; } -PassRefPtr<Uint8ClampedArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect, CoordinateSystem) const +template<typename Unit> +inline Unit backingStoreUnit(const Unit& value, ImageBuffer::CoordinateSystem coordinateSystemOfValue, float resolutionScale) { - return getImageData<Premultiplied>(rect, m_data, m_size); + if (coordinateSystemOfValue == ImageBuffer::BackingStoreCoordinateSystem || resolutionScale == 1.0) + return value; + Unit result(value); + result.scale(resolutionScale); + return result; } -void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, CoordinateSystem) +RefPtr<Uint8ClampedArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect, CoordinateSystem coordinateSystem) const { + IntRect logicalRect = logicalUnit(rect, coordinateSystem, m_resolutionScale); + IntRect backingStoreRect = backingStoreUnit(rect, coordinateSystem, m_resolutionScale); + return getImageData<Unmultiplied>(backingStoreRect, logicalRect, m_data, m_size, m_logicalSize, m_resolutionScale); +} - ASSERT(sourceRect.width() > 0); - ASSERT(sourceRect.height() > 0); +RefPtr<Uint8ClampedArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect, CoordinateSystem coordinateSystem) const +{ + IntRect logicalRect = logicalUnit(rect, coordinateSystem, m_resolutionScale); + IntRect backingStoreRect = backingStoreUnit(rect, coordinateSystem, m_resolutionScale); + return getImageData<Premultiplied>(backingStoreRect, logicalRect, m_data, m_size, m_logicalSize, m_resolutionScale); +} - int originx = sourceRect.x(); - int destx = destPoint.x() + sourceRect.x(); +void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, CoordinateSystem coordinateSystem) +{ + IntRect scaledSourceRect = backingStoreUnit(sourceRect, coordinateSystem, m_resolutionScale); + IntSize scaledSourceSize = backingStoreUnit(sourceSize, coordinateSystem, m_resolutionScale); + IntPoint scaledDestPoint = backingStoreUnit(destPoint, coordinateSystem, m_resolutionScale); + IntRect logicalSourceRect = logicalUnit(sourceRect, coordinateSystem, m_resolutionScale); + IntPoint logicalDestPoint = logicalUnit(destPoint, coordinateSystem, m_resolutionScale); + + ASSERT(scaledSourceRect.width() > 0); + ASSERT(scaledSourceRect.height() > 0); + + int originx = scaledSourceRect.x(); + int destx = scaledDestPoint.x() + scaledSourceRect.x(); + int logicalDestx = logicalDestPoint.x() + logicalSourceRect.x(); ASSERT(destx >= 0); ASSERT(destx < m_size.width()); ASSERT(originx >= 0); - ASSERT(originx <= sourceRect.maxX()); + ASSERT(originx <= scaledSourceRect.maxX()); - int endx = destPoint.x() + sourceRect.maxX(); + int endx = scaledDestPoint.x() + scaledSourceRect.maxX(); + int logicalEndx = logicalDestPoint.x() + logicalSourceRect.maxX(); ASSERT(endx <= m_size.width()); int numColumns = endx - destx; + int logicalNumColumns = logicalEndx - logicalDestx; - int originy = sourceRect.y(); - int desty = destPoint.y() + sourceRect.y(); + int originy = scaledSourceRect.y(); + int desty = scaledDestPoint.y() + scaledSourceRect.y(); + int logicalDesty = logicalDestPoint.y() + logicalSourceRect.y(); ASSERT(desty >= 0); ASSERT(desty < m_size.height()); ASSERT(originy >= 0); - ASSERT(originy <= sourceRect.maxY()); + ASSERT(originy <= scaledSourceRect.maxY()); - int endy = destPoint.y() + sourceRect.maxY(); + int endy = scaledDestPoint.y() + scaledSourceRect.maxY(); + int logicalEndy = logicalDestPoint.y() + logicalSourceRect.maxY(); ASSERT(endy <= m_size.height()); int numRows = endy - desty; + int logicalNumRows = logicalEndy - logicalDesty; + // The size of the derived surface is in BackingStoreCoordinateSystem. + // We need to set the device scale for the derived surface from this ImageBuffer. IntRect imageRect(destx, desty, numColumns, numRows); RefPtr<cairo_surface_t> imageSurface = copySurfaceToImageAndAdjustRect(m_data.m_surface.get(), imageRect); + cairoSurfaceSetDeviceScale(imageSurface.get(), m_resolutionScale, m_resolutionScale); destx = imageRect.x(); desty = imageRect.y(); unsigned char* pixelData = cairo_image_surface_get_data(imageSurface.get()); - unsigned srcBytesPerRow = 4 * sourceSize.width(); + unsigned srcBytesPerRow = 4 * scaledSourceSize.width(); int stride = cairo_image_surface_get_stride(imageSurface.get()); unsigned char* srcRows = source->data() + originy * srcBytesPerRow + originx * 4; @@ -351,10 +527,13 @@ void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, c srcRows += srcBytesPerRow; } - cairo_surface_mark_dirty_rectangle(imageSurface.get(), destx, desty, numColumns, numRows); + // This cairo surface operation is done in LogicalCoordinateSystem. + cairo_surface_mark_dirty_rectangle(imageSurface.get(), logicalDestx, logicalDesty, logicalNumColumns, logicalNumRows); - if (imageSurface != m_data.m_surface.get()) - copyRectFromOneSurfaceToAnother(imageSurface.get(), m_data.m_surface.get(), IntSize(), IntRect(0, 0, numColumns, numRows), IntSize(destPoint.x() + sourceRect.x(), destPoint.y() + sourceRect.y()), CAIRO_OPERATOR_SOURCE); + if (imageSurface != m_data.m_surface.get()) { + // This cairo surface operation is done in LogicalCoordinateSystem. + copyRectFromOneSurfaceToAnother(imageSurface.get(), m_data.m_surface.get(), IntSize(), IntRect(0, 0, logicalNumColumns, logicalNumRows), IntSize(logicalDestPoint.x() + logicalSourceRect.x(), logicalDestPoint.y() + logicalSourceRect.y()), CAIRO_OPERATOR_SOURCE); + } } #if !PLATFORM(GTK) @@ -372,11 +551,11 @@ static bool encodeImage(cairo_surface_t* image, const String& mimeType, Vector<c return cairo_surface_write_to_png_stream(image, writeFunction, output) == CAIRO_STATUS_SUCCESS; } -String ImageBuffer::toDataURL(const String& mimeType, const double*, CoordinateSystem) const +String ImageBuffer::toDataURL(const String& mimeType, std::optional<double> quality, CoordinateSystem) const { ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); - cairo_surface_t* image = cairo_get_target(context()->platformContext()->cr()); + cairo_surface_t* image = cairo_get_target(context().platformContext()->cr()); Vector<char> encodedImage; if (!image || !encodeImage(image, mimeType, &encodedImage)) @@ -389,26 +568,20 @@ String ImageBuffer::toDataURL(const String& mimeType, const double*, CoordinateS } #endif -#if ENABLE(ACCELERATED_2D_CANVAS) -void ImageBufferData::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity) +#if ENABLE(ACCELERATED_2D_CANVAS) && !USE(COORDINATED_GRAPHICS_THREADED) +void ImageBufferData::paintToTextureMapper(TextureMapper& textureMapper, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity) { - if (textureMapper->accelerationMode() != TextureMapper::OpenGLMode) { - notImplemented(); - return; - } - ASSERT(m_texture); // Cairo may change the active context, so we make sure to change it back after flushing. - GLContext* previousActiveContext = GLContext::getCurrent(); + GLContext* previousActiveContext = GLContext::current(); cairo_surface_flush(m_surface.get()); previousActiveContext->makeContextCurrent(); - static_cast<TextureMapperGL*>(textureMapper)->drawTexture(m_texture, TextureMapperGL::ShouldBlend, m_size, targetRect, matrix, opacity); + static_cast<TextureMapperGL&>(textureMapper).drawTexture(m_texture, TextureMapperGL::ShouldBlend, m_size, targetRect, matrix, opacity); } #endif -#if USE(ACCELERATED_COMPOSITING) PlatformLayer* ImageBuffer::platformLayer() const { #if ENABLE(ACCELERATED_2D_CANVAS) @@ -417,6 +590,59 @@ PlatformLayer* ImageBuffer::platformLayer() const #endif return 0; } + +bool ImageBuffer::copyToPlatformTexture(GraphicsContext3D&, GC3Denum target, Platform3DObject destinationTexture, GC3Denum internalformat, bool premultiplyAlpha, bool flipY) +{ +#if ENABLE(ACCELERATED_2D_CANVAS) + ASSERT_WITH_MESSAGE(m_resolutionScale == 1.0, "Since the HiDPI Canvas feature is removed, the resolution factor here is always 1."); + if (premultiplyAlpha || flipY) + return false; + + if (!m_data.m_texture) + return false; + + GC3Denum bindTextureTarget; + switch (target) { + case GL_TEXTURE_2D: + bindTextureTarget = GL_TEXTURE_2D; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + bindTextureTarget = GL_TEXTURE_CUBE_MAP; + break; + default: + return false; + } + + cairo_surface_flush(m_data.m_surface.get()); + + std::unique_ptr<GLContext> context = GLContext::createOffscreenContext(&PlatformDisplay::sharedDisplayForCompositing()); + context->makeContextCurrent(); + uint32_t fbo; + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_data.m_texture, 0); + glBindTexture(bindTextureTarget, destinationTexture); + glCopyTexImage2D(target, 0, internalformat, 0, 0, m_size.width(), m_size.height(), 0); + glBindTexture(bindTextureTarget, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glFlush(); + glDeleteFramebuffers(1, &fbo); + return true; +#else + UNUSED_PARAM(target); + UNUSED_PARAM(destinationTexture); + UNUSED_PARAM(internalformat); + UNUSED_PARAM(premultiplyAlpha); + UNUSED_PARAM(flipY); + return false; #endif +} } // namespace WebCore + +#endif // USE(CAIRO) |