1/* 2 * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> 3 * 2008 Dirk Schulze <krit@webkit.org> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "config.h" 28 29#if ENABLE(SVG) 30#include "SVGPaintServerPattern.h" 31 32#include "AffineTransform.h" 33#include "GraphicsContext.h" 34#include "Image.h" 35#include "ImageBuffer.h" 36#include "Pattern.h" 37#include "RenderObject.h" 38#include "SVGPatternElement.h" 39#include "SVGRenderTreeAsText.h" 40 41using namespace std; 42 43namespace WebCore { 44 45SVGPaintServerPattern::SVGPaintServerPattern(const SVGPatternElement* owner) 46 : m_ownerElement(owner) 47 , m_pattern(0) 48{ 49 ASSERT(owner); 50} 51 52SVGPaintServerPattern::~SVGPaintServerPattern() 53{ 54} 55 56FloatRect SVGPaintServerPattern::patternBoundaries() const 57{ 58 return m_patternBoundaries; 59} 60 61void SVGPaintServerPattern::setPatternBoundaries(const FloatRect& rect) 62{ 63 m_patternBoundaries = rect; 64} 65 66ImageBuffer* SVGPaintServerPattern::tile() const 67{ 68 return m_tile.get(); 69} 70 71void SVGPaintServerPattern::setTile(PassOwnPtr<ImageBuffer> tile) 72{ 73 m_tile = tile; 74} 75 76AffineTransform SVGPaintServerPattern::patternTransform() const 77{ 78 return m_patternTransform; 79} 80 81void SVGPaintServerPattern::setPatternTransform(const AffineTransform& transform) 82{ 83 m_patternTransform = transform; 84} 85 86TextStream& SVGPaintServerPattern::externalRepresentation(TextStream& ts) const 87{ 88 // Gradients/patterns aren't setup, until they are used for painting. Work around that fact. 89 m_ownerElement->buildPattern(FloatRect(0.0f, 0.0f, 1.0f, 1.0f)); 90 91 ts << "[type=PATTERN]" 92 << " [bbox=" << patternBoundaries() << "]"; 93 if (!patternTransform().isIdentity()) 94 ts << " [pattern transform=" << patternTransform() << "]"; 95 return ts; 96} 97 98bool SVGPaintServerPattern::setup(GraphicsContext*& context, const RenderObject* object, const RenderStyle* style, SVGPaintTargetType type, bool isPaintingText) const 99{ 100 FloatRect targetRect = object->objectBoundingBox(); 101 102 const SVGRenderStyle* svgStyle = style->svgStyle(); 103 bool isFilled = (type & ApplyToFillTargetType) && svgStyle->hasFill(); 104 bool isStroked = (type & ApplyToStrokeTargetType) && svgStyle->hasStroke(); 105 106 ASSERT((isFilled && !isStroked) || (!isFilled && isStroked)); 107 108 m_ownerElement->buildPattern(targetRect); 109 if (!tile()) 110 return false; 111 112 context->save(); 113 114 ASSERT(!m_pattern); 115 116 IntRect tileRect = tile()->image()->rect(); 117 if (tileRect.width() > patternBoundaries().width() || tileRect.height() > patternBoundaries().height()) { 118 // Draw the first cell of the pattern manually to support overflow="visible" on all platforms. 119 int tileWidth = static_cast<int>(patternBoundaries().width() + 0.5f); 120 int tileHeight = static_cast<int>(patternBoundaries().height() + 0.5f); 121 OwnPtr<ImageBuffer> tileImage = ImageBuffer::create(IntSize(tileWidth, tileHeight)); 122 123 GraphicsContext* tileImageContext = tileImage->context(); 124 125 int numY = static_cast<int>(ceilf(tileRect.height() / tileHeight)) + 1; 126 int numX = static_cast<int>(ceilf(tileRect.width() / tileWidth)) + 1; 127 128 tileImageContext->save(); 129 tileImageContext->translate(-patternBoundaries().width() * numX, -patternBoundaries().height() * numY); 130 for (int i = numY; i > 0; i--) { 131 tileImageContext->translate(0, patternBoundaries().height()); 132 for (int j = numX; j > 0; j--) { 133 tileImageContext->translate(patternBoundaries().width(), 0); 134 tileImageContext->drawImage(tile()->image(), style->colorSpace(), tileRect, tileRect); 135 } 136 tileImageContext->translate(-patternBoundaries().width() * numX, 0); 137 } 138 tileImageContext->restore(); 139 140 m_pattern = Pattern::create(tileImage->image(), true, true); 141 } 142 else 143 m_pattern = Pattern::create(tile()->image(), true, true); 144 145 if (isFilled) { 146 context->setAlpha(svgStyle->fillOpacity()); 147 context->setFillPattern(m_pattern); 148 context->setFillRule(svgStyle->fillRule()); 149 } 150 if (isStroked) { 151 context->setAlpha(svgStyle->strokeOpacity()); 152 context->setStrokePattern(m_pattern); 153 applyStrokeStyleToContext(context, style, object); 154 } 155 156 AffineTransform matrix; 157 matrix.translate(patternBoundaries().x(), patternBoundaries().y()); 158 matrix.multiply(patternTransform()); 159 m_pattern->setPatternSpaceTransform(matrix); 160 161 if (isPaintingText) { 162 context->setTextDrawingMode(isFilled ? cTextFill : cTextStroke); 163#if PLATFORM(CG) 164 if (isFilled) 165 context->applyFillPattern(); 166 else 167 context->applyStrokePattern(); 168#endif 169 } 170 171 return true; 172} 173 174void SVGPaintServerPattern::teardown(GraphicsContext*& context, const RenderObject*, SVGPaintTargetType, bool) const 175{ 176 m_pattern = 0; 177 178 context->restore(); 179} 180 181} // namespace WebCore 182 183#endif 184