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