1 /* 2 * Copyright (C) 2006 Nikolas Zimmermann <zimmermann (at) kde.org> 3 * 2008 Dirk Schulze <krit (at) 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 41 using namespace std; 42 43 namespace WebCore { 44 45 SVGPaintServerPattern::SVGPaintServerPattern(const SVGPatternElement* owner) 46 : m_ownerElement(owner) 47 , m_pattern(0) 48 { 49 ASSERT(owner); 50 } 51 52 SVGPaintServerPattern::~SVGPaintServerPattern() 53 { 54 } 55 56 FloatRect SVGPaintServerPattern::patternBoundaries() const 57 { 58 return m_patternBoundaries; 59 } 60 61 void SVGPaintServerPattern::setPatternBoundaries(const FloatRect& rect) 62 { 63 m_patternBoundaries = rect; 64 } 65 66 ImageBuffer* SVGPaintServerPattern::tile() const 67 { 68 return m_tile.get(); 69 } 70 71 void SVGPaintServerPattern::setTile(PassOwnPtr<ImageBuffer> tile) 72 { 73 m_tile = tile; 74 } 75 76 AffineTransform SVGPaintServerPattern::patternTransform() const 77 { 78 return m_patternTransform; 79 } 80 81 void SVGPaintServerPattern::setPatternTransform(const AffineTransform& transform) 82 { 83 m_patternTransform = transform; 84 } 85 86 TextStream& 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 98 bool 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 174 void 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