1 //
2 // Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012
3 // Free Software Foundation, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 #include "DynamicShape.h"
20 #include "FillStyle.h"
21 #include "Renderer.h"
22 #include "DisplayObject.h"
23
24 #include <vector>
25
26 namespace gnash {
27
DynamicShape()28 DynamicShape::DynamicShape()
29 :
30 _currpath(nullptr),
31 _currfill(0),
32 _currline(0),
33 _x(0),
34 _y(0),
35 _changed(false)
36 {}
37
38 void
clear()39 DynamicShape::clear()
40 {
41 _shape.clear();
42 _currpath = nullptr;
43 _currfill = _currline = 0;
44 _currsubshape.clear();
45 // TODO: worth setting _changed=true ?
46 }
47
48 void
display(Renderer & renderer,const Transform & xform) const49 DynamicShape::display(Renderer& renderer, const Transform& xform) const
50 {
51 renderer.drawShape(_shape, xform);
52 }
53
54 void
add_path(const Path & pth)55 DynamicShape::add_path(const Path& pth)
56 {
57 _currsubshape.addPath(pth);
58 _currpath = &_currsubshape.currentPath();
59 _changed = true;
60 }
61
62 void
endFill()63 DynamicShape::endFill()
64 {
65 // Close the path
66 if ( _currpath && _currfill )
67 {
68 // TODO: should not just close the last path
69 // but rather append the point where
70 // the fill actually begun (could be
71 // in a previous path).
72 //
73 // NOTE that doing so will require changing
74 // the hitTest code to do stop considering
75 // each path in isolation when doing PIP testing
76 //
77
78 _currpath->close();
79
80 // reset _x and _y to reflect closing point
81 _x = _currpath->ap.x;
82 _y = _currpath->ap.y;
83 }
84
85 if (_currline) {
86 _shape.addSubshape(_currsubshape);
87 _currsubshape.paths().clear(); // Retain style info
88 }
89
90 // Remove reference to the "current" path, as
91 // next drawing will happen on a different one
92 _currpath = nullptr;
93 // Remove fill information
94 _currfill = 0;
95 }
96
97 void
beginFill(const FillStyle & f)98 DynamicShape::beginFill(const FillStyle& f)
99 {
100 // End previous fill
101 endFill();
102
103
104 _currfill = addFillStyle(f);
105
106 // TODO: how to know wheter the fill should be set
107 // as *left* or *right* fill ?
108 // A quick test shows that *left* always work fine !
109 Path newPath(_x, _y, _currfill, 0, _currline);
110 add_path(newPath);
111 }
112
113 void
startNewPath(bool newShape)114 DynamicShape::startNewPath(bool newShape)
115 {
116 // Close any pending filled path
117 if ( _currpath && _currfill)
118 {
119 // TODO: this is probably bogus
120 _currpath->close();
121 }
122
123 if (newShape) {
124 _shape.addSubshape(_currsubshape);
125 _currsubshape.paths().clear(); // Retain style info
126 }
127
128
129 // The DrawingApiTest.swf file shows we should not
130 // end the current fill when starting a new path.
131
132 // A quick test shows that *left* always work fine !
133 // More than that, using a *right* fill seems to break the tests !
134 Path newPath(_x, _y, _currfill, 0, _currline);
135 add_path(newPath);
136 }
137
138 void
finalize() const139 DynamicShape::finalize() const
140 {
141 // Nothing to do if not changed
142 if ( ! _changed ) return;
143
144 // Close any pending filled path (_currpath should be last path)
145 if ( _currpath && _currfill)
146 {
147 assert(!_currsubshape.paths().empty());
148 assert(_currpath == &(_currsubshape.paths().back()));
149 _currpath->close();
150 }
151
152 // This function being const seems to be at odds with its purpose...
153 _shape.addSubshape(_currsubshape);
154
155 _currsubshape.paths().clear(); // Retain style info
156
157 // TODO: check consistency of fills and such !
158
159 _changed = false;
160 }
161
162 void
lineStyle(std::uint16_t thickness,const rgba & color,bool vScale,bool hScale,bool pixelHinting,bool noClose,CapStyle startCapStyle,CapStyle endCapStyle,JoinStyle joinStyle,float miterLimitFactor)163 DynamicShape::lineStyle(std::uint16_t thickness, const rgba& color,
164 bool vScale, bool hScale, bool pixelHinting, bool noClose,
165 CapStyle startCapStyle, CapStyle endCapStyle,
166 JoinStyle joinStyle, float miterLimitFactor)
167 {
168 LineStyle style(thickness, color, vScale, hScale, pixelHinting,
169 noClose, startCapStyle, endCapStyle, joinStyle,
170 miterLimitFactor);
171
172 _currline = add_line_style(style);
173 startNewPath(false);
174 }
175
176 void
resetLineStyle()177 DynamicShape::resetLineStyle()
178 {
179 _currline = 0;
180 startNewPath(false);
181 }
182
183 void
moveTo(std::int32_t x,std::int32_t y)184 DynamicShape::moveTo(std::int32_t x, std::int32_t y)
185 {
186 // It was manually tested that a moveTo, even
187 // when moving to the same point of current cursor,
188 // will start a new path.
189
190 _x = x;
191 _y = y;
192 startNewPath(false);
193 }
194
195 void
lineTo(std::int32_t x,std::int32_t y,int swfVersion)196 DynamicShape::lineTo(std::int32_t x, std::int32_t y, int swfVersion)
197 {
198 if (!_currpath) startNewPath(false);
199 assert(_currpath);
200
201 _currpath->drawLineTo(x, y);
202
203 // Update bounds
204 SWFRect bounds = _shape.getBounds();
205
206 unsigned thickness = _currline ?
207 _currsubshape.lineStyles().back().getThickness() : 0;
208
209 if (_currpath->size() == 1) {
210 _currpath->expandBounds(bounds, thickness, swfVersion);
211 } else {
212 bounds.expand_to_circle(x, y, swfVersion < 8 ? thickness :
213 thickness / 2.0);
214 }
215
216 _shape.setBounds(bounds);
217
218 // Update current pen position
219 _x = x;
220 _y = y;
221
222 // Mark as changed
223 _changed = true;
224 }
225
226 void
curveTo(std::int32_t cx,std::int32_t cy,std::int32_t ax,std::int32_t ay,int swfVersion)227 DynamicShape::curveTo(std::int32_t cx, std::int32_t cy,
228 std::int32_t ax, std::int32_t ay, int swfVersion)
229 {
230 if (!_currpath) startNewPath(false);
231 assert(_currpath);
232
233 _currpath->drawCurveTo(cx, cy, ax, ay);
234
235 SWFRect bounds = _shape.getBounds();
236
237 unsigned thickness = _currline ?
238 _currsubshape.lineStyles().back().getThickness() : 0;
239
240 if (_currpath->size() == 1) {
241 _currpath->expandBounds(bounds, thickness, swfVersion);
242 }
243 else {
244 bounds.expand_to_circle(ax, ay,
245 swfVersion < 8 ? thickness : thickness / 2.0);
246 bounds.expand_to_circle(cx, cy,
247 swfVersion < 8 ? thickness : thickness / 2.0);
248 }
249
250 _shape.setBounds(bounds);
251
252 // Update current pen position
253 _x = ax;
254 _y = ay;
255
256 // Mark as changed
257 _changed = true;
258 }
259
260 size_t
addFillStyle(const FillStyle & stl)261 DynamicShape::addFillStyle(const FillStyle& stl)
262 {
263 _currsubshape.addFillStyle(stl);
264 return _currsubshape.fillStyles().size();
265 }
266
267 size_t
add_line_style(const LineStyle & stl)268 DynamicShape::add_line_style(const LineStyle& stl)
269 {
270 _currsubshape.addLineStyle(stl);
271 return _currsubshape.lineStyles().size();
272 }
273
274 } // end namespace gnash
275
276
277 // Local Variables:
278 // mode: C++
279 // indent-tabs-mode: t
280 // End:
281