summaryrefslogtreecommitdiff
path: root/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp')
-rw-r--r--Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp370
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)