1bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen/* 2bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * Copyright (C) 2010 Sencha, Inc. 3bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * Copyright (C) 2010 Igalia S.L. 4bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * 5bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * All rights reserved. 6bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * 7bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * Redistribution and use in source and binary forms, with or without 8bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * modification, are permitted provided that the following conditions 9bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * are met: 10bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * 1. Redistributions of source code must retain the above copyright 11bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * notice, this list of conditions and the following disclaimer. 12bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * 2. Redistributions in binary form must reproduce the above copyright 13bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * notice, this list of conditions and the following disclaimer in the 14bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * documentation and/or other materials provided with the distribution. 15bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * 16bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 17bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 20bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen */ 28bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 29bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen#include "config.h" 30bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen#include "ContextShadow.h" 31bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 32a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "AffineTransform.h" 33bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen#include "CairoUtilities.h" 34cad810f21b803229eb11403f9209855525a25d57Steve Block#include "GraphicsContext.h" 35a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "OwnPtrCairo.h" 36a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "Path.h" 372bde8e466a4451c7319e3a072d118917957d6554Steve Block#include "PlatformContextCairo.h" 38bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen#include "Timer.h" 39bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen#include <cairo.h> 40bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 41a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochusing WTF::max; 42a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 43bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsennamespace WebCore { 44bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 452daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic RefPtr<cairo_surface_t> gScratchBuffer; 46bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsenstatic void purgeScratchBuffer() 47bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 482daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch gScratchBuffer.clear(); 49bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 50bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 51bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen// ContextShadow needs a scratch image as the buffer for the blur filter. 52bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen// Instead of creating and destroying the buffer for every operation, 53bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen// we create a buffer which will be automatically purged via a timer. 54bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsenclass PurgeScratchBufferTimer : public TimerBase { 55bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsenprivate: 56bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen virtual void fired() { purgeScratchBuffer(); } 57bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen}; 58bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsenstatic PurgeScratchBufferTimer purgeScratchBufferTimer; 59bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsenstatic void scheduleScratchBufferPurge() 60bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 61bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen if (purgeScratchBufferTimer.isActive()) 62bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen purgeScratchBufferTimer.stop(); 63bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen purgeScratchBufferTimer.startOneShot(2); 64bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 65bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 66bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsenstatic cairo_surface_t* getScratchBuffer(const IntSize& size) 67bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 68bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen int width = size.width(); 69bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen int height = size.height(); 702daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int scratchWidth = gScratchBuffer.get() ? cairo_image_surface_get_width(gScratchBuffer.get()) : 0; 712daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int scratchHeight = gScratchBuffer.get() ? cairo_image_surface_get_height(gScratchBuffer.get()) : 0; 72bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 73bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen // We do not need to recreate the buffer if the current buffer is large enough. 742daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (gScratchBuffer.get() && scratchWidth >= width && scratchHeight >= height) 752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return gScratchBuffer.get(); 76bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 77bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen purgeScratchBuffer(); 78bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 79bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen // Round to the nearest 32 pixels so we do not grow the buffer for similar sized requests. 80bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen width = (1 + (width >> 5)) << 5; 81bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen height = (1 + (height >> 5)) << 5; 822daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch gScratchBuffer = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height)); 832daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return gScratchBuffer.get(); 84bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 85bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 86cad810f21b803229eb11403f9209855525a25d57Steve BlockPlatformContext ContextShadow::beginShadowLayer(GraphicsContext* context, const FloatRect& layerArea) 87bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 88f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch adjustBlurDistance(context); 89f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 90bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen double x1, x2, y1, y2; 912bde8e466a4451c7319e3a072d118917957d6554Steve Block cairo_clip_extents(context->platformContext()->cr(), &x1, &y1, &x2, &y2); 92f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch IntRect layerRect = calculateLayerBoundingRect(context, layerArea, IntRect(x1, y1, x2 - x1, y2 - y1)); 93bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 94bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen // Don't paint if we are totally outside the clip region. 95f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (layerRect.isEmpty()) 96bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen return 0; 97bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 98f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch m_layerImage = getScratchBuffer(layerRect.size()); 99bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen m_layerContext = cairo_create(m_layerImage); 100bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 101bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen // Always clear the surface first. 102bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen cairo_set_operator(m_layerContext, CAIRO_OPERATOR_CLEAR); 103bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen cairo_paint(m_layerContext); 104bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen cairo_set_operator(m_layerContext, CAIRO_OPERATOR_OVER); 105bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 106f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch cairo_translate(m_layerContext, m_layerContextTranslation.x(), m_layerContextTranslation.y()); 107bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen return m_layerContext; 108bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 109bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 110cad810f21b803229eb11403f9209855525a25d57Steve Blockvoid ContextShadow::endShadowLayer(GraphicsContext* context) 111bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 112bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen cairo_destroy(m_layerContext); 113bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen m_layerContext = 0; 114bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 115a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (m_type == BlurShadow) { 116a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_surface_flush(m_layerImage); 117bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen blurLayerImage(cairo_image_surface_get_data(m_layerImage), 118bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen IntSize(cairo_image_surface_get_width(m_layerImage), cairo_image_surface_get_height(m_layerImage)), 119bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen cairo_image_surface_get_stride(m_layerImage)); 120a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_surface_mark_dirty(m_layerImage); 121a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 122bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 1232bde8e466a4451c7319e3a072d118917957d6554Steve Block cairo_t* cr = context->platformContext()->cr(); 124bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen cairo_save(cr); 125bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen setSourceRGBAFromColor(cr, m_color); 126f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch cairo_mask_surface(cr, m_layerImage, m_layerOrigin.x(), m_layerOrigin.y()); 127bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen cairo_restore(cr); 128bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 129bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen // Schedule a purge of the scratch buffer. We do not need to destroy the surface. 130bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen scheduleScratchBufferPurge(); 131bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 132bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 133cad810f21b803229eb11403f9209855525a25d57Steve Blockvoid ContextShadow::drawRectShadowWithoutTiling(GraphicsContext* context, const IntRect& shadowRect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius, float alpha) 134a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 135a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch beginShadowLayer(context, shadowRect); 136a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 137a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!m_layerContext) 138a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 139a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 140a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch Path path; 141a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch path.addRoundedRect(shadowRect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); 142a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 143a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch appendWebCorePathToCairoContext(m_layerContext, path); 144a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_set_source_rgba(m_layerContext, 0, 0, 0, alpha); 145a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_fill(m_layerContext); 146a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 147a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch endShadowLayer(context); 148a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 149a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 150a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochstatic inline FloatPoint getPhase(const FloatRect& dest, const FloatRect& tile) 151a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 152a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch FloatPoint phase = dest.location(); 153a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch phase.move(-tile.x(), -tile.y()); 154a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 155a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return phase; 156a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 157a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 158a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch/* 159a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch This function uses tiling to improve the performance of the shadow 160a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch drawing of rounded rectangles. The code basically does the following 161a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch steps: 162a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 163a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 1. Calculate the size of the shadow template, a rectangle that 164a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch contains all the necessary tiles to draw the complete shadow. 165a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 166a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 2. If that size is smaller than the real rectangle render the new 167a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch template rectangle and its shadow in a new surface, in other case 168a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch render the shadow of the real rectangle in the destination 169a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch surface. 170a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 171a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 3. Calculate the sizes and positions of the tiles and their 172a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destinations and use drawPattern to render the final shadow. The 173a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch code divides the rendering in 8 tiles: 174a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 175a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 1 | 2 | 3 176a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ----------- 177a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 4 | | 5 178a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ----------- 179a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 6 | 7 | 8 180a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 181a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch The corners are directly copied from the template rectangle to the 182a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch real one and the side tiles are 1 pixel width, we use them as 183a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 184a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch tiles to cover the destination side. The corner tiles are bigger 185a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch than just the side of the rounded corner, we need to increase it 186a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch because the modifications caused by the corner over the blur 187a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch effect. We fill the central part with solid color to complete the 188a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch shadow. 189a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch */ 190a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid ContextShadow::drawRectShadow(GraphicsContext* context, const IntRect& rect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius) 191a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 192a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 193a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch float radiusTwice = m_blurDistance * 2; 194cad810f21b803229eb11403f9209855525a25d57Steve Block 195cad810f21b803229eb11403f9209855525a25d57Steve Block // Find the space the corners need inside the rect for its shadows. 196cad810f21b803229eb11403f9209855525a25d57Steve Block int internalShadowWidth = radiusTwice + max(topLeftRadius.width(), bottomLeftRadius.width()) + 197cad810f21b803229eb11403f9209855525a25d57Steve Block max(topRightRadius.width(), bottomRightRadius.width()); 198cad810f21b803229eb11403f9209855525a25d57Steve Block int internalShadowHeight = radiusTwice + max(topLeftRadius.height(), topRightRadius.height()) + 199cad810f21b803229eb11403f9209855525a25d57Steve Block max(bottomLeftRadius.height(), bottomRightRadius.height()); 200cad810f21b803229eb11403f9209855525a25d57Steve Block 2012bde8e466a4451c7319e3a072d118917957d6554Steve Block cairo_t* cr = context->platformContext()->cr(); 202cad810f21b803229eb11403f9209855525a25d57Steve Block 203cad810f21b803229eb11403f9209855525a25d57Steve Block // drawShadowedRect still does not work with rotations. 204cad810f21b803229eb11403f9209855525a25d57Steve Block // https://bugs.webkit.org/show_bug.cgi?id=45042 205cad810f21b803229eb11403f9209855525a25d57Steve Block if ((!context->getCTM().isIdentityOrTranslationOrFlipped()) || (internalShadowWidth > rect.width()) 206cad810f21b803229eb11403f9209855525a25d57Steve Block || (internalShadowHeight > rect.height()) || (m_type != BlurShadow)) { 207cad810f21b803229eb11403f9209855525a25d57Steve Block drawRectShadowWithoutTiling(context, rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius, context->getAlpha()); 208a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 209a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 210a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 211a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Calculate size of the template shadow buffer. 212a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch IntSize shadowBufferSize = IntSize(rect.width() + radiusTwice, rect.height() + radiusTwice); 213a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 214a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Determine dimensions of shadow rect. 215a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch FloatRect shadowRect = FloatRect(rect.location(), shadowBufferSize); 216a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch shadowRect.move(- m_blurDistance, - m_blurDistance); 217a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 218a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Size of the tiling side. 219a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch int sideTileWidth = 1; 220a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 221a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // The length of a side of the buffer is the enough space for four blur radii, 222a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // the radii of the corners, and then 1 pixel to draw the side tiles. 223cad810f21b803229eb11403f9209855525a25d57Steve Block IntSize shadowTemplateSize = IntSize(sideTileWidth + radiusTwice + internalShadowWidth, 224cad810f21b803229eb11403f9209855525a25d57Steve Block sideTileWidth + radiusTwice + internalShadowHeight); 225a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 226a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Reduce the size of what we have to draw with the clip area. 227a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch double x1, x2, y1, y2; 228a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_clip_extents(cr, &x1, &y1, &x2, &y2); 229cad810f21b803229eb11403f9209855525a25d57Steve Block calculateLayerBoundingRect(context, shadowRect, IntRect(x1, y1, x2 - x1, y2 - y1)); 230a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 231f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if ((shadowTemplateSize.width() * shadowTemplateSize.height() > m_sourceRect.width() * m_sourceRect.height())) { 232cad810f21b803229eb11403f9209855525a25d57Steve Block drawRectShadowWithoutTiling(context, rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius, context->getAlpha()); 233a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 234a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 235a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 236a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch shadowRect.move(m_offset.width(), m_offset.height()); 237a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 238a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_layerImage = getScratchBuffer(shadowTemplateSize); 239a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 240a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Draw shadow into a new ImageBuffer. 241a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_layerContext = cairo_create(m_layerImage); 242a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 243a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Clear the surface first. 244a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_set_operator(m_layerContext, CAIRO_OPERATOR_CLEAR); 245a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_paint(m_layerContext); 246a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_set_operator(m_layerContext, CAIRO_OPERATOR_OVER); 247a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 248a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Draw the rectangle. 249a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch IntRect templateRect = IntRect(m_blurDistance, m_blurDistance, shadowTemplateSize.width() - radiusTwice, shadowTemplateSize.height() - radiusTwice); 250a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch Path path; 251a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch path.addRoundedRect(templateRect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); 252a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch appendWebCorePathToCairoContext(m_layerContext, path); 253a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 254a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_set_source_rgba(m_layerContext, 0, 0, 0, context->getAlpha()); 255a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_fill(m_layerContext); 256a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 257a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Blur the image. 258a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_surface_flush(m_layerImage); 259a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch blurLayerImage(cairo_image_surface_get_data(m_layerImage), shadowTemplateSize, cairo_image_surface_get_stride(m_layerImage)); 260a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_surface_mark_dirty(m_layerImage); 261a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 262a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Mask the image with the shadow color. 263a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_set_operator(m_layerContext, CAIRO_OPERATOR_IN); 264a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch setSourceRGBAFromColor(m_layerContext, m_color); 265a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_paint(m_layerContext); 266a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 267a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_destroy(m_layerContext); 268a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_layerContext = 0; 269a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 270a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Fill the internal part of the shadow. 271a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch shadowRect.inflate(-radiusTwice); 272a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!shadowRect.isEmpty()) { 273a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_save(cr); 274a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch path.clear(); 275a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch path.addRoundedRect(shadowRect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); 276a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch appendWebCorePathToCairoContext(cr, path); 277a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch setSourceRGBAFromColor(cr, m_color); 278a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_fill(cr); 279a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch cairo_restore(cr); 280a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 281a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch shadowRect.inflate(radiusTwice); 282a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 283a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Draw top side. 284a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch FloatRect tileRect = FloatRect(radiusTwice + topLeftRadius.width(), 0, sideTileWidth, radiusTwice); 285a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch FloatRect destRect = tileRect; 286a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect.move(shadowRect.x(), shadowRect.y()); 287a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect.setWidth(shadowRect.width() - topLeftRadius.width() - topRightRadius.width() - m_blurDistance * 4); 288a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch FloatPoint phase = getPhase(destRect, tileRect); 289a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch AffineTransform patternTransform; 290a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch patternTransform.makeIdentity(); 291a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect); 292a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 293a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Draw the bottom side. 294a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch tileRect = FloatRect(radiusTwice + bottomLeftRadius.width(), shadowTemplateSize.height() - radiusTwice, sideTileWidth, radiusTwice); 295a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect = tileRect; 296a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect.move(shadowRect.x(), shadowRect.y() + radiusTwice + rect.height() - shadowTemplateSize.height()); 297a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect.setWidth(shadowRect.width() - bottomLeftRadius.width() - bottomRightRadius.width() - m_blurDistance * 4); 298a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch phase = getPhase(destRect, tileRect); 299a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect); 300a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 301a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Draw the right side. 302a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch tileRect = FloatRect(shadowTemplateSize.width() - radiusTwice, radiusTwice + topRightRadius.height(), radiusTwice, sideTileWidth); 303a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect = tileRect; 304a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect.move(shadowRect.x() + radiusTwice + rect.width() - shadowTemplateSize.width(), shadowRect.y()); 305a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect.setHeight(shadowRect.height() - topRightRadius.height() - bottomRightRadius.height() - m_blurDistance * 4); 306a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch phase = getPhase(destRect, tileRect); 307a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect); 308a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 309a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Draw the left side. 310a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch tileRect = FloatRect(0, radiusTwice + topLeftRadius.height(), radiusTwice, sideTileWidth); 311a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect = tileRect; 312a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect.move(shadowRect.x(), shadowRect.y()); 313a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect.setHeight(shadowRect.height() - topLeftRadius.height() - bottomLeftRadius.height() - m_blurDistance * 4); 314a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch phase = FloatPoint(destRect.x() - tileRect.x(), destRect.y() - tileRect.y()); 315a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect); 316a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 317a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Draw the top left corner. 318a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch tileRect = FloatRect(0, 0, radiusTwice + topLeftRadius.width(), radiusTwice + topLeftRadius.height()); 319a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect = tileRect; 320a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect.move(shadowRect.x(), shadowRect.y()); 321a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch phase = getPhase(destRect, tileRect); 322a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect); 323a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 324a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Draw the top right corner. 325a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch tileRect = FloatRect(shadowTemplateSize.width() - radiusTwice - topRightRadius.width(), 0, radiusTwice + topRightRadius.width(), 326a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch radiusTwice + topRightRadius.height()); 327a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect = tileRect; 328a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect.move(shadowRect.x() + rect.width() - shadowTemplateSize.width() + radiusTwice, shadowRect.y()); 329a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch phase = getPhase(destRect, tileRect); 330a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect); 331a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 332a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Draw the bottom right corner. 333a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch tileRect = FloatRect(shadowTemplateSize.width() - radiusTwice - bottomRightRadius.width(), 334a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch shadowTemplateSize.height() - radiusTwice - bottomRightRadius.height(), 335a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch radiusTwice + bottomRightRadius.width(), radiusTwice + bottomRightRadius.height()); 336a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect = tileRect; 337a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect.move(shadowRect.x() + rect.width() - shadowTemplateSize.width() + radiusTwice, 338a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch shadowRect.y() + rect.height() - shadowTemplateSize.height() + radiusTwice); 339a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch phase = getPhase(destRect, tileRect); 340a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect); 341a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 342a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Draw the bottom left corner. 343a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch tileRect = FloatRect(0, shadowTemplateSize.height() - radiusTwice - bottomLeftRadius.height(), 344a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch radiusTwice + bottomLeftRadius.width(), radiusTwice + bottomLeftRadius.height()); 345a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect = tileRect; 346a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect.move(shadowRect.x(), shadowRect.y() + rect.height() - shadowTemplateSize.height() + radiusTwice); 347a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch phase = getPhase(destRect, tileRect); 348a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect); 349a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 350a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Schedule a purge of the scratch buffer. 351a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch scheduleScratchBufferPurge(); 352a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 353a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 354bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 355