diff options
Diffstat (limited to 'Source/WebCore/platform/graphics/cairo')
34 files changed, 1897 insertions, 881 deletions
diff --git a/Source/WebCore/platform/graphics/cairo/BackingStoreBackendCairo.h b/Source/WebCore/platform/graphics/cairo/BackingStoreBackendCairo.h new file mode 100644 index 000000000..63828c761 --- /dev/null +++ b/Source/WebCore/platform/graphics/cairo/BackingStoreBackendCairo.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2011,2014 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 + */ + +#ifndef BackingStoreBackendCairo_h +#define BackingStoreBackendCairo_h + +#if USE(CAIRO) + +#include "IntRect.h" +#include "RefPtrCairo.h" +#include <wtf/FastMalloc.h> +#include <wtf/Noncopyable.h> + +typedef struct _cairo_surface cairo_surface_t; + +namespace WebCore { + +class BackingStoreBackendCairo { + WTF_MAKE_NONCOPYABLE(BackingStoreBackendCairo); + WTF_MAKE_FAST_ALLOCATED; +public: + virtual ~BackingStoreBackendCairo() { } + + cairo_surface_t* surface() const { return m_surface.get(); } + const IntSize& size() const { return m_size; } + + virtual void scroll(const IntRect& scrollRect, const IntSize& scrollOffset) = 0; + +protected: + BackingStoreBackendCairo(const IntSize& size) + : m_size(size) + { + } + + RefPtr<cairo_surface_t> m_surface; + IntSize m_size; +}; + + +} // namespace WebCore + +#endif // USE(CAIRO) + +#endif // BackingStoreBackendCairo_h diff --git a/Source/WebCore/platform/graphics/cairo/BackingStoreBackendCairoImpl.cpp b/Source/WebCore/platform/graphics/cairo/BackingStoreBackendCairoImpl.cpp new file mode 100644 index 000000000..40d06dbf8 --- /dev/null +++ b/Source/WebCore/platform/graphics/cairo/BackingStoreBackendCairoImpl.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2011,2014 Igalia S.L. + * Copyright (C) 2011 Samsung Electronics + * + * 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 "BackingStoreBackendCairoImpl.h" + +#if USE(CAIRO) + +#include "CairoUtilities.h" + +namespace WebCore { + +BackingStoreBackendCairoImpl::BackingStoreBackendCairoImpl(cairo_surface_t* surface, const IntSize& size) + : BackingStoreBackendCairo(size) +{ + m_surface = surface; + + // We keep two copies of the surface here, which will double the memory usage, but increase + // scrolling performance since we do not have to keep reallocating a memory region during + // quick scrolling requests. + double xScale, yScale; + cairoSurfaceGetDeviceScale(m_surface.get(), xScale, yScale); + IntSize scaledSize = size; + scaledSize.scale(xScale, yScale); + m_scrollSurface = adoptRef(cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR_ALPHA, scaledSize.width(), scaledSize.height())); +} + +BackingStoreBackendCairoImpl::~BackingStoreBackendCairoImpl() +{ +} + +void BackingStoreBackendCairoImpl::scroll(const IntRect& scrollRect, const IntSize& scrollOffset) +{ + IntRect targetRect = scrollRect; + targetRect.move(scrollOffset); + targetRect.shiftMaxXEdgeTo(targetRect.maxX() - scrollOffset.width()); + targetRect.shiftMaxYEdgeTo(targetRect.maxY() - scrollOffset.height()); + if (targetRect.isEmpty()) + return; + + copyRectFromOneSurfaceToAnother(m_surface.get(), m_scrollSurface.get(), scrollOffset, targetRect); + copyRectFromOneSurfaceToAnother(m_scrollSurface.get(), m_surface.get(), IntSize(), targetRect); +} + +} // namespace WebCore + +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/BackingStoreBackendCairoImpl.h b/Source/WebCore/platform/graphics/cairo/BackingStoreBackendCairoImpl.h new file mode 100644 index 000000000..b1a0149bb --- /dev/null +++ b/Source/WebCore/platform/graphics/cairo/BackingStoreBackendCairoImpl.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2013,2014 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 + */ + +#ifndef BackingStoreBackendCairoImpl_h +#define BackingStoreBackendCairoImpl_h + +#include "BackingStoreBackendCairo.h" + +#if USE(CAIRO) + +namespace WebCore { + +class BackingStoreBackendCairoImpl final : public BackingStoreBackendCairo { +public: + BackingStoreBackendCairoImpl(cairo_surface_t*, const IntSize&); + virtual ~BackingStoreBackendCairoImpl(); + + void scroll(const IntRect&, const IntSize&) override; + +private: + RefPtr<cairo_surface_t> m_scrollSurface; +}; + +} // namespace WebCore + +#endif // USE(CAIRO) + +#endif // BackingStoreBackendCairoImpl_h diff --git a/Source/WebCore/platform/graphics/cairo/BackingStoreBackendCairoX11.cpp b/Source/WebCore/platform/graphics/cairo/BackingStoreBackendCairoX11.cpp new file mode 100644 index 000000000..437dafc82 --- /dev/null +++ b/Source/WebCore/platform/graphics/cairo/BackingStoreBackendCairoX11.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2011,2014 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 "BackingStoreBackendCairoX11.h" + +#if USE(CAIRO) && PLATFORM(X11) + +#include "CairoUtilities.h" +#include <cairo-xlib.h> + +namespace WebCore { + +BackingStoreBackendCairoX11::BackingStoreBackendCairoX11(unsigned long rootWindowID, Visual* visual, int depth, const IntSize& size, float deviceScaleFactor) + : BackingStoreBackendCairo(size) +{ + IntSize scaledSize = size; + scaledSize.scale(deviceScaleFactor); + + auto* display = downcast<PlatformDisplayX11>(PlatformDisplay::sharedDisplay()).native(); + m_pixmap = XCreatePixmap(display, rootWindowID, scaledSize.width(), scaledSize.height(), depth); + m_gc.reset(XCreateGC(display, m_pixmap.get(), 0, nullptr)); + + m_surface = adoptRef(cairo_xlib_surface_create(display, m_pixmap.get(), visual, scaledSize.width(), scaledSize.height())); + cairoSurfaceSetDeviceScale(m_surface.get(), deviceScaleFactor, deviceScaleFactor); +} + +BackingStoreBackendCairoX11::~BackingStoreBackendCairoX11() +{ + // The pixmap needs to exist when the surface is destroyed, so begin by clearing it. + m_surface = nullptr; +} + +void BackingStoreBackendCairoX11::scroll(const IntRect& scrollRect, const IntSize& scrollOffset) +{ + IntRect targetRect = scrollRect; + targetRect.move(scrollOffset); + targetRect.intersect(scrollRect); + if (targetRect.isEmpty()) + return; + + double xScale, yScale; + cairoSurfaceGetDeviceScale(m_surface.get(), xScale, yScale); + ASSERT(xScale == yScale); + + IntSize scaledScrollOffset = scrollOffset; + targetRect.scale(xScale); + scaledScrollOffset.scale(xScale, yScale); + + cairo_surface_flush(m_surface.get()); + XCopyArea(downcast<PlatformDisplayX11>(PlatformDisplay::sharedDisplay()).native(), m_pixmap.get(), m_pixmap.get(), m_gc.get(), + targetRect.x() - scaledScrollOffset.width(), targetRect.y() - scaledScrollOffset.height(), + targetRect.width(), targetRect.height(), targetRect.x(), targetRect.y()); + cairo_surface_mark_dirty_rectangle(m_surface.get(), targetRect.x(), targetRect.y(), targetRect.width(), targetRect.height()); +} + +} // namespace WebCore + +#endif // USE(CAIRO) && PLATFORM(X11) diff --git a/Source/WebCore/platform/graphics/cairo/BackingStoreBackendCairoX11.h b/Source/WebCore/platform/graphics/cairo/BackingStoreBackendCairoX11.h new file mode 100644 index 000000000..3441809f5 --- /dev/null +++ b/Source/WebCore/platform/graphics/cairo/BackingStoreBackendCairoX11.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2013,2014 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 + */ + +#ifndef BackingStoreBackendCairoX11_h +#define BackingStoreBackendCairoX11_h + +#include "BackingStoreBackendCairo.h" + +#if USE(CAIRO) && PLATFORM(X11) +#include "XUniquePtr.h" +#include "XUniqueResource.h" + +namespace WebCore { + +class BackingStoreBackendCairoX11 final : public BackingStoreBackendCairo { +public: + BackingStoreBackendCairoX11(unsigned long rootWindowID, Visual*, int depth, const IntSize&, float deviceScaleFactor); + virtual ~BackingStoreBackendCairoX11(); + + void scroll(const IntRect& scrollRect, const IntSize& scrollOffset) override; + +private: + XUniquePixmap m_pixmap; + XUniqueGC m_gc; +}; + +} // namespace WebCore + +#endif // USE(CAIRO) && PLATFORM(X11) + +#endif // GtkWidgetBackingStoreX11_h diff --git a/Source/WebCore/platform/graphics/cairo/BitmapImageCairo.cpp b/Source/WebCore/platform/graphics/cairo/BitmapImageCairo.cpp deleted file mode 100644 index 4611a306a..000000000 --- a/Source/WebCore/platform/graphics/cairo/BitmapImageCairo.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * 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" - -#include "CairoUtilities.h" -#include "ImageObserver.h" -#include "PlatformContextCairo.h" -#include "Timer.h" -#include <cairo.h> - -namespace WebCore { - -BitmapImage::BitmapImage(PassRefPtr<cairo_surface_t> nativeImage, ImageObserver* observer) - : Image(observer) - , m_size(cairoSurfaceSize(nativeImage.get())) - , m_currentFrame(0) - , m_repetitionCount(cAnimationNone) - , m_repetitionCountStatus(Unknown) - , m_repetitionsComplete(0) - , m_decodedSize(m_size.width() * m_size.height() * 4) - , m_frameCount(1) - , m_isSolidColor(false) - , m_checkedForSolidColor(false) - , m_animationFinished(true) - , m_allDataReceived(true) - , m_haveSize(true) - , m_sizeAvailable(true) - , m_haveFrameCount(true) -{ - m_frames.grow(1); - m_frames[0].m_hasAlpha = cairo_surface_get_content(nativeImage.get()) != CAIRO_CONTENT_COLOR; - m_frames[0].m_frame = nativeImage; - m_frames[0].m_haveMetadata = true; - - checkForSolidColor(); -} - -void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op, - BlendMode blendMode, ImageOrientationDescription description) -{ - if (!dst.width() || !dst.height() || !src.width() || !src.height()) - return; - - startAnimation(); - - RefPtr<cairo_surface_t> surface = frameAtIndex(m_currentFrame); - if (!surface) // If it's too early we won't have an image yet. - return; - - if (mayFillWithSolidColor()) { - fillWithSolidColor(context, dst, solidColor(), styleColorSpace, op); - return; - } - - context->save(); - - // Set the compositing operation. - if (op == CompositeSourceOver && blendMode == BlendModeNormal && !frameHasAlphaAtIndex(m_currentFrame)) - context->setCompositeOperation(CompositeCopy); - else - context->setCompositeOperation(op, blendMode); - -#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) - IntSize scaledSize = cairoSurfaceSize(surface.get()); - FloatRect adjustedSrcRect = adjustSourceRectForDownSampling(src, scaledSize); -#else - FloatRect adjustedSrcRect(src); -#endif - - ImageOrientation frameOrientation(description.imageOrientation()); - if (description.respectImageOrientation() == RespectImageOrientation) - frameOrientation = frameOrientationAtIndex(m_currentFrame); - - FloatRect dstRect = dst; - - if (frameOrientation != DefaultImageOrientation) { - // ImageOrientation expects the origin to be at (0, 0). - context->translate(dstRect.x(), dstRect.y()); - dstRect.setLocation(FloatPoint()); - context->concatCTM(frameOrientation.transformFromDefault(dstRect.size())); - if (frameOrientation.usesWidthAsHeight()) { - // The destination rectangle will have it's width and height already reversed for the orientation of - // the image, as it was needed for page layout, so we need to reverse it back here. - dstRect = FloatRect(dstRect.x(), dstRect.y(), dstRect.height(), dstRect.width()); - } - } - - context->platformContext()->drawSurfaceToContext(surface.get(), dstRect, adjustedSrcRect, context); - - context->restore(); - - if (imageObserver()) - imageObserver()->didDraw(this); -} - -void BitmapImage::checkForSolidColor() -{ - m_isSolidColor = false; - m_checkedForSolidColor = true; - - if (frameCount() > 1) - return; - - RefPtr<cairo_surface_t> surface = frameAtIndex(m_currentFrame); - if (!surface) // If it's too early we won't have an image yet. - return; - - if (cairo_surface_get_type(surface.get()) != CAIRO_SURFACE_TYPE_IMAGE) - return; - - IntSize size = cairoSurfaceSize(surface.get()); - - if (size.width() != 1 || size.height() != 1) - return; - - unsigned* pixelColor = reinterpret_cast_ptr<unsigned*>(cairo_image_surface_get_data(surface.get())); - m_solidColor = colorFromPremultipliedARGB(*pixelColor); - - m_isSolidColor = true; -} - -bool FrameData::clear(bool clearMetadata) -{ - if (clearMetadata) - m_haveMetadata = false; - - if (m_frame) { - m_frame.clear(); - return true; - } - return false; -} - -} // namespace WebCore - diff --git a/Source/WebCore/platform/graphics/cairo/DrawingBufferCairo.cpp b/Source/WebCore/platform/graphics/cairo/CairoUniquePtr.h index 738e49381..f7a5007d2 100644 --- a/Source/WebCore/platform/graphics/cairo/DrawingBufferCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/CairoUniquePtr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2016 Igalia S.L. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -13,38 +13,35 @@ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" +#pragma once -#if ENABLE(ACCELERATED_2D_CANVAS) || USE(3D_GRAPHICS) - -#include "DrawingBuffer.h" - -#include "Extensions3D.h" +#include <cairo.h> +#include <memory> namespace WebCore { -#if USE(ACCELERATED_COMPOSITING) - -unsigned DrawingBuffer::frontColorBuffer() const -{ - return colorBuffer(); -} +template<typename T> struct CairoPtrDeleter { + void operator()(T* ptr) const = delete; +}; -void DrawingBuffer::paintCompositedResultsToCanvas(ImageBuffer*) -{ -} -#endif +template<typename T> +using CairoUniquePtr = std::unique_ptr<T, CairoPtrDeleter<T>>; -} +template<> struct CairoPtrDeleter<cairo_font_options_t> { + void operator() (cairo_font_options_t* ptr) const + { + cairo_font_options_destroy(ptr); + } +}; -#endif +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp b/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp index 98207e4b2..8a3ff33d0 100644 --- a/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp +++ b/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -27,16 +27,19 @@ #include "config.h" #include "CairoUtilities.h" +#if USE(CAIRO) + #include "AffineTransform.h" #include "Color.h" #include "FloatPoint.h" #include "FloatRect.h" #include "IntRect.h" -#include "OwnPtrCairo.h" #include "Path.h" #include "PlatformPathCairo.h" #include "RefPtrCairo.h" +#include "Region.h" #include <wtf/Assertions.h> +#include <wtf/NeverDestroyed.h> #include <wtf/Vector.h> #if ENABLE(ACCELERATED_2D_CANVAS) @@ -45,6 +48,14 @@ namespace WebCore { +#if USE(FREETYPE) && !PLATFORM(GTK) +const cairo_font_options_t* getDefaultCairoFontOptions() +{ + static NeverDestroyed<cairo_font_options_t*> options = cairo_font_options_create(); + return options; +} +#endif + void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr) { cairo_set_antialias(dstCr, cairo_get_antialias(srcCr)); @@ -64,15 +75,20 @@ void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr) void setSourceRGBAFromColor(cairo_t* context, const Color& color) { - float red, green, blue, alpha; - color.getRGBA(red, green, blue, alpha); - cairo_set_source_rgba(context, red, green, blue, alpha); + if (color.isExtended()) + cairo_set_source_rgba(context, color.asExtended().red(), color.asExtended().green(), color.asExtended().blue(), color.asExtended().alpha()); + else { + float red, green, blue, alpha; + color.getRGBA(red, green, blue, alpha); + cairo_set_source_rgba(context, red, green, blue, alpha); + } } void appendPathToCairoContext(cairo_t* to, cairo_t* from) { - OwnPtr<cairo_path_t> cairoPath = adoptPtr(cairo_copy_path(from)); - cairo_append_path(to, cairoPath.get()); + auto cairoPath = cairo_copy_path(from); + cairo_append_path(to, cairoPath); + cairo_path_destroy(cairoPath); } void setPathOnCairoContext(cairo_t* to, cairo_t* from) @@ -101,7 +117,7 @@ void appendRegionToCairoContext(cairo_t* to, const cairo_region_t* region) } } -cairo_operator_t toCairoOperator(CompositeOperator op) +static cairo_operator_t toCairoCompositeOperator(CompositeOperator op) { switch (op) { case CompositeClear: @@ -136,11 +152,12 @@ cairo_operator_t toCairoOperator(CompositeOperator op) return CAIRO_OPERATOR_SOURCE; } } -cairo_operator_t toCairoOperator(BlendMode blendOp) + +cairo_operator_t toCairoOperator(CompositeOperator op, BlendMode blendOp) { switch (blendOp) { case BlendModeNormal: - return CAIRO_OPERATOR_OVER; + return toCairoCompositeOperator(op); case BlendModeMultiply: return CAIRO_OPERATOR_MULTIPLY; case BlendModeScreen: @@ -198,8 +215,46 @@ void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSiz cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); + // Due to a limitation in pixman, cairo cannot handle transformation matrices with values bigger than 32768. If the value is + // bigger, cairo is not able to paint anything, and this is the reason for the missing backgrounds reported in + // https://bugs.webkit.org/show_bug.cgi?id=154283. + + // When drawing a pattern there are 2 matrices that can overflow this limitation, and they are the current transformation + // matrix (which translates user space coordinates to coordinates of the output device) and the pattern matrix (which translates + // user space coordinates to pattern coordinates). The overflow happens only in the translation components of the matrices. + + // To avoid the problem in the transformation matrix what we do is remove the translation components of the transformation matrix + // and perform the translation by moving the destination rectangle instead. For this, we get its translation components (which are in + // device coordinates) and divide them by the scale factor to take them to user space coordinates. Then we move the transformation + // matrix by the opposite of that amount (which will zero the translation components of the transformation matrix), and move + // the destination rectangle by the same amount. We also need to apply the same translation to the pattern matrix, so we get the + // same pattern coordinates for the new destination rectangle. + + cairo_matrix_t ctm; + cairo_get_matrix(cr, &ctm); + double dx = 0, dy = 0; + cairo_matrix_transform_point(&ctm, &dx, &dy); + double xScale = 1, yScale = 1; + cairo_matrix_transform_distance(&ctm, &xScale, &yScale); + + dx = dx / xScale; + dy = dy / yScale; + cairo_translate(cr, -dx, -dy); + FloatRect adjustedDestRect(destRect); + adjustedDestRect.move(dx, dy); + + // Regarding the pattern matrix, what we do is reduce the translation component of the matrix taking advantage of the fact that we + // are drawing a repeated pattern. This means that, assuming that (w, h) is the size of the pattern, samplig it at (x, y) is the same + // than sampling it at (x mod w, y mod h), so we transform the translation component of the pattern matrix in that way. + cairo_matrix_t patternMatrix = cairo_matrix_t(patternTransform); - cairo_matrix_t phaseMatrix = {1, 0, 0, 1, phase.x() + tileRect.x() * patternTransform.a(), phase.y() + tileRect.y() * patternTransform.d()}; + // dx and dy are added here as well to compensate the previous translation of the destination rectangle. + double phaseOffsetX = phase.x() + tileRect.x() * patternTransform.a() + dx; + double phaseOffsetY = phase.y() + tileRect.y() * patternTransform.d() + dy; + // this is where we perform the (x mod w, y mod h) metioned above, but with floats instead of integers. + phaseOffsetX -= std::trunc(phaseOffsetX / (tileRect.width() * patternTransform.a())) * tileRect.width() * patternTransform.a(); + phaseOffsetY -= std::trunc(phaseOffsetY / (tileRect.height() * patternTransform.d())) * tileRect.height() * patternTransform.d(); + cairo_matrix_t phaseMatrix = {1, 0, 0, 1, phaseOffsetX, phaseOffsetY}; cairo_matrix_t combined; cairo_matrix_multiply(&combined, &patternMatrix, &phaseMatrix); cairo_matrix_invert(&combined); @@ -208,13 +263,13 @@ void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSiz cairo_set_operator(cr, op); cairo_set_source(cr, pattern); cairo_pattern_destroy(pattern); - cairo_rectangle(cr, destRect.x(), destRect.y(), destRect.width(), destRect.height()); + cairo_rectangle(cr, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height()); cairo_fill(cr); cairo_restore(cr); } -PassRefPtr<cairo_surface_t> copyCairoImageSurface(cairo_surface_t* originalSurface) +RefPtr<cairo_surface_t> copyCairoImageSurface(cairo_surface_t* originalSurface) { // Cairo doesn't provide a way to copy a cairo_surface_t. // See http://lists.cairographics.org/archives/cairo/2007-June/010877.html @@ -260,6 +315,29 @@ IntSize cairoSurfaceSize(cairo_surface_t* surface) } } +void flipImageSurfaceVertically(cairo_surface_t* surface) +{ + ASSERT(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE); + + IntSize size = cairoSurfaceSize(surface); + ASSERT(!size.isEmpty()); + + int stride = cairo_image_surface_get_stride(surface); + int halfHeight = size.height() / 2; + + uint8_t* source = static_cast<uint8_t*>(cairo_image_surface_get_data(surface)); + std::unique_ptr<uint8_t[]> tmp = std::make_unique<uint8_t[]>(stride); + + for (int i = 0; i < halfHeight; ++i) { + uint8_t* top = source + (i * stride); + uint8_t* bottom = source + ((size.height()-i-1) * stride); + + memcpy(tmp.get(), top, stride); + memcpy(top, bottom, stride); + memcpy(bottom, tmp.get(), stride); + } +} + void cairoSurfaceSetDeviceScale(cairo_surface_t* surface, double xScale, double yScale) { // This function was added pretty much simultaneous to when 1.13 was branched. @@ -271,4 +349,28 @@ void cairoSurfaceSetDeviceScale(cairo_surface_t* surface, double xScale, double ASSERT_UNUSED(yScale, 1 == yScale); #endif } + +void cairoSurfaceGetDeviceScale(cairo_surface_t* surface, double& xScale, double& yScale) +{ +#if HAVE(CAIRO_SURFACE_SET_DEVICE_SCALE) + cairo_surface_get_device_scale(surface, &xScale, &yScale); +#else + UNUSED_PARAM(surface); + xScale = 1; + yScale = 1; +#endif +} + +RefPtr<cairo_region_t> toCairoRegion(const Region& region) +{ + RefPtr<cairo_region_t> cairoRegion = adoptRef(cairo_region_create()); + for (const auto& rect : region.rects()) { + cairo_rectangle_int_t cairoRect = rect; + cairo_region_union_rectangle(cairoRegion.get(), &cairoRect); + } + return cairoRegion; +} + } // namespace WebCore + +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/CairoUtilities.h b/Source/WebCore/platform/graphics/cairo/CairoUtilities.h index df3680c01..9528e0210 100644 --- a/Source/WebCore/platform/graphics/cairo/CairoUtilities.h +++ b/Source/WebCore/platform/graphics/cairo/CairoUtilities.h @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -24,8 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CairoUtilities_h -#define CairoUtilities_h +#pragma once + +#if USE(CAIRO) #include "GraphicsTypes.h" #include "IntSize.h" @@ -34,6 +35,10 @@ // This function was added pretty much simultaneous to when 1.13 was branched. #define HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE CAIRO_VERSION_MAJOR > 1 || (CAIRO_VERSION_MAJOR == 1 && CAIRO_VERSION_MINOR >= 13) +#if USE(FREETYPE) +#include <cairo-ft.h> +#endif + namespace WebCore { class AffineTransform; class Color; @@ -42,6 +47,32 @@ class FloatPoint; class IntSize; class IntRect; class Path; +class Region; + +#if USE(FREETYPE) +class CairoFtFaceLocker { +public: + CairoFtFaceLocker(cairo_scaled_font_t* scaledFont) + : m_scaledFont(scaledFont) + , m_ftFace(cairo_ft_scaled_font_lock_face(scaledFont)) + { + } + + ~CairoFtFaceLocker() + { + if (m_ftFace) + cairo_ft_scaled_font_unlock_face(m_scaledFont); + } + + FT_Face ftFace() const { return m_ftFace; } + +private: + cairo_scaled_font_t* m_scaledFont { nullptr }; + FT_Face m_ftFace { nullptr }; +}; + +const cairo_font_options_t* getDefaultCairoFontOptions(); +#endif void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr); void setSourceRGBAFromColor(cairo_t*, const Color&); @@ -49,18 +80,21 @@ void appendPathToCairoContext(cairo_t* to, cairo_t* from); void setPathOnCairoContext(cairo_t* to, cairo_t* from); void appendWebCorePathToCairoContext(cairo_t* context, const Path& path); void appendRegionToCairoContext(cairo_t*, const cairo_region_t*); -cairo_operator_t toCairoOperator(CompositeOperator op); -cairo_operator_t toCairoOperator(BlendMode blendOp); +cairo_operator_t toCairoOperator(CompositeOperator, BlendMode = BlendModeNormal); 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); -PassRefPtr<cairo_surface_t> copyCairoImageSurface(cairo_surface_t*); +RefPtr<cairo_surface_t> copyCairoImageSurface(cairo_surface_t*); void copyRectFromCairoSurfaceToContext(cairo_surface_t* from, cairo_t* to, const IntSize& offset, const IntRect&); void copyRectFromOneSurfaceToAnother(cairo_surface_t* from, cairo_surface_t* to, const IntSize& offset, const IntRect&, const IntSize& = IntSize(), cairo_operator_t = CAIRO_OPERATOR_OVER); IntSize cairoSurfaceSize(cairo_surface_t*); +void flipImageSurfaceVertically(cairo_surface_t*); void cairoSurfaceSetDeviceScale(cairo_surface_t*, double xScale, double yScale); +void cairoSurfaceGetDeviceScale(cairo_surface_t*, double& xScale, double& yScale); + +RefPtr<cairo_region_t> toCairoRegion(const Region&); } // namespace WebCore -#endif // CairoUtilities_h +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h b/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h index 4eca4e4c5..ececc562d 100644 --- a/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h +++ b/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h @@ -21,11 +21,11 @@ * */ -#if USE(CAIRO) - #ifndef DrawErrorUnderline_h #define DrawErrorUnderline_h +#if USE(CAIRO) + #include <cairo.h> // @@ -101,6 +101,6 @@ static inline void drawErrorUnderline(cairo_t* cr, double x, double y, double wi cairo_fill(cr); } -#endif // DrawErrorUnderline_h +#endif // USE(CAIRO) -#endif +#endif // DrawErrorUnderline_h diff --git a/Source/WebCore/platform/graphics/cairo/FloatRectCairo.cpp b/Source/WebCore/platform/graphics/cairo/FloatRectCairo.cpp index 9f86f747e..ede90c90f 100644 --- a/Source/WebCore/platform/graphics/cairo/FloatRectCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/FloatRectCairo.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,6 +26,8 @@ #include "config.h" #include "FloatRect.h" +#if USE(CAIRO) + #include <cairo.h> namespace WebCore { @@ -43,3 +45,5 @@ FloatRect::operator cairo_rectangle_t() const } } // namespace WebCore + +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/FontCairo.cpp b/Source/WebCore/platform/graphics/cairo/FontCairo.cpp index a09e555d2..a712d0011 100644 --- a/Source/WebCore/platform/graphics/cairo/FontCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/FontCairo.cpp @@ -1,9 +1,10 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple 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 + * Copyright (C) 2014 Igalia S.L. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,10 +15,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -28,29 +29,32 @@ */ #include "config.h" -#include "Font.h" +#include "FontCascade.h" + +#if USE(CAIRO) #include "AffineTransform.h" #include "CairoUtilities.h" +#include "Font.h" #include "GlyphBuffer.h" #include "Gradient.h" #include "GraphicsContext.h" #include "ImageBuffer.h" #include "Pattern.h" #include "PlatformContextCairo.h" +#include "PlatformPathCairo.h" #include "ShadowBlur.h" -#include "SimpleFontData.h" namespace WebCore { -static void drawGlyphsToContext(cairo_t* context, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs) +static void drawGlyphsToContext(cairo_t* context, const Font& font, GlyphBufferGlyph* glyphs, unsigned numGlyphs) { cairo_matrix_t originalTransform; - float syntheticBoldOffset = font->syntheticBoldOffset(); + float syntheticBoldOffset = font.syntheticBoldOffset(); if (syntheticBoldOffset) cairo_get_matrix(context, &originalTransform); - cairo_set_scaled_font(context, font->platformData().scaledFont()); + cairo_set_scaled_font(context, font.platformData().scaledFont()); cairo_show_glyphs(context, glyphs, numGlyphs); if (syntheticBoldOffset) { @@ -62,21 +66,21 @@ static void drawGlyphsToContext(cairo_t* context, const SimpleFontData* font, Gl cairo_set_matrix(context, &originalTransform); } -static void drawGlyphsShadow(GraphicsContext* graphicsContext, const FloatPoint& point, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs) +static void drawGlyphsShadow(GraphicsContext& graphicsContext, const FloatPoint& point, const Font& font, GlyphBufferGlyph* glyphs, unsigned numGlyphs) { - ShadowBlur& shadow = graphicsContext->platformContext()->shadowBlur(); + ShadowBlur& shadow = graphicsContext.platformContext()->shadowBlur(); - if (!(graphicsContext->textDrawingMode() & TextModeFill) || shadow.type() == ShadowBlur::NoShadow) + if (!(graphicsContext.textDrawingMode() & TextModeFill) || shadow.type() == ShadowBlur::NoShadow) return; - if (!graphicsContext->mustUseShadowBlur()) { + if (!graphicsContext.mustUseShadowBlur()) { // Optimize non-blurry shadows, by just drawing text without the ShadowBlur. - cairo_t* context = graphicsContext->platformContext()->cr(); + cairo_t* context = graphicsContext.platformContext()->cr(); cairo_save(context); - FloatSize shadowOffset(graphicsContext->state().shadowOffset); + FloatSize shadowOffset(graphicsContext.state().shadowOffset); cairo_translate(context, shadowOffset.width(), shadowOffset.height()); - setSourceRGBAFromColor(context, graphicsContext->state().shadowColor); + setSourceRGBAFromColor(context, graphicsContext.state().shadowColor); drawGlyphsToContext(context, font, glyphs, numGlyphs); cairo_restore(context); @@ -84,7 +88,7 @@ static void drawGlyphsShadow(GraphicsContext* graphicsContext, const FloatPoint& } cairo_text_extents_t extents; - cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents); + cairo_scaled_font_glyph_extents(font.platformData().scaledFont(), glyphs, numGlyphs, &extents); FloatRect fontExtentsRect(point.x() + extents.x_bearing, point.y() + extents.y_bearing, extents.width, extents.height); if (GraphicsContext* shadowContext = shadow.beginShadowLayer(graphicsContext, fontExtentsRect)) { @@ -93,29 +97,29 @@ static void drawGlyphsShadow(GraphicsContext* graphicsContext, const FloatPoint& } } -void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, - int from, int numGlyphs, const FloatPoint& point) const +void FontCascade::drawGlyphs(GraphicsContext& context, const Font& font, const GlyphBuffer& glyphBuffer, + unsigned from, unsigned numGlyphs, const FloatPoint& point, FontSmoothingMode) { - if (!font->platformData().size()) + if (!font.platformData().size()) return; GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from)); float offset = point.x(); - for (int i = 0; i < numGlyphs; i++) { + for (unsigned i = 0; i < numGlyphs; i++) { glyphs[i].x = offset; glyphs[i].y = point.y(); offset += glyphBuffer.advanceAt(from + i).width(); } - PlatformContextCairo* platformContext = context->platformContext(); + PlatformContextCairo* platformContext = context.platformContext(); drawGlyphsShadow(context, point, font, glyphs, numGlyphs); cairo_t* cr = platformContext->cr(); cairo_save(cr); - if (context->textDrawingMode() & TextModeFill) { - platformContext->prepareForFilling(context->state(), PlatformContextCairo::AdjustPatternForGlobalAlpha); + if (context.textDrawingMode() & TextModeFill) { + platformContext->prepareForFilling(context.state(), PlatformContextCairo::AdjustPatternForGlobalAlpha); drawGlyphsToContext(cr, font, glyphs, numGlyphs); } @@ -123,12 +127,12 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons // 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) { - platformContext->prepareForStroking(context->state()); - cairo_set_line_width(cr, context->strokeThickness()); + if (context.textDrawingMode() & TextModeStroke && context.strokeThickness() < 2 * offset) { + platformContext->prepareForStroking(context.state()); + cairo_set_line_width(cr, context.strokeThickness()); // This may disturb the CTM, but we are going to call cairo_restore soon after. - cairo_set_scaled_font(cr, font->platformData().scaledFont()); + cairo_set_scaled_font(cr, font.platformData().scaledFont()); cairo_glyph_path(cr, glyphs, numGlyphs); cairo_stroke(cr); } @@ -136,4 +140,198 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons cairo_restore(cr); } +#if ENABLE(CSS3_TEXT_DECORATION_SKIP_INK) +struct GlyphIterationState { + GlyphIterationState(FloatPoint startingPoint, FloatPoint currentPoint, float centerOfLine, float minX, float maxX) + : startingPoint(startingPoint) + , currentPoint(currentPoint) + , centerOfLine(centerOfLine) + , minX(minX) + , maxX(maxX) + { + } + FloatPoint startingPoint; + FloatPoint currentPoint; + float centerOfLine; + float minX; + float maxX; +}; + +static bool findIntersectionPoint(float y, FloatPoint p1, FloatPoint p2, float& x) +{ + x = p1.x() + (y - p1.y()) * (p2.x() - p1.x()) / (p2.y() - p1.y()); + return (p1.y() < y && p2.y() > y) || (p1.y() > y && p2.y() < y); +} + +static void updateX(GlyphIterationState& state, float x) +{ + state.minX = std::min(state.minX, x); + state.maxX = std::max(state.maxX, x); +} + +// This function is called by Path::apply and is therefore invoked for each contour in a glyph. This +// function models each contours as a straight line and calculates the intersections between each +// pseudo-contour and the vertical center of the underline found in GlyphIterationState::centerOfLine. +// It keeps track of the leftmost and rightmost intersection in GlyphIterationState::minX and +// GlyphIterationState::maxX. +static void findPathIntersections(GlyphIterationState& state, const PathElement& element) +{ + bool doIntersection = false; + FloatPoint point = FloatPoint(); + switch (element.type) { + case PathElementMoveToPoint: + state.startingPoint = element.points[0]; + state.currentPoint = element.points[0]; + break; + case PathElementAddLineToPoint: + doIntersection = true; + point = element.points[0]; + break; + case PathElementAddQuadCurveToPoint: + doIntersection = true; + point = element.points[1]; + break; + case PathElementAddCurveToPoint: + doIntersection = true; + point = element.points[2]; + break; + case PathElementCloseSubpath: + doIntersection = true; + point = state.startingPoint; + break; + } + + if (!doIntersection) + return; + + float x; + if (findIntersectionPoint(state.centerOfLine, state.currentPoint, point, x)) + updateX(state, x); + + state.currentPoint = point; } + +class CairoGlyphToPathTranslator final : public GlyphToPathTranslator { +public: + CairoGlyphToPathTranslator(const TextRun& textRun, const GlyphBuffer& glyphBuffer, const FloatPoint& textOrigin) + : m_index(0) + , m_textRun(textRun) + , m_glyphBuffer(glyphBuffer) + , m_fontData(glyphBuffer.fontAt(m_index)) + , m_translation(AffineTransform().translate(textOrigin.x(), textOrigin.y())) + { + } + + bool containsMorePaths() final { return m_index != m_glyphBuffer.size(); } + Path path() final; + std::pair<float, float> extents() final; + GlyphUnderlineType underlineType() final; + void advance() final; + +private: + unsigned m_index; + const TextRun& m_textRun; + const GlyphBuffer& m_glyphBuffer; + const Font* m_fontData; + AffineTransform m_translation; +}; + +Path CairoGlyphToPathTranslator::path() +{ + Path path; + path.ensurePlatformPath(); + + cairo_glyph_t cairoGlyph = { m_glyphBuffer.glyphAt(m_index), 0, 0 }; + cairo_set_scaled_font(path.platformPath()->context(), m_fontData->platformData().scaledFont()); + cairo_glyph_path(path.platformPath()->context(), &cairoGlyph, 1); + + float syntheticBoldOffset = m_fontData->syntheticBoldOffset(); + if (syntheticBoldOffset) { + cairo_translate(path.platformPath()->context(), syntheticBoldOffset, 0); + cairo_show_glyphs(path.platformPath()->context(), &cairoGlyph, 1); + } + + path.transform(m_translation); + return path; +} + +std::pair<float, float> CairoGlyphToPathTranslator::extents() +{ + FloatPoint beginning = m_translation.mapPoint(FloatPoint()); + FloatSize end = m_translation.mapSize(m_glyphBuffer.advanceAt(m_index)); + return std::make_pair(static_cast<float>(beginning.x()), static_cast<float>(beginning.x() + end.width())); +} + +GlyphToPathTranslator::GlyphUnderlineType CairoGlyphToPathTranslator::underlineType() +{ + return computeUnderlineType(m_textRun, m_glyphBuffer, m_index); +} + +void CairoGlyphToPathTranslator::advance() +{ + GlyphBufferAdvance advance = m_glyphBuffer.advanceAt(m_index); + m_translation = m_translation.translate(advance.width(), advance.height()); + ++m_index; + if (m_index < m_glyphBuffer.size()) + m_fontData = m_glyphBuffer.fontAt(m_index); +} + +DashArray FontCascade::dashesForIntersectionsWithRect(const TextRun& run, const FloatPoint& textOrigin, const FloatRect& lineExtents) const +{ + if (isLoadingCustomFonts()) + return DashArray(); + + GlyphBuffer glyphBuffer; + glyphBuffer.saveOffsetsInString(); + float deltaX; + if (codePath(run) != FontCascade::Complex) + deltaX = getGlyphsAndAdvancesForSimpleText(run, 0, run.length(), glyphBuffer); + else + deltaX = getGlyphsAndAdvancesForComplexText(run, 0, run.length(), glyphBuffer); + + if (!glyphBuffer.size()) + return DashArray(); + + // FIXME: Handle SVG + non-SVG interleaved runs. https://bugs.webkit.org/show_bug.cgi?id=133778 + FloatPoint origin = FloatPoint(textOrigin.x() + deltaX, textOrigin.y()); + CairoGlyphToPathTranslator translator(run, glyphBuffer, origin); + DashArray result; + for (int index = 0; translator.containsMorePaths(); ++index, translator.advance()) { + float centerOfLine = lineExtents.y() + (lineExtents.height() / 2); + GlyphIterationState info = GlyphIterationState(FloatPoint(), FloatPoint(), centerOfLine, lineExtents.x() + lineExtents.width(), lineExtents.x()); + const Font* localFontData = glyphBuffer.fontAt(index); + if (!localFontData) { + // The advances will get all messed up if we do anything other than bail here. + result.clear(); + break; + } + switch (translator.underlineType()) { + case GlyphToPathTranslator::GlyphUnderlineType::SkipDescenders: { + Path path = translator.path(); + path.apply([&info](const PathElement& pathElement) { + findPathIntersections(info, pathElement); + }); + if (info.minX < info.maxX) { + result.append(info.minX - lineExtents.x()); + result.append(info.maxX - lineExtents.x()); + } + break; + } + case GlyphToPathTranslator::GlyphUnderlineType::SkipGlyph: { + std::pair<float, float> extents = translator.extents(); + result.append(extents.first - lineExtents.x()); + result.append(extents.second - lineExtents.x()); + break; + } + case GlyphToPathTranslator::GlyphUnderlineType::DrawOverGlyph: + // Nothing to do + break; + } + } + return result; +} +#endif // ENABLE(CSS3_TEXT_DECORATION_SKIP_INK) + +} // namespace WebCore + +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/FontCairoHarfbuzzNG.cpp b/Source/WebCore/platform/graphics/cairo/FontCairoHarfbuzzNG.cpp index 0c940c5d6..cc37d7d58 100644 --- a/Source/WebCore/platform/graphics/cairo/FontCairoHarfbuzzNG.cpp +++ b/Source/WebCore/platform/graphics/cairo/FontCairoHarfbuzzNG.cpp @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -25,48 +25,44 @@ */ #include "config.h" -#include "Font.h" +#include "FontCascade.h" + +#if USE(CAIRO) +#include "Font.h" #include "GraphicsContext.h" #include "HarfBuzzShaper.h" +#include "LayoutRect.h" #include "Logging.h" #include "NotImplemented.h" #include "PlatformContextCairo.h" -#include "SimpleFontData.h" #include <cairo.h> namespace WebCore { -float Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int, int) const +float FontCascade::getGlyphsAndAdvancesForComplexText(const TextRun& run, unsigned, unsigned, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot /* forTextEmphasis */) const { - GlyphBuffer glyphBuffer; HarfBuzzShaper shaper(this, run); - if (shaper.shape(&glyphBuffer)) { - FloatPoint startPoint = point; - float startX = startPoint.x(); - drawGlyphBuffer(context, run, glyphBuffer, startPoint); - return startPoint.x() - startX; + if (!shaper.shape(&glyphBuffer)) { + LOG_ERROR("Shaper couldn't shape glyphBuffer."); + return 0; } - LOG_ERROR("Shaper couldn't shape glyphBuffer."); - return 0; -} -void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const -{ - notImplemented(); + // FIXME: Mac returns an initial advance here. + return 0; } -bool Font::canReturnFallbackFontsForComplexText() +bool FontCascade::canReturnFallbackFontsForComplexText() { return false; } -bool Font::canExpandAroundIdeographsInComplexText() +bool FontCascade::canExpandAroundIdeographsInComplexText() { return false; } -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*, GlyphOverflow*) const +float FontCascade::floatWidthForComplexText(const TextRun& run, HashSet<const Font*>*, GlyphOverflow*) const { HarfBuzzShaper shaper(this, run); if (shaper.shape()) @@ -75,7 +71,7 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon return 0; } -int Font::offsetForPositionForComplexText(const TextRun& run, float x, bool) const +int FontCascade::offsetForPositionForComplexText(const TextRun& run, float x, bool) const { HarfBuzzShaper shaper(this, run); if (shaper.shape()) @@ -84,13 +80,18 @@ int Font::offsetForPositionForComplexText(const TextRun& run, float x, bool) con return 0; } -FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const +void FontCascade::adjustSelectionRectForComplexText(const TextRun& run, LayoutRect& selectionRect, unsigned from, unsigned to) const { HarfBuzzShaper shaper(this, run); - if (shaper.shape()) - return shaper.selectionRect(point, h, from, to); + if (shaper.shape()) { + // FIXME: This should mimic Mac port. + FloatRect rect = shaper.selectionRect(FloatPoint(selectionRect.location()), selectionRect.height().toInt(), from, to); + selectionRect = LayoutRect(rect); + return; + } LOG_ERROR("Shaper couldn't shape text run."); - return FloatRect(); } -} +} // namespace WebCore + +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h index 1514526c2..c95ef9b5b 100644 --- a/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h @@ -22,9 +22,9 @@ #ifndef FontCustomPlatformData_h #define FontCustomPlatformData_h -#include "FontOrientation.h" -#include "FontRenderingMode.h" -#include "FontWidthVariant.h" +#if USE(CAIRO) + +#include "TextFlags.h" #include <wtf/Forward.h> #include <wtf/Noncopyable.h> @@ -33,6 +33,7 @@ typedef struct _cairo_font_face cairo_font_face_t; namespace WebCore { +class FontDescription; class FontPlatformData; class SharedBuffer; @@ -41,16 +42,17 @@ struct FontCustomPlatformData { public: FontCustomPlatformData(FT_Face, SharedBuffer&); ~FontCustomPlatformData(); - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); + FontPlatformData fontPlatformData(const FontDescription&, bool bold, bool italic); static bool supportsFormat(const String&); private: - FT_Face m_freeTypeFace; cairo_font_face_t* m_fontFace; }; std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer&); -} +} // namespace WebCore + +#endif // USE(CAIRO) -#endif +#endif // FontCustomPlatformData_h diff --git a/Source/WebCore/platform/graphics/cairo/GradientCairo.cpp b/Source/WebCore/platform/graphics/cairo/GradientCairo.cpp index e0cfe3e65..724d832cc 100644 --- a/Source/WebCore/platform/graphics/cairo/GradientCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/GradientCairo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2007 Alp Toker <alp@atoker.com> * * Redistribution and use in source and binary forms, with or without @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -27,6 +27,8 @@ #include "config.h" #include "Gradient.h" +#if USE(CAIRO) + #include "GraphicsContext.h" #include "PlatformContextCairo.h" #include <cairo.h> @@ -106,4 +108,6 @@ void Gradient::fill(GraphicsContext* context, const FloatRect& rect) context->restore(); } -} //namespace +} // namespace WebCore + +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/GraphicsContext3DCairo.cpp b/Source/WebCore/platform/graphics/cairo/GraphicsContext3DCairo.cpp index 940265a9a..b4ae79e4a 100644 --- a/Source/WebCore/platform/graphics/cairo/GraphicsContext3DCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/GraphicsContext3DCairo.cpp @@ -12,10 +12,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -27,7 +27,9 @@ #include "config.h" -#if USE(3D_GRAPHICS) +#if USE(CAIRO) + +#if ENABLE(GRAPHICS_CONTEXT_3D) #include "GraphicsContext3D.h" #include "CairoUtilities.h" @@ -38,13 +40,11 @@ #include "PlatformContextCairo.h" #include "RefPtrCairo.h" #include <cairo.h> -#include <wtf/OwnPtr.h> -#include <wtf/PassOwnPtr.h> #if PLATFORM(WIN) -#include "GLSLANG/ShaderLang.h" +#include <GLSLANG/ShaderLang.h> #else -#include "ShaderLang.h" +#include <ANGLE/ShaderLang.h> #endif #if USE(OPENGL_ES_2) @@ -54,9 +54,13 @@ #include "OpenGLShims.h" #endif +#if USE(TEXTURE_MAPPER) +#include "TextureMapperGC3DPlatformLayer.h" +#endif + namespace WebCore { -PassRefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attributes, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle) +RefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3DAttributes attributes, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle) { // This implementation doesn't currently support rendering directly to the HostWindow. if (renderStyle == RenderDirectlyToHostWindow) @@ -73,24 +77,30 @@ PassRefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attri if (!success) return 0; - RefPtr<GraphicsContext3D> context = adoptRef(new GraphicsContext3D(attributes, hostWindow, renderStyle)); - return context.release(); + return adoptRef(new GraphicsContext3D(attributes, hostWindow, renderStyle)); } -GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attributes, HostWindow*, GraphicsContext3D::RenderStyle renderStyle) +GraphicsContext3D::GraphicsContext3D(GraphicsContext3DAttributes attributes, HostWindow*, GraphicsContext3D::RenderStyle renderStyle) : m_currentWidth(0) , m_currentHeight(0) - , m_compiler(isGLES2Compliant() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT) , m_attrs(attributes) , m_texture(0) , m_compositorTexture(0) , m_fbo(0) - , m_depthStencilBuffer(0) +#if USE(COORDINATED_GRAPHICS_THREADED) + , m_intermediateTexture(0) +#endif + , m_layerComposited(false) , m_multisampleFBO(0) , m_multisampleDepthStencilBuffer(0) , m_multisampleColorBuffer(0) - , m_private(GraphicsContext3DPrivate::create(this, renderStyle)) { +#if USE(TEXTURE_MAPPER) + m_texmapLayer = std::make_unique<TextureMapperGC3DPlatformLayer>(*this, renderStyle); +#else + m_private = std::make_unique<GraphicsContext3DPrivate>(this, renderStyle); +#endif + makeContextCurrent(); validateAttributes(); @@ -109,9 +119,24 @@ GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attributes, H ::glGenFramebuffers(1, &m_fbo); ::glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); - m_state.boundFBO = m_fbo; - if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth)) - ::glGenRenderbuffers(1, &m_depthStencilBuffer); +#if USE(COORDINATED_GRAPHICS_THREADED) + ::glGenTextures(1, &m_compositorTexture); + ::glBindTexture(GL_TEXTURE_2D, m_compositorTexture); + ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + ::glGenTextures(1, &m_intermediateTexture); + ::glBindTexture(GL_TEXTURE_2D, m_intermediateTexture); + ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + ::glBindTexture(GL_TEXTURE_2D, 0); +#endif + // Create a multisample FBO. if (m_attrs.antialias) { @@ -121,9 +146,51 @@ GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attributes, H ::glGenRenderbuffers(1, &m_multisampleColorBuffer); if (m_attrs.stencil || m_attrs.depth) ::glGenRenderbuffers(1, &m_multisampleDepthStencilBuffer); + } else { + // Bind canvas FBO. + glBindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); + m_state.boundFBO = m_fbo; +#if USE(OPENGL_ES_2) + if (m_attrs.depth) + glGenRenderbuffers(1, &m_depthBuffer); + if (m_attrs.stencil) + glGenRenderbuffers(1, &m_stencilBuffer); +#endif + if (m_attrs.stencil || m_attrs.depth) + glGenRenderbuffers(1, &m_depthStencilBuffer); } } +#if !USE(OPENGL_ES_2) + ::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + + if (GLContext::current()->version() >= 320) { + m_usingCoreProfile = true; + + // From version 3.2 on we use the OpenGL Core profile, so request that ouput to the shader compiler. + // OpenGL version 3.2 uses GLSL version 1.50. + m_compiler = ANGLEWebKitBridge(SH_GLSL_150_CORE_OUTPUT); + + // From version 3.2 on we use the OpenGL Core profile, and we need a VAO for rendering. + // A VAO could be created and bound by each component using GL rendering (TextureMapper, WebGL, etc). This is + // a simpler solution: the first GraphicsContext3D created on a GLContext will create and bind a VAO for that context. + GC3Dint currentVAO = 0; + getIntegerv(GraphicsContext3D::VERTEX_ARRAY_BINDING, ¤tVAO); + if (!currentVAO) { + m_vao = createVertexArray(); + bindVertexArray(m_vao); + } + } else { + // For lower versions request the compatibility output to the shader compiler. + m_compiler = ANGLEWebKitBridge(SH_GLSL_COMPATIBILITY_OUTPUT); + + // GL_POINT_SPRITE is needed in lower versions. + ::glEnable(GL_POINT_SPRITE); + } +#else + m_compiler = ANGLEWebKitBridge(SH_ESSL_OUTPUT); +#endif + // ANGLE initialization. ShBuiltInResources ANGLEResources; ShInitBuiltInResources(&ANGLEResources); @@ -145,18 +212,18 @@ GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attributes, H m_compiler.setResources(ANGLEResources); -#if !USE(OPENGL_ES_2) - ::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); - ::glEnable(GL_POINT_SPRITE); -#endif - ::glClearColor(0, 0, 0, 0); } GraphicsContext3D::~GraphicsContext3D() { +#if USE(TEXTURE_MAPPER) + if (m_texmapLayer->renderStyle() == RenderToCurrentGLContext) + return; +#else if (m_private->renderStyle() == RenderToCurrentGLContext) return; +#endif makeContextCurrent(); if (m_texture) @@ -169,11 +236,24 @@ GraphicsContext3D::~GraphicsContext3D() if (m_attrs.stencil || m_attrs.depth) ::glDeleteRenderbuffers(1, &m_multisampleDepthStencilBuffer); ::glDeleteFramebuffers(1, &m_multisampleFBO); - } else { - if (m_attrs.stencil || m_attrs.depth) + } else if (m_attrs.stencil || m_attrs.depth) { +#if USE(OPENGL_ES_2) + if (m_depthBuffer) + glDeleteRenderbuffers(1, &m_depthBuffer); + + if (m_stencilBuffer) + glDeleteRenderbuffers(1, &m_stencilBuffer); +#endif + if (m_depthStencilBuffer) ::glDeleteRenderbuffers(1, &m_depthStencilBuffer); } ::glDeleteFramebuffers(1, &m_fbo); +#if USE(COORDINATED_GRAPHICS_THREADED) + ::glDeleteTextures(1, &m_intermediateTexture); +#endif + + if (m_vao) + deleteVertexArray(m_vao); } GraphicsContext3D::ImageExtractor::~ImageExtractor() @@ -187,17 +267,21 @@ bool GraphicsContext3D::ImageExtractor::extractImage(bool premultiplyAlpha, bool if (!m_image) return false; // We need this to stay in scope because the native image is just a shallow copy of the data. - m_decoder = new ImageSource(premultiplyAlpha ? ImageSource::AlphaPremultiplied : ImageSource::AlphaNotPremultiplied, ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied); + AlphaOption alphaOption = premultiplyAlpha ? AlphaOption::Premultiplied : AlphaOption::NotPremultiplied; + GammaAndColorProfileOption gammaAndColorProfileOption = ignoreGammaAndColorProfile ? GammaAndColorProfileOption::Ignored : GammaAndColorProfileOption::Applied; + m_decoder = new ImageSource(nullptr, alphaOption, gammaAndColorProfileOption); + if (!m_decoder) return false; - ImageSource& decoder = *m_decoder; + ImageSource& decoder = *m_decoder; m_alphaOp = AlphaDoNothing; + if (m_image->data()) { decoder.setData(m_image->data(), true); - if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0)) + if (!decoder.frameCount()) return false; - m_imageSurface = decoder.createFrameAtIndex(0); + m_imageSurface = decoder.createFrameImageAtIndex(0); } else { m_imageSurface = m_image->nativeImageForCurrentFrame(); // 1. For texImage2D with HTMLVideoElment input, assume no PremultiplyAlpha had been applied and the alpha value is 0xFF for each pixel, @@ -209,9 +293,10 @@ bool GraphicsContext3D::ImageExtractor::extractImage(bool premultiplyAlpha, bool // if m_imageSurface is not an image, extract a copy of the surface if (m_imageSurface && cairo_surface_get_type(m_imageSurface.get()) != CAIRO_SURFACE_TYPE_IMAGE) { - RefPtr<cairo_surface_t> tmpSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, m_imageWidth, m_imageHeight)); - copyRectFromOneSurfaceToAnother(m_imageSurface.get(), tmpSurface.get(), IntSize(), IntRect(0, 0, m_imageWidth, m_imageHeight), IntSize(), CAIRO_OPERATOR_SOURCE); - m_imageSurface = tmpSurface.release(); + IntSize surfaceSize = cairoSurfaceSize(m_imageSurface.get()); + auto tmpSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, surfaceSize.width(), surfaceSize.height())); + copyRectFromOneSurfaceToAnother(m_imageSurface.get(), tmpSurface.get(), IntSize(), IntRect(IntPoint(), surfaceSize), IntSize(), CAIRO_OPERATOR_SOURCE); + m_imageSurface = WTFMove(tmpSurface); } } @@ -272,24 +357,37 @@ void GraphicsContext3D::paintToCanvas(const unsigned char* imagePixels, int imag context->restore(); } -void GraphicsContext3D::setContextLostCallback(PassOwnPtr<ContextLostCallback>) +void GraphicsContext3D::setContextLostCallback(std::unique_ptr<ContextLostCallback>) { } -void GraphicsContext3D::setErrorMessageCallback(PassOwnPtr<ErrorMessageCallback>) +void GraphicsContext3D::setErrorMessageCallback(std::unique_ptr<ErrorMessageCallback>) { } bool GraphicsContext3D::makeContextCurrent() { - if (!m_private) - return false; - return m_private->makeContextCurrent(); +#if USE(TEXTURE_MAPPER) + if (m_texmapLayer) + return m_texmapLayer->makeContextCurrent(); +#else + if (m_private) + return m_private->makeContextCurrent(); +#endif + return false; +} + +void GraphicsContext3D::checkGPUStatusIfNecessary() +{ } PlatformGraphicsContext3D GraphicsContext3D::platformGraphicsContext3D() { +#if USE(TEXTURE_MAPPER) + return m_texmapLayer->platformContext(); +#else return m_private->platformContext(); +#endif } Platform3DObject GraphicsContext3D::platformTexture() const @@ -306,13 +404,33 @@ bool GraphicsContext3D::isGLES2Compliant() const #endif } -#if USE(ACCELERATED_COMPOSITING) PlatformLayer* GraphicsContext3D::platformLayer() const { +#if USE(TEXTURE_MAPPER) + return m_texmapLayer.get(); +#else return m_private.get(); +#endif +} + +#if PLATFORM(GTK) +Extensions3D& GraphicsContext3D::getExtensions() +{ + if (!m_extensions) { +#if USE(OPENGL_ES_2) + // glGetStringi is not available on GLES2. + m_extensions = std::make_unique<Extensions3DOpenGLES>(this, false); +#else + // From OpenGL 3.2 on we use the Core profile, and there we must use glGetStringi. + m_extensions = std::make_unique<Extensions3DOpenGL>(this, GLContext::current()->version() >= 320); +#endif + } + return *m_extensions; } #endif } // namespace WebCore -#endif // USE(3D_GRAPHICS) +#endif // ENABLE(GRAPHICS_CONTEXT_3D) + +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index 0fa750396..ac4b4a089 100644 --- a/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple 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. @@ -17,10 +17,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -37,30 +37,29 @@ #include "AffineTransform.h" #include "CairoUtilities.h" +#include "DisplayListRecorder.h" #include "DrawErrorUnderline.h" #include "FloatConversion.h" #include "FloatRect.h" +#include "FloatRoundedRect.h" #include "Font.h" #include "GraphicsContextPlatformPrivateCairo.h" +#include "ImageBuffer.h" #include "IntRect.h" #include "NotImplemented.h" -#include "OwnPtrCairo.h" #include "Path.h" #include "Pattern.h" #include "PlatformContextCairo.h" #include "PlatformPathCairo.h" #include "RefPtrCairo.h" #include "ShadowBlur.h" -#include "SimpleFontData.h" #include "TransformationMatrix.h" #include <cairo.h> #include <math.h> #include <stdio.h> #include <wtf/MathExtras.h> -#if PLATFORM(GTK) -#include <gdk/gdk.h> -#elif PLATFORM(WIN) +#if PLATFORM(WIN) #include <cairo-win32.h> #endif @@ -71,36 +70,31 @@ namespace WebCore { // A helper which quickly fills a rectangle with a simple color fill. static inline void fillRectWithColor(cairo_t* cr, const FloatRect& rect, const Color& color) { - if (!color.alpha() && cairo_get_operator(cr) == CAIRO_OPERATOR_OVER) + if (!color.isVisible() && cairo_get_operator(cr) == CAIRO_OPERATOR_OVER) return; + setSourceRGBAFromColor(cr, color); cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); 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) +static inline void drawPathShadow(GraphicsContext& context, PathDrawingStyle drawingStyle) { - ShadowBlur& shadow = context->platformContext()->shadowBlur(); + ShadowBlur& shadow = context.platformContext()->shadowBlur(); if (shadow.type() == ShadowBlur::NoShadow) return; // Calculate the extents of the rendered solid paths. - cairo_t* cairoContext = context->platformContext()->cr(); - OwnPtr<cairo_path_t> path = adoptPtr(cairo_copy_path(cairoContext)); + cairo_t* cairoContext = context.platformContext()->cr(); + std::unique_ptr<cairo_path_t, void(*)(cairo_path_t*)> path(cairo_copy_path(cairoContext), [](cairo_path_t* path) { + cairo_path_destroy(path); + }); FloatRect solidFigureExtents; double x0 = 0; @@ -130,14 +124,14 @@ static inline void drawPathShadow(GraphicsContext* context, PathDrawingStyle dra if (drawingStyle & Fill) { cairo_save(cairoShadowContext); cairo_append_path(cairoShadowContext, path.get()); - shadowContext->platformContext()->prepareForFilling(context->state(), PlatformContextCairo::NoAdjustment); + shadowContext->platformContext()->prepareForFilling(context.state(), PlatformContextCairo::NoAdjustment); cairo_fill(cairoShadowContext); cairo_restore(cairoShadowContext); } if (drawingStyle & Stroke) { cairo_append_path(cairoShadowContext, path.get()); - shadowContext->platformContext()->prepareForStroking(context->state(), PlatformContextCairo::DoNotPreserveAlpha); + shadowContext->platformContext()->prepareForStroking(context.state(), PlatformContextCairo::DoNotPreserveAlpha); cairo_stroke(cairoShadowContext); } @@ -150,44 +144,45 @@ static inline void drawPathShadow(GraphicsContext* context, PathDrawingStyle dra cairo_append_path(cairoContext, path.get()); } -static inline void fillCurrentCairoPath(GraphicsContext* context) +static inline void fillCurrentCairoPath(GraphicsContext& context) { - cairo_t* cr = context->platformContext()->cr(); + cairo_t* cr = context.platformContext()->cr(); cairo_save(cr); - context->platformContext()->prepareForFilling(context->state(), PlatformContextCairo::AdjustPatternForGlobalAlpha); + context.platformContext()->prepareForFilling(context.state(), PlatformContextCairo::AdjustPatternForGlobalAlpha); cairo_fill(cr); cairo_restore(cr); } -static inline void shadowAndFillCurrentCairoPath(GraphicsContext* context) +static inline void shadowAndFillCurrentCairoPath(GraphicsContext& context) { drawPathShadow(context, Fill); fillCurrentCairoPath(context); } -static inline void shadowAndStrokeCurrentCairoPath(GraphicsContext* context) +static inline void shadowAndStrokeCurrentCairoPath(GraphicsContext& context) { drawPathShadow(context, Stroke); - context->platformContext()->prepareForStroking(context->state()); - cairo_stroke(context->platformContext()->cr()); + context.platformContext()->prepareForStroking(context.state()); + cairo_stroke(context.platformContext()->cr()); } GraphicsContext::GraphicsContext(cairo_t* cr) - : m_updatingControlTints(false), - m_transparencyCount(0) { + if (!cr) + return; + m_data = new GraphicsContextPlatformPrivateToplevel(new PlatformContextCairo(cr)); } void GraphicsContext::platformInit(PlatformContextCairo* platformContext) { + if (!platformContext) + return; + m_data = new GraphicsContextPlatformPrivate(platformContext); - if (platformContext) - m_data->syncContext(platformContext->cr()); - else - setPaintingDisabled(true); + m_data->syncContext(platformContext->cr()); } void GraphicsContext::platformDestroy() @@ -200,6 +195,11 @@ AffineTransform GraphicsContext::getCTM(IncludeDeviceScale) const if (paintingDisabled()) return AffineTransform(); + if (isRecording()) { + WTFLogAlways("GraphicsContext::getCTM() is not yet compatible with recording contexts."); + return AffineTransform(); + } + cairo_t* cr = platformContext()->cr(); cairo_matrix_t m; cairo_get_matrix(cr, &m); @@ -213,28 +213,34 @@ PlatformContextCairo* GraphicsContext::platformContext() const void GraphicsContext::savePlatformState() { + ASSERT(!isRecording()); platformContext()->save(); m_data->save(); } void GraphicsContext::restorePlatformState() { + ASSERT(!isRecording()); platformContext()->restore(); m_data->restore(); platformContext()->shadowBlur().setShadowValues(FloatSize(m_state.shadowBlur, m_state.shadowBlur), m_state.shadowOffset, m_state.shadowColor, - m_state.shadowColorSpace, m_state.shadowsIgnoreTransforms); } // Draws a filled rectangle with a stroked border. -void GraphicsContext::drawRect(const IntRect& rect) +void GraphicsContext::drawRect(const FloatRect& rect, float borderThickness) { if (paintingDisabled()) return; + if (isRecording()) { + m_displayListRecorder->drawRect(rect, borderThickness); + return; + } + ASSERT(!rect.isEmpty()); cairo_t* cr = platformContext()->cr(); @@ -247,108 +253,132 @@ void GraphicsContext::drawRect(const IntRect& rect) 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_set_line_width(cr, 1.0); // borderThickness? cairo_stroke(cr); } cairo_restore(cr); } -static double calculateStrokePatternOffset(int distance, int patternWidth) +void GraphicsContext::drawNativeImage(const NativeImagePtr& image, const FloatSize& imageSize, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode, ImageOrientation orientation) { - // 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 remainder = distance % patternWidth; - int numSegments = (distance - remainder) / patternWidth; + if (paintingDisabled()) + return; - // Special case 1px dotted borders for speed. - if (patternWidth == 1) - return 1; + if (isRecording()) { + m_displayListRecorder->drawNativeImage(image, imageSize, destRect, srcRect, op, blendMode, orientation); + return; + } - bool evenNumberOfSegments = !(numSegments % 2); - if (remainder) - evenNumberOfSegments = !evenNumberOfSegments; + platformContext()->save(); - if (evenNumberOfSegments) { - if (remainder) - return (patternWidth - remainder) + (remainder / 2); - return patternWidth / 2; + // Set the compositing operation. + if (op == CompositeSourceOver && blendMode == BlendModeNormal) + setCompositeOperation(CompositeCopy); + else + setCompositeOperation(op, blendMode); + + FloatRect dst = destRect; + + if (orientation != DefaultImageOrientation) { + // ImageOrientation expects the origin to be at (0, 0). + translate(dst.x(), dst.y()); + dst.setLocation(FloatPoint()); + concatCTM(orientation.transformFromDefault(dst.size())); + if (orientation.usesWidthAsHeight()) { + // The destination rectangle will have its width and height already reversed for the orientation of + // the image, as it was needed for page layout, so we need to reverse it back here. + dst = FloatRect(dst.x(), dst.y(), dst.height(), dst.width()); + } } - // Odd number of segments. - if (remainder) - return (patternWidth - remainder) / 2.f; - return 0; + platformContext()->drawSurfaceToContext(image.get(), dst, srcRect, *this); + platformContext()->restore(); } -static void drawLineOnCairoContext(GraphicsContext* graphicsContext, cairo_t* context, const FloatPoint& point1, const FloatPoint& point2) +// This is only used to draw borders, so we should not draw shadows. +void GraphicsContext::drawLine(const FloatPoint& point1, const FloatPoint& point2) { - StrokeStyle style = graphicsContext->strokeStyle(); - if (style == NoStroke) + if (paintingDisabled()) return; - const Color& strokeColor = graphicsContext->strokeColor(); - int strokeThickness = floorf(graphicsContext->strokeThickness()); - if (graphicsContext->strokeThickness() < 1) - strokeThickness = 1; + if (strokeStyle() == NoStroke) + return; - int patternWidth = 0; - if (style == DottedStroke) - patternWidth = strokeThickness; - else if (style == DashedStroke) - patternWidth = 3 * strokeThickness; + if (isRecording()) { + m_displayListRecorder->drawLine(point1, point2); + return; + } - bool isVerticalLine = point1.x() == point2.x(); - FloatPoint point1OnPixelBoundaries = point1; - FloatPoint point2OnPixelBoundaries = point2; - GraphicsContext::adjustLineToPixelBoundaries(point1OnPixelBoundaries, point2OnPixelBoundaries, strokeThickness, style); + const Color& strokeColor = this->strokeColor(); + float thickness = strokeThickness(); + bool isVerticalLine = (point1.x() + thickness == point2.x()); + float strokeWidth = isVerticalLine ? point2.y() - point1.y() : point2.x() - point1.x(); + if (!thickness || !strokeWidth) + return; - if (patternWidth) { - // 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. - FloatRect firstRect(point1OnPixelBoundaries, FloatSize(strokeThickness, strokeThickness)); - FloatRect secondRect(point2OnPixelBoundaries, FloatSize(strokeThickness, strokeThickness)); + cairo_t* cairoContext = platformContext()->cr(); + StrokeStyle strokeStyle = this->strokeStyle(); + float cornerWidth = 0; + bool drawsDashedLine = strokeStyle == DottedStroke || strokeStyle == DashedStroke; + + if (drawsDashedLine) { + cairo_save(cairoContext); + // Figure out end points to ensure we always paint corners. + cornerWidth = dashedLineCornerWidthForStrokeWidth(strokeWidth); if (isVerticalLine) { - firstRect.move(-strokeThickness / 2, -strokeThickness); - secondRect.move(-strokeThickness / 2, 0); + fillRectWithColor(cairoContext, FloatRect(point1.x(), point1.y(), thickness, cornerWidth), strokeColor); + fillRectWithColor(cairoContext, FloatRect(point1.x(), point2.y() - cornerWidth, thickness, cornerWidth), strokeColor); } else { - firstRect.move(-strokeThickness, -strokeThickness / 2); - secondRect.move(0, -strokeThickness / 2); + fillRectWithColor(cairoContext, FloatRect(point1.x(), point1.y(), cornerWidth, thickness), strokeColor); + fillRectWithColor(cairoContext, FloatRect(point2.x() - cornerWidth, point1.y(), cornerWidth, thickness), strokeColor); + } + strokeWidth -= 2 * cornerWidth; + float patternWidth = dashedLinePatternWidthForStrokeWidth(strokeWidth); + // Check if corner drawing sufficiently covers the line. + if (strokeWidth <= patternWidth + 1) { + cairo_restore(cairoContext); + return; } - fillRectWithColor(context, firstRect, strokeColor); - fillRectWithColor(context, secondRect, strokeColor); - int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2 * strokeThickness; - double patternOffset = calculateStrokePatternOffset(distance, patternWidth); - double patternWidthAsDouble = patternWidth; - cairo_set_dash(context, &patternWidthAsDouble, 1, patternOffset); + float patternOffset = dashedLinePatternOffsetForPatternAndStrokeWidth(patternWidth, strokeWidth); + const double dashedLine[2] = { static_cast<double>(patternWidth), static_cast<double>(patternWidth) }; + cairo_set_dash(cairoContext, dashedLine, 2, patternOffset); + } else { + setSourceRGBAFromColor(cairoContext, strokeColor); + if (thickness < 1) + cairo_set_line_width(cairoContext, 1); } - setSourceRGBAFromColor(context, strokeColor); - cairo_set_line_width(context, strokeThickness); - cairo_move_to(context, point1OnPixelBoundaries.x(), point1OnPixelBoundaries.y()); - cairo_line_to(context, point2OnPixelBoundaries.x(), point2OnPixelBoundaries.y()); - cairo_stroke(context); -} -// This is only used to draw borders, so we should not draw shadows. -void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) -{ - if (paintingDisabled()) - return; + auto centeredPoints = centerLineAndCutOffCorners(isVerticalLine, cornerWidth, point1, point2); + auto p1 = centeredPoints[0]; + auto p2 = centeredPoints[1]; - cairo_t* cairoContext = platformContext()->cr(); - cairo_save(cairoContext); - drawLineOnCairoContext(this, cairoContext, point1, point2); - cairo_restore(cairoContext); + if (shouldAntialias()) + cairo_set_antialias(cairoContext, CAIRO_ANTIALIAS_NONE); + + cairo_new_path(cairoContext); + cairo_move_to(cairoContext, p1.x(), p1.y()); + cairo_line_to(cairoContext, p2.x(), p2.y()); + cairo_stroke(cairoContext); + if (drawsDashedLine) + cairo_restore(cairoContext); + if (shouldAntialias()) + cairo_set_antialias(cairoContext, CAIRO_ANTIALIAS_DEFAULT); } // This method is only used to draw the little circles used in lists. -void GraphicsContext::drawEllipse(const IntRect& rect) +void GraphicsContext::drawEllipse(const FloatRect& rect) { if (paintingDisabled()) return; + if (isRecording()) { + m_displayListRecorder->drawEllipse(rect); + return; + } + cairo_t* cr = platformContext()->cr(); cairo_save(cr); float yRadius = .5 * rect.height(); @@ -358,7 +388,7 @@ void GraphicsContext::drawEllipse(const IntRect& rect) cairo_arc(cr, 0., 0., 1., 0., 2 * piFloat); cairo_restore(cr); - if (fillColor().alpha()) { + if (fillColor().isVisible()) { setSourceRGBAFromColor(cr, fillColor()); cairo_fill_preserve(cr); } @@ -371,67 +401,19 @@ void GraphicsContext::drawEllipse(const IntRect& rect) cairo_new_path(cr); } -void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias) +void GraphicsContext::fillPath(const Path& path) { - if (paintingDisabled()) + if (paintingDisabled() || path.isEmpty()) return; - if (npoints <= 1) + if (isRecording()) { + m_displayListRecorder->fillPath(path); return; - - cairo_t* cr = platformContext()->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 = platformContext()->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() || path.isEmpty()) - return; - cairo_t* cr = platformContext()->cr(); setPathOnCairoContext(cr, path.platformPath()->context()); - shadowAndFillCurrentCairoPath(this); + shadowAndFillCurrentCairoPath(*this); } void GraphicsContext::strokePath(const Path& path) @@ -439,9 +421,14 @@ void GraphicsContext::strokePath(const Path& path) if (paintingDisabled() || path.isEmpty()) return; + if (isRecording()) { + m_displayListRecorder->strokePath(path); + return; + } + cairo_t* cr = platformContext()->cr(); setPathOnCairoContext(cr, path.platformPath()->context()); - shadowAndStrokeCurrentCairoPath(this); + shadowAndStrokeCurrentCairoPath(*this); } void GraphicsContext::fillRect(const FloatRect& rect) @@ -449,18 +436,28 @@ void GraphicsContext::fillRect(const FloatRect& rect) if (paintingDisabled()) return; + if (isRecording()) { + m_displayListRecorder->fillRect(rect); + return; + } + cairo_t* cr = platformContext()->cr(); cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); - shadowAndFillCurrentCairoPath(this); + shadowAndFillCurrentCairoPath(*this); } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) { if (paintingDisabled()) return; + if (isRecording()) { + m_displayListRecorder->fillRect(rect, color); + return; + } + if (hasShadow()) - platformContext()->shadowBlur().drawRectShadow(this, rect, RoundedRect::Radii()); + platformContext()->shadowBlur().drawRectShadow(*this, FloatRoundedRect(rect)); fillRectWithColor(platformContext()->cr(), rect, color); } @@ -470,6 +467,11 @@ void GraphicsContext::clip(const FloatRect& rect) if (paintingDisabled()) return; + if (isRecording()) { + m_displayListRecorder->clip(rect); + return; + } + cairo_t* cr = platformContext()->cr(); cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); @@ -492,15 +494,44 @@ void GraphicsContext::clipPath(const Path& path, WindRule clipRule) if (paintingDisabled()) return; + if (isRecording()) { + m_displayListRecorder->clipPath(path, clipRule); + return; + } + cairo_t* cr = platformContext()->cr(); if (!path.isNull()) setPathOnCairoContext(cr, path.platformPath()->context()); + + cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); cairo_set_fill_rule(cr, clipRule == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); cairo_clip(cr); + cairo_set_fill_rule(cr, savedFillRule); + + m_data->clip(path); +} + +void GraphicsContext::clipToImageBuffer(ImageBuffer& buffer, const FloatRect& destRect) +{ + if (paintingDisabled()) + return; + + RefPtr<Image> image = buffer.copyImage(DontCopyBackingStore); + RefPtr<cairo_surface_t> surface = image->nativeImageForCurrentFrame(); + if (surface) + platformContext()->pushImageMask(surface.get(), destRect); } IntRect GraphicsContext::clipBounds() const { + if (paintingDisabled()) + return IntRect(); + + if (isRecording()) { + WTFLogAlways("Getting the clip bounds not yet supported with display lists"); + return IntRect(-2048, -2048, 4096, 4096); // FIXME: display lists. + } + double x1, x2, y1, y2; cairo_clip_extents(platformContext()->cr(), &x1, &y1, &x2, &y2); return enclosingIntRect(FloatRect(x1, y1, x2 - x1, y2 - y1)); @@ -510,11 +541,13 @@ 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)); + color = Color(makeRGBA(color.red(), color.green(), color.blue(), 127)); +#else + UNUSED_PARAM(color); #endif } -static inline void adjustFocusRingLineWidth(int& width) +static inline void adjustFocusRingLineWidth(float& width) { #if PLATFORM(GTK) width = 2; @@ -532,8 +565,11 @@ static inline StrokeStyle focusRingStrokeStyle() #endif } -void GraphicsContext::drawFocusRing(const Path& path, int width, int /* offset */, const Color& color) +void GraphicsContext::drawFocusRing(const Path& path, float width, float /* offset */, const Color& color) { + if (paintingDisabled()) + return; + // 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; @@ -542,109 +578,91 @@ void GraphicsContext::drawFocusRing(const Path& path, int width, int /* offset * cairo_t* cr = platformContext()->cr(); cairo_save(cr); + cairo_push_group(cr); appendWebCorePathToCairoContext(cr, path); setSourceRGBAFromColor(cr, ringColor); cairo_set_line_width(cr, width); setPlatformStrokeStyle(focusRingStrokeStyle()); - cairo_stroke(cr); + 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::drawFocusRing(const Vector<IntRect>& rects, int width, int /* offset */, const Color& color) +void GraphicsContext::drawFocusRing(const Vector<FloatRect>& rects, float width, float /* offset */, const Color& color) { if (paintingDisabled()) return; - unsigned rectCount = rects.size(); - - cairo_t* cr = platformContext()->cr(); - cairo_save(cr); - cairo_push_group(cr); - cairo_new_path(cr); - + Path path; #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 + for (const auto& rect : rects) + path.addRect(rect); #else + unsigned rectCount = rects.size(); int radius = (width - 1) / 2; - Path path; + Path subPath; for (unsigned i = 0; i < rectCount; ++i) { if (i > 0) - path.clear(); - path.addRoundedRect(rects[i], FloatSize(radius, radius)); - appendWebCorePathToCairoContext(cr, path); + subPath.clear(); + subPath.addRoundedRect(rects[i], FloatSize(radius, radius)); + path.addPath(subPath, AffineTransform()); } #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); + drawFocusRing(path, width, 0, color); } -FloatRect GraphicsContext::computeLineBoundsForText(const FloatPoint& origin, float width, bool) +void GraphicsContext::drawLineForText(const FloatPoint& origin, float width, bool printing, bool doubleUnderlines, StrokeStyle) { - return FloatRect(origin, FloatSize(width, strokeThickness())); + DashArray widths; + widths.append(width); + widths.append(0); + drawLinesForText(origin, widths, printing, doubleUnderlines); } -void GraphicsContext::drawLineForText(const FloatPoint& origin, float width, bool printing) +void GraphicsContext::drawLinesForText(const FloatPoint& point, const DashArray& widths, bool printing, bool doubleUnderlines, StrokeStyle) { if (paintingDisabled()) return; - cairo_t* cairoContext = platformContext()->cr(); - cairo_save(cairoContext); - - // This bumping of <1 stroke thicknesses matches the one in drawLineOnCairoContext. - FloatPoint endPoint(origin + IntSize(width, 0)); - FloatRect lineExtents = computeLineBoundsForText(origin, width, printing); + if (widths.size() <= 0) + return; - ShadowBlur& shadow = platformContext()->shadowBlur(); - if (GraphicsContext* shadowContext = shadow.beginShadowLayer(this, lineExtents)) { - drawLineOnCairoContext(this, shadowContext->platformContext()->cr(), origin, endPoint); - shadow.endShadowLayer(this); + if (isRecording()) { + m_displayListRecorder->drawLinesForText(point, widths, printing, doubleUnderlines, strokeThickness()); + return; } - drawLineOnCairoContext(this, cairoContext, origin, endPoint); - cairo_restore(cairoContext); -} + Color localStrokeColor(strokeColor()); -void GraphicsContext::drawLinesForText(const FloatPoint& point, const DashArray& widths, bool printing) -{ + FloatRect bounds = computeLineBoundsAndAntialiasingModeForText(point, widths.last(), printing, localStrokeColor); + + Vector<FloatRect, 4> dashBounds; + ASSERT(!(widths.size() % 2)); + dashBounds.reserveInitialCapacity(dashBounds.size() / 2); for (size_t i = 0; i < widths.size(); i += 2) - drawLineForText(FloatPoint(point.x() + widths[i], point.y()), widths[i+1] - widths[i], printing); + dashBounds.append(FloatRect(FloatPoint(bounds.x() + widths[i], bounds.y()), FloatSize(widths[i+1] - widths[i], bounds.height()))); + + if (doubleUnderlines) { + // The space between double underlines is equal to the height of the underline + for (size_t i = 0; i < widths.size(); i += 2) + dashBounds.append(FloatRect(FloatPoint(bounds.x() + widths[i], bounds.y() + 2 * bounds.height()), FloatSize(widths[i+1] - widths[i], bounds.height()))); + } + + cairo_t* cr = platformContext()->cr(); + cairo_save(cr); + + for (auto& dash : dashBounds) + fillRectWithColor(cr, dash, localStrokeColor); + + cairo_restore(cr); } void GraphicsContext::updateDocumentMarkerResources() @@ -679,6 +697,14 @@ void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& origin, float FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode) { + if (paintingDisabled()) + return frect; + + if (isRecording()) { + WTFLogAlways("GraphicsContext::roundToDevicePixels() is not yet compatible with recording contexts."); + return frect; + } + FloatRect result; double x = frect.x(); double y = frect.y(); @@ -701,7 +727,7 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingM width = 1; else width = round(width); - if (height > -1 && width < 0) + if (height > -1 && height < 0) height = -1; else if (height > 0 && height < 1) height = 1; @@ -719,18 +745,23 @@ void GraphicsContext::translate(float x, float y) if (paintingDisabled()) return; + if (isRecording()) { + m_displayListRecorder->translate(x, y); + return; + } + cairo_t* cr = platformContext()->cr(); cairo_translate(cr, x, y); m_data->translate(x, y); } -void GraphicsContext::setPlatformFillColor(const Color&, ColorSpace) +void GraphicsContext::setPlatformFillColor(const Color&) { // 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&, ColorSpace) +void GraphicsContext::setPlatformStrokeColor(const Color&) { // Cairo contexts can't hold separate fill and stroke colors // so we set them just before we actually fill or stroke @@ -741,17 +772,21 @@ void GraphicsContext::setPlatformStrokeThickness(float strokeThickness) if (paintingDisabled()) return; + ASSERT(!isRecording()); + cairo_set_line_width(platformContext()->cr(), strokeThickness); } void GraphicsContext::setPlatformStrokeStyle(StrokeStyle strokeStyle) { - static double dashPattern[] = {5.0, 5.0}; - static double dotPattern[] = {1.0, 1.0}; + static const double dashPattern[] = { 5.0, 5.0 }; + static const double dotPattern[] = { 1.0, 1.0 }; if (paintingDisabled()) return; + ASSERT(!isRecording()); + switch (strokeStyle) { case NoStroke: // FIXME: is it the right way to emulate NoStroke? @@ -771,7 +806,7 @@ void GraphicsContext::setPlatformStrokeStyle(StrokeStyle strokeStyle) } } -void GraphicsContext::setURLForRect(const URL&, const IntRect&) +void GraphicsContext::setURLForRect(const URL&, const FloatRect&) { notImplemented(); } @@ -781,6 +816,11 @@ void GraphicsContext::concatCTM(const AffineTransform& transform) if (paintingDisabled()) return; + if (isRecording()) { + m_displayListRecorder->concatCTM(transform); + return; + } + cairo_t* cr = platformContext()->cr(); const cairo_matrix_t matrix = cairo_matrix_t(transform); cairo_transform(cr, &matrix); @@ -792,13 +832,18 @@ void GraphicsContext::setCTM(const AffineTransform& transform) if (paintingDisabled()) return; + if (isRecording()) { + WTFLogAlways("GraphicsContext::setCTM() is not compatible with recording contexts."); + return; + } + cairo_t* cr = platformContext()->cr(); const cairo_matrix_t matrix = cairo_matrix_t(transform); cairo_set_matrix(cr, &matrix); m_data->setCTM(transform); } -void GraphicsContext::setPlatformShadow(FloatSize const& size, float, Color const&, ColorSpace) +void GraphicsContext::setPlatformShadow(FloatSize const& size, float, Color const&) { if (paintingDisabled()) return; @@ -813,7 +858,6 @@ void GraphicsContext::setPlatformShadow(FloatSize const& size, float, Color cons platformContext()->shadowBlur().setShadowValues(FloatSize(m_state.shadowBlur, m_state.shadowBlur), m_state.shadowOffset, m_state.shadowColor, - m_state.shadowColorSpace, m_state.shadowsIgnoreTransforms); } @@ -830,6 +874,8 @@ void GraphicsContext::beginPlatformTransparencyLayer(float opacity) if (paintingDisabled()) return; + ASSERT(!isRecording()); + cairo_t* cr = platformContext()->cr(); cairo_push_group(cr); m_data->layers.append(opacity); @@ -840,6 +886,8 @@ void GraphicsContext::endPlatformTransparencyLayer() if (paintingDisabled()) return; + ASSERT(!isRecording()); + cairo_t* cr = platformContext()->cr(); cairo_pop_group_to_source(cr); @@ -857,6 +905,11 @@ void GraphicsContext::clearRect(const FloatRect& rect) if (paintingDisabled()) return; + if (isRecording()) { + m_displayListRecorder->clearRect(rect); + return; + } + cairo_t* cr = platformContext()->cr(); cairo_save(cr); @@ -871,11 +924,16 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float width) if (paintingDisabled()) return; + if (isRecording()) { + m_displayListRecorder->strokeRect(rect, width); + return; + } + cairo_t* cr = platformContext()->cr(); cairo_save(cr); cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); cairo_set_line_width(cr, width); - shadowAndStrokeCurrentCairoPath(this); + shadowAndStrokeCurrentCairoPath(*this); cairo_restore(cr); } @@ -884,6 +942,11 @@ void GraphicsContext::setLineCap(LineCap lineCap) if (paintingDisabled()) return; + if (isRecording()) { + m_displayListRecorder->setLineCap(lineCap); + return; + } + cairo_line_cap_t cairoCap = CAIRO_LINE_CAP_BUTT; switch (lineCap) { case ButtCap: @@ -899,9 +962,29 @@ void GraphicsContext::setLineCap(LineCap lineCap) cairo_set_line_cap(platformContext()->cr(), cairoCap); } +static inline bool isDashArrayAllZero(const DashArray& dashes) +{ + for (auto& dash : dashes) { + if (dash) + return false; + } + return true; +} + void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) { - cairo_set_dash(platformContext()->cr(), dashes.data(), dashes.size(), dashOffset); + if (paintingDisabled()) + return; + + if (isRecording()) { + m_displayListRecorder->setLineDash(dashes, dashOffset); + return; + } + + if (isDashArrayAllZero(dashes)) + cairo_set_dash(platformContext()->cr(), 0, 0, 0); + else + cairo_set_dash(platformContext()->cr(), dashes.data(), dashes.size(), dashOffset); } void GraphicsContext::setLineJoin(LineJoin lineJoin) @@ -909,6 +992,11 @@ void GraphicsContext::setLineJoin(LineJoin lineJoin) if (paintingDisabled()) return; + if (isRecording()) { + m_displayListRecorder->setLineJoin(lineJoin); + return; + } + cairo_line_join_t cairoJoin = CAIRO_LINE_JOIN_MITER; switch (lineJoin) { case MiterJoin: @@ -929,10 +1017,16 @@ void GraphicsContext::setMiterLimit(float miter) if (paintingDisabled()) return; + if (isRecording()) { + // Maybe this should be part of the state. + m_displayListRecorder->setMiterLimit(miter); + return; + } + cairo_set_miter_limit(platformContext()->cr(), miter); } -void GraphicsContext::setAlpha(float alpha) +void GraphicsContext::setPlatformAlpha(float alpha) { platformContext()->setGlobalAlpha(alpha); } @@ -942,39 +1036,12 @@ void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op, BlendM if (paintingDisabled()) return; - cairo_operator_t cairo_op; - if (blendOp == BlendModeNormal) - cairo_op = toCairoOperator(op); - else - cairo_op = toCairoOperator(blendOp); - - cairo_set_operator(platformContext()->cr(), cairo_op); -} - -void GraphicsContext::clip(const Path& path, WindRule windRule) -{ - if (paintingDisabled()) - return; - - cairo_t* cr = platformContext()->cr(); - OwnPtr<cairo_path_t> pathCopy; - if (!path.isNull()) { - pathCopy = adoptPtr(cairo_copy_path(path.platformPath()->context())); - cairo_append_path(cr, pathCopy.get()); - } - cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); - if (windRule == RULE_NONZERO) - cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING); - else - cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); - cairo_clip(cr); - cairo_set_fill_rule(cr, savedFillRule); - m_data->clip(path); + cairo_set_operator(platformContext()->cr(), toCairoOperator(op, blendOp)); } void GraphicsContext::canvasClip(const Path& path, WindRule windRule) { - clip(path, windRule); + clipPath(path, windRule); } void GraphicsContext::clipOut(const Path& path) @@ -982,6 +1049,11 @@ void GraphicsContext::clipOut(const Path& path) if (paintingDisabled()) return; + if (isRecording()) { + m_displayListRecorder->clipOut(path); + return; + } + cairo_t* cr = platformContext()->cr(); double x1, y1, x2, y2; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); @@ -999,6 +1071,11 @@ void GraphicsContext::rotate(float radians) if (paintingDisabled()) return; + if (isRecording()) { + m_displayListRecorder->rotate(radians); + return; + } + cairo_rotate(platformContext()->cr(), radians); m_data->rotate(radians); } @@ -1008,15 +1085,25 @@ void GraphicsContext::scale(const FloatSize& size) if (paintingDisabled()) return; + if (isRecording()) { + m_displayListRecorder->scale(size); + return; + } + cairo_scale(platformContext()->cr(), size.width(), size.height()); m_data->scale(size); } -void GraphicsContext::clipOut(const IntRect& r) +void GraphicsContext::clipOut(const FloatRect& r) { if (paintingDisabled()) return; + if (isRecording()) { + m_displayListRecorder->clipOut(r); + return; + } + cairo_t* cr = platformContext()->cr(); double x1, y1, x2, y2; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); @@ -1028,31 +1115,38 @@ void GraphicsContext::clipOut(const IntRect& r) cairo_set_fill_rule(cr, savedFillRule); } -void GraphicsContext::fillRoundedRect(const IntRect& r, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace) +void GraphicsContext::platformFillRoundedRect(const FloatRoundedRect& rect, const Color& color) { if (paintingDisabled()) return; + ASSERT(!isRecording()); + if (hasShadow()) - platformContext()->shadowBlur().drawRectShadow(this, r, RoundedRect::Radii(topLeft, topRight, bottomLeft, bottomRight)); + platformContext()->shadowBlur().drawRectShadow(*this, rect); cairo_t* cr = platformContext()->cr(); cairo_save(cr); Path path; - path.addRoundedRect(r, topLeft, topRight, bottomLeft, bottomRight); + path.addRoundedRect(rect); appendWebCorePathToCairoContext(cr, path); setSourceRGBAFromColor(cr, color); cairo_fill(cr); cairo_restore(cr); } -void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedRect& roundedHoleRect, const Color& color, ColorSpace) +void GraphicsContext::fillRectWithRoundedHole(const FloatRect& rect, const FloatRoundedRect& roundedHoleRect, const Color& color) { if (paintingDisabled() || !color.isValid()) return; + if (isRecording()) { + m_displayListRecorder->fillRectWithRoundedHole(rect, roundedHoleRect, color); + return; + } + if (this->mustUseShadowBlur()) - platformContext()->shadowBlur().drawInsetShadow(this, rect, roundedHoleRect.rect(), roundedHoleRect.radii()); + platformContext()->shadowBlur().drawInsetShadow(*this, rect, roundedHoleRect); Path path; path.addRect(rect); @@ -1064,57 +1158,57 @@ void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const Rounded cairo_t* cr = platformContext()->cr(); cairo_save(cr); setPathOnCairoContext(platformContext()->cr(), path.platformPath()->context()); - fillCurrentCairoPath(this); + fillCurrentCairoPath(*this); cairo_restore(cr); } -#if PLATFORM(GTK) -void GraphicsContext::setGdkExposeEvent(GdkEventExpose* expose) +void GraphicsContext::drawPattern(Image& image, const FloatRect& destRect, const FloatRect& tileRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, BlendMode blendMode) { - m_data->expose = expose; -} + if (paintingDisabled()) + return; -GdkEventExpose* GraphicsContext::gdkExposeEvent() const -{ - return m_data->expose; -} + if (isRecording()) { + m_displayListRecorder->drawPattern(image, destRect, tileRect, patternTransform, phase, spacing, op, blendMode); + return; + } -GdkWindow* GraphicsContext::gdkWindow() const -{ - if (!m_data->expose) - return 0; + RefPtr<cairo_surface_t> surface = image.nativeImageForCurrentFrame(); + if (!surface) // If it's too early we won't have an image yet. + return; - return m_data->expose->window; + cairo_t* cr = platformContext()->cr(); + drawPatternToCairoContext(cr, surface.get(), IntSize(image.size()), tileRect, patternTransform, phase, toCairoOperator(op, blendMode), destRect); } -#endif void GraphicsContext::setPlatformShouldAntialias(bool enable) { if (paintingDisabled()) return; + ASSERT(!isRecording()); + // 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(). + // antialiasing. cairo_set_antialias(platformContext()->cr(), enable ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE); } -void GraphicsContext::setImageInterpolationQuality(InterpolationQuality quality) +void GraphicsContext::setPlatformImageInterpolationQuality(InterpolationQuality quality) { - platformContext()->setImageInterpolationQuality(quality); -} + ASSERT(!isRecording()); -InterpolationQuality GraphicsContext::imageInterpolationQuality() const -{ - return platformContext()->imageInterpolationQuality(); + platformContext()->setImageInterpolationQuality(quality); } bool GraphicsContext::isAcceleratedContext() const { + if (isRecording()) + return false; + return cairo_surface_get_type(cairo_get_target(platformContext()->cr())) == CAIRO_SURFACE_TYPE_GL; } -#if ENABLE(3D_RENDERING) && USE(TEXTURE_MAPPER) +#if ENABLE(3D_TRANSFORMS) && USE(TEXTURE_MAPPER) TransformationMatrix GraphicsContext::get3DTransform() const { // FIXME: Can we approximate the transformation better than this? @@ -1130,7 +1224,7 @@ void GraphicsContext::set3DTransform(const TransformationMatrix& transform) { setCTM(transform.toAffineTransform()); } -#endif +#endif // ENABLE(3D_TRANSFORMS) && USE(TEXTURE_MAPPER) } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h index fc7c8a5d4..b2d25d6a7 100644 --- a/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h +++ b/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * Copyright (C) 2007 Alp Toker <alp@atoker.com> * Copyright (C) 2008 Brent Fulgham <bfulgham@gmail.com> * @@ -12,10 +12,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -30,17 +30,15 @@ #include "GraphicsContext.h" +#if USE(CAIRO) + #include "PlatformContextCairo.h" #include "RefPtrCairo.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) +#if PLATFORM(WIN) #include <cairo-win32.h> #endif @@ -50,9 +48,6 @@ class GraphicsContextPlatformPrivate { public: GraphicsContextPlatformPrivate(PlatformContextCairo* newPlatformContext) : platformContext(newPlatformContext) -#if PLATFORM(GTK) - , expose(0) -#endif #if PLATFORM(WIN) || (PLATFORM(GTK) && OS(WINDOWS)) // NOTE: These may note be needed: review and remove once Cairo implementation is complete , m_hdc(0) @@ -96,9 +91,6 @@ public: PlatformContextCairo* platformContext; Vector<float> layers; -#if PLATFORM(GTK) - GdkEventExpose* expose; -#endif #if PLATFORM(WIN) || (PLATFORM(GTK) && OS(WINDOWS)) HDC m_hdc; bool m_shouldIncludeChildWindows; @@ -124,4 +116,6 @@ public: } // namespace WebCore +#endif // USE(CAIRO) + #endif // GraphicsContextPlatformPrivateCairo_h diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index 0d97204f4..041373a01 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -13,10 +13,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -29,6 +29,8 @@ #include "config.h" #include "ImageBuffer.h" +#if USE(CAIRO) + #include "BitmapImage.h" #include "CairoUtilities.h" #include "Color.h" @@ -39,82 +41,201 @@ #include "PlatformContextCairo.h" #include "RefPtrCairo.h" #include <cairo.h> +#include <runtime/JSCInlines.h> +#include <runtime/TypedArrayInlines.h> #include <wtf/Vector.h> #include <wtf/text/Base64.h> #include <wtf/text/WTFString.h> #if ENABLE(ACCELERATED_2D_CANVAS) #include "GLContext.h" -#include "OpenGLShims.h" #include "TextureMapperGL.h" #include <cairo-gl.h> + +#if USE(OPENGL_ES_2) +#include <GLES2/gl2.h> +#else +#include "OpenGLShims.h" +#endif + +#if USE(COORDINATED_GRAPHICS_THREADED) +#include "TextureMapperPlatformLayerBuffer.h" +#include "TextureMapperPlatformLayerProxy.h" +#endif #endif using namespace std; namespace WebCore { -ImageBufferData::ImageBufferData(const IntSize& size) +ImageBufferData::ImageBufferData(const IntSize& size, RenderingMode renderingMode) : m_platformContext(0) , m_size(size) + , m_renderingMode(renderingMode) #if ENABLE(ACCELERATED_2D_CANVAS) +#if USE(COORDINATED_GRAPHICS_THREADED) + , m_compositorTexture(0) +#endif , m_texture(0) #endif { +#if ENABLE(ACCELERATED_2D_CANVAS) && USE(COORDINATED_GRAPHICS_THREADED) + if (m_renderingMode == RenderingMode::Accelerated) + m_platformLayerProxy = adoptRef(new TextureMapperPlatformLayerProxy); +#endif +} + +ImageBufferData::~ImageBufferData() +{ + if (m_renderingMode != Accelerated) + return; + +#if ENABLE(ACCELERATED_2D_CANVAS) + GLContext* previousActiveContext = GLContext::current(); + PlatformDisplay::sharedDisplayForCompositing().sharingGLContext()->makeContextCurrent(); + + if (m_texture) + glDeleteTextures(1, &m_texture); + +#if USE(COORDINATED_GRAPHICS_THREADED) + if (m_compositorTexture) + glDeleteTextures(1, &m_compositorTexture); +#endif + + if (previousActiveContext) + previousActiveContext->makeContextCurrent(); +#endif } #if ENABLE(ACCELERATED_2D_CANVAS) -PassRefPtr<cairo_surface_t> createCairoGLSurface(const IntSize& size, uint32_t& texture) +#if USE(COORDINATED_GRAPHICS_THREADED) +void ImageBufferData::createCompositorBuffer() +{ + auto* context = PlatformDisplay::sharedDisplayForCompositing().sharingGLContext(); + context->makeContextCurrent(); + + glGenTextures(1, &m_compositorTexture); + glBindTexture(GL_TEXTURE_2D, m_compositorTexture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0 , GL_RGBA, m_size.width(), m_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + + m_compositorSurface = adoptRef(cairo_gl_surface_create_for_texture(context->cairoDevice(), CAIRO_CONTENT_COLOR_ALPHA, m_compositorTexture, m_size.width(), m_size.height())); + m_compositorCr = adoptRef(cairo_create(m_compositorSurface.get())); + cairo_set_antialias(m_compositorCr.get(), CAIRO_ANTIALIAS_NONE); +} + +void ImageBufferData::swapBuffersIfNeeded() +{ + GLContext* previousActiveContext = GLContext::current(); + + if (!m_compositorTexture) { + createCompositorBuffer(); + LockHolder holder(m_platformLayerProxy->lock()); + m_platformLayerProxy->pushNextBuffer(std::make_unique<TextureMapperPlatformLayerBuffer>(m_compositorTexture, m_size, TextureMapperGL::ShouldBlend)); + } + + // It would be great if we could just swap the buffers here as we do with webgl, but that breaks the cases + // where one frame uses the content already rendered in the previous frame. So we just copy the content + // into the compositor buffer. + cairo_set_source_surface(m_compositorCr.get(), m_surface.get(), 0, 0); + cairo_set_operator(m_compositorCr.get(), CAIRO_OPERATOR_SOURCE); + cairo_paint(m_compositorCr.get()); + + if (previousActiveContext) + previousActiveContext->makeContextCurrent(); +} +#endif + +void clearSurface(cairo_surface_t* surface) +{ + if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) + return; + + RefPtr<cairo_t> cr = adoptRef(cairo_create(surface)); + cairo_set_operator(cr.get(), CAIRO_OPERATOR_CLEAR); + cairo_paint(cr.get()); +} + +void ImageBufferData::createCairoGLSurface() { - GLContext::sharingContext()->makeContextCurrent(); + auto* context = PlatformDisplay::sharedDisplayForCompositing().sharingGLContext(); + context->makeContextCurrent(); // We must generate the texture ourselves, because there is no Cairo API for extracting it // from a pre-existing surface. - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glGenTextures(1, &m_texture); + glBindTexture(GL_TEXTURE_2D, m_texture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0 /* level */, GL_RGBA8, size.width(), size.height(), 0 /* border */, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 0 /* level */, GL_RGBA, m_size.width(), m_size.height(), 0 /* border */, GL_RGBA, GL_UNSIGNED_BYTE, 0); - GLContext* context = GLContext::sharingContext(); cairo_device_t* device = context->cairoDevice(); // Thread-awareness is a huge performance hit on non-Intel drivers. cairo_gl_device_set_thread_aware(device, FALSE); - return adoptRef(cairo_gl_surface_create_for_texture(device, CAIRO_CONTENT_COLOR_ALPHA, texture, size.width(), size.height())); + m_surface = adoptRef(cairo_gl_surface_create_for_texture(device, CAIRO_CONTENT_COLOR_ALPHA, m_texture, m_size.width(), m_size.height())); + clearSurface(m_surface.get()); } #endif -ImageBuffer::ImageBuffer(const IntSize& size, float /* resolutionScale */, ColorSpace, RenderingMode renderingMode, bool& success) - : m_data(size) - , m_size(size) +ImageBuffer::ImageBuffer(const FloatSize& size, float resolutionScale, ColorSpace, RenderingMode renderingMode, bool& success) + : m_data(IntSize(size), renderingMode) , m_logicalSize(size) + , m_resolutionScale(resolutionScale) { success = false; // Make early return mean error. + + float scaledWidth = ceilf(m_resolutionScale * size.width()); + float scaledHeight = ceilf(m_resolutionScale * size.height()); + + // FIXME: Should we automatically use a lower resolution? + if (!FloatSize(scaledWidth, scaledHeight).isExpressibleAsIntSize()) + return; + + m_size = IntSize(scaledWidth, scaledHeight); + m_data.m_size = m_size; + if (m_size.isEmpty()) return; #if ENABLE(ACCELERATED_2D_CANVAS) - if (renderingMode == Accelerated) - m_data.m_surface = createCairoGLSurface(size, m_data.m_texture); - else + if (m_data.m_renderingMode == Accelerated) { + m_data.createCairoGLSurface(); + if (!m_data.m_surface || cairo_surface_status(m_data.m_surface.get()) != CAIRO_STATUS_SUCCESS) + m_data.m_renderingMode = Unaccelerated; // If allocation fails, fall back to non-accelerated path. + } + if (m_data.m_renderingMode == Unaccelerated) #else - ASSERT_UNUSED(renderingMode, renderingMode != Accelerated); + ASSERT(m_data.m_renderingMode != Accelerated); #endif - m_data.m_surface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size.width(), size.height())); + { + static cairo_user_data_key_t s_surfaceDataKey; + + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, m_size.width()); + auto* surfaceData = fastZeroedMalloc(m_size.height() * stride); + + m_data.m_surface = adoptRef(cairo_image_surface_create_for_data(static_cast<unsigned char*>(surfaceData), CAIRO_FORMAT_ARGB32, m_size.width(), m_size.height(), stride)); + cairo_surface_set_user_data(m_data.m_surface.get(), &s_surfaceDataKey, surfaceData, [](void* data) { fastFree(data); }); + } if (cairo_surface_status(m_data.m_surface.get()) != CAIRO_STATUS_SUCCESS) return; // create will notice we didn't set m_initialized and fail. + cairoSurfaceSetDeviceScale(m_data.m_surface.get(), m_resolutionScale, m_resolutionScale); + RefPtr<cairo_t> cr = adoptRef(cairo_create(m_data.m_surface.get())); m_data.m_platformContext.setCr(cr.get()); - m_context = adoptPtr(new GraphicsContext(&m_data.m_platformContext)); + m_data.m_context = std::make_unique<GraphicsContext>(&m_data.m_platformContext); success = true; } @@ -122,18 +243,29 @@ ImageBuffer::~ImageBuffer() { } -GraphicsContext* ImageBuffer::context() const +std::unique_ptr<ImageBuffer> ImageBuffer::createCompatibleBuffer(const FloatSize& size, const GraphicsContext& context) +{ + return createCompatibleBuffer(size, ColorSpaceSRGB, context); +} + +GraphicsContext& ImageBuffer::context() const +{ + return *m_data.m_context; +} + +RefPtr<Image> ImageBuffer::sinkIntoImage(std::unique_ptr<ImageBuffer> imageBuffer, ScaleBehavior scaleBehavior) { - return m_context.get(); + return imageBuffer->copyImage(DontCopyBackingStore, scaleBehavior); } -PassRefPtr<Image> ImageBuffer::copyImage(BackingStoreCopy copyBehavior, ScaleBehavior) const +RefPtr<Image> ImageBuffer::copyImage(BackingStoreCopy copyBehavior, ScaleBehavior) const { + // copyCairoImageSurface inherits surface's device scale factor. if (copyBehavior == CopyBackingStore) return BitmapImage::create(copyCairoImageSurface(m_data.m_surface.get())); // BitmapImage will release the passed in surface on destruction - return BitmapImage::create(m_data.m_surface); + return BitmapImage::create(RefPtr<cairo_surface_t>(m_data.m_surface)); } BackingStoreCopy ImageBuffer::fastCopyImageMode() @@ -141,24 +273,24 @@ BackingStoreCopy ImageBuffer::fastCopyImageMode() return DontCopyBackingStore; } -void ImageBuffer::clip(GraphicsContext* context, const FloatRect& maskRect) const +void ImageBuffer::drawConsuming(std::unique_ptr<ImageBuffer> imageBuffer, GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode) { - context->platformContext()->pushImageMask(m_data.m_surface.get(), maskRect); + imageBuffer->draw(destContext, destRect, srcRect, op, blendMode); } -void ImageBuffer::draw(GraphicsContext* destinationContext, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, - CompositeOperator op, BlendMode blendMode, bool useLowQualityScale) +void ImageBuffer::draw(GraphicsContext& destinationContext, const FloatRect& destRect, const FloatRect& srcRect, + CompositeOperator op, BlendMode blendMode) { - BackingStoreCopy copyMode = destinationContext == context() ? CopyBackingStore : DontCopyBackingStore; + BackingStoreCopy copyMode = &destinationContext == &context() ? CopyBackingStore : DontCopyBackingStore; RefPtr<Image> image = copyImage(copyMode); - destinationContext->drawImage(image.get(), styleColorSpace, destRect, srcRect, op, blendMode, ImageOrientationDescription(), useLowQualityScale); + destinationContext.drawImage(*image, destRect, srcRect, ImagePaintingOptions(op, blendMode, ImageOrientationDescription())); } -void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform, - const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, BlendMode) +void ImageBuffer::drawPattern(GraphicsContext& context, const FloatRect& destRect, const FloatRect& srcRect, const AffineTransform& patternTransform, + const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, BlendMode) { - RefPtr<Image> image = copyImage(DontCopyBackingStore); - image->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect); + if (RefPtr<Image> image = copyImage(DontCopyBackingStore)) + image->drawPattern(context, destRect, srcRect, patternTransform, phase, spacing, op); } void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) @@ -181,10 +313,10 @@ void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) *pixel = premultipliedARGBFromColor(pixelColor); } } - cairo_surface_mark_dirty_rectangle(m_data.m_surface.get(), 0, 0, m_size.width(), m_size.height()); + cairo_surface_mark_dirty_rectangle(m_data.m_surface.get(), 0, 0, m_logicalSize.width(), m_logicalSize.height()); } -PassRefPtr<cairo_surface_t> copySurfaceToImageAndAdjustRect(cairo_surface_t* surface, IntRect& rect) +RefPtr<cairo_surface_t> copySurfaceToImageAndAdjustRect(cairo_surface_t* surface, IntRect& rect) { cairo_surface_type_t surfaceType = cairo_surface_get_type(surface); @@ -199,9 +331,11 @@ PassRefPtr<cairo_surface_t> copySurfaceToImageAndAdjustRect(cairo_surface_t* sur } template <Multiply multiplied> -PassRefPtr<Uint8ClampedArray> getImageData(const IntRect& rect, const ImageBufferData& data, const IntSize& size) +RefPtr<Uint8ClampedArray> getImageData(const IntRect& rect, const IntRect& logicalRect, const ImageBufferData& data, const IntSize& size, const IntSize& logicalSize, float resolutionScale) { RefPtr<Uint8ClampedArray> result = Uint8ClampedArray::createUninitialized(rect.width() * rect.height() * 4); + if (!result) + return nullptr; if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > size.width() || (rect.y() + rect.height()) > size.height()) result->zeroFill(); @@ -228,13 +362,17 @@ PassRefPtr<Uint8ClampedArray> getImageData(const IntRect& rect, const ImageBuffe endy = size.height(); int numRows = endy - originy; + // The size of the derived surface is in BackingStoreCoordinateSystem. + // We need to set the device scale for the derived surface from this ImageBuffer. IntRect imageRect(originx, originy, numColumns, numRows); RefPtr<cairo_surface_t> imageSurface = copySurfaceToImageAndAdjustRect(data.m_surface.get(), imageRect); + cairoSurfaceSetDeviceScale(imageSurface.get(), resolutionScale, resolutionScale); originx = imageRect.x(); originy = imageRect.y(); if (imageSurface != data.m_surface.get()) { - IntRect area = intersection(rect, IntRect(0, 0, size.width(), size.height())); - copyRectFromOneSurfaceToAnother(data.m_surface.get(), imageSurface.get(), IntSize(-area.x(), -area.y()), IntRect(IntPoint(), area.size()), IntSize(), CAIRO_OPERATOR_SOURCE); + // This cairo surface operation is done in LogicalCoordinateSystem. + IntRect logicalArea = intersection(logicalRect, IntRect(0, 0, logicalSize.width(), logicalSize.height())); + copyRectFromOneSurfaceToAnother(data.m_surface.get(), imageSurface.get(), IntSize(-logicalArea.x(), -logicalArea.y()), IntRect(IntPoint(), logicalArea.size()), IntSize(), CAIRO_OPERATOR_SOURCE); } unsigned char* dataSrc = cairo_image_surface_get_data(imageSurface.get()); @@ -275,53 +413,91 @@ PassRefPtr<Uint8ClampedArray> getImageData(const IntRect& rect, const ImageBuffe return result.release(); } -PassRefPtr<Uint8ClampedArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect, CoordinateSystem) const +template<typename Unit> +inline Unit logicalUnit(const Unit& value, ImageBuffer::CoordinateSystem coordinateSystemOfValue, float resolutionScale) { - return getImageData<Unmultiplied>(rect, m_data, m_size); + if (coordinateSystemOfValue == ImageBuffer::LogicalCoordinateSystem || resolutionScale == 1.0) + return value; + Unit result(value); + result.scale(1.0 / resolutionScale); + return result; } -PassRefPtr<Uint8ClampedArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect, CoordinateSystem) const +template<typename Unit> +inline Unit backingStoreUnit(const Unit& value, ImageBuffer::CoordinateSystem coordinateSystemOfValue, float resolutionScale) { - return getImageData<Premultiplied>(rect, m_data, m_size); + if (coordinateSystemOfValue == ImageBuffer::BackingStoreCoordinateSystem || resolutionScale == 1.0) + return value; + Unit result(value); + result.scale(resolutionScale); + return result; } -void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, CoordinateSystem) +RefPtr<Uint8ClampedArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect, CoordinateSystem coordinateSystem) const { + IntRect logicalRect = logicalUnit(rect, coordinateSystem, m_resolutionScale); + IntRect backingStoreRect = backingStoreUnit(rect, coordinateSystem, m_resolutionScale); + return getImageData<Unmultiplied>(backingStoreRect, logicalRect, m_data, m_size, m_logicalSize, m_resolutionScale); +} - ASSERT(sourceRect.width() > 0); - ASSERT(sourceRect.height() > 0); +RefPtr<Uint8ClampedArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect, CoordinateSystem coordinateSystem) const +{ + IntRect logicalRect = logicalUnit(rect, coordinateSystem, m_resolutionScale); + IntRect backingStoreRect = backingStoreUnit(rect, coordinateSystem, m_resolutionScale); + return getImageData<Premultiplied>(backingStoreRect, logicalRect, m_data, m_size, m_logicalSize, m_resolutionScale); +} - int originx = sourceRect.x(); - int destx = destPoint.x() + sourceRect.x(); +void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, CoordinateSystem coordinateSystem) +{ + IntRect scaledSourceRect = backingStoreUnit(sourceRect, coordinateSystem, m_resolutionScale); + IntSize scaledSourceSize = backingStoreUnit(sourceSize, coordinateSystem, m_resolutionScale); + IntPoint scaledDestPoint = backingStoreUnit(destPoint, coordinateSystem, m_resolutionScale); + IntRect logicalSourceRect = logicalUnit(sourceRect, coordinateSystem, m_resolutionScale); + IntPoint logicalDestPoint = logicalUnit(destPoint, coordinateSystem, m_resolutionScale); + + ASSERT(scaledSourceRect.width() > 0); + ASSERT(scaledSourceRect.height() > 0); + + int originx = scaledSourceRect.x(); + int destx = scaledDestPoint.x() + scaledSourceRect.x(); + int logicalDestx = logicalDestPoint.x() + logicalSourceRect.x(); ASSERT(destx >= 0); ASSERT(destx < m_size.width()); ASSERT(originx >= 0); - ASSERT(originx <= sourceRect.maxX()); + ASSERT(originx <= scaledSourceRect.maxX()); - int endx = destPoint.x() + sourceRect.maxX(); + int endx = scaledDestPoint.x() + scaledSourceRect.maxX(); + int logicalEndx = logicalDestPoint.x() + logicalSourceRect.maxX(); ASSERT(endx <= m_size.width()); int numColumns = endx - destx; + int logicalNumColumns = logicalEndx - logicalDestx; - int originy = sourceRect.y(); - int desty = destPoint.y() + sourceRect.y(); + int originy = scaledSourceRect.y(); + int desty = scaledDestPoint.y() + scaledSourceRect.y(); + int logicalDesty = logicalDestPoint.y() + logicalSourceRect.y(); ASSERT(desty >= 0); ASSERT(desty < m_size.height()); ASSERT(originy >= 0); - ASSERT(originy <= sourceRect.maxY()); + ASSERT(originy <= scaledSourceRect.maxY()); - int endy = destPoint.y() + sourceRect.maxY(); + int endy = scaledDestPoint.y() + scaledSourceRect.maxY(); + int logicalEndy = logicalDestPoint.y() + logicalSourceRect.maxY(); ASSERT(endy <= m_size.height()); int numRows = endy - desty; + int logicalNumRows = logicalEndy - logicalDesty; + // The size of the derived surface is in BackingStoreCoordinateSystem. + // We need to set the device scale for the derived surface from this ImageBuffer. IntRect imageRect(destx, desty, numColumns, numRows); RefPtr<cairo_surface_t> imageSurface = copySurfaceToImageAndAdjustRect(m_data.m_surface.get(), imageRect); + cairoSurfaceSetDeviceScale(imageSurface.get(), m_resolutionScale, m_resolutionScale); destx = imageRect.x(); desty = imageRect.y(); unsigned char* pixelData = cairo_image_surface_get_data(imageSurface.get()); - unsigned srcBytesPerRow = 4 * sourceSize.width(); + unsigned srcBytesPerRow = 4 * scaledSourceSize.width(); int stride = cairo_image_surface_get_stride(imageSurface.get()); unsigned char* srcRows = source->data() + originy * srcBytesPerRow + originx * 4; @@ -351,10 +527,13 @@ void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, c srcRows += srcBytesPerRow; } - cairo_surface_mark_dirty_rectangle(imageSurface.get(), destx, desty, numColumns, numRows); + // This cairo surface operation is done in LogicalCoordinateSystem. + cairo_surface_mark_dirty_rectangle(imageSurface.get(), logicalDestx, logicalDesty, logicalNumColumns, logicalNumRows); - if (imageSurface != m_data.m_surface.get()) - copyRectFromOneSurfaceToAnother(imageSurface.get(), m_data.m_surface.get(), IntSize(), IntRect(0, 0, numColumns, numRows), IntSize(destPoint.x() + sourceRect.x(), destPoint.y() + sourceRect.y()), CAIRO_OPERATOR_SOURCE); + if (imageSurface != m_data.m_surface.get()) { + // This cairo surface operation is done in LogicalCoordinateSystem. + copyRectFromOneSurfaceToAnother(imageSurface.get(), m_data.m_surface.get(), IntSize(), IntRect(0, 0, logicalNumColumns, logicalNumRows), IntSize(logicalDestPoint.x() + logicalSourceRect.x(), logicalDestPoint.y() + logicalSourceRect.y()), CAIRO_OPERATOR_SOURCE); + } } #if !PLATFORM(GTK) @@ -372,11 +551,11 @@ static bool encodeImage(cairo_surface_t* image, const String& mimeType, Vector<c return cairo_surface_write_to_png_stream(image, writeFunction, output) == CAIRO_STATUS_SUCCESS; } -String ImageBuffer::toDataURL(const String& mimeType, const double*, CoordinateSystem) const +String ImageBuffer::toDataURL(const String& mimeType, std::optional<double> quality, CoordinateSystem) const { ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); - cairo_surface_t* image = cairo_get_target(context()->platformContext()->cr()); + cairo_surface_t* image = cairo_get_target(context().platformContext()->cr()); Vector<char> encodedImage; if (!image || !encodeImage(image, mimeType, &encodedImage)) @@ -389,26 +568,20 @@ String ImageBuffer::toDataURL(const String& mimeType, const double*, CoordinateS } #endif -#if ENABLE(ACCELERATED_2D_CANVAS) -void ImageBufferData::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity) +#if ENABLE(ACCELERATED_2D_CANVAS) && !USE(COORDINATED_GRAPHICS_THREADED) +void ImageBufferData::paintToTextureMapper(TextureMapper& textureMapper, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity) { - if (textureMapper->accelerationMode() != TextureMapper::OpenGLMode) { - notImplemented(); - return; - } - ASSERT(m_texture); // Cairo may change the active context, so we make sure to change it back after flushing. - GLContext* previousActiveContext = GLContext::getCurrent(); + GLContext* previousActiveContext = GLContext::current(); cairo_surface_flush(m_surface.get()); previousActiveContext->makeContextCurrent(); - static_cast<TextureMapperGL*>(textureMapper)->drawTexture(m_texture, TextureMapperGL::ShouldBlend, m_size, targetRect, matrix, opacity); + static_cast<TextureMapperGL&>(textureMapper).drawTexture(m_texture, TextureMapperGL::ShouldBlend, m_size, targetRect, matrix, opacity); } #endif -#if USE(ACCELERATED_COMPOSITING) PlatformLayer* ImageBuffer::platformLayer() const { #if ENABLE(ACCELERATED_2D_CANVAS) @@ -417,6 +590,59 @@ PlatformLayer* ImageBuffer::platformLayer() const #endif return 0; } + +bool ImageBuffer::copyToPlatformTexture(GraphicsContext3D&, GC3Denum target, Platform3DObject destinationTexture, GC3Denum internalformat, bool premultiplyAlpha, bool flipY) +{ +#if ENABLE(ACCELERATED_2D_CANVAS) + ASSERT_WITH_MESSAGE(m_resolutionScale == 1.0, "Since the HiDPI Canvas feature is removed, the resolution factor here is always 1."); + if (premultiplyAlpha || flipY) + return false; + + if (!m_data.m_texture) + return false; + + GC3Denum bindTextureTarget; + switch (target) { + case GL_TEXTURE_2D: + bindTextureTarget = GL_TEXTURE_2D; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + bindTextureTarget = GL_TEXTURE_CUBE_MAP; + break; + default: + return false; + } + + cairo_surface_flush(m_data.m_surface.get()); + + std::unique_ptr<GLContext> context = GLContext::createOffscreenContext(&PlatformDisplay::sharedDisplayForCompositing()); + context->makeContextCurrent(); + uint32_t fbo; + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_data.m_texture, 0); + glBindTexture(bindTextureTarget, destinationTexture); + glCopyTexImage2D(target, 0, internalformat, 0, 0, m_size.width(), m_size.height(), 0); + glBindTexture(bindTextureTarget, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glFlush(); + glDeleteFramebuffers(1, &fbo); + return true; +#else + UNUSED_PARAM(target); + UNUSED_PARAM(destinationTexture); + UNUSED_PARAM(internalformat); + UNUSED_PARAM(premultiplyAlpha); + UNUSED_PARAM(flipY); + return false; #endif +} } // namespace WebCore + +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferDataCairo.h b/Source/WebCore/platform/graphics/cairo/ImageBufferDataCairo.h index 72ea4c34f..93d817614 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageBufferDataCairo.h +++ b/Source/WebCore/platform/graphics/cairo/ImageBufferDataCairo.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,12 +23,19 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef ImageBufferDataCairo_h +#define ImageBufferDataCairo_h + +#if USE(CAIRO) + #include "PlatformContextCairo.h" #include "RefPtrCairo.h" #if ENABLE(ACCELERATED_2D_CANVAS) +#include "PlatformLayer.h" #include "TextureMapper.h" #include "TextureMapperPlatformLayer.h" +#include "TextureMapperPlatformLayerProxy.h" #endif namespace WebCore { @@ -37,20 +44,40 @@ class IntSize; class ImageBufferData #if ENABLE(ACCELERATED_2D_CANVAS) - : public TextureMapperPlatformLayer + : public PlatformLayer #endif { public: - ImageBufferData(const IntSize&); + ImageBufferData(const IntSize&, RenderingMode); + virtual ~ImageBufferData(); RefPtr<cairo_surface_t> m_surface; PlatformContextCairo m_platformContext; + std::unique_ptr<GraphicsContext> m_context; IntSize m_size; + RenderingMode m_renderingMode; #if ENABLE(ACCELERATED_2D_CANVAS) - virtual void paintToTextureMapper(TextureMapper*, const FloatRect& target, const TransformationMatrix&, float opacity); + void createCairoGLSurface(); + +#if USE(COORDINATED_GRAPHICS_THREADED) + RefPtr<TextureMapperPlatformLayerProxy> proxy() const override { return m_platformLayerProxy.copyRef(); } + void swapBuffersIfNeeded() override; + void createCompositorBuffer(); + + RefPtr<TextureMapperPlatformLayerProxy> m_platformLayerProxy; + RefPtr<cairo_surface_t> m_compositorSurface; + uint32_t m_compositorTexture; + RefPtr<cairo_t> m_compositorCr; +#else + virtual void paintToTextureMapper(TextureMapper&, const FloatRect& target, const TransformationMatrix&, float opacity); +#endif uint32_t m_texture; #endif }; } // namespace WebCore + +#endif // USE(CAIRO) + +#endif // ImageBufferDataCairo_h diff --git a/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp index 46a39b45b..4e5365958 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006 Apple Inc. All rights reserved. * Copyright (C) 2007 Alp Toker <alp@atoker.com> * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> * @@ -12,10 +12,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -31,30 +31,21 @@ #if USE(CAIRO) #include "AffineTransform.h" -#include "CairoUtilities.h" #include "Color.h" #include "GraphicsContext.h" #include "ImageObserver.h" -#include "PlatformContextCairo.h" -#include <cairo.h> -#include <math.h> namespace WebCore { -void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const AffineTransform& patternTransform, - const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& destRect, BlendMode) +void Image::drawPattern(GraphicsContext& context, const FloatRect& destRect, const FloatRect& tileRect, const AffineTransform& patternTransform, + const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, BlendMode blendMode) { - RefPtr<cairo_surface_t> surface = nativeImageForCurrentFrame(); - if (!surface) // If it's too early we won't have an image yet. - return; - - cairo_t* cr = context->platformContext()->cr(); - drawPatternToCairoContext(cr, surface.get(), size(), tileRect, patternTransform, phase, toCairoOperator(op), destRect); + context.drawPattern(*this, destRect, tileRect, patternTransform, phase, spacing, op, blendMode); if (imageObserver()) imageObserver()->didDraw(this); } -} +} // namespace WebCore #endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/IntRectCairo.cpp b/Source/WebCore/platform/graphics/cairo/IntRectCairo.cpp index cef3af905..054bd2ac3 100644 --- a/Source/WebCore/platform/graphics/cairo/IntRectCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/IntRectCairo.cpp @@ -21,6 +21,8 @@ #include "config.h" #include "IntRect.h" +#if USE(CAIRO) + #include <cairo.h> namespace WebCore { @@ -37,4 +39,6 @@ IntRect::operator cairo_rectangle_int_t() const return r; } -} +} // namespace WebCore + +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/NativeImageCairo.cpp b/Source/WebCore/platform/graphics/cairo/NativeImageCairo.cpp new file mode 100644 index 000000000..69b7bb0f8 --- /dev/null +++ b/Source/WebCore/platform/graphics/cairo/NativeImageCairo.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2016 Apple 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 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 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 "NativeImage.h" + +#if USE(CAIRO) + +#include "CairoUtilities.h" +#include "PlatformContextCairo.h" +#include <cairo.h> + +namespace WebCore { + +IntSize nativeImageSize(const NativeImagePtr& image) +{ + return image ? cairoSurfaceSize(image.get()) : IntSize(); +} + +bool nativeImageHasAlpha(const NativeImagePtr& image) +{ + return !image || cairo_surface_get_content(image.get()) != CAIRO_CONTENT_COLOR; +} + +Color nativeImageSinglePixelSolidColor(const NativeImagePtr& image) +{ + if (!image || nativeImageSize(image) != IntSize(1, 1)) + return Color(); + + if (cairo_surface_get_type(image.get()) != CAIRO_SURFACE_TYPE_IMAGE) + return Color(); + + RGBA32* pixel = reinterpret_cast_ptr<RGBA32*>(cairo_image_surface_get_data(image.get())); + return colorFromPremultipliedARGB(*pixel); +} + +float subsamplingScale(GraphicsContext&, const FloatRect&, const FloatRect&) +{ + return 1; +} + +void drawNativeImage(const NativeImagePtr& image, GraphicsContext& context, const FloatRect& destRect, const FloatRect& srcRect, const IntSize&, CompositeOperator op, BlendMode mode, const ImageOrientation& orientation) +{ + context.save(); + + // Set the compositing operation. + if (op == CompositeSourceOver && mode == BlendModeNormal && !nativeImageHasAlpha(image)) + context.setCompositeOperation(CompositeCopy); + else + context.setCompositeOperation(op, mode); + +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + IntSize scaledSize = nativeImageSize(image); + FloatRect adjustedSrcRect = adjustSourceRectForDownSampling(srcRect, scaledSize); +#else + FloatRect adjustedSrcRect(srcRect); +#endif + + FloatRect adjustedDestRect = destRect; + + if (orientation != DefaultImageOrientation) { + // ImageOrientation expects the origin to be at (0, 0). + context.translate(destRect.x(), destRect.y()); + adjustedDestRect.setLocation(FloatPoint()); + context.concatCTM(orientation.transformFromDefault(adjustedDestRect.size())); + if (orientation.usesWidthAsHeight()) { + // The destination rectangle will have it's width and height already reversed for the orientation of + // the image, as it was needed for page layout, so we need to reverse it back here. + adjustedDestRect.setSize(adjustedDestRect.size().transposedSize()); + } + } + + context.platformContext()->drawSurfaceToContext(image.get(), adjustedDestRect, adjustedSrcRect, context); + context.restore(); +} + +void clearNativeImageSubimages(const NativeImagePtr&) +{ +} + +} // namespace WebCore + +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.cpp b/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.cpp deleted file mode 100644 index 1594e7b5d..000000000 --- a/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 USE(FREETYPE) -#include <cairo-ft.h> -#include <fontconfig/fcfreetype.h> -#endif - -#include <cairo.h> - -namespace WTF { - -#if 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 deleted file mode 100644 index 3704b6a17..000000000 --- a/Source/WebCore/platform/graphics/cairo/OwnPtrCairo.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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 <wtf/OwnPtr.h> -#include <wtf/PassOwnPtr.h> - -#if USE(FREETYPE) -typedef struct _FcObjectSet FcObjectSet; -typedef struct _FcFontSet FcFontSet; -#endif - -typedef struct cairo_path cairo_path_t; - -namespace WTF { - -#if 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 index 5fac5f0b9..6ab79100c 100644 --- a/Source/WebCore/platform/graphics/cairo/PathCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/PathCairo.cpp @@ -26,10 +26,11 @@ #include "config.h" #include "Path.h" +#if USE(CAIRO) + #include "AffineTransform.h" #include "FloatRect.h" #include "GraphicsContext.h" -#include "OwnPtrCairo.h" #include "PlatformPathCairo.h" #include "StrokeStyleApplier.h" #include <cairo.h> @@ -57,8 +58,9 @@ Path::Path(const Path& other) return; cairo_t* cr = ensurePlatformPath()->context(); - OwnPtr<cairo_path_t> pathCopy = adoptPtr(cairo_copy_path(other.platformPath()->context())); - cairo_append_path(cr, pathCopy.get()); + auto pathCopy = cairo_copy_path(other.platformPath()->context()); + cairo_append_path(cr, pathCopy); + cairo_path_destroy(pathCopy); } PlatformPathPtr Path::ensurePlatformPath() @@ -81,8 +83,9 @@ Path& Path::operator=(const Path& other) } else { clear(); cairo_t* cr = ensurePlatformPath()->context(); - OwnPtr<cairo_path_t> pathCopy = adoptPtr(cairo_copy_path(other.platformPath()->context())); - cairo_append_path(cr, pathCopy.get()); + auto pathCopy = cairo_copy_path(other.platformPath()->context()); + cairo_append_path(cr, pathCopy); + cairo_path_destroy(pathCopy); } return *this; @@ -281,6 +284,22 @@ void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) addArc(p, radius, sa, ea, anticlockwise); } +void Path::addEllipse(FloatPoint point, float radiusX, float radiusY, float rotation, float startAngle, float endAngle, bool anticlockwise) +{ + cairo_t* cr = ensurePlatformPath()->context(); + cairo_save(cr); + cairo_translate(cr, point.x(), point.y()); + cairo_rotate(cr, rotation); + cairo_scale(cr, radiusX, radiusY); + + if (anticlockwise) + cairo_arc_negative(cr, 0, 0, 1, startAngle, endAngle); + else + cairo_arc(cr, 0, 0, 1, startAngle, endAngle); + + cairo_restore(cr); +} + void Path::addEllipse(const FloatRect& rect) { cairo_t* cr = ensurePlatformPath()->context(); @@ -293,6 +312,24 @@ void Path::addEllipse(const FloatRect& rect) cairo_restore(cr); } +void Path::addPath(const Path& path, const AffineTransform& transform) +{ + if (path.isNull()) + return; + + cairo_matrix_t matrix(transform); + if (cairo_matrix_invert(&matrix) != CAIRO_STATUS_SUCCESS) + return; + + cairo_t* cr = path.platformPath()->context(); + cairo_save(cr); + cairo_transform(cr, &matrix); + auto pathCopy = cairo_copy_path(cr); + cairo_restore(cr); + cairo_append_path(ensurePlatformPath()->context(), pathCopy); + cairo_path_destroy(pathCopy); +} + void Path::closeSubpath() { cairo_t* cr = ensurePlatformPath()->context(); @@ -353,13 +390,13 @@ bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) return cairo_in_stroke(cr, point.x(), point.y()); } -void Path::apply(void* info, PathApplierFunction function) const +void Path::apply(const PathApplierFunction& function) const { if (isNull()) return; cairo_t* cr = platformPath()->context(); - OwnPtr<cairo_path_t> pathCopy = adoptPtr(cairo_copy_path(cr)); + auto pathCopy = cairo_copy_path(cr); cairo_path_data_t* data; PathElement pelement; FloatPoint points[3]; @@ -371,26 +408,27 @@ void Path::apply(void* info, PathApplierFunction function) const case CAIRO_PATH_MOVE_TO: pelement.type = PathElementMoveToPoint; pelement.points[0] = FloatPoint(data[1].point.x,data[1].point.y); - function(info, &pelement); + function(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); + function(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); + function(pelement); break; case CAIRO_PATH_CLOSE_PATH: pelement.type = PathElementCloseSubpath; - function(info, &pelement); + function(pelement); break; } } + cairo_path_destroy(pathCopy); } void Path::transform(const AffineTransform& trans) @@ -402,3 +440,5 @@ void Path::transform(const AffineTransform& trans) } } // namespace WebCore + +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/PatternCairo.cpp b/Source/WebCore/platform/graphics/cairo/PatternCairo.cpp index 8870d3e03..81bc7ce96 100644 --- a/Source/WebCore/platform/graphics/cairo/PatternCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/PatternCairo.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,6 +26,8 @@ #include "config.h" #include "Pattern.h" +#if USE(CAIRO) + #include "AffineTransform.h" #include "GraphicsContext.h" #include <cairo.h> @@ -50,4 +52,6 @@ cairo_pattern_t* Pattern::createPlatformPattern(const AffineTransform&) const return pattern; } -} +} // namespace WebCore + +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp b/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp index fc2b2b0fc..65d7eeee9 100644 --- a/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp @@ -12,10 +12,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -28,10 +28,11 @@ #include "config.h" #include "PlatformContextCairo.h" +#if USE(CAIRO) + #include "CairoUtilities.h" #include "Gradient.h" #include "GraphicsContext.h" -#include "OwnPtrCairo.h" #include "Pattern.h" #include <cairo.h> @@ -136,9 +137,13 @@ void PlatformContextCairo::pushImageMask(cairo_surface_t* surface, const FloatRe cairo_push_group(m_cr.get()); cairo_set_operator(m_cr.get(), CAIRO_OPERATOR_SOURCE); - cairo_set_source_surface(m_cr.get(), currentTarget, 0, 0); - cairo_rectangle(m_cr.get(), rect.x(), rect.y(), rect.width(), rect.height()); + // To avoid the limit of Pixman backend, we need to reduce the size of pattern matrix + // See https://bugs.webkit.org/show_bug.cgi?id=154283 + cairo_set_source_surface(m_cr.get(), currentTarget, rect.x(), rect.y()); + cairo_translate(m_cr.get(), rect.x(), rect.y()); + cairo_rectangle(m_cr.get(), 0, 0, rect.width(), rect.height()); cairo_fill(m_cr.get()); + cairo_translate(m_cr.get(), -rect.x(), -rect.y()); } static void drawPatternToCairoContext(cairo_t* cr, cairo_pattern_t* pattern, const FloatRect& destRect, float alpha) @@ -154,7 +159,7 @@ static void drawPatternToCairoContext(cairo_t* cr, cairo_pattern_t* pattern, con cairo_fill(cr); } -void PlatformContextCairo::drawSurfaceToContext(cairo_surface_t* surface, const FloatRect& destRect, const FloatRect& originalSrcRect, GraphicsContext* context) +void PlatformContextCairo::drawSurfaceToContext(cairo_surface_t* surface, const FloatRect& destRect, const FloatRect& originalSrcRect, GraphicsContext& context) { // Avoid invalid cairo matrix with small values. if (std::fabs(destRect.width()) < 0.5f || std::fabs(destRect.height()) < 0.5f) @@ -197,11 +202,11 @@ void PlatformContextCairo::drawSurfaceToContext(cairo_surface_t* surface, const cairo_pattern_set_filter(pattern.get(), CAIRO_FILTER_FAST); break; case InterpolationMedium: - case InterpolationHigh: - cairo_pattern_set_filter(pattern.get(), CAIRO_FILTER_BILINEAR); - break; case InterpolationDefault: - cairo_pattern_set_filter(pattern.get(), CAIRO_FILTER_BILINEAR); + cairo_pattern_set_filter(pattern.get(), CAIRO_FILTER_GOOD); + break; + case InterpolationHigh: + cairo_pattern_set_filter(pattern.get(), CAIRO_FILTER_BEST); break; } cairo_pattern_set_extend(pattern.get(), CAIRO_EXTEND_PAD); @@ -215,7 +220,7 @@ void PlatformContextCairo::drawSurfaceToContext(cairo_surface_t* surface, const cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, leftPadding, topPadding }; cairo_pattern_set_matrix(pattern.get(), &matrix); - ShadowBlur& shadow = context->platformContext()->shadowBlur(); + ShadowBlur& shadow = context.platformContext()->shadowBlur(); if (shadow.type() != ShadowBlur::NoShadow) { if (GraphicsContext* shadowContext = shadow.beginShadowLayer(context, destRect)) { drawPatternToCairoContext(shadowContext->platformContext()->cr(), pattern.get(), destRect, 1); @@ -304,7 +309,7 @@ void PlatformContextCairo::clipForPatternFilling(const GraphicsContextState& sta ASSERT(state.fillPattern); // Hold current cairo path in a variable for restoring it after configuring the pattern clip rectangle. - OwnPtr<cairo_path_t> currentPath = adoptPtr(cairo_copy_path(m_cr.get())); + auto currentPath = cairo_copy_path(m_cr.get()); cairo_new_path(m_cr.get()); // Initialize clipping extent from current cairo clip extents, then shrink if needed according to pattern. @@ -335,7 +340,10 @@ void PlatformContextCairo::clipForPatternFilling(const GraphicsContextState& sta } // Restoring cairo path. - cairo_append_path(m_cr.get(), currentPath.get()); + cairo_append_path(m_cr.get(), currentPath); + cairo_path_destroy(currentPath); } } // namespace WebCore + +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h b/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h index d7f1205f7..642a3052c 100644 --- a/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h +++ b/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,6 +26,8 @@ #ifndef PlatformContextCairo_h #define PlatformContextCairo_h +#if USE(CAIRO) + #include "GraphicsContext.h" #include "RefPtrCairo.h" #include "ShadowBlur.h" @@ -56,7 +58,7 @@ public: float globalAlpha() const; void pushImageMask(cairo_surface_t*, const FloatRect&); - void drawSurfaceToContext(cairo_surface_t*, const FloatRect& destRect, const FloatRect& srcRect, GraphicsContext*); + void drawSurfaceToContext(cairo_surface_t*, const FloatRect& destRect, const FloatRect& srcRect, GraphicsContext&); void setImageInterpolationQuality(InterpolationQuality); InterpolationQuality imageInterpolationQuality() const; @@ -84,4 +86,6 @@ private: } // namespace WebCore +#endif // USE(CAIRO) + #endif // PlatformContextCairo_h diff --git a/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.cpp b/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.cpp index 3a7d5128a..14c8d9bcd 100644 --- a/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.cpp @@ -20,20 +20,23 @@ #include "config.h" #include "PlatformPathCairo.h" +#if USE(CAIRO) + #include <cairo.h> namespace WebCore { -static cairo_surface_t* getPathSurface() +static cairo_surface_t* pathSurface() { - return cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1); + static cairo_surface_t* s_pathSurface = cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1); + return s_pathSurface; } -static cairo_surface_t* gPathSurface = getPathSurface(); - CairoPath::CairoPath() - : m_cr(adoptRef(cairo_create(gPathSurface))) + : m_cr(adoptRef(cairo_create(pathSurface()))) { } -} +} // namespace WebCore + +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.h b/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.h index 938b942a4..5f1059446 100644 --- a/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.h +++ b/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.h @@ -21,6 +21,8 @@ #ifndef PlatformPathCairo_h #define PlatformPathCairo_h +#if USE(CAIRO) + #include "RefPtrCairo.h" namespace WebCore { @@ -40,4 +42,6 @@ private: } // namespace WebCore +#endif // USE(CAIRO) + #endif // PlatformPathCairo_h diff --git a/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp index 0f55f5797..61a0369f5 100644 --- a/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp @@ -19,6 +19,8 @@ #include "config.h" #include "RefPtrCairo.h" +#if USE(CAIRO) + #include <cairo.h> #if USE(FREETYPE) @@ -30,89 +32,102 @@ namespace WTF { template<> void refIfNotNull(cairo_t* ptr) { - if (LIKELY(ptr != 0)) + if (LIKELY(ptr)) cairo_reference(ptr); } template<> void derefIfNotNull(cairo_t* ptr) { - if (LIKELY(ptr != 0)) + if (LIKELY(ptr)) cairo_destroy(ptr); } template<> void refIfNotNull(cairo_surface_t* ptr) { - if (LIKELY(ptr != 0)) + if (LIKELY(ptr)) cairo_surface_reference(ptr); } template<> void derefIfNotNull(cairo_surface_t* ptr) { - if (LIKELY(ptr != 0)) + if (LIKELY(ptr)) cairo_surface_destroy(ptr); } template<> void refIfNotNull(cairo_font_face_t* ptr) { - if (LIKELY(ptr != 0)) + if (LIKELY(ptr)) cairo_font_face_reference(ptr); } template<> void derefIfNotNull(cairo_font_face_t* ptr) { - if (LIKELY(ptr != 0)) + if (LIKELY(ptr)) cairo_font_face_destroy(ptr); } template<> void refIfNotNull(cairo_scaled_font_t* ptr) { - if (LIKELY(ptr != 0)) + if (LIKELY(ptr)) cairo_scaled_font_reference(ptr); } template<> void derefIfNotNull(cairo_scaled_font_t* ptr) { - if (LIKELY(ptr != 0)) + if (LIKELY(ptr)) cairo_scaled_font_destroy(ptr); } template<> void refIfNotNull(cairo_pattern_t* ptr) { - if (LIKELY(ptr != 0)) + if (LIKELY(ptr)) cairo_pattern_reference(ptr); } template<> void derefIfNotNull(cairo_pattern_t* ptr) { - if (LIKELY(ptr != 0)) + if (LIKELY(ptr)) cairo_pattern_destroy(ptr); } template<> void refIfNotNull(cairo_region_t* ptr) { - if (LIKELY(ptr != 0)) + if (LIKELY(ptr)) cairo_region_reference(ptr); } template<> void derefIfNotNull(cairo_region_t* ptr) { - if (LIKELY(ptr != 0)) + if (LIKELY(ptr)) cairo_region_destroy(ptr); } #if USE(FREETYPE) template<> void refIfNotNull(FcPattern* ptr) { - if (LIKELY(ptr != 0)) + if (LIKELY(ptr)) FcPatternReference(ptr); } template<> void derefIfNotNull(FcPattern* ptr) { - if (LIKELY(ptr != 0)) + if (LIKELY(ptr)) FcPatternDestroy(ptr); } -#endif +template<> void refIfNotNull(FcConfig* ptr) +{ + if (LIKELY(ptr)) + FcConfigReference(ptr); +} +template<> void derefIfNotNull(FcConfig* ptr) +{ + if (LIKELY(ptr)) + FcConfigDestroy(ptr); } +#endif + +} // namespace WTF + +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/RefPtrCairo.h b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.h index 0e1baf50a..8e92f4e6d 100644 --- a/Source/WebCore/platform/graphics/cairo/RefPtrCairo.h +++ b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.h @@ -20,6 +20,8 @@ #ifndef RefPtrCairo_h #define RefPtrCairo_h +#if USE(CAIRO) + #include <wtf/RefPtr.h> typedef struct _cairo cairo_t; @@ -31,6 +33,7 @@ typedef struct _cairo_region cairo_region_t; #if USE(FREETYPE) typedef struct _FcPattern FcPattern; +typedef struct _FcConfig FcConfig; #endif namespace WTF { @@ -56,8 +59,13 @@ template<> void derefIfNotNull(cairo_region_t*); #if USE(FREETYPE) template<> void refIfNotNull(FcPattern* ptr); template<> void derefIfNotNull(FcPattern* ptr); + +template<> void refIfNotNull(FcConfig* ptr); +template<> void derefIfNotNull(FcConfig* ptr); #endif -} +} // namespace WTF + +#endif // USE(CAIRO) #endif // RefPtrCairo_h diff --git a/Source/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp b/Source/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp index bebc4a321..a5cc372f8 100644 --- a/Source/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp @@ -9,10 +9,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,12 +23,13 @@ */ #include "config.h" -#include "AffineTransform.h" #include "TransformationMatrix.h" +#if USE(CAIRO) + +#include "AffineTransform.h" #include "FloatRect.h" #include "IntRect.h" - #include <cairo.h> namespace WebCore { @@ -61,6 +62,6 @@ AffineTransform::operator cairo_matrix_t() const return m; } -} +} // namespace WebCore -// vim: ts=4 sw=4 et +#endif // USE(CAIRO) |