summaryrefslogtreecommitdiff
path: root/Source/WebCore/platform/graphics/cairo/CairoUtilities.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/CairoUtilities.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp')
-rw-r--r--Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp130
1 files changed, 116 insertions, 14 deletions
diff --git a/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp b/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp
index 98207e4b2..8a3ff33d0 100644
--- a/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp
+++ b/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp
@@ -11,10 +11,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
@@ -27,16 +27,19 @@
#include "config.h"
#include "CairoUtilities.h"
+#if USE(CAIRO)
+
#include "AffineTransform.h"
#include "Color.h"
#include "FloatPoint.h"
#include "FloatRect.h"
#include "IntRect.h"
-#include "OwnPtrCairo.h"
#include "Path.h"
#include "PlatformPathCairo.h"
#include "RefPtrCairo.h"
+#include "Region.h"
#include <wtf/Assertions.h>
+#include <wtf/NeverDestroyed.h>
#include <wtf/Vector.h>
#if ENABLE(ACCELERATED_2D_CANVAS)
@@ -45,6 +48,14 @@
namespace WebCore {
+#if USE(FREETYPE) && !PLATFORM(GTK)
+const cairo_font_options_t* getDefaultCairoFontOptions()
+{
+ static NeverDestroyed<cairo_font_options_t*> options = cairo_font_options_create();
+ return options;
+}
+#endif
+
void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr)
{
cairo_set_antialias(dstCr, cairo_get_antialias(srcCr));
@@ -64,15 +75,20 @@ void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr)
void setSourceRGBAFromColor(cairo_t* context, const Color& color)
{
- float red, green, blue, alpha;
- color.getRGBA(red, green, blue, alpha);
- cairo_set_source_rgba(context, red, green, blue, alpha);
+ if (color.isExtended())
+ cairo_set_source_rgba(context, color.asExtended().red(), color.asExtended().green(), color.asExtended().blue(), color.asExtended().alpha());
+ else {
+ float red, green, blue, alpha;
+ color.getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(context, red, green, blue, alpha);
+ }
}
void appendPathToCairoContext(cairo_t* to, cairo_t* from)
{
- OwnPtr<cairo_path_t> cairoPath = adoptPtr(cairo_copy_path(from));
- cairo_append_path(to, cairoPath.get());
+ auto cairoPath = cairo_copy_path(from);
+ cairo_append_path(to, cairoPath);
+ cairo_path_destroy(cairoPath);
}
void setPathOnCairoContext(cairo_t* to, cairo_t* from)
@@ -101,7 +117,7 @@ void appendRegionToCairoContext(cairo_t* to, const cairo_region_t* region)
}
}
-cairo_operator_t toCairoOperator(CompositeOperator op)
+static cairo_operator_t toCairoCompositeOperator(CompositeOperator op)
{
switch (op) {
case CompositeClear:
@@ -136,11 +152,12 @@ cairo_operator_t toCairoOperator(CompositeOperator op)
return CAIRO_OPERATOR_SOURCE;
}
}
-cairo_operator_t toCairoOperator(BlendMode blendOp)
+
+cairo_operator_t toCairoOperator(CompositeOperator op, BlendMode blendOp)
{
switch (blendOp) {
case BlendModeNormal:
- return CAIRO_OPERATOR_OVER;
+ return toCairoCompositeOperator(op);
case BlendModeMultiply:
return CAIRO_OPERATOR_MULTIPLY;
case BlendModeScreen:
@@ -198,8 +215,46 @@ void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSiz
cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image);
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
+ // Due to a limitation in pixman, cairo cannot handle transformation matrices with values bigger than 32768. If the value is
+ // bigger, cairo is not able to paint anything, and this is the reason for the missing backgrounds reported in
+ // https://bugs.webkit.org/show_bug.cgi?id=154283.
+
+ // When drawing a pattern there are 2 matrices that can overflow this limitation, and they are the current transformation
+ // matrix (which translates user space coordinates to coordinates of the output device) and the pattern matrix (which translates
+ // user space coordinates to pattern coordinates). The overflow happens only in the translation components of the matrices.
+
+ // To avoid the problem in the transformation matrix what we do is remove the translation components of the transformation matrix
+ // and perform the translation by moving the destination rectangle instead. For this, we get its translation components (which are in
+ // device coordinates) and divide them by the scale factor to take them to user space coordinates. Then we move the transformation
+ // matrix by the opposite of that amount (which will zero the translation components of the transformation matrix), and move
+ // the destination rectangle by the same amount. We also need to apply the same translation to the pattern matrix, so we get the
+ // same pattern coordinates for the new destination rectangle.
+
+ cairo_matrix_t ctm;
+ cairo_get_matrix(cr, &ctm);
+ double dx = 0, dy = 0;
+ cairo_matrix_transform_point(&ctm, &dx, &dy);
+ double xScale = 1, yScale = 1;
+ cairo_matrix_transform_distance(&ctm, &xScale, &yScale);
+
+ dx = dx / xScale;
+ dy = dy / yScale;
+ cairo_translate(cr, -dx, -dy);
+ FloatRect adjustedDestRect(destRect);
+ adjustedDestRect.move(dx, dy);
+
+ // Regarding the pattern matrix, what we do is reduce the translation component of the matrix taking advantage of the fact that we
+ // are drawing a repeated pattern. This means that, assuming that (w, h) is the size of the pattern, samplig it at (x, y) is the same
+ // than sampling it at (x mod w, y mod h), so we transform the translation component of the pattern matrix in that way.
+
cairo_matrix_t patternMatrix = cairo_matrix_t(patternTransform);
- cairo_matrix_t phaseMatrix = {1, 0, 0, 1, phase.x() + tileRect.x() * patternTransform.a(), phase.y() + tileRect.y() * patternTransform.d()};
+ // dx and dy are added here as well to compensate the previous translation of the destination rectangle.
+ double phaseOffsetX = phase.x() + tileRect.x() * patternTransform.a() + dx;
+ double phaseOffsetY = phase.y() + tileRect.y() * patternTransform.d() + dy;
+ // this is where we perform the (x mod w, y mod h) metioned above, but with floats instead of integers.
+ phaseOffsetX -= std::trunc(phaseOffsetX / (tileRect.width() * patternTransform.a())) * tileRect.width() * patternTransform.a();
+ phaseOffsetY -= std::trunc(phaseOffsetY / (tileRect.height() * patternTransform.d())) * tileRect.height() * patternTransform.d();
+ cairo_matrix_t phaseMatrix = {1, 0, 0, 1, phaseOffsetX, phaseOffsetY};
cairo_matrix_t combined;
cairo_matrix_multiply(&combined, &patternMatrix, &phaseMatrix);
cairo_matrix_invert(&combined);
@@ -208,13 +263,13 @@ void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSiz
cairo_set_operator(cr, op);
cairo_set_source(cr, pattern);
cairo_pattern_destroy(pattern);
- cairo_rectangle(cr, destRect.x(), destRect.y(), destRect.width(), destRect.height());
+ cairo_rectangle(cr, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height());
cairo_fill(cr);
cairo_restore(cr);
}
-PassRefPtr<cairo_surface_t> copyCairoImageSurface(cairo_surface_t* originalSurface)
+RefPtr<cairo_surface_t> copyCairoImageSurface(cairo_surface_t* originalSurface)
{
// Cairo doesn't provide a way to copy a cairo_surface_t.
// See http://lists.cairographics.org/archives/cairo/2007-June/010877.html
@@ -260,6 +315,29 @@ IntSize cairoSurfaceSize(cairo_surface_t* surface)
}
}
+void flipImageSurfaceVertically(cairo_surface_t* surface)
+{
+ ASSERT(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE);
+
+ IntSize size = cairoSurfaceSize(surface);
+ ASSERT(!size.isEmpty());
+
+ int stride = cairo_image_surface_get_stride(surface);
+ int halfHeight = size.height() / 2;
+
+ uint8_t* source = static_cast<uint8_t*>(cairo_image_surface_get_data(surface));
+ std::unique_ptr<uint8_t[]> tmp = std::make_unique<uint8_t[]>(stride);
+
+ for (int i = 0; i < halfHeight; ++i) {
+ uint8_t* top = source + (i * stride);
+ uint8_t* bottom = source + ((size.height()-i-1) * stride);
+
+ memcpy(tmp.get(), top, stride);
+ memcpy(top, bottom, stride);
+ memcpy(bottom, tmp.get(), stride);
+ }
+}
+
void cairoSurfaceSetDeviceScale(cairo_surface_t* surface, double xScale, double yScale)
{
// This function was added pretty much simultaneous to when 1.13 was branched.
@@ -271,4 +349,28 @@ void cairoSurfaceSetDeviceScale(cairo_surface_t* surface, double xScale, double
ASSERT_UNUSED(yScale, 1 == yScale);
#endif
}
+
+void cairoSurfaceGetDeviceScale(cairo_surface_t* surface, double& xScale, double& yScale)
+{
+#if HAVE(CAIRO_SURFACE_SET_DEVICE_SCALE)
+ cairo_surface_get_device_scale(surface, &xScale, &yScale);
+#else
+ UNUSED_PARAM(surface);
+ xScale = 1;
+ yScale = 1;
+#endif
+}
+
+RefPtr<cairo_region_t> toCairoRegion(const Region& region)
+{
+ RefPtr<cairo_region_t> cairoRegion = adoptRef(cairo_region_create());
+ for (const auto& rect : region.rects()) {
+ cairo_rectangle_int_t cairoRect = rect;
+ cairo_region_union_rectangle(cairoRegion.get(), &cairoRect);
+ }
+ return cairoRegion;
+}
+
} // namespace WebCore
+
+#endif // USE(CAIRO)