Home | History | Annotate | Download | only in graphics
      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