1 /*
2 * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
3 * (C) 2009 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 "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
SVGResourceClipper()42 SVGResourceClipper::SVGResourceClipper()
43 : SVGResource()
44 {
45 }
46
~SVGResourceClipper()47 SVGResourceClipper::~SVGResourceClipper()
48 {
49 }
50
resetClipData()51 void SVGResourceClipper::resetClipData()
52 {
53 m_clipData.clear();
54 m_clipperBoundingBox = FloatRect();
55 }
56
invalidate()57 void SVGResourceClipper::invalidate()
58 {
59 SVGResource::invalidate();
60 resetClipData();
61 }
62
clipperBoundingBox(const FloatRect & objectBoundingBox)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
applyClip(GraphicsContext * context,const FloatRect & boundingBox) const86 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
addClipData(const Path & path,WindRule rule,bool bboxUnits)119 void SVGResourceClipper::addClipData(const Path& path, WindRule rule, bool bboxUnits)
120 {
121 m_clipData.addPath(path, rule, bboxUnits);
122 }
123
clipData() const124 const ClipDataList& SVGResourceClipper::clipData() const
125 {
126 return m_clipData;
127 }
128
externalRepresentation(TextStream & ts) const129 TextStream& SVGResourceClipper::externalRepresentation(TextStream& ts) const
130 {
131 ts << "[type=CLIPPER]";
132 ts << " [clip data=" << clipData().clipData() << "]";
133 return ts;
134 }
135
operator <<(TextStream & ts,WindRule rule)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
operator <<(TextStream & ts,const ClipData & d)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
getClipperById(Document * document,const AtomicString & id,const RenderObject * object)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