Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2006 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  *           (C) 2009 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 "SVGResourceClipper.h"
     31 
     32 #include "AffineTransform.h"
     33 #include "GraphicsContext.h"
     34 #include "SVGRenderTreeAsText.h"
     35 
     36 #if PLATFORM(CG)
     37 #include <ApplicationServices/ApplicationServices.h>
     38 #endif
     39 
     40 namespace WebCore {
     41 
     42 SVGResourceClipper::SVGResourceClipper()
     43     : SVGResource()
     44 {
     45 }
     46 
     47 SVGResourceClipper::~SVGResourceClipper()
     48 {
     49 }
     50 
     51 void SVGResourceClipper::resetClipData()
     52 {
     53     m_clipData.clear();
     54     m_clipperBoundingBox = FloatRect();
     55 }
     56 
     57 void SVGResourceClipper::invalidate()
     58 {
     59     SVGResource::invalidate();
     60     resetClipData();
     61 }
     62 
     63 FloatRect SVGResourceClipper::clipperBoundingBox(const FloatRect& objectBoundingBox)
     64 {
     65     // FIXME: We need a different calculation for other clip content than paths.
     66     if (!m_clipperBoundingBox.isEmpty())
     67         return m_clipperBoundingBox;
     68 
     69     if (m_clipData.clipData().isEmpty())
     70         return FloatRect();
     71 
     72     for (unsigned x = 0; x < m_clipData.clipData().size(); x++) {
     73         ClipData clipData = m_clipData.clipData()[x];
     74 
     75         FloatRect clipPathRect = clipData.path.boundingRect();
     76         if (clipData.bboxUnits) {
     77             clipPathRect.scale(objectBoundingBox.width(), objectBoundingBox.height());
     78             clipPathRect.move(objectBoundingBox.x(), objectBoundingBox.y());
     79         }
     80         m_clipperBoundingBox.unite(clipPathRect);
     81     }
     82 
     83     return m_clipperBoundingBox;
     84 }
     85 
     86 void SVGResourceClipper::applyClip(GraphicsContext* context, const FloatRect& boundingBox) const
     87 {
     88     if (m_clipData.clipData().isEmpty())
     89         return;
     90 
     91     bool heterogenousClipRules = false;
     92     WindRule clipRule = m_clipData.clipData()[0].windRule;
     93 
     94     context->beginPath();
     95 
     96     for (unsigned x = 0; x < m_clipData.clipData().size(); x++) {
     97         ClipData clipData = m_clipData.clipData()[x];
     98         if (clipData.windRule != clipRule)
     99             heterogenousClipRules = true;
    100 
    101         Path clipPath = clipData.path;
    102 
    103         if (clipData.bboxUnits) {
    104             AffineTransform transform;
    105             transform.translate(boundingBox.x(), boundingBox.y());
    106             transform.scaleNonUniform(boundingBox.width(), boundingBox.height());
    107             clipPath.transform(transform);
    108         }
    109         context->addPath(clipPath);
    110     }
    111 
    112     // FIXME!
    113     // We don't currently allow for heterogenous clip rules.
    114     // we would have to detect such, draw to a mask, and then clip
    115     // to that mask
    116     context->clipPath(clipRule);
    117 }
    118 
    119 void SVGResourceClipper::addClipData(const Path& path, WindRule rule, bool bboxUnits)
    120 {
    121     m_clipData.addPath(path, rule, bboxUnits);
    122 }
    123 
    124 const ClipDataList& SVGResourceClipper::clipData() const
    125 {
    126     return m_clipData;
    127 }
    128 
    129 TextStream& SVGResourceClipper::externalRepresentation(TextStream& ts) const
    130 {
    131     ts << "[type=CLIPPER]";
    132     ts << " [clip data=" << clipData().clipData() << "]";
    133     return ts;
    134 }
    135 
    136 TextStream& operator<<(TextStream& ts, WindRule rule)
    137 {
    138     switch (rule) {
    139         case RULE_NONZERO:
    140             ts << "NON-ZERO"; break;
    141         case RULE_EVENODD:
    142             ts << "EVEN-ODD"; break;
    143     }
    144 
    145     return ts;
    146 }
    147 
    148 TextStream& operator<<(TextStream& ts, const ClipData& d)
    149 {
    150     ts << "[winding=" << d.windRule << "]";
    151 
    152     if (d.bboxUnits)
    153         ts << " [bounding box mode=" << d.bboxUnits << "]";
    154 
    155     ts << " [path=" << d.path.debugString() << "]";
    156     return ts;
    157 }
    158 
    159 SVGResourceClipper* getClipperById(Document* document, const AtomicString& id, const RenderObject* object)
    160 {
    161     SVGResource* resource = getResourceById(document, id, object);
    162     if (resource && resource->isClipper())
    163         return static_cast<SVGResourceClipper*>(resource);
    164 
    165     return 0;
    166 }
    167 
    168 } // namespace WebCore
    169 
    170 #endif
    171