summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics/cairo
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/platform/graphics/cairo
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/platform/graphics/cairo')
-rw-r--r--Source/WebCore/platform/graphics/cairo/CairoPath.h50
-rw-r--r--Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp158
-rw-r--r--Source/WebCore/platform/graphics/cairo/CairoUtilities.h51
-rw-r--r--Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp354
-rw-r--r--Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h99
-rw-r--r--Source/WebCore/platform/graphics/cairo/FloatRectCairo.cpp45
-rw-r--r--Source/WebCore/platform/graphics/cairo/FontCairo.cpp175
-rw-r--r--Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h54
-rw-r--r--Source/WebCore/platform/graphics/cairo/GradientCairo.cpp99
-rw-r--r--Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp1149
-rw-r--r--Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h113
-rw-r--r--Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp319
-rw-r--r--Source/WebCore/platform/graphics/cairo/ImageBufferData.h44
-rw-r--r--Source/WebCore/platform/graphics/cairo/ImageCairo.cpp208
-rw-r--r--Source/WebCore/platform/graphics/cairo/OwnPtrCairo.cpp52
-rw-r--r--Source/WebCore/platform/graphics/cairo/OwnPtrCairo.h43
-rw-r--r--Source/WebCore/platform/graphics/cairo/PathCairo.cpp342
-rw-r--r--Source/WebCore/platform/graphics/cairo/PatternCairo.cpp54
-rw-r--r--Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp106
-rw-r--r--Source/WebCore/platform/graphics/cairo/RefPtrCairo.h59
-rw-r--r--Source/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp66
-rw-r--r--Source/WebCore/platform/graphics/cairo/rgb24-hacks.txt32
-rw-r--r--Source/WebCore/platform/graphics/cairo/scale-removal.txt13
23 files changed, 3685 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/cairo/CairoPath.h b/Source/WebCore/platform/graphics/cairo/CairoPath.h
new file mode 100644
index 0000000..da7affb
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/CairoPath.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk>
+ Copyright (C) 2010 Igalia S.L.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CairoPath_h
+#define CairoPath_h
+
+#include <cairo.h>
+
+namespace WebCore {
+
+// This is necessary since cairo_path_fixed_t isn't exposed in Cairo's public API.
+class CairoPath {
+public:
+ CairoPath()
+ {
+ static cairo_surface_t* pathSurface = cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1);
+ m_cr = cairo_create(pathSurface);
+ }
+
+ ~CairoPath()
+ {
+ cairo_destroy(m_cr);
+ }
+
+ cairo_t* context() { return m_cr; }
+
+private:
+ cairo_t* m_cr;
+};
+
+} // namespace WebCore
+
+#endif // CairoPath_h
diff --git a/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp b/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp
new file mode 100644
index 0000000..013a4af
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * 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
+ * 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
+ * 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
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CairoUtilities.h"
+
+#include "AffineTransform.h"
+#include "CairoPath.h"
+#include "Color.h"
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "IntRect.h"
+#include "OwnPtrCairo.h"
+#include "Path.h"
+#include "RefPtrCairo.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr)
+{
+ cairo_set_antialias(dstCr, cairo_get_antialias(srcCr));
+
+ size_t dashCount = cairo_get_dash_count(srcCr);
+ Vector<double> dashes(dashCount);
+
+ double offset;
+ cairo_get_dash(srcCr, dashes.data(), &offset);
+ cairo_set_dash(dstCr, dashes.data(), dashCount, offset);
+ cairo_set_line_cap(dstCr, cairo_get_line_cap(srcCr));
+ cairo_set_line_join(dstCr, cairo_get_line_join(srcCr));
+ cairo_set_line_width(dstCr, cairo_get_line_width(srcCr));
+ cairo_set_miter_limit(dstCr, cairo_get_miter_limit(srcCr));
+ cairo_set_fill_rule(dstCr, cairo_get_fill_rule(srcCr));
+}
+
+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);
+}
+
+void appendPathToCairoContext(cairo_t* to, cairo_t* from)
+{
+ OwnPtr<cairo_path_t> cairoPath(cairo_copy_path(from));
+ cairo_append_path(to, cairoPath.get());
+}
+
+void setPathOnCairoContext(cairo_t* to, cairo_t* from)
+{
+ cairo_new_path(to);
+ appendPathToCairoContext(to, from);
+}
+
+void appendWebCorePathToCairoContext(cairo_t* context, const Path& path)
+{
+ appendPathToCairoContext(context, path.platformPath()->context());
+}
+
+cairo_operator_t toCairoOperator(CompositeOperator op)
+{
+ switch (op) {
+ case CompositeClear:
+ return CAIRO_OPERATOR_CLEAR;
+ case CompositeCopy:
+ return CAIRO_OPERATOR_SOURCE;
+ case CompositeSourceOver:
+ return CAIRO_OPERATOR_OVER;
+ case CompositeSourceIn:
+ return CAIRO_OPERATOR_IN;
+ case CompositeSourceOut:
+ return CAIRO_OPERATOR_OUT;
+ case CompositeSourceAtop:
+ return CAIRO_OPERATOR_ATOP;
+ case CompositeDestinationOver:
+ return CAIRO_OPERATOR_DEST_OVER;
+ case CompositeDestinationIn:
+ return CAIRO_OPERATOR_DEST_IN;
+ case CompositeDestinationOut:
+ return CAIRO_OPERATOR_DEST_OUT;
+ case CompositeDestinationAtop:
+ return CAIRO_OPERATOR_DEST_ATOP;
+ case CompositeXOR:
+ return CAIRO_OPERATOR_XOR;
+ case CompositePlusDarker:
+ return CAIRO_OPERATOR_SATURATE;
+ case CompositeHighlight:
+ // There is no Cairo equivalent for CompositeHighlight.
+ return CAIRO_OPERATOR_OVER;
+ case CompositePlusLighter:
+ return CAIRO_OPERATOR_ADD;
+ default:
+ return CAIRO_OPERATOR_SOURCE;
+ }
+}
+
+void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSize& imageSize, const FloatRect& tileRect,
+ const AffineTransform& patternTransform, const FloatPoint& phase, cairo_operator_t op, const FloatRect& destRect)
+{
+ // Avoid NaN
+ if (!isfinite(phase.x()) || !isfinite(phase.y()))
+ return;
+
+ cairo_save(cr);
+
+ RefPtr<cairo_surface_t> clippedImageSurface = 0;
+ if (tileRect.size() != imageSize) {
+ IntRect imageRect = enclosingIntRect(tileRect);
+ clippedImageSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, imageRect.width(), imageRect.height()));
+ RefPtr<cairo_t> clippedImageContext = adoptRef(cairo_create(clippedImageSurface.get()));
+ cairo_set_source_surface(clippedImageContext.get(), image, -tileRect.x(), -tileRect.y());
+ cairo_paint(clippedImageContext.get());
+ image = clippedImageSurface.get();
+ }
+
+ cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image);
+ cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
+
+ 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()};
+ cairo_matrix_t combined;
+ cairo_matrix_multiply(&combined, &patternMatrix, &phaseMatrix);
+ cairo_matrix_invert(&combined);
+ cairo_pattern_set_matrix(pattern, &combined);
+
+ 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_fill(cr);
+
+ cairo_restore(cr);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/cairo/CairoUtilities.h b/Source/WebCore/platform/graphics/cairo/CairoUtilities.h
new file mode 100644
index 0000000..d8fff8d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/CairoUtilities.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * 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
+ * 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
+ * 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
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CairoUtilities_h
+#define CairoUtilities_h
+
+#include <GraphicsTypes.h>
+#include <cairo.h>
+
+namespace WebCore {
+class AffineTransform;
+class Color;
+class FloatRect;
+class FloatPoint;
+class IntSize;
+class Path;
+
+void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr);
+void setSourceRGBAFromColor(cairo_t*, const Color&);
+void appendPathToCairoContext(cairo_t* to, cairo_t* from);
+void setPathOnCairoContext(cairo_t* to, cairo_t* from);
+void appendWebCorePathToCairoContext(cairo_t* context, const Path& path);
+cairo_operator_t toCairoOperator(CompositeOperator op);
+void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSize& imageSize, const FloatRect& tileRect,
+ const AffineTransform& patternTransform, const FloatPoint& phase, cairo_operator_t op, const FloatRect& destRect);
+
+} // namespace WebCore
+
+#endif // CairoUtilities_h
diff --git a/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp b/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp
new file mode 100644
index 0000000..b0588d6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2010 Sencha, Inc.
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * 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
+ * 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
+ * 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
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ContextShadow.h"
+
+#include "AffineTransform.h"
+#include "CairoUtilities.h"
+#include "GraphicsContext.h"
+#include "OwnPtrCairo.h"
+#include "Path.h"
+#include "Timer.h"
+#include <cairo.h>
+
+using WTF::max;
+
+namespace WebCore {
+
+static cairo_surface_t* scratchBuffer = 0;
+static void purgeScratchBuffer()
+{
+ cairo_surface_destroy(scratchBuffer);
+ scratchBuffer = 0;
+}
+
+// ContextShadow needs a scratch image as the buffer for the blur filter.
+// Instead of creating and destroying the buffer for every operation,
+// we create a buffer which will be automatically purged via a timer.
+class PurgeScratchBufferTimer : public TimerBase {
+private:
+ virtual void fired() { purgeScratchBuffer(); }
+};
+static PurgeScratchBufferTimer purgeScratchBufferTimer;
+static void scheduleScratchBufferPurge()
+{
+ if (purgeScratchBufferTimer.isActive())
+ purgeScratchBufferTimer.stop();
+ purgeScratchBufferTimer.startOneShot(2);
+}
+
+static cairo_surface_t* getScratchBuffer(const IntSize& size)
+{
+ int width = size.width();
+ int height = size.height();
+ int scratchWidth = scratchBuffer ? cairo_image_surface_get_width(scratchBuffer) : 0;
+ int scratchHeight = scratchBuffer ? cairo_image_surface_get_height(scratchBuffer) : 0;
+
+ // We do not need to recreate the buffer if the current buffer is large enough.
+ if (scratchBuffer && scratchWidth >= width && scratchHeight >= height)
+ return scratchBuffer;
+
+ purgeScratchBuffer();
+
+ // Round to the nearest 32 pixels so we do not grow the buffer for similar sized requests.
+ width = (1 + (width >> 5)) << 5;
+ height = (1 + (height >> 5)) << 5;
+ scratchBuffer = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+ return scratchBuffer;
+}
+
+PlatformContext ContextShadow::beginShadowLayer(GraphicsContext* context, const FloatRect& layerArea)
+{
+ adjustBlurDistance(context);
+
+ double x1, x2, y1, y2;
+ cairo_clip_extents(context->platformContext(), &x1, &y1, &x2, &y2);
+ IntRect layerRect = calculateLayerBoundingRect(context, layerArea, IntRect(x1, y1, x2 - x1, y2 - y1));
+
+ // Don't paint if we are totally outside the clip region.
+ if (layerRect.isEmpty())
+ return 0;
+
+ m_layerImage = getScratchBuffer(layerRect.size());
+ m_layerContext = cairo_create(m_layerImage);
+
+ // Always clear the surface first.
+ cairo_set_operator(m_layerContext, CAIRO_OPERATOR_CLEAR);
+ cairo_paint(m_layerContext);
+ cairo_set_operator(m_layerContext, CAIRO_OPERATOR_OVER);
+
+ cairo_translate(m_layerContext, m_layerContextTranslation.x(), m_layerContextTranslation.y());
+ return m_layerContext;
+}
+
+void ContextShadow::endShadowLayer(GraphicsContext* context)
+{
+ cairo_destroy(m_layerContext);
+ m_layerContext = 0;
+
+ if (m_type == BlurShadow) {
+ cairo_surface_flush(m_layerImage);
+ blurLayerImage(cairo_image_surface_get_data(m_layerImage),
+ IntSize(cairo_image_surface_get_width(m_layerImage), cairo_image_surface_get_height(m_layerImage)),
+ cairo_image_surface_get_stride(m_layerImage));
+ cairo_surface_mark_dirty(m_layerImage);
+ }
+
+ cairo_t* cr = context->platformContext();
+ cairo_save(cr);
+ setSourceRGBAFromColor(cr, m_color);
+ cairo_mask_surface(cr, m_layerImage, m_layerOrigin.x(), m_layerOrigin.y());
+ cairo_restore(cr);
+
+ // Schedule a purge of the scratch buffer. We do not need to destroy the surface.
+ scheduleScratchBufferPurge();
+}
+
+void ContextShadow::drawRectShadowWithoutTiling(GraphicsContext* context, const IntRect& shadowRect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius, float alpha)
+{
+ beginShadowLayer(context, shadowRect);
+
+ if (!m_layerContext)
+ return;
+
+ Path path;
+ path.addRoundedRect(shadowRect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
+
+ appendWebCorePathToCairoContext(m_layerContext, path);
+ cairo_set_source_rgba(m_layerContext, 0, 0, 0, alpha);
+ cairo_fill(m_layerContext);
+
+ endShadowLayer(context);
+}
+
+static inline FloatPoint getPhase(const FloatRect& dest, const FloatRect& tile)
+{
+ FloatPoint phase = dest.location();
+ phase.move(-tile.x(), -tile.y());
+
+ return phase;
+}
+
+/*
+ This function uses tiling to improve the performance of the shadow
+ drawing of rounded rectangles. The code basically does the following
+ steps:
+
+ 1. Calculate the size of the shadow template, a rectangle that
+ contains all the necessary tiles to draw the complete shadow.
+
+ 2. If that size is smaller than the real rectangle render the new
+ template rectangle and its shadow in a new surface, in other case
+ render the shadow of the real rectangle in the destination
+ surface.
+
+ 3. Calculate the sizes and positions of the tiles and their
+ destinations and use drawPattern to render the final shadow. The
+ code divides the rendering in 8 tiles:
+
+ 1 | 2 | 3
+ -----------
+ 4 | | 5
+ -----------
+ 6 | 7 | 8
+
+ The corners are directly copied from the template rectangle to the
+ real one and the side tiles are 1 pixel width, we use them as
+
+ tiles to cover the destination side. The corner tiles are bigger
+ than just the side of the rounded corner, we need to increase it
+ because the modifications caused by the corner over the blur
+ effect. We fill the central part with solid color to complete the
+ shadow.
+ */
+void ContextShadow::drawRectShadow(GraphicsContext* context, const IntRect& rect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius)
+{
+
+ float radiusTwice = m_blurDistance * 2;
+
+ // Find the space the corners need inside the rect for its shadows.
+ int internalShadowWidth = radiusTwice + max(topLeftRadius.width(), bottomLeftRadius.width()) +
+ max(topRightRadius.width(), bottomRightRadius.width());
+ int internalShadowHeight = radiusTwice + max(topLeftRadius.height(), topRightRadius.height()) +
+ max(bottomLeftRadius.height(), bottomRightRadius.height());
+
+ cairo_t* cr = context->platformContext();
+
+ // drawShadowedRect still does not work with rotations.
+ // https://bugs.webkit.org/show_bug.cgi?id=45042
+ if ((!context->getCTM().isIdentityOrTranslationOrFlipped()) || (internalShadowWidth > rect.width())
+ || (internalShadowHeight > rect.height()) || (m_type != BlurShadow)) {
+ drawRectShadowWithoutTiling(context, rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius, context->getAlpha());
+ return;
+ }
+
+ // Calculate size of the template shadow buffer.
+ IntSize shadowBufferSize = IntSize(rect.width() + radiusTwice, rect.height() + radiusTwice);
+
+ // Determine dimensions of shadow rect.
+ FloatRect shadowRect = FloatRect(rect.location(), shadowBufferSize);
+ shadowRect.move(- m_blurDistance, - m_blurDistance);
+
+ // Size of the tiling side.
+ int sideTileWidth = 1;
+
+ // The length of a side of the buffer is the enough space for four blur radii,
+ // the radii of the corners, and then 1 pixel to draw the side tiles.
+ IntSize shadowTemplateSize = IntSize(sideTileWidth + radiusTwice + internalShadowWidth,
+ sideTileWidth + radiusTwice + internalShadowHeight);
+
+ // Reduce the size of what we have to draw with the clip area.
+ double x1, x2, y1, y2;
+ cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
+ calculateLayerBoundingRect(context, shadowRect, IntRect(x1, y1, x2 - x1, y2 - y1));
+
+ if ((shadowTemplateSize.width() * shadowTemplateSize.height() > m_sourceRect.width() * m_sourceRect.height())) {
+ drawRectShadowWithoutTiling(context, rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius, context->getAlpha());
+ return;
+ }
+
+ shadowRect.move(m_offset.width(), m_offset.height());
+
+ m_layerImage = getScratchBuffer(shadowTemplateSize);
+
+ // Draw shadow into a new ImageBuffer.
+ m_layerContext = cairo_create(m_layerImage);
+
+ // Clear the surface first.
+ cairo_set_operator(m_layerContext, CAIRO_OPERATOR_CLEAR);
+ cairo_paint(m_layerContext);
+ cairo_set_operator(m_layerContext, CAIRO_OPERATOR_OVER);
+
+ // Draw the rectangle.
+ IntRect templateRect = IntRect(m_blurDistance, m_blurDistance, shadowTemplateSize.width() - radiusTwice, shadowTemplateSize.height() - radiusTwice);
+ Path path;
+ path.addRoundedRect(templateRect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
+ appendWebCorePathToCairoContext(m_layerContext, path);
+
+ cairo_set_source_rgba(m_layerContext, 0, 0, 0, context->getAlpha());
+ cairo_fill(m_layerContext);
+
+ // Blur the image.
+ cairo_surface_flush(m_layerImage);
+ blurLayerImage(cairo_image_surface_get_data(m_layerImage), shadowTemplateSize, cairo_image_surface_get_stride(m_layerImage));
+ cairo_surface_mark_dirty(m_layerImage);
+
+ // Mask the image with the shadow color.
+ cairo_set_operator(m_layerContext, CAIRO_OPERATOR_IN);
+ setSourceRGBAFromColor(m_layerContext, m_color);
+ cairo_paint(m_layerContext);
+
+ cairo_destroy(m_layerContext);
+ m_layerContext = 0;
+
+ // Fill the internal part of the shadow.
+ shadowRect.inflate(-radiusTwice);
+ if (!shadowRect.isEmpty()) {
+ cairo_save(cr);
+ path.clear();
+ path.addRoundedRect(shadowRect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
+ appendWebCorePathToCairoContext(cr, path);
+ setSourceRGBAFromColor(cr, m_color);
+ cairo_fill(cr);
+ cairo_restore(cr);
+ }
+ shadowRect.inflate(radiusTwice);
+
+ // Draw top side.
+ FloatRect tileRect = FloatRect(radiusTwice + topLeftRadius.width(), 0, sideTileWidth, radiusTwice);
+ FloatRect destRect = tileRect;
+ destRect.move(shadowRect.x(), shadowRect.y());
+ destRect.setWidth(shadowRect.width() - topLeftRadius.width() - topRightRadius.width() - m_blurDistance * 4);
+ FloatPoint phase = getPhase(destRect, tileRect);
+ AffineTransform patternTransform;
+ patternTransform.makeIdentity();
+ drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect);
+
+ // Draw the bottom side.
+ tileRect = FloatRect(radiusTwice + bottomLeftRadius.width(), shadowTemplateSize.height() - radiusTwice, sideTileWidth, radiusTwice);
+ destRect = tileRect;
+ destRect.move(shadowRect.x(), shadowRect.y() + radiusTwice + rect.height() - shadowTemplateSize.height());
+ destRect.setWidth(shadowRect.width() - bottomLeftRadius.width() - bottomRightRadius.width() - m_blurDistance * 4);
+ phase = getPhase(destRect, tileRect);
+ drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect);
+
+ // Draw the right side.
+ tileRect = FloatRect(shadowTemplateSize.width() - radiusTwice, radiusTwice + topRightRadius.height(), radiusTwice, sideTileWidth);
+ destRect = tileRect;
+ destRect.move(shadowRect.x() + radiusTwice + rect.width() - shadowTemplateSize.width(), shadowRect.y());
+ destRect.setHeight(shadowRect.height() - topRightRadius.height() - bottomRightRadius.height() - m_blurDistance * 4);
+ phase = getPhase(destRect, tileRect);
+ drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect);
+
+ // Draw the left side.
+ tileRect = FloatRect(0, radiusTwice + topLeftRadius.height(), radiusTwice, sideTileWidth);
+ destRect = tileRect;
+ destRect.move(shadowRect.x(), shadowRect.y());
+ destRect.setHeight(shadowRect.height() - topLeftRadius.height() - bottomLeftRadius.height() - m_blurDistance * 4);
+ phase = FloatPoint(destRect.x() - tileRect.x(), destRect.y() - tileRect.y());
+ drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect);
+
+ // Draw the top left corner.
+ tileRect = FloatRect(0, 0, radiusTwice + topLeftRadius.width(), radiusTwice + topLeftRadius.height());
+ destRect = tileRect;
+ destRect.move(shadowRect.x(), shadowRect.y());
+ phase = getPhase(destRect, tileRect);
+ drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect);
+
+ // Draw the top right corner.
+ tileRect = FloatRect(shadowTemplateSize.width() - radiusTwice - topRightRadius.width(), 0, radiusTwice + topRightRadius.width(),
+ radiusTwice + topRightRadius.height());
+ destRect = tileRect;
+ destRect.move(shadowRect.x() + rect.width() - shadowTemplateSize.width() + radiusTwice, shadowRect.y());
+ phase = getPhase(destRect, tileRect);
+ drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect);
+
+ // Draw the bottom right corner.
+ tileRect = FloatRect(shadowTemplateSize.width() - radiusTwice - bottomRightRadius.width(),
+ shadowTemplateSize.height() - radiusTwice - bottomRightRadius.height(),
+ radiusTwice + bottomRightRadius.width(), radiusTwice + bottomRightRadius.height());
+ destRect = tileRect;
+ destRect.move(shadowRect.x() + rect.width() - shadowTemplateSize.width() + radiusTwice,
+ shadowRect.y() + rect.height() - shadowTemplateSize.height() + radiusTwice);
+ phase = getPhase(destRect, tileRect);
+ drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect);
+
+ // Draw the bottom left corner.
+ tileRect = FloatRect(0, shadowTemplateSize.height() - radiusTwice - bottomLeftRadius.height(),
+ radiusTwice + bottomLeftRadius.width(), radiusTwice + bottomLeftRadius.height());
+ destRect = tileRect;
+ destRect.move(shadowRect.x(), shadowRect.y() + rect.height() - shadowTemplateSize.height() + radiusTwice);
+ phase = getPhase(destRect, tileRect);
+ drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect);
+
+ // Schedule a purge of the scratch buffer.
+ scheduleScratchBufferPurge();
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h b/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h
new file mode 100644
index 0000000..1e0a846
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2004 Red Hat, Inc.
+ * Copyright (C) 2010 Brent Fulgham <bfulgham@webkit.org>
+ *
+ * Based on Pango sources (see pangocairo-render.c)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#if PLATFORM(CAIRO)
+
+#include <cairo.h>
+
+//
+// Draws an error underline that looks like one of:
+//
+// H E H
+// /\ /\ /\ /\ /\ -
+// A/ \ / \ / \ A/ \ / \ |
+// \ \ / \ / /D \ \ / \ |
+// \ \/ C \/ / \ \/ C \ | height = heightSquares * square
+// \ /\ F / \ F /\ \ |
+// \ / \ / \ / \ \G |
+// \ / \ / \ / \ / |
+// \/ \/ \/ \/ -
+// B B
+// |---|
+// unitWidth = (heightSquares - 1) * square
+//
+// The x, y, width, height passed in give the desired bounding box;
+// x/width are adjusted to make the underline a integer number of units
+// wide.
+//
+static inline void drawErrorUnderline(cairo_t* cr, double x, double y, double width, double height)
+{
+ static const double heightSquares = 2.5;
+
+ double square = height / heightSquares;
+ double halfSquare = 0.5 * square;
+
+ double unitWidth = (heightSquares - 1.0) * square;
+ int widthUnits = static_cast<int>((width + 0.5 * unitWidth) / unitWidth);
+
+ x += 0.5 * (width - widthUnits * unitWidth);
+ width = widthUnits * unitWidth;
+
+ double bottom = y + height;
+ double top = y;
+
+ // Bottom of squiggle
+ cairo_move_to(cr, x - halfSquare, top + halfSquare); // A
+
+ int i = 0;
+ for (i = 0; i < widthUnits; i += 2) {
+ double middle = x + (i + 1) * unitWidth;
+ double right = x + (i + 2) * unitWidth;
+
+ cairo_line_to(cr, middle, bottom); // B
+
+ if (i + 2 == widthUnits)
+ cairo_line_to(cr, right + halfSquare, top + halfSquare); // D
+ else if (i + 1 != widthUnits)
+ cairo_line_to(cr, right, top + square); // C
+ }
+
+ // Top of squiggle
+ for (i -= 2; i >= 0; i -= 2) {
+ double left = x + i * unitWidth;
+ double middle = x + (i + 1) * unitWidth;
+ double right = x + (i + 2) * unitWidth;
+
+ if (i + 1 == widthUnits)
+ cairo_line_to(cr, middle + halfSquare, bottom - halfSquare); // G
+ else {
+ if (i + 2 == widthUnits)
+ cairo_line_to(cr, right, top); // E
+
+ cairo_line_to(cr, middle, bottom - halfSquare); // F
+ }
+
+ cairo_line_to(cr, left, top); // H
+ }
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/cairo/FloatRectCairo.cpp b/Source/WebCore/platform/graphics/cairo/FloatRectCairo.cpp
new file mode 100644
index 0000000..9f86f74
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/FloatRectCairo.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * 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
+ * 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
+ * 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
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FloatRect.h"
+
+#include <cairo.h>
+
+namespace WebCore {
+
+FloatRect::FloatRect(const cairo_rectangle_t& r)
+ : m_location(r.x, r.y)
+ , m_size(r.width, r.height)
+{
+}
+
+FloatRect::operator cairo_rectangle_t() const
+{
+ cairo_rectangle_t r = { x(), y(), width(), height() };
+ return r;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/cairo/FontCairo.cpp b/Source/WebCore/platform/graphics/cairo/FontCairo.cpp
new file mode 100644
index 0000000..2d79499
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/FontCairo.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2010 Holger Hans Peter Freyther
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * 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
+ * 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
+ * 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
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "AffineTransform.h"
+#include "CairoUtilities.h"
+#include "ContextShadow.h"
+#include "GlyphBuffer.h"
+#include "Gradient.h"
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+#include "Pattern.h"
+#include "SimpleFontData.h"
+
+namespace WebCore {
+
+static void prepareContextForGlyphDrawing(cairo_t* context, const SimpleFontData* font, const FloatPoint& point)
+{
+ static const float syntheticObliqueSkew = -tanf(14 * acosf(0) / 90);
+ cairo_set_scaled_font(context, font->platformData().scaledFont());
+ if (font->platformData().syntheticOblique()) {
+ cairo_matrix_t mat = {1, 0, syntheticObliqueSkew, 1, point.x(), point.y()};
+ cairo_transform(context, &mat);
+ } else
+ cairo_translate(context, point.x(), point.y());
+}
+
+static void drawGlyphsToContext(cairo_t* context, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs)
+{
+ cairo_show_glyphs(context, glyphs, numGlyphs);
+ if (font->syntheticBoldOffset()) {
+ // We could use cairo_save/cairo_restore here, but two translations are likely faster.
+ cairo_translate(context, font->syntheticBoldOffset(), 0);
+ cairo_show_glyphs(context, glyphs, numGlyphs);
+ cairo_translate(context, -font->syntheticBoldOffset(), 0);
+ }
+}
+
+static void drawGlyphsShadow(GraphicsContext* graphicsContext, cairo_t* context, const FloatPoint& point, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs)
+{
+ ContextShadow* shadow = graphicsContext->contextShadow();
+ ASSERT(shadow);
+
+ if (!(graphicsContext->textDrawingMode() & TextModeFill) || shadow->m_type == ContextShadow::NoShadow)
+ return;
+
+ if (!shadow->mustUseContextShadow(graphicsContext)) {
+ // Optimize non-blurry shadows, by just drawing text without the ContextShadow.
+ cairo_save(context);
+ cairo_translate(context, shadow->m_offset.width(), shadow->m_offset.height());
+ setSourceRGBAFromColor(context, shadow->m_color);
+ prepareContextForGlyphDrawing(context, font, point);
+ cairo_show_glyphs(context, glyphs, numGlyphs);
+ cairo_restore(context);
+ return;
+ }
+
+ cairo_text_extents_t extents;
+ cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents);
+ FloatRect fontExtentsRect(point.x(), point.y() - extents.height, extents.width, extents.height);
+ cairo_t* shadowContext = shadow->beginShadowLayer(graphicsContext, fontExtentsRect);
+ if (shadowContext) {
+ prepareContextForGlyphDrawing(shadowContext, font, point);
+ drawGlyphsToContext(shadowContext, font, glyphs, numGlyphs);
+ shadow->endShadowLayer(graphicsContext);
+ }
+}
+
+void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs, const FloatPoint& point) const
+{
+ GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from);
+
+ float offset = 0.0f;
+ for (int i = 0; i < numGlyphs; i++) {
+ glyphs[i].x = offset;
+ glyphs[i].y = 0.0f;
+ offset += glyphBuffer.advanceAt(from + i);
+ }
+
+ cairo_t* cr = context->platformContext();
+ drawGlyphsShadow(context, cr, point, font, glyphs, numGlyphs);
+
+ cairo_save(cr);
+ prepareContextForGlyphDrawing(cr, font, point);
+ if (context->textDrawingMode() & TextModeFill) {
+ if (context->fillGradient()) {
+ cairo_set_source(cr, context->fillGradient()->platformGradient());
+ if (context->getAlpha() < 1.0f) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+ cairo_pop_group_to_source(cr);
+ }
+ } else if (context->fillPattern()) {
+ AffineTransform affine;
+ cairo_pattern_t* pattern = context->fillPattern()->createPlatformPattern(affine);
+ cairo_set_source(cr, pattern);
+ if (context->getAlpha() < 1.0f) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+ cairo_pop_group_to_source(cr);
+ }
+ cairo_pattern_destroy(pattern);
+ } else {
+ float red, green, blue, alpha;
+ context->fillColor().getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
+ }
+ drawGlyphsToContext(cr, font, glyphs, numGlyphs);
+ }
+
+ // Prevent running into a long computation within cairo. If the stroke width is
+ // twice the size of the width of the text we will not ask cairo to stroke
+ // the text as even one single stroke would cover the full wdth of the text.
+ // See https://bugs.webkit.org/show_bug.cgi?id=33759.
+ if (context->textDrawingMode() & TextModeStroke && context->strokeThickness() < 2 * offset) {
+ if (context->strokeGradient()) {
+ cairo_set_source(cr, context->strokeGradient()->platformGradient());
+ if (context->getAlpha() < 1.0f) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+ cairo_pop_group_to_source(cr);
+ }
+ } else if (context->strokePattern()) {
+ AffineTransform affine;
+ cairo_pattern_t* pattern = context->strokePattern()->createPlatformPattern(affine);
+ cairo_set_source(cr, pattern);
+ if (context->getAlpha() < 1.0f) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+ cairo_pop_group_to_source(cr);
+ }
+ cairo_pattern_destroy(pattern);
+ } else {
+ float red, green, blue, alpha;
+ context->strokeColor().getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
+ }
+ cairo_glyph_path(cr, glyphs, numGlyphs);
+ cairo_set_line_width(cr, context->strokeThickness());
+ cairo_stroke(cr);
+ }
+
+ cairo_restore(cr);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h
new file mode 100644
index 0000000..dac31f8
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontCustomPlatformData_h
+#define FontCustomPlatformData_h
+
+#include "FontOrientation.h"
+#include "FontRenderingMode.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+
+typedef struct FT_FaceRec_* FT_Face;
+typedef struct _cairo_font_face cairo_font_face_t;
+
+namespace WebCore {
+
+class FontPlatformData;
+class SharedBuffer;
+
+struct FontCustomPlatformData : Noncopyable {
+public:
+ FontCustomPlatformData(FT_Face, SharedBuffer*);
+ ~FontCustomPlatformData();
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode);
+ static bool supportsFormat(const String&);
+
+private:
+ FT_Face m_freeTypeFace;
+ cairo_font_face_t* m_fontFace;
+};
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer);
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/cairo/GradientCairo.cpp b/Source/WebCore/platform/graphics/cairo/GradientCairo.cpp
new file mode 100644
index 0000000..4e6ed07
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/GradientCairo.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * 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
+ * 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
+ * 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
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Gradient.h"
+
+#include "CSSParser.h"
+#include "GraphicsContext.h"
+#include <cairo.h>
+
+namespace WebCore {
+
+void Gradient::platformDestroy()
+{
+ if (m_gradient) {
+ cairo_pattern_destroy(m_gradient);
+ m_gradient = 0;
+ }
+}
+
+cairo_pattern_t* Gradient::platformGradient()
+{
+ if (m_gradient)
+ return m_gradient;
+
+ if (m_radial)
+ m_gradient = cairo_pattern_create_radial(m_p0.x(), m_p0.y(), m_r0, m_p1.x(), m_p1.y(), m_r1);
+ else
+ m_gradient = cairo_pattern_create_linear(m_p0.x(), m_p0.y(), m_p1.x(), m_p1.y());
+
+ Vector<ColorStop>::iterator stopIterator = m_stops.begin();
+ while (stopIterator != m_stops.end()) {
+ cairo_pattern_add_color_stop_rgba(m_gradient, stopIterator->stop, stopIterator->red, stopIterator->green, stopIterator->blue, stopIterator->alpha);
+ ++stopIterator;
+ }
+
+ switch (m_spreadMethod) {
+ case SpreadMethodPad:
+ cairo_pattern_set_extend(m_gradient, CAIRO_EXTEND_PAD);
+ break;
+ case SpreadMethodReflect:
+ cairo_pattern_set_extend(m_gradient, CAIRO_EXTEND_REFLECT);
+ break;
+ case SpreadMethodRepeat:
+ cairo_pattern_set_extend(m_gradient, CAIRO_EXTEND_REPEAT);
+ break;
+ }
+
+ cairo_matrix_t matrix = m_gradientSpaceTransformation;
+ cairo_matrix_invert(&matrix);
+ cairo_pattern_set_matrix(m_gradient, &matrix);
+
+ return m_gradient;
+}
+
+void Gradient::setPlatformGradientSpaceTransform(const AffineTransform& gradientSpaceTransformation)
+{
+ if (m_gradient) {
+ cairo_matrix_t matrix = gradientSpaceTransformation;
+ cairo_matrix_invert(&matrix);
+ cairo_pattern_set_matrix(m_gradient, &matrix);
+ }
+}
+
+void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
+{
+ cairo_t* cr = context->platformContext();
+
+ context->save();
+ cairo_set_source(cr, platformGradient());
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ cairo_fill(cr);
+ context->restore();
+}
+
+} //namespace
diff --git a/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
new file mode 100644
index 0000000..cdbfc57
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
@@ -0,0 +1,1149 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008, 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org>
+ * Copyright (C) 2010 Igalia S.L.
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * 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
+ * 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
+ * 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
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GraphicsContext.h"
+
+#if PLATFORM(CAIRO)
+
+#include "AffineTransform.h"
+#include "CairoPath.h"
+#include "CairoUtilities.h"
+#include "ContextShadow.h"
+#include "FloatRect.h"
+#include "Font.h"
+#include "GraphicsContextPlatformPrivateCairo.h"
+#include "OwnPtrCairo.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+#include "Path.h"
+#include "Pattern.h"
+#include "RefPtrCairo.h"
+#include "SimpleFontData.h"
+#include <cairo.h>
+#include <math.h>
+#include <stdio.h>
+#include <wtf/MathExtras.h>
+
+#if PLATFORM(GTK)
+#include <gdk/gdk.h>
+#include <pango/pango.h>
+#elif PLATFORM(WIN)
+#include <cairo-win32.h>
+#endif
+
+using namespace std;
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+namespace WebCore {
+
+static inline void setPlatformFill(GraphicsContext* context, cairo_t* cr)
+{
+ cairo_pattern_t* pattern = 0;
+ cairo_save(cr);
+
+ const GraphicsContextState& state = context->state();
+ if (state.fillPattern) {
+ AffineTransform affine;
+ pattern = state.fillPattern->createPlatformPattern(affine);
+ cairo_set_source(cr, pattern);
+ } else if (state.fillGradient)
+ cairo_set_source(cr, state.fillGradient->platformGradient());
+ else
+ setSourceRGBAFromColor(cr, context->fillColor());
+ cairo_clip_preserve(cr);
+ cairo_paint_with_alpha(cr, state.globalAlpha);
+ cairo_restore(cr);
+ if (pattern)
+ cairo_pattern_destroy(pattern);
+}
+
+static inline void setPlatformStroke(GraphicsContext* context, cairo_t* cr)
+{
+ cairo_pattern_t* pattern = 0;
+ cairo_save(cr);
+
+ const GraphicsContextState& state = context->state();
+ if (state.strokePattern) {
+ AffineTransform affine;
+ pattern = state.strokePattern->createPlatformPattern(affine);
+ cairo_set_source(cr, pattern);
+ } else if (state.strokeGradient)
+ cairo_set_source(cr, state.strokeGradient->platformGradient());
+ else {
+ Color strokeColor = colorWithOverrideAlpha(context->strokeColor().rgb(), context->strokeColor().alpha() / 255.f * state.globalAlpha);
+ setSourceRGBAFromColor(cr, strokeColor);
+ }
+ if (state.globalAlpha < 1.0f && (state.strokePattern || state.strokeGradient)) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, state.globalAlpha);
+ cairo_pop_group_to_source(cr);
+ }
+ cairo_stroke_preserve(cr);
+ cairo_restore(cr);
+ if (pattern)
+ cairo_pattern_destroy(pattern);
+}
+
+// A fillRect helper
+static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const Color& col)
+{
+ setSourceRGBAFromColor(cr, col);
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ cairo_fill(cr);
+}
+
+static void addConvexPolygonToContext(cairo_t* context, size_t numPoints, const FloatPoint* points)
+{
+ cairo_move_to(context, points[0].x(), points[0].y());
+ for (size_t i = 1; i < numPoints; i++)
+ cairo_line_to(context, points[i].x(), points[i].y());
+ cairo_close_path(context);
+}
+
+enum PathDrawingStyle {
+ Fill = 1,
+ Stroke = 2,
+ FillAndStroke = Fill + Stroke
+};
+
+static inline void drawPathShadow(GraphicsContext* context, PathDrawingStyle drawingStyle)
+{
+ ContextShadow* shadow = context->contextShadow();
+ ASSERT(shadow);
+ if (shadow->m_type == ContextShadow::NoShadow)
+ return;
+
+ // Calculate the extents of the rendered solid paths.
+ cairo_t* cairoContext = context->platformContext();
+ OwnPtr<cairo_path_t> path(cairo_copy_path(cairoContext));
+
+ FloatRect solidFigureExtents;
+ double x0 = 0;
+ double x1 = 0;
+ double y0 = 0;
+ double y1 = 0;
+ if (drawingStyle & Stroke) {
+ cairo_stroke_extents(cairoContext, &x0, &y0, &x1, &y1);
+ solidFigureExtents = FloatRect(x0, y0, x1 - x0, y1 - y0);
+ }
+ if (drawingStyle & Fill) {
+ cairo_fill_extents(cairoContext, &x0, &y0, &x1, &y1);
+ FloatRect fillExtents(x0, y0, x1 - x0, y1 - y0);
+ solidFigureExtents.unite(fillExtents);
+ }
+
+ cairo_t* shadowContext = shadow->beginShadowLayer(context, solidFigureExtents);
+ if (!shadowContext)
+ return;
+
+ // It's important to copy the context properties to the new shadow
+ // context to preserve things such as the fill rule and stroke width.
+ copyContextProperties(cairoContext, shadowContext);
+ cairo_append_path(shadowContext, path.get());
+
+ if (drawingStyle & Fill)
+ setPlatformFill(context, shadowContext);
+ if (drawingStyle & Stroke)
+ setPlatformStroke(context, shadowContext);
+
+ shadow->endShadowLayer(context);
+}
+
+static void fillCurrentCairoPath(GraphicsContext* context, cairo_t* cairoContext)
+{
+ cairo_set_fill_rule(cairoContext, context->fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
+ drawPathShadow(context, Fill);
+
+ setPlatformFill(context, cairoContext);
+ cairo_new_path(cairoContext);
+}
+
+static void strokeCurrentCairoPath(GraphicsContext* context, cairo_t* cairoContext)
+{
+ drawPathShadow(context, Stroke);
+ setPlatformStroke(context, cairoContext);
+ cairo_new_path(cairoContext);
+}
+
+void GraphicsContext::platformInit(PlatformGraphicsContext* cr)
+{
+ m_data = new GraphicsContextPlatformPrivate;
+ m_data->cr = cairo_reference(cr);
+ m_data->syncContext(cr);
+ setPaintingDisabled(!cr);
+}
+
+void GraphicsContext::platformDestroy()
+{
+ delete m_data;
+}
+
+AffineTransform GraphicsContext::getCTM() const
+{
+ cairo_t* cr = platformContext();
+ cairo_matrix_t m;
+ cairo_get_matrix(cr, &m);
+ return AffineTransform(m.xx, m.yx, m.xy, m.yy, m.x0, m.y0);
+}
+
+cairo_t* GraphicsContext::platformContext() const
+{
+ return m_data->cr;
+}
+
+void GraphicsContext::savePlatformState()
+{
+ cairo_save(m_data->cr);
+ m_data->save();
+ m_data->shadowStack.append(m_data->shadow);
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ cairo_restore(m_data->cr);
+ m_data->restore();
+
+ if (m_data->shadowStack.isEmpty())
+ m_data->shadow = ContextShadow();
+ else {
+ m_data->shadow = m_data->shadowStack.last();
+ m_data->shadowStack.removeLast();
+ }
+}
+
+// Draws a filled rectangle with a stroked border.
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+
+ if (fillColor().alpha())
+ fillRectSourceOver(cr, rect, fillColor());
+
+ if (strokeStyle() != NoStroke) {
+ setSourceRGBAFromColor(cr, strokeColor());
+ FloatRect r(rect);
+ r.inflate(-.5f);
+ cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height());
+ cairo_set_line_width(cr, 1.0);
+ cairo_stroke(cr);
+ }
+
+ cairo_restore(cr);
+}
+
+// This is only used to draw borders.
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (paintingDisabled())
+ return;
+
+ StrokeStyle style = strokeStyle();
+ if (style == NoStroke)
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+
+ float width = strokeThickness();
+ if (width < 1)
+ width = 1;
+
+ FloatPoint p1 = point1;
+ FloatPoint p2 = point2;
+ bool isVerticalLine = (p1.x() == p2.x());
+
+ adjustLineToPixelBoundaries(p1, p2, width, style);
+ cairo_set_line_width(cr, width);
+
+ int patWidth = 0;
+ switch (style) {
+ case NoStroke:
+ case SolidStroke:
+ break;
+ case DottedStroke:
+ patWidth = static_cast<int>(width);
+ break;
+ case DashedStroke:
+ patWidth = 3*static_cast<int>(width);
+ break;
+ }
+
+ setSourceRGBAFromColor(cr, strokeColor());
+
+ cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
+
+ if (patWidth) {
+ // Do a rect fill of our endpoints. This ensures we always have the
+ // appearance of being a border. We then draw the actual dotted/dashed line.
+ if (isVerticalLine) {
+ fillRectSourceOver(cr, FloatRect(p1.x() - width/2, p1.y() - width, width, width), strokeColor());
+ fillRectSourceOver(cr, FloatRect(p2.x() - width/2, p2.y(), width, width), strokeColor());
+ } else {
+ fillRectSourceOver(cr, FloatRect(p1.x() - width, p1.y() - width/2, width, width), strokeColor());
+ fillRectSourceOver(cr, FloatRect(p2.x(), p2.y() - width/2, width, width), strokeColor());
+ }
+
+ // Example: 80 pixels with a width of 30 pixels.
+ // Remainder is 20. The maximum pixels of line we could paint
+ // will be 50 pixels.
+ int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*static_cast<int>(width);
+ int remainder = distance%patWidth;
+ int coverage = distance-remainder;
+ int numSegments = coverage/patWidth;
+
+ float patternOffset = 0;
+ // Special case 1px dotted borders for speed.
+ if (patWidth == 1)
+ patternOffset = 1.0;
+ else {
+ bool evenNumberOfSegments = !(numSegments % 2);
+ if (remainder)
+ evenNumberOfSegments = !evenNumberOfSegments;
+ if (evenNumberOfSegments) {
+ if (remainder) {
+ patternOffset += patWidth - remainder;
+ patternOffset += remainder / 2;
+ } else
+ patternOffset = patWidth / 2;
+ } else if (!evenNumberOfSegments) {
+ if (remainder)
+ patternOffset = (patWidth - remainder) / 2;
+ }
+ }
+
+ double dash = patWidth;
+ cairo_set_dash(cr, &dash, 1, patternOffset);
+ }
+
+ cairo_move_to(cr, p1.x(), p1.y());
+ cairo_line_to(cr, p2.x(), p2.y());
+
+ cairo_stroke(cr);
+ cairo_restore(cr);
+}
+
+// This method is only used to draw the little circles used in lists.
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+ float yRadius = .5 * rect.height();
+ float xRadius = .5 * rect.width();
+ cairo_translate(cr, rect.x() + xRadius, rect.y() + yRadius);
+ cairo_scale(cr, xRadius, yRadius);
+ cairo_arc(cr, 0., 0., 1., 0., 2 * M_PI);
+ cairo_restore(cr);
+
+ if (fillColor().alpha()) {
+ setSourceRGBAFromColor(cr, fillColor());
+ cairo_fill_preserve(cr);
+ }
+
+ if (strokeStyle() != NoStroke) {
+ setSourceRGBAFromColor(cr, strokeColor());
+ cairo_set_line_width(cr, strokeThickness());
+ cairo_stroke(cr);
+ } else
+ cairo_new_path(cr);
+}
+
+void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
+{
+ if (paintingDisabled() || strokeStyle() == NoStroke)
+ return;
+
+ int x = rect.x();
+ int y = rect.y();
+ float w = rect.width();
+ float h = rect.height();
+ float scaleFactor = h / w;
+ float reverseScaleFactor = w / h;
+
+ float hRadius = w / 2;
+ float vRadius = h / 2;
+ float fa = startAngle;
+ float falen = fa + angleSpan;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+
+ if (w != h)
+ cairo_scale(cr, 1., scaleFactor);
+
+ cairo_arc_negative(cr, x + hRadius, (y + vRadius) * reverseScaleFactor, hRadius, -fa * M_PI/180, -falen * M_PI/180);
+
+ if (w != h)
+ cairo_scale(cr, 1., reverseScaleFactor);
+
+ float width = strokeThickness();
+ int patWidth = 0;
+
+ switch (strokeStyle()) {
+ case DottedStroke:
+ patWidth = static_cast<int>(width / 2);
+ break;
+ case DashedStroke:
+ patWidth = 3 * static_cast<int>(width / 2);
+ break;
+ default:
+ break;
+ }
+
+ setSourceRGBAFromColor(cr, strokeColor());
+
+ if (patWidth) {
+ // Example: 80 pixels with a width of 30 pixels.
+ // Remainder is 20. The maximum pixels of line we could paint
+ // will be 50 pixels.
+ int distance;
+ if (hRadius == vRadius)
+ distance = static_cast<int>((M_PI * hRadius) / 2.0);
+ else // We are elliptical and will have to estimate the distance
+ distance = static_cast<int>((M_PI * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.0)) / 2.0);
+
+ int remainder = distance % patWidth;
+ int coverage = distance - remainder;
+ int numSegments = coverage / patWidth;
+
+ float patternOffset = 0.0;
+ // Special case 1px dotted borders for speed.
+ if (patWidth == 1)
+ patternOffset = 1.0;
+ else {
+ bool evenNumberOfSegments = !(numSegments % 2);
+ if (remainder)
+ evenNumberOfSegments = !evenNumberOfSegments;
+ if (evenNumberOfSegments) {
+ if (remainder) {
+ patternOffset += patWidth - remainder;
+ patternOffset += remainder / 2.0;
+ } else
+ patternOffset = patWidth / 2.0;
+ } else {
+ if (remainder)
+ patternOffset = (patWidth - remainder) / 2.0;
+ }
+ }
+
+ double dash = patWidth;
+ cairo_set_dash(cr, &dash, 1, patternOffset);
+ }
+
+ cairo_stroke(cr);
+ cairo_restore(cr);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
+{
+ if (paintingDisabled())
+ return;
+
+ if (npoints <= 1)
+ return;
+
+ cairo_t* cr = m_data->cr;
+
+ cairo_save(cr);
+ cairo_set_antialias(cr, shouldAntialias ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE);
+ addConvexPolygonToContext(cr, npoints, points);
+
+ if (fillColor().alpha()) {
+ setSourceRGBAFromColor(cr, fillColor());
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_fill_preserve(cr);
+ }
+
+ if (strokeStyle() != NoStroke) {
+ setSourceRGBAFromColor(cr, strokeColor());
+ cairo_set_line_width(cr, strokeThickness());
+ cairo_stroke(cr);
+ } else
+ cairo_new_path(cr);
+
+ cairo_restore(cr);
+}
+
+void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
+{
+ if (paintingDisabled())
+ return;
+
+ if (numPoints <= 1)
+ return;
+
+ cairo_t* cr = m_data->cr;
+
+ cairo_new_path(cr);
+ cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
+ cairo_antialias_t savedAntialiasRule = cairo_get_antialias(cr);
+
+ cairo_set_antialias(cr, antialiased ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
+ addConvexPolygonToContext(cr, numPoints, points);
+ cairo_clip(cr);
+
+ cairo_set_antialias(cr, savedAntialiasRule);
+ cairo_set_fill_rule(cr, savedFillRule);
+}
+
+void GraphicsContext::fillPath(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ setPathOnCairoContext(cr, path.platformPath()->context());
+ fillCurrentCairoPath(this, cr);
+}
+
+void GraphicsContext::strokePath(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ setPathOnCairoContext(cr, path.platformPath()->context());
+ strokeCurrentCairoPath(this, cr);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ fillCurrentCairoPath(this, cr);
+ cairo_restore(cr);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ if (hasShadow())
+ m_data->shadow.drawRectShadow(this, enclosingIntRect(rect));
+
+ if (color.alpha())
+ fillRectSourceOver(m_data->cr, rect, color);
+}
+
+void GraphicsContext::clip(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
+ cairo_clip(cr);
+ cairo_set_fill_rule(cr, savedFillRule);
+ m_data->clip(rect);
+}
+
+void GraphicsContext::clipPath(const Path& path, WindRule clipRule)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ setPathOnCairoContext(cr, path.platformPath()->context());
+ cairo_set_fill_rule(cr, clipRule == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
+ cairo_clip(cr);
+}
+
+static inline void adjustFocusRingColor(Color& color)
+{
+#if !PLATFORM(GTK)
+ // Force the alpha to 50%. This matches what the Mac does with outline rings.
+ color.setRGB(makeRGBA(color.red(), color.green(), color.blue(), 127));
+#endif
+}
+
+static inline void adjustFocusRingLineWidth(int& width)
+{
+#if PLATFORM(GTK)
+ width = 2;
+#endif
+}
+
+static inline StrokeStyle focusRingStrokeStyle()
+{
+#if PLATFORM(GTK)
+ return DottedStroke;
+#else
+ return SolidStroke;
+#endif
+}
+
+void GraphicsContext::drawFocusRing(const Path& path, int width, int /* offset */, const Color& color)
+{
+ // FIXME: We should draw paths that describe a rectangle with rounded corners
+ // so as to be consistent with how we draw rectangular focus rings.
+ Color ringColor = color;
+ adjustFocusRingColor(ringColor);
+ adjustFocusRingLineWidth(width);
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+ appendWebCorePathToCairoContext(cr, path);
+ setSourceRGBAFromColor(cr, ringColor);
+ cairo_set_line_width(cr, width);
+ setPlatformStrokeStyle(focusRingStrokeStyle());
+ cairo_stroke(cr);
+ cairo_restore(cr);
+}
+
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int /* offset */, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ unsigned rectCount = rects.size();
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+ cairo_push_group(cr);
+ cairo_new_path(cr);
+
+#if PLATFORM(GTK)
+#ifdef GTK_API_VERSION_2
+ GdkRegion* reg = gdk_region_new();
+#else
+ cairo_region_t* reg = cairo_region_create();
+#endif
+
+ for (unsigned i = 0; i < rectCount; i++) {
+#ifdef GTK_API_VERSION_2
+ GdkRectangle rect = rects[i];
+ gdk_region_union_with_rect(reg, &rect);
+#else
+ cairo_rectangle_int_t rect = rects[i];
+ cairo_region_union_rectangle(reg, &rect);
+#endif
+ }
+ gdk_cairo_region(cr, reg);
+#ifdef GTK_API_VERSION_2
+ gdk_region_destroy(reg);
+#else
+ cairo_region_destroy(reg);
+#endif
+#else
+ int radius = (width - 1) / 2;
+ Path path;
+ for (unsigned i = 0; i < rectCount; ++i) {
+ if (i > 0)
+ path.clear();
+ path.addRoundedRect(rects[i], FloatSize(radius, radius));
+ appendWebCorePathToCairoContext(cr, path);
+ }
+#endif
+ Color ringColor = color;
+ adjustFocusRingColor(ringColor);
+ adjustFocusRingLineWidth(width);
+ setSourceRGBAFromColor(cr, ringColor);
+ cairo_set_line_width(cr, width);
+ setPlatformStrokeStyle(focusRingStrokeStyle());
+
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ cairo_stroke_preserve(cr);
+
+ cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
+ cairo_fill(cr);
+
+ cairo_pop_group_to_source(cr);
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ cairo_paint(cr);
+ cairo_restore(cr);
+}
+
+void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
+{
+ if (paintingDisabled())
+ return;
+
+ IntPoint endPoint = origin + IntSize(width, 0);
+ drawLine(origin, endPoint);
+}
+
+#if !PLATFORM(GTK)
+#include "DrawErrorUnderline.h"
+#endif
+
+void GraphicsContext::drawLineForTextChecking(const IntPoint& origin, int width, TextCheckingLineStyle style)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+
+ switch (style) {
+ case TextCheckingSpellingLineStyle:
+ cairo_set_source_rgb(cr, 1, 0, 0);
+ break;
+ case TextCheckingGrammarLineStyle:
+ cairo_set_source_rgb(cr, 0, 1, 0);
+ break;
+ default:
+ cairo_restore(cr);
+ return;
+ }
+
+#if PLATFORM(GTK)
+ // We ignore most of the provided constants in favour of the platform style
+ pango_cairo_show_error_underline(cr, origin.x(), origin.y(), width, cMisspellingLineThickness);
+#else
+ drawErrorUnderline(cr, origin.x(), origin.y(), width, cMisspellingLineThickness);
+#endif
+
+ cairo_restore(cr);
+}
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
+{
+ FloatRect result;
+ double x = frect.x();
+ double y = frect.y();
+ cairo_t* cr = m_data->cr;
+ cairo_user_to_device(cr, &x, &y);
+ x = round(x);
+ y = round(y);
+ cairo_device_to_user(cr, &x, &y);
+ result.setX(static_cast<float>(x));
+ result.setY(static_cast<float>(y));
+ x = frect.width();
+ y = frect.height();
+ cairo_user_to_device_distance(cr, &x, &y);
+ x = round(x);
+ y = round(y);
+ cairo_device_to_user_distance(cr, &x, &y);
+ result.setWidth(static_cast<float>(x));
+ result.setHeight(static_cast<float>(y));
+ return result;
+}
+
+void GraphicsContext::translate(float x, float y)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_translate(cr, x, y);
+ m_data->translate(x, y);
+}
+
+void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace colorSpace)
+{
+ // Cairo contexts can't hold separate fill and stroke colors
+ // so we set them just before we actually fill or stroke
+}
+
+void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace colorSpace)
+{
+ // Cairo contexts can't hold separate fill and stroke colors
+ // so we set them just before we actually fill or stroke
+}
+
+void GraphicsContext::setPlatformStrokeThickness(float strokeThickness)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_set_line_width(m_data->cr, strokeThickness);
+}
+
+void GraphicsContext::setPlatformStrokeStyle(StrokeStyle strokeStyle)
+{
+ static double dashPattern[] = {5.0, 5.0};
+ static double dotPattern[] = {1.0, 1.0};
+
+ if (paintingDisabled())
+ return;
+
+ switch (strokeStyle) {
+ case NoStroke:
+ // FIXME: is it the right way to emulate NoStroke?
+ cairo_set_line_width(m_data->cr, 0);
+ break;
+ case SolidStroke:
+ cairo_set_dash(m_data->cr, 0, 0, 0);
+ break;
+ case DottedStroke:
+ cairo_set_dash(m_data->cr, dotPattern, 2, 0);
+ break;
+ case DashedStroke:
+ cairo_set_dash(m_data->cr, dashPattern, 2, 0);
+ break;
+ }
+}
+
+void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
+{
+ notImplemented();
+}
+
+void GraphicsContext::concatCTM(const AffineTransform& transform)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ const cairo_matrix_t matrix = cairo_matrix_t(transform);
+ cairo_transform(cr, &matrix);
+ m_data->concatCTM(transform);
+}
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ clip(rect);
+
+ Path p;
+ FloatRect r(rect);
+ // Add outer ellipse
+ p.addEllipse(r);
+ // Add inner ellipse
+ r.inflate(-thickness);
+ p.addEllipse(r);
+ appendWebCorePathToCairoContext(cr, p);
+
+ cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_clip(cr);
+ cairo_set_fill_rule(cr, savedFillRule);
+}
+
+void GraphicsContext::setPlatformShadow(FloatSize const& size, float blur, Color const& color, ColorSpace)
+{
+ // Cairo doesn't support shadows natively, they are drawn manually in the draw* functions
+ if (m_state.shadowsIgnoreTransforms) {
+ // Meaning that this graphics context is associated with a CanvasRenderingContext
+ // We flip the height since CG and HTML5 Canvas have opposite Y axis
+ m_state.shadowOffset = FloatSize(size.width(), -size.height());
+ m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), -size.height()));
+ } else
+ m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), size.height()));
+
+ m_data->shadow.setShadowsIgnoreTransforms(m_state.shadowsIgnoreTransforms);
+}
+
+ContextShadow* GraphicsContext::contextShadow()
+{
+ return &m_data->shadow;
+}
+
+void GraphicsContext::clearPlatformShadow()
+{
+ m_data->shadow.clear();
+}
+
+void GraphicsContext::beginTransparencyLayer(float opacity)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_push_group(cr);
+ m_data->layers.append(opacity);
+ m_data->beginTransparencyLayer();
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+
+ cairo_pop_group_to_source(cr);
+ cairo_paint_with_alpha(cr, m_data->layers.last());
+ m_data->layers.removeLast();
+ m_data->endTransparencyLayer();
+}
+
+void GraphicsContext::clearRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+
+ cairo_save(cr);
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
+ cairo_fill(cr);
+ cairo_restore(cr);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float width)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ cairo_set_line_width(cr, width);
+ strokeCurrentCairoPath(this, cr);
+ cairo_restore(cr);
+}
+
+void GraphicsContext::setLineCap(LineCap lineCap)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_line_cap_t cairoCap = CAIRO_LINE_CAP_BUTT;
+ switch (lineCap) {
+ case ButtCap:
+ // no-op
+ break;
+ case RoundCap:
+ cairoCap = CAIRO_LINE_CAP_ROUND;
+ break;
+ case SquareCap:
+ cairoCap = CAIRO_LINE_CAP_SQUARE;
+ break;
+ }
+ cairo_set_line_cap(m_data->cr, cairoCap);
+}
+
+void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
+{
+ cairo_set_dash(m_data->cr, dashes.data(), dashes.size(), dashOffset);
+}
+
+void GraphicsContext::setLineJoin(LineJoin lineJoin)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_line_join_t cairoJoin = CAIRO_LINE_JOIN_MITER;
+ switch (lineJoin) {
+ case MiterJoin:
+ // no-op
+ break;
+ case RoundJoin:
+ cairoJoin = CAIRO_LINE_JOIN_ROUND;
+ break;
+ case BevelJoin:
+ cairoJoin = CAIRO_LINE_JOIN_BEVEL;
+ break;
+ }
+ cairo_set_line_join(m_data->cr, cairoJoin);
+}
+
+void GraphicsContext::setMiterLimit(float miter)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_set_miter_limit(m_data->cr, miter);
+}
+
+void GraphicsContext::setAlpha(float alpha)
+{
+ m_state.globalAlpha = alpha;
+}
+
+float GraphicsContext::getAlpha()
+{
+ return m_state.globalAlpha;
+}
+
+void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_set_operator(m_data->cr, toCairoOperator(op));
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ OwnPtr<cairo_path_t> p(cairo_copy_path(path.platformPath()->context()));
+ cairo_append_path(cr, p.get());
+ cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
+ cairo_clip(cr);
+ cairo_set_fill_rule(cr, savedFillRule);
+ m_data->clip(path);
+}
+
+void GraphicsContext::canvasClip(const Path& path)
+{
+ clip(path);
+}
+
+void GraphicsContext::clipOut(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ double x1, y1, x2, y2;
+ cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
+ cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1);
+ appendWebCorePathToCairoContext(cr, path);
+
+ cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_clip(cr);
+ cairo_set_fill_rule(cr, savedFillRule);
+}
+
+void GraphicsContext::rotate(float radians)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_rotate(m_data->cr, radians);
+ m_data->rotate(radians);
+}
+
+void GraphicsContext::scale(const FloatSize& size)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_scale(m_data->cr, size.width(), size.height());
+ m_data->scale(size);
+}
+
+void GraphicsContext::clipOut(const IntRect& r)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ double x1, y1, x2, y2;
+ cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
+ cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1);
+ cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height());
+ cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_clip(cr);
+ cairo_set_fill_rule(cr, savedFillRule);
+}
+
+static inline FloatPoint getPhase(const FloatRect& dest, const FloatRect& tile)
+{
+ FloatPoint phase = dest.location();
+ phase.move(-tile.x(), -tile.y());
+
+ return phase;
+}
+
+void GraphicsContext::fillRoundedRect(const IntRect& r, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ if (hasShadow())
+ m_data->shadow.drawRectShadow(this, r, topLeft, topRight, bottomLeft, bottomRight);
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+ Path path;
+ path.addRoundedRect(r, topLeft, topRight, bottomLeft, bottomRight);
+ appendWebCorePathToCairoContext(cr, path);
+ setSourceRGBAFromColor(cr, color);
+ cairo_fill(cr);
+ cairo_restore(cr);
+}
+
+#if PLATFORM(GTK)
+void GraphicsContext::setGdkExposeEvent(GdkEventExpose* expose)
+{
+ m_data->expose = expose;
+}
+
+GdkEventExpose* GraphicsContext::gdkExposeEvent() const
+{
+ return m_data->expose;
+}
+
+GdkWindow* GraphicsContext::gdkWindow() const
+{
+ if (!m_data->expose)
+ return 0;
+
+ return m_data->expose->window;
+}
+#endif
+
+void GraphicsContext::setPlatformShouldAntialias(bool enable)
+{
+ if (paintingDisabled())
+ return;
+
+ // When true, use the default Cairo backend antialias mode (usually this
+ // enables standard 'grayscale' antialiasing); false to explicitly disable
+ // antialiasing. This is the same strategy as used in drawConvexPolygon().
+ cairo_set_antialias(m_data->cr, enable ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE);
+}
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
+{
+}
+
+InterpolationQuality GraphicsContext::imageInterpolationQuality() const
+{
+ return InterpolationDefault;
+}
+
+} // namespace WebCore
+
+#endif // PLATFORM(CAIRO)
diff --git a/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
new file mode 100644
index 0000000..5602b6c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008 Brent Fulgham <bfulgham@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * 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
+ * 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
+ * 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
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "GraphicsContext.h"
+
+#include "ContextShadow.h"
+#include <cairo.h>
+#include <math.h>
+#include <stdio.h>
+#include <wtf/MathExtras.h>
+
+#if PLATFORM(GTK)
+#include <pango/pango.h>
+typedef struct _GdkExposeEvent GdkExposeEvent;
+#elif PLATFORM(WIN)
+#include <cairo-win32.h>
+#endif
+
+namespace WebCore {
+
+class GraphicsContextPlatformPrivate {
+public:
+ GraphicsContextPlatformPrivate()
+ : cr(0)
+#if PLATFORM(GTK)
+ , expose(0)
+#elif PLATFORM(WIN)
+ // NOTE: These may note be needed: review and remove once Cairo implementation is complete
+ , m_hdc(0)
+ , m_transparencyCount(0)
+ , m_shouldIncludeChildWindows(false)
+#endif
+ {
+ }
+
+ ~GraphicsContextPlatformPrivate()
+ {
+ cairo_destroy(cr);
+ }
+
+#if PLATFORM(WIN)
+ // On Windows, we need to update the HDC for form controls to draw in the right place.
+ void save();
+ void restore();
+ void flush();
+ void clip(const FloatRect&);
+ void clip(const Path&);
+ void scale(const FloatSize&);
+ void rotate(float);
+ void translate(float, float);
+ void concatCTM(const AffineTransform&);
+ void concatCTM(const TransformationMatrix&);
+ void beginTransparencyLayer() { m_transparencyCount++; }
+ void endTransparencyLayer() { m_transparencyCount--; }
+ void syncContext(PlatformGraphicsContext* cr);
+#else
+ // On everything else, we do nothing.
+ void save() {}
+ void restore() {}
+ void flush() {}
+ void clip(const FloatRect&) {}
+ void clip(const Path&) {}
+ void scale(const FloatSize&) {}
+ void rotate(float) {}
+ void translate(float, float) {}
+ void concatCTM(const AffineTransform&) {}
+ void concatCTM(const TransformationMatrix&) {}
+ void beginTransparencyLayer() {}
+ void endTransparencyLayer() {}
+ void syncContext(PlatformGraphicsContext* cr) {}
+#endif
+
+ cairo_t* cr;
+ Vector<float> layers;
+
+ ContextShadow shadow;
+ Vector<ContextShadow> shadowStack;
+
+#if PLATFORM(GTK)
+ GdkEventExpose* expose;
+#elif PLATFORM(WIN)
+ HDC m_hdc;
+ unsigned m_transparencyCount;
+ bool m_shouldIncludeChildWindows;
+#endif
+};
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
new file mode 100644
index 0000000..ac5da3d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2007 Holger Hans Peter Freyther <zecke@selfish.org>
+ * Copyright (C) 2008, 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * 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
+ * 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
+ * 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
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#include "Base64.h"
+#include "BitmapImage.h"
+#include "Color.h"
+#include "GraphicsContext.h"
+#include "ImageData.h"
+#include "MIMETypeRegistry.h"
+#include "NotImplemented.h"
+#include "Pattern.h"
+#include "PlatformString.h"
+#include <cairo.h>
+#include <wtf/Vector.h>
+
+using namespace std;
+
+// Cairo doesn't provide a way to copy a cairo_surface_t.
+// See http://lists.cairographics.org/archives/cairo/2007-June/010877.html
+// Once cairo provides the way, use the function instead of this.
+static inline cairo_surface_t* copySurface(cairo_surface_t* surface)
+{
+ cairo_format_t format = cairo_image_surface_get_format(surface);
+ int width = cairo_image_surface_get_width(surface);
+ int height = cairo_image_surface_get_height(surface);
+ cairo_surface_t* newsurface = cairo_image_surface_create(format, width, height);
+
+ cairo_t* cr = cairo_create(newsurface);
+ cairo_set_source_surface(cr, surface, 0, 0);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(cr);
+ cairo_destroy(cr);
+
+ return newsurface;
+}
+
+namespace WebCore {
+
+ImageBufferData::ImageBufferData(const IntSize& size)
+ : m_surface(0)
+{
+}
+
+ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& success)
+ : m_data(size)
+ , m_size(size)
+{
+ success = false; // Make early return mean error.
+ m_data.m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ size.width(),
+ size.height());
+ if (cairo_surface_status(m_data.m_surface) != CAIRO_STATUS_SUCCESS)
+ return; // create will notice we didn't set m_initialized and fail.
+
+ cairo_t* cr = cairo_create(m_data.m_surface);
+ m_context.set(new GraphicsContext(cr));
+ cairo_destroy(cr); // The context is now owned by the GraphicsContext.
+ success = true;
+}
+
+ImageBuffer::~ImageBuffer()
+{
+ cairo_surface_destroy(m_data.m_surface);
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ return m_context.get();
+}
+
+bool ImageBuffer::drawsUsingCopy() const
+{
+ return false;
+}
+
+PassRefPtr<Image> ImageBuffer::copyImage() const
+{
+ // BitmapImage will release the passed in surface on destruction
+ return BitmapImage::create(copySurface(m_data.m_surface));
+}
+
+void ImageBuffer::clip(GraphicsContext*, const FloatRect&) const
+{
+ notImplemented();
+ // See https://bugs.webkit.org/show_bug.cgi?id=23526 for why this is unimplemented.
+}
+
+void ImageBuffer::draw(GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect,
+ CompositeOperator op , bool useLowQualityScale)
+{
+ // BitmapImage will release the passed in surface on destruction
+ RefPtr<Image> image = BitmapImage::create(cairo_surface_reference(m_data.m_surface));
+ context->drawImage(image.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale);
+}
+
+void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect)
+{
+ // BitmapImage will release the passed in surface on destruction
+ RefPtr<Image> image = BitmapImage::create(cairo_surface_reference(m_data.m_surface));
+ image->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect);
+}
+
+void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
+{
+ ASSERT(cairo_surface_get_type(m_data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE);
+
+ unsigned char* dataSrc = cairo_image_surface_get_data(m_data.m_surface);
+ int stride = cairo_image_surface_get_stride(m_data.m_surface);
+ for (int y = 0; y < m_size.height(); ++y) {
+ unsigned* row = reinterpret_cast<unsigned*>(dataSrc + stride * y);
+ for (int x = 0; x < m_size.width(); x++) {
+ unsigned* pixel = row + x;
+ Color pixelColor = colorFromPremultipliedARGB(*pixel);
+ pixelColor = Color(lookUpTable[pixelColor.red()],
+ lookUpTable[pixelColor.green()],
+ lookUpTable[pixelColor.blue()],
+ pixelColor.alpha());
+ *pixel = premultipliedARGBFromColor(pixelColor);
+ }
+ }
+ cairo_surface_mark_dirty_rectangle (m_data.m_surface, 0, 0, m_size.width(), m_size.height());
+}
+
+template <Multiply multiplied>
+PassRefPtr<ByteArray> getImageData(const IntRect& rect, const ImageBufferData& data, const IntSize& size)
+{
+ ASSERT(cairo_surface_get_type(data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE);
+
+ RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4);
+ unsigned char* dataSrc = cairo_image_surface_get_data(data.m_surface);
+ unsigned char* dataDst = result->data();
+
+ if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > size.width() || (rect.y() + rect.height()) > size.height())
+ memset(dataDst, 0, result->length());
+
+ int originx = rect.x();
+ int destx = 0;
+ if (originx < 0) {
+ destx = -originx;
+ originx = 0;
+ }
+ int endx = rect.right();
+ if (endx > size.width())
+ endx = size.width();
+ int numColumns = endx - originx;
+
+ int originy = rect.y();
+ int desty = 0;
+ if (originy < 0) {
+ desty = -originy;
+ originy = 0;
+ }
+ int endy = rect.bottom();
+ if (endy > size.height())
+ endy = size.height();
+ int numRows = endy - originy;
+
+ int stride = cairo_image_surface_get_stride(data.m_surface);
+ unsigned destBytesPerRow = 4 * rect.width();
+
+ unsigned char* destRows = dataDst + desty * destBytesPerRow + destx * 4;
+ for (int y = 0; y < numRows; ++y) {
+ unsigned* row = reinterpret_cast<unsigned*>(dataSrc + stride * (y + originy));
+ for (int x = 0; x < numColumns; x++) {
+ int basex = x * 4;
+ unsigned* pixel = row + x + originx;
+ Color pixelColor;
+ if (multiplied == Unmultiplied)
+ pixelColor = colorFromPremultipliedARGB(*pixel);
+ else
+ pixelColor = Color(*pixel);
+ destRows[basex] = pixelColor.red();
+ destRows[basex + 1] = pixelColor.green();
+ destRows[basex + 2] = pixelColor.blue();
+ destRows[basex + 3] = pixelColor.alpha();
+ }
+ destRows += destBytesPerRow;
+ }
+
+ return result.release();
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const
+{
+ return getImageData<Unmultiplied>(rect, m_data, m_size);
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const
+{
+ return getImageData<Premultiplied>(rect, m_data, m_size);
+}
+
+template <Multiply multiplied>
+void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& data, const IntSize& size)
+{
+ ASSERT(cairo_surface_get_type(data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE);
+
+ unsigned char* dataDst = cairo_image_surface_get_data(data.m_surface);
+
+ ASSERT(sourceRect.width() > 0);
+ ASSERT(sourceRect.height() > 0);
+
+ int originx = sourceRect.x();
+ int destx = destPoint.x() + sourceRect.x();
+ ASSERT(destx >= 0);
+ ASSERT(destx < size.width());
+ ASSERT(originx >= 0);
+ ASSERT(originx <= sourceRect.right());
+
+ int endx = destPoint.x() + sourceRect.right();
+ ASSERT(endx <= size.width());
+
+ int numColumns = endx - destx;
+
+ int originy = sourceRect.y();
+ int desty = destPoint.y() + sourceRect.y();
+ ASSERT(desty >= 0);
+ ASSERT(desty < size.height());
+ ASSERT(originy >= 0);
+ ASSERT(originy <= sourceRect.bottom());
+
+ int endy = destPoint.y() + sourceRect.bottom();
+ ASSERT(endy <= size.height());
+ int numRows = endy - desty;
+
+ unsigned srcBytesPerRow = 4 * sourceSize.width();
+ int stride = cairo_image_surface_get_stride(data.m_surface);
+
+ unsigned char* srcRows = source->data() + originy * srcBytesPerRow + originx * 4;
+ for (int y = 0; y < numRows; ++y) {
+ unsigned* row = reinterpret_cast<unsigned*>(dataDst + stride * (y + desty));
+ for (int x = 0; x < numColumns; x++) {
+ int basex = x * 4;
+ unsigned* pixel = row + x + destx;
+ Color pixelColor(srcRows[basex],
+ srcRows[basex + 1],
+ srcRows[basex + 2],
+ srcRows[basex + 3]);
+ if (multiplied == Unmultiplied)
+ *pixel = premultipliedARGBFromColor(pixelColor);
+ else
+ *pixel = pixelColor.rgb();
+ }
+ srcRows += srcBytesPerRow;
+ }
+ cairo_surface_mark_dirty_rectangle (data.m_surface,
+ destx, desty,
+ numColumns, numRows);
+}
+
+void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ putImageData<Unmultiplied>(source, sourceSize, sourceRect, destPoint, m_data, m_size);
+}
+
+void ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ putImageData<Premultiplied>(source, sourceSize, sourceRect, destPoint, m_data, m_size);
+}
+
+#if !PLATFORM(GTK)
+static cairo_status_t writeFunction(void* closure, const unsigned char* data, unsigned int length)
+{
+ Vector<char>* in = reinterpret_cast<Vector<char>*>(closure);
+ in->append(data, length);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+String ImageBuffer::toDataURL(const String& mimeType, const double*) const
+{
+ cairo_surface_t* image = cairo_get_target(context()->platformContext());
+ if (!image)
+ return "data:,";
+
+ String actualMimeType("image/png");
+ if (MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType))
+ actualMimeType = mimeType;
+
+ Vector<char> in;
+ // Only PNG output is supported for now.
+ cairo_surface_write_to_png_stream(image, writeFunction, &in);
+
+ Vector<char> out;
+ base64Encode(in, out);
+
+ return "data:" + actualMimeType + ";base64," + String(out.data(), out.size());
+}
+#endif
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferData.h b/Source/WebCore/platform/graphics/cairo/ImageBufferData.h
new file mode 100644
index 0000000..49f15df
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/ImageBufferData.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2008 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * 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
+ * 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
+ * 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
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ImageBufferData_h
+#define ImageBufferData_h
+
+#include "cairo.h"
+
+namespace WebCore {
+
+class IntSize;
+
+class ImageBufferData {
+public:
+ ImageBufferData(const IntSize&);
+
+ cairo_surface_t* m_surface;
+};
+
+} // namespace WebCore
+
+#endif // ImageBufferData_h
diff --git a/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp
new file mode 100644
index 0000000..e51d65a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * 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
+ * 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
+ * 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
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "BitmapImage.h"
+
+#if PLATFORM(CAIRO)
+
+#include "AffineTransform.h"
+#include "CairoUtilities.h"
+#include "Color.h"
+#include "ContextShadow.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+#include "ImageObserver.h"
+#include "RefPtrCairo.h"
+#include <cairo.h>
+#include <math.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+bool FrameData::clear(bool clearMetadata)
+{
+ if (clearMetadata)
+ m_haveMetadata = false;
+
+ if (m_frame) {
+ cairo_surface_destroy(m_frame);
+ m_frame = 0;
+ return true;
+ }
+ return false;
+}
+
+BitmapImage::BitmapImage(cairo_surface_t* surface, ImageObserver* observer)
+ : Image(observer)
+ , m_currentFrame(0)
+ , m_frames(0)
+ , m_frameTimer(0)
+ , m_repetitionCount(cAnimationNone)
+ , m_repetitionCountStatus(Unknown)
+ , m_repetitionsComplete(0)
+ , m_isSolidColor(false)
+ , m_checkedForSolidColor(false)
+ , m_animationFinished(true)
+ , m_allDataReceived(true)
+ , m_haveSize(true)
+ , m_sizeAvailable(true)
+ , m_decodedSize(0)
+ , m_haveFrameCount(true)
+ , m_frameCount(1)
+{
+ initPlatformData();
+
+ // TODO: check to be sure this is an image surface
+
+ int width = cairo_image_surface_get_width(surface);
+ int height = cairo_image_surface_get_height(surface);
+ m_decodedSize = width * height * 4;
+ m_size = IntSize(width, height);
+
+ m_frames.grow(1);
+ m_frames[0].m_frame = surface;
+ m_frames[0].m_hasAlpha = cairo_surface_get_content(surface) != CAIRO_CONTENT_COLOR;
+ m_frames[0].m_haveMetadata = true;
+ checkForSolidColor();
+}
+
+void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op)
+{
+ FloatRect srcRect(src);
+ FloatRect dstRect(dst);
+
+ if (dstRect.width() == 0.0f || dstRect.height() == 0.0f ||
+ srcRect.width() == 0.0f || srcRect.height() == 0.0f)
+ return;
+
+ startAnimation();
+
+ cairo_surface_t* image = frameAtIndex(m_currentFrame);
+ if (!image) // If it's too early we won't have an image yet.
+ return;
+
+ if (mayFillWithSolidColor()) {
+ fillWithSolidColor(context, dstRect, solidColor(), styleColorSpace, op);
+ return;
+ }
+
+ IntSize selfSize = size();
+
+ cairo_t* cr = context->platformContext();
+ context->save();
+
+ // Set the compositing operation.
+ if (op == CompositeSourceOver && !frameHasAlphaAtIndex(m_currentFrame))
+ context->setCompositeOperation(CompositeCopy);
+ else
+ context->setCompositeOperation(op);
+
+ // If we're drawing a sub portion of the image or scaling then create
+ // a pattern transformation on the image and draw the transformed pattern.
+ // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
+ cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image);
+
+ cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
+
+ float scaleX = srcRect.width() / dstRect.width();
+ float scaleY = srcRect.height() / dstRect.height();
+ cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, srcRect.x(), srcRect.y() };
+ cairo_pattern_set_matrix(pattern, &matrix);
+
+ ContextShadow* shadow = context->contextShadow();
+ ASSERT(shadow);
+ if (shadow->m_type != ContextShadow::NoShadow) {
+ cairo_t* shadowContext = shadow->beginShadowLayer(context, dstRect);
+ if (shadowContext) {
+ cairo_translate(shadowContext, dstRect.x(), dstRect.y());
+ cairo_set_source(shadowContext, pattern);
+ cairo_rectangle(shadowContext, 0, 0, dstRect.width(), dstRect.height());
+ cairo_fill(shadowContext);
+ shadow->endShadowLayer(context);
+ }
+ }
+
+ // Draw the image.
+ cairo_translate(cr, dstRect.x(), dstRect.y());
+ cairo_set_source(cr, pattern);
+ cairo_pattern_destroy(pattern);
+ cairo_rectangle(cr, 0, 0, dstRect.width(), dstRect.height());
+ cairo_clip(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+
+ context->restore();
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace colorSpace, CompositeOperator op, const FloatRect& destRect)
+{
+ cairo_surface_t* image = nativeImageForCurrentFrame();
+ if (!image) // If it's too early we won't have an image yet.
+ return;
+
+ cairo_t* cr = context->platformContext();
+
+ drawPatternToCairoContext(cr, image, size(), tileRect, patternTransform, phase, toCairoOperator(op), destRect);
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+void BitmapImage::checkForSolidColor()
+{
+ m_isSolidColor = false;
+ m_checkedForSolidColor = true;
+
+ if (frameCount() > 1)
+ return;
+
+ cairo_surface_t* frameSurface = frameAtIndex(0);
+ if (!frameSurface)
+ return;
+
+ ASSERT(cairo_surface_get_type(frameSurface) == CAIRO_SURFACE_TYPE_IMAGE);
+
+ int width = cairo_image_surface_get_width(frameSurface);
+ int height = cairo_image_surface_get_height(frameSurface);
+
+ if (width != 1 || height != 1)
+ return;
+
+ unsigned* pixelColor = reinterpret_cast<unsigned*>(cairo_image_surface_get_data(frameSurface));
+ m_solidColor = colorFromPremultipliedARGB(*pixelColor);
+
+ m_isSolidColor = true;
+}
+
+}
+
+#endif // PLATFORM(CAIRO)
diff --git a/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.cpp b/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.cpp
new file mode 100644
index 0000000..94f6809
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "OwnPtrCairo.h"
+
+#if defined(USE_FREETYPE)
+#include <cairo-ft.h>
+#include <fontconfig/fcfreetype.h>
+#endif
+
+#include <cairo.h>
+
+namespace WTF {
+
+#if defined(USE_FREETYPE)
+template <> void deleteOwnedPtr<FcObjectSet>(FcObjectSet* ptr)
+{
+ if (ptr)
+ FcObjectSetDestroy(ptr);
+}
+
+template <> void deleteOwnedPtr<FcFontSet>(FcFontSet* ptr)
+{
+ if (ptr)
+ FcFontSetDestroy(ptr);
+}
+#endif
+
+template <> void deleteOwnedPtr<cairo_path_t>(cairo_path_t* ptr)
+{
+ if (ptr)
+ cairo_path_destroy(ptr);
+}
+
+} // namespace WTF
diff --git a/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.h b/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.h
new file mode 100644
index 0000000..035d80e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef OwnPtrCairo_h
+#define OwnPtrCairo_h
+
+#include "OwnPtr.h"
+
+#if defined(USE_FREETYPE)
+typedef struct _FcObjectSet FcObjectSet;
+typedef struct _FcFontSet FcFontSet;
+#endif
+
+typedef struct cairo_path cairo_path_t;
+
+namespace WTF {
+
+#if defined(USE_FREETYPE)
+template <> void deleteOwnedPtr<FcObjectSet>(FcObjectSet*);
+template <> void deleteOwnedPtr<FcFontSet>(FcFontSet*);
+#endif
+
+template <> void deleteOwnedPtr<cairo_path_t>(cairo_path_t*);
+
+} // namespace WTF
+
+#endif
diff --git a/Source/WebCore/platform/graphics/cairo/PathCairo.cpp b/Source/WebCore/platform/graphics/cairo/PathCairo.cpp
new file mode 100644
index 0000000..03f1d10
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/PathCairo.cpp
@@ -0,0 +1,342 @@
+/*
+ Copyright (C) 2007 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+ Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <wildfox@kde.org>
+ 2004, 2005, 2006 Rob Buis <buis@kde.org>
+ 2005, 2007 Apple Inc. All Rights reserved.
+ 2007 Alp Toker <alp@atoker.com>
+ 2008 Dirk Schulze <krit@webkit.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#include "Path.h"
+
+#include "AffineTransform.h"
+#include "CairoPath.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "OwnPtrCairo.h"
+#include "PlatformString.h"
+#include "StrokeStyleApplier.h"
+#include <cairo.h>
+#include <math.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+Path::Path()
+ : m_path(new CairoPath())
+{
+}
+
+Path::~Path()
+{
+ delete m_path;
+}
+
+Path::Path(const Path& other)
+ : m_path(new CairoPath())
+{
+ cairo_t* cr = platformPath()->context();
+ OwnPtr<cairo_path_t> p(cairo_copy_path(other.platformPath()->context()));
+ cairo_append_path(cr, p.get());
+}
+
+Path& Path::operator=(const Path& other)
+{
+ if (&other == this)
+ return *this;
+
+ clear();
+ cairo_t* cr = platformPath()->context();
+ OwnPtr<cairo_path_t> p(cairo_copy_path(other.platformPath()->context()));
+ cairo_append_path(cr, p.get());
+ return *this;
+}
+
+void Path::clear()
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_new_path(cr);
+}
+
+bool Path::isEmpty() const
+{
+ return !cairo_has_current_point(platformPath()->context());
+}
+
+bool Path::hasCurrentPoint() const
+{
+ return !isEmpty();
+}
+
+FloatPoint Path::currentPoint() const
+{
+ // FIXME: Is this the correct way?
+ double x;
+ double y;
+ cairo_get_current_point(platformPath()->context(), &x, &y);
+ return FloatPoint(x, y);
+}
+
+void Path::translate(const FloatSize& p)
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_translate(cr, -p.width(), -p.height());
+}
+
+void Path::moveTo(const FloatPoint& p)
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_move_to(cr, p.x(), p.y());
+}
+
+void Path::addLineTo(const FloatPoint& p)
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_line_to(cr, p.x(), p.y());
+}
+
+void Path::addRect(const FloatRect& rect)
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+/*
+ * inspired by libsvg-cairo
+ */
+void Path::addQuadCurveTo(const FloatPoint& controlPoint, const FloatPoint& point)
+{
+ cairo_t* cr = platformPath()->context();
+ double x, y;
+ double x1 = controlPoint.x();
+ double y1 = controlPoint.y();
+ double x2 = point.x();
+ double y2 = point.y();
+ cairo_get_current_point(cr, &x, &y);
+ cairo_curve_to(cr,
+ x + 2.0 / 3.0 * (x1 - x), y + 2.0 / 3.0 * (y1 - y),
+ x2 + 2.0 / 3.0 * (x1 - x2), y2 + 2.0 / 3.0 * (y1 - y2),
+ x2, y2);
+}
+
+void Path::addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint& controlPoint3)
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_curve_to(cr, controlPoint1.x(), controlPoint1.y(),
+ controlPoint2.x(), controlPoint2.y(),
+ controlPoint3.x(), controlPoint3.y());
+}
+
+void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool anticlockwise)
+{
+ // http://bugs.webkit.org/show_bug.cgi?id=16449
+ // cairo_arc() functions hang or crash when passed inf as radius or start/end angle
+ if (!isfinite(r) || !isfinite(sa) || !isfinite(ea))
+ return;
+
+ cairo_t* cr = platformPath()->context();
+ if (anticlockwise)
+ cairo_arc_negative(cr, p.x(), p.y(), r, sa, ea);
+ else
+ cairo_arc(cr, p.x(), p.y(), r, sa, ea);
+}
+
+void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
+{
+ if (isEmpty())
+ return;
+
+ cairo_t* cr = platformPath()->context();
+
+ double x0, y0;
+ cairo_get_current_point(cr, &x0, &y0);
+ FloatPoint p0(x0, y0);
+ if ((p1.x() == p0.x() && p1.y() == p0.y()) || (p1.x() == p2.x() && p1.y() == p2.y()) || radius == 0.f) {
+ cairo_line_to(cr, p1.x(), p1.y());
+ return;
+ }
+
+ FloatPoint p1p0((p0.x() - p1.x()),(p0.y() - p1.y()));
+ FloatPoint p1p2((p2.x() - p1.x()),(p2.y() - p1.y()));
+ float p1p0_length = sqrtf(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
+ float p1p2_length = sqrtf(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
+
+ double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
+ // all points on a line logic
+ if (cos_phi == -1) {
+ cairo_line_to(cr, p1.x(), p1.y());
+ return;
+ }
+ if (cos_phi == 1) {
+ // add infinite far away point
+ unsigned int max_length = 65535;
+ double factor_max = max_length / p1p0_length;
+ FloatPoint ep((p0.x() + factor_max * p1p0.x()), (p0.y() + factor_max * p1p0.y()));
+ cairo_line_to(cr, ep.x(), ep.y());
+ return;
+ }
+
+ float tangent = radius / tan(acos(cos_phi) / 2);
+ float factor_p1p0 = tangent / p1p0_length;
+ FloatPoint t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
+
+ FloatPoint orth_p1p0(p1p0.y(), -p1p0.x());
+ float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
+ float factor_ra = radius / orth_p1p0_length;
+
+ // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
+ double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
+ if (cos_alpha < 0.f)
+ orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y());
+
+ FloatPoint p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
+
+ // calculate angles for addArc
+ orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y());
+ float sa = acos(orth_p1p0.x() / orth_p1p0_length);
+ if (orth_p1p0.y() < 0.f)
+ sa = 2 * piDouble - sa;
+
+ // anticlockwise logic
+ bool anticlockwise = false;
+
+ float factor_p1p2 = tangent / p1p2_length;
+ FloatPoint t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
+ FloatPoint orth_p1p2((t_p1p2.x() - p.x()),(t_p1p2.y() - p.y()));
+ float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
+ float ea = acos(orth_p1p2.x() / orth_p1p2_length);
+ if (orth_p1p2.y() < 0)
+ ea = 2 * piDouble - ea;
+ if ((sa > ea) && ((sa - ea) < piDouble))
+ anticlockwise = true;
+ if ((sa < ea) && ((ea - sa) > piDouble))
+ anticlockwise = true;
+
+ cairo_line_to(cr, t_p1p0.x(), t_p1p0.y());
+
+ addArc(p, radius, sa, ea, anticlockwise);
+}
+
+void Path::addEllipse(const FloatRect& rect)
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_save(cr);
+ float yRadius = .5 * rect.height();
+ float xRadius = .5 * rect.width();
+ cairo_translate(cr, rect.x() + xRadius, rect.y() + yRadius);
+ cairo_scale(cr, xRadius, yRadius);
+ cairo_arc(cr, 0., 0., 1., 0., 2 * piDouble);
+ cairo_restore(cr);
+}
+
+void Path::closeSubpath()
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_close_path(cr);
+}
+
+FloatRect Path::boundingRect() const
+{
+ cairo_t* cr = platformPath()->context();
+ double x0, x1, y0, y1;
+ cairo_path_extents(cr, &x0, &y0, &x1, &y1);
+ return FloatRect(x0, y0, x1 - x0, y1 - y0);
+}
+
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+ cairo_t* cr = platformPath()->context();
+ if (applier) {
+ GraphicsContext gc(cr);
+ applier->strokeStyle(&gc);
+ }
+
+ double x0, x1, y0, y1;
+ cairo_stroke_extents(cr, &x0, &y0, &x1, &y1);
+ return FloatRect(x0, y0, x1 - x0, y1 - y0);
+}
+
+bool Path::contains(const FloatPoint& point, WindRule rule) const
+{
+ if (!isfinite(point.x()) || !isfinite(point.y()))
+ return false;
+ cairo_t* cr = platformPath()->context();
+ cairo_fill_rule_t cur = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, rule == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
+ bool contains = cairo_in_fill(cr, point.x(), point.y());
+ cairo_set_fill_rule(cr, cur);
+ return contains;
+}
+
+bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const
+{
+ ASSERT(applier);
+ cairo_t* cr = platformPath()->context();
+ GraphicsContext gc(cr);
+ applier->strokeStyle(&gc);
+
+ return cairo_in_stroke(cr, point.x(), point.y());
+}
+
+void Path::apply(void* info, PathApplierFunction function) const
+{
+ cairo_t* cr = platformPath()->context();
+ OwnPtr<cairo_path_t> path(cairo_copy_path(cr));
+ cairo_path_data_t* data;
+ PathElement pelement;
+ FloatPoint points[3];
+ pelement.points = points;
+
+ for (int i = 0; i < path->num_data; i += path->data[i].header.length) {
+ data = &path->data[i];
+ switch (data->header.type) {
+ case CAIRO_PATH_MOVE_TO:
+ pelement.type = PathElementMoveToPoint;
+ pelement.points[0] = FloatPoint(data[1].point.x,data[1].point.y);
+ function(info, &pelement);
+ break;
+ case CAIRO_PATH_LINE_TO:
+ pelement.type = PathElementAddLineToPoint;
+ pelement.points[0] = FloatPoint(data[1].point.x,data[1].point.y);
+ function(info, &pelement);
+ break;
+ case CAIRO_PATH_CURVE_TO:
+ pelement.type = PathElementAddCurveToPoint;
+ pelement.points[0] = FloatPoint(data[1].point.x,data[1].point.y);
+ pelement.points[1] = FloatPoint(data[2].point.x,data[2].point.y);
+ pelement.points[2] = FloatPoint(data[3].point.x,data[3].point.y);
+ function(info, &pelement);
+ break;
+ case CAIRO_PATH_CLOSE_PATH:
+ pelement.type = PathElementCloseSubpath;
+ function(info, &pelement);
+ break;
+ }
+ }
+}
+
+void Path::transform(const AffineTransform& trans)
+{
+ cairo_t* cr = platformPath()->context();
+ cairo_matrix_t c_matrix = cairo_matrix_t(trans);
+ cairo_matrix_invert(&c_matrix);
+ cairo_transform(cr, &c_matrix);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/cairo/PatternCairo.cpp b/Source/WebCore/platform/graphics/cairo/PatternCairo.cpp
new file mode 100644
index 0000000..b067acc
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/PatternCairo.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * 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
+ * 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
+ * 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
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Pattern.h"
+
+#include "AffineTransform.h"
+#include "GraphicsContext.h"
+
+#include <cairo.h>
+
+namespace WebCore {
+
+cairo_pattern_t* Pattern::createPlatformPattern(const AffineTransform&) const
+{
+ cairo_surface_t* surface = tileImage()->nativeImageForCurrentFrame();
+ if (!surface)
+ return 0;
+
+ cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surface);
+
+ // cairo merges patter space and user space itself
+ cairo_matrix_t matrix = m_patternSpaceTransformation;
+ cairo_matrix_invert(&matrix);
+ cairo_pattern_set_matrix(pattern, &matrix);
+
+ if (m_repeatX || m_repeatY)
+ cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
+ return pattern;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp
new file mode 100644
index 0000000..c8b242c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "RefPtrCairo.h"
+
+#include <cairo.h>
+
+#if defined(USE_FREETYPE)
+#include <cairo-ft.h>
+#include <fontconfig/fcfreetype.h>
+#endif
+
+namespace WTF {
+
+template<> void refIfNotNull(cairo_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_reference(ptr);
+}
+
+template<> void derefIfNotNull(cairo_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_destroy(ptr);
+}
+
+template<> void refIfNotNull(cairo_surface_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_surface_reference(ptr);
+}
+
+template<> void derefIfNotNull(cairo_surface_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_surface_destroy(ptr);
+}
+
+template<> void refIfNotNull(cairo_font_face_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_font_face_reference(ptr);
+}
+
+template<> void derefIfNotNull(cairo_font_face_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_font_face_reference(ptr);
+}
+
+template<> void refIfNotNull(cairo_scaled_font_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_scaled_font_reference(ptr);
+}
+
+template<> void derefIfNotNull(cairo_scaled_font_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_scaled_font_destroy(ptr);
+}
+
+template<> void refIfNotNull(cairo_pattern_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_pattern_reference(ptr);
+}
+
+template<> void derefIfNotNull(cairo_pattern_t* ptr)
+{
+ if (LIKELY(ptr != 0))
+ cairo_pattern_destroy(ptr);
+}
+
+#if defined(USE_FREETYPE)
+template<> void refIfNotNull(FcPattern* ptr)
+{
+ if (LIKELY(ptr != 0))
+ FcPatternReference(ptr);
+}
+
+template<> void derefIfNotNull(FcPattern* ptr)
+{
+ if (LIKELY(ptr != 0))
+ FcPatternDestroy(ptr);
+}
+
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/cairo/RefPtrCairo.h b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.h
new file mode 100644
index 0000000..204d1e3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef RefPtrCairo_h
+#define RefPtrCairo_h
+
+#include "RefPtr.h"
+
+typedef struct _cairo cairo_t;
+typedef struct _cairo_surface cairo_surface_t;
+typedef struct _cairo_font_face cairo_font_face_t;
+typedef struct _cairo_scaled_font cairo_scaled_font_t;
+typedef struct _cairo_pattern cairo_pattern_t;
+
+#if defined(USE_FREETYPE)
+typedef struct _FcPattern FcPattern;
+#endif
+
+namespace WTF {
+
+template<> void refIfNotNull(cairo_t* ptr);
+template<> void derefIfNotNull(cairo_t* ptr);
+
+template<> void refIfNotNull(cairo_surface_t* ptr);
+template<> void derefIfNotNull(cairo_surface_t* ptr);
+
+template<> void refIfNotNull(cairo_font_face_t* ptr);
+template<> void derefIfNotNull(cairo_font_face_t* ptr);
+
+template<> void refIfNotNull(cairo_scaled_font_t* ptr);
+template<> void derefIfNotNull(cairo_scaled_font_t* ptr);
+
+template<> void refIfNotNull(cairo_pattern_t*);
+template<> void derefIfNotNull(cairo_pattern_t*);
+
+#if defined(USE_FREETYPE)
+template<> void refIfNotNull(FcPattern* ptr);
+template<> void derefIfNotNull(FcPattern* ptr);
+#endif
+
+}
+
+#endif // RefPtrCairo_h
diff --git a/Source/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp b/Source/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp
new file mode 100644
index 0000000..c73dd02
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp
@@ -0,0 +1,66 @@
+/*
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * 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
+ * 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
+ * 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
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AffineTransform.h"
+#include "TransformationMatrix.h"
+
+#include "IntRect.h"
+#include "FloatRect.h"
+
+#include <cairo.h>
+
+namespace WebCore {
+
+TransformationMatrix::operator cairo_matrix_t() const
+{
+ cairo_matrix_t m;
+
+ cairo_matrix_init (&m,
+ a(),
+ b(),
+ c(),
+ d(),
+ e(),
+ f());
+ return m;
+}
+
+AffineTransform::operator cairo_matrix_t() const
+{
+ cairo_matrix_t m;
+
+ cairo_matrix_init (&m,
+ a(),
+ b(),
+ c(),
+ d(),
+ e(),
+ f());
+ return m;
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/cairo/rgb24-hacks.txt b/Source/WebCore/platform/graphics/cairo/rgb24-hacks.txt
new file mode 100644
index 0000000..59f8070
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/rgb24-hacks.txt
@@ -0,0 +1,32 @@
+Index: cairo/src/cairo-win32-surface.c
+===================================================================
+--- cairo/src/cairo-win32-surface.c (revision 14498)
++++ cairo/src/cairo-win32-surface.c (working copy)
+@@ -824,8 +824,13 @@
+ * to figure out when we can use GDI. We don't have that checking
+ * anywhere at the moment, so just bail and use the fallback
+ * paths. */
+- if (surface->format != CAIRO_FORMAT_RGB24)
+- return CAIRO_INT_STATUS_UNSUPPORTED;
++ //if (surface->format != CAIRO_FORMAT_RGB24)
++ // return CAIRO_INT_STATUS_UNSUPPORTED;
++ // FIXME: We'll go ahead and optimize this now and just assume we're ok if
++ // the color has no alpha. Probably need to check various composite operators to
++ // get this exactly right.
++ if (color->alpha != 1.0)
++ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* Optimize for no destination alpha (surface->pixman_image is non-NULL for all
+ * surfaces with alpha.)
+@@ -1016,8 +1021,9 @@
+
+ /* We can only handle operator SOURCE or OVER with the destination
+ * having no alpha */
+- if ((op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) ||
+- (dst->format != CAIRO_FORMAT_RGB24))
++ if ((op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER))
++ // FIXME: It's not clear why ExtTextOut can't be called when the
++ // destination has alpha. Remove the RGB24 restriction. || (dst->format != CAIRO_FORMAT_RGB24))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* If we have a fallback mask clip set on the dst, we have
diff --git a/Source/WebCore/platform/graphics/cairo/scale-removal.txt b/Source/WebCore/platform/graphics/cairo/scale-removal.txt
new file mode 100644
index 0000000..47c0d70
--- /dev/null
+++ b/Source/WebCore/platform/graphics/cairo/scale-removal.txt
@@ -0,0 +1,13 @@
+Index: cairo/src/cairo-win32-private.h
+===================================================================
+--- cairo/src/cairo-win32-private.h (revision 14582)
++++ cairo/src/cairo-win32-private.h (working copy)
+@@ -39,7 +39,7 @@
+ #include <cairo-win32.h>
+ #include <cairoint.h>
+
+-#define WIN32_FONT_LOGICAL_SCALE 32
++#define WIN32_FONT_LOGICAL_SCALE 1
+
+ typedef struct _cairo_win32_surface {
+ cairo_surface_t base;