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/CairoUtilities.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/CairoUtilities.cpp')
-rw-r--r-- | Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp | 130 |
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) |