1 /*
2     Ming, an SWF output library
3     Copyright (C) 2002  Opaque Industries - http://www.opaque.net/
4 
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9 
10     This library 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 GNU
13     Lesser General Public License for more details.
14 
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 /* $Id$ */
21 
22 #include <stdlib.h>
23 
24 #include "libming.h"
25 #include "linestyle.h"
26 #include "fillstyle.h"
27 #include "error.h"
28 
29 #define SWF_LINESTYLE_FLAG_FILL		(1<<11)
30 
31 struct SWFLineStyle_s
32 {
33 	unsigned short width;
34 	byte r;
35 	byte g;
36 	byte b;
37 	byte a;
38 
39 	/* LINESTYLE2 extensions */
40 	// 16 bit flags
41 	int flags;
42 	float miterLimit;
43 	SWFFillStyle fill;
44 };
45 
46 
47 /*
48  * sets simple linestyle
49  * width is set in TWIPS
50  */
newSWFLineStyle(unsigned short width,byte r,byte g,byte b,byte a)51 SWFLineStyle newSWFLineStyle(unsigned short width,
52                              byte r, byte g, byte b, byte a)
53 {
54 	SWFLineStyle line = (SWFLineStyle)malloc(sizeof(struct SWFLineStyle_s));
55 
56 	line->width = width;
57 	line->r = r;
58 	line->g = g;
59 	line->b = b;
60 	line->a = a;
61 	line->flags = 0;
62 
63 	return line;
64 }
65 
66 /*
67  * create Linestyle2 introduce with SWF 8.
68  * Linestyle2 extends Linestyle1 with some extra flags:
69  *
70  * Line cap style: select one of the following flags (default is round cap style)
71  * SWF_LINESTYLE_CAP_ROUND
72  * SWF_LINESTYLE_CAP_NONE
73  * SWF_LINESTYLE_CAP_SQUARE
74  *
75  * Line join style: select one of the following flags (default is round join style)
76  * SWF_LINESTYLE_JOIN_ROUND
77  * SWF_LINESTYLE_JOIN_BEVEL
78  * SWF_LINESTYLE_JOIN_MITER
79  *
80  * Scaling flags: disable horizontal / vertical scaling
81  * SWF_LINESTYLE_FLAG_NOHSCALE
82  * SWF_LINESTYLE_FLAG_NOVSCALE
83  *
84  * Enable pixel hinting to correct blurry vertical / horizontal lines
85  * -> all anchors will be aligned to full pixels
86  * SWF_LINESTYLE_FLAG_HINTING
87  *
88  * Disable stroke closure: if no-close flag is set caps will be applied
89  * instead of joins
90  * SWF_LINESTYLE_FLAG_NOCLOSE
91  *
92  * End-cap style: default round
93  * SWF_LINESTYLE_FLAG_ENDCAP_ROUND
94  * SWF_LINESTYLE_FLAG_ENDCAP_NONE
95  * SWF_LINESTYLE_FLAG_ENDCAP_SQUARE
96  *
97  * If join style is SWF_LINESTYLE_JOIN_MITER a miter limit factor
98  * must be set. Miter max length is then calculated as:
99  * max miter len = miter limit * width.
100  * If join style is not miter, this value will be ignored.
101  */
newSWFLineStyle2(unsigned short width,byte r,byte g,byte b,byte a,int flags,float miterLimit)102 SWFLineStyle newSWFLineStyle2(unsigned short width, byte r, byte g, byte b, byte a,
103                               int flags, float miterLimit)
104 {
105 	SWFLineStyle line = (SWFLineStyle)malloc(sizeof(struct SWFLineStyle_s));
106 
107 	line->width = width;
108 	line->r = r;
109 	line->g = g;
110 	line->b = b;
111 	line->a = a;
112 
113 	line->flags = 0 | flags;
114 	line->miterLimit = miterLimit;
115 	line->fill = NULL;
116 	return line;
117 }
118 
119 
120 /*
121  * create Linestyle2 introduce with SWF 8.
122  *
123  * Instead of providing a fill color, a FillStyle can be applied
124  * to a line.
125  *
126  * Linestyle2 also extends Linestyle1 with some extra flags:
127  *
128  * Line cap style: select one of the following flags (default is round cap style)
129  * SWF_LINESTYLE_CAP_ROUND
130  * SWF_LINESTYLE_CAP_NONE
131  * SWF_LINESTYLE_CAP_SQUARE
132  *
133  * Line join style: select one of the following flags (default is round join style)
134  * SWF_LINESTYLE_JOIN_ROUND
135  * SWF_LINESTYLE_JOIN_BEVEL
136  * SWF_LINESTYLE_JOIN_MITER
137  *
138  * Scaling flags: disable horizontal / vertical scaling
139  * SWF_LINESTYLE_FLAG_NOHSCALE
140  * SWF_LINESTYLE_FLAG_NOVSCALE
141  *
142  * Enable pixel hinting to correct blurry vertical / horizontal lines
143  * -> all anchors will be aligned to full pixels
144  * SWF_LINESTYLE_FLAG_HINTING
145  *
146  * Disable stroke closure: if no-close flag is set caps will be applied
147  * instead of joins
148  * SWF_LINESTYLE_FLAG_NOCLOSE
149  *
150  * End-cap style: default round
151  * SWF_LINESTYLE_FLAG_ENDCAP_ROUND
152  * SWF_LINESTYLE_FLAG_ENDCAP_NONE
153  * SWF_LINESTYLE_FLAG_ENDCAP_SQUARE
154  *
155  * If join style is SWF_LINESTYLE_JOIN_MITER a miter limit factor
156  * must be set. Miter max length is then calculated as:
157  * max miter len = miter limit * width.
158  * If join style is not miter, this value will be ignored.
159  */
newSWFLineStyle2_filled(unsigned short width,SWFFillStyle fill,int flags,float miterLimit)160 SWFLineStyle newSWFLineStyle2_filled(unsigned short width, SWFFillStyle fill,
161                                      int flags, float miterLimit)
162 {
163 	SWFLineStyle line;
164 
165 	if(fill == NULL)
166 		return NULL;
167 
168 	line = (SWFLineStyle)malloc(sizeof(struct SWFLineStyle_s));
169 	line->width = width;
170 	line->flags = SWF_LINESTYLE_FLAG_FILL | flags;
171 	line->miterLimit = miterLimit;
172 	line->fill = fill;
173 	return line;
174 }
175 
SWFLineStyle_equals(SWFLineStyle line,unsigned short width,byte r,byte g,byte b,byte a,int flags)176 byte SWFLineStyle_equals(SWFLineStyle line, unsigned short width,
177 			 byte r, byte g, byte b, byte a, int flags)
178 {
179 //	if(line->width == 0 && width == 0)
180 //		return TRUE;
181 
182 	if(line->width == width &&
183 		 line->r == r &&
184 		 line->g == g &&
185 		 line->b == b &&
186 		 line->a == a &&
187                  line->flags == flags)
188 	{
189 		return TRUE;
190 	}
191 
192 	return FALSE;
193 }
194 
SWFLineStyle_equals2filled(SWFLineStyle line,unsigned short width,SWFFillStyle fill,int flags)195 byte SWFLineStyle_equals2filled(SWFLineStyle line, unsigned short width,
196                                 SWFFillStyle fill, int flags)
197 {
198 	if(line->width == width &&
199            line->flags == flags &&
200            SWFFillStyle_equals(line->fill, fill))
201 	{
202 		return TRUE;
203 	}
204 	return FALSE;
205 }
206 
207 
SWFLineStyle_getWidth(SWFLineStyle line)208 unsigned short SWFLineStyle_getWidth(SWFLineStyle line)
209 {
210 	return line->width;
211 }
212 
213 
writeLineStyle1(SWFOutput out,SWFLineStyle line,int shapeType)214 static inline void writeLineStyle1(SWFOutput out, SWFLineStyle line, int shapeType)
215 {
216 	SWFOutput_writeUInt16(out, line->width);
217 	SWFOutput_writeUInt8(out, line->r);
218 	SWFOutput_writeUInt8(out, line->g);
219 	SWFOutput_writeUInt8(out, line->b);
220 
221 	if(shapeType >= SWF_DEFINESHAPE3)
222 		SWFOutput_writeUInt8(out, line->a);
223 }
224 
writeLineStyle2(SWFOutput out,SWFLineStyle line,SWFBlocktype shapeType,SWFRect bounds)225 static inline void writeLineStyle2(SWFOutput out, SWFLineStyle line, SWFBlocktype shapeType, SWFRect bounds)
226 {
227 	SWFOutput_writeUInt16(out, line->width);
228 	SWFOutput_writeUInt8(out, (line->flags >> 8));
229 	SWFOutput_writeUInt8(out, line->flags);
230 	if(line->flags & SWF_LINESTYLE_JOIN_MITER)
231 		SWFOutput_writeFixed8(out, line->miterLimit);
232 	if(line->flags & SWF_LINESTYLE_FLAG_FILL)
233 		SWFOutput_writeFillStyle(out, line->fill, shapeType, bounds);
234 	else
235 	{
236 		SWFOutput_writeUInt8(out, line->r);
237 		SWFOutput_writeUInt8(out, line->g);
238 		SWFOutput_writeUInt8(out, line->b);
239 		SWFOutput_writeUInt8(out, line->a);
240 	}
241 }
242 
SWFOutput_writeLineStyles(SWFOutput out,SWFLineStyle * lines,int nLines,SWFBlocktype shapeType,SWFRect bounds)243 void SWFOutput_writeLineStyles(SWFOutput out,
244                                SWFLineStyle *lines, int nLines,
245                                SWFBlocktype shapeType,
246                                SWFRect bounds)
247 {
248 	SWFLineStyle line;
249 	int i;
250 
251 	if(nLines<255)
252 		SWFOutput_writeUInt8(out, nLines);
253 	else
254 	{
255 		SWFOutput_writeUInt8(out, 255);
256 		SWFOutput_writeUInt16(out, nLines);
257 	}
258 
259 	for(i=0; i<nLines; ++i)
260 	{
261 		line = lines[i];
262 		if(shapeType == SWF_DEFINESHAPE4)
263 			writeLineStyle2(out, line, shapeType, bounds);
264 		else
265 			writeLineStyle1(out, line, shapeType);
266 	}
267 }
268 
269 
SWFOutput_writeMorphLineStyles2(SWFOutput out,SWFLineStyle * lines1,int nLines1,SWFLineStyle * lines2,int nLines2)270 void SWFOutput_writeMorphLineStyles2(SWFOutput out,
271 		SWFLineStyle *lines1, int nLines1,
272 		SWFLineStyle *lines2, int nLines2)
273 {
274 	SWFLineStyle line1, line2;
275 	int i;
276 
277 	SWF_assert(nLines1 == nLines2);
278 
279 	if(nLines1<255)
280 		SWFOutput_writeUInt8(out, nLines1);
281 	else
282 	{
283 		SWFOutput_writeUInt8(out, 255);
284 		SWFOutput_writeUInt16(out, nLines1);
285 	}
286 
287 	for(i=0; i<nLines1; ++i)
288 	{
289 		line1 = lines1[i];
290 		line2 = lines2[i];
291 
292 		SWFOutput_writeUInt16(out, line1->width);
293 		SWFOutput_writeUInt16(out, line2->width);
294 
295 		if(line1->flags != line2->flags)
296 			SWF_warnOnce("Morph: shapes _must_ us equal line flags\n");
297 		SWFOutput_writeUInt8(out, (line1->flags >> 8));
298 		SWFOutput_writeUInt8(out, line1->flags);
299 
300 		if(line1->flags & SWF_LINESTYLE_JOIN_MITER)
301 			SWFOutput_writeFixed8(out, line1->miterLimit);
302 		if(line1->flags & SWF_LINESTYLE_FLAG_FILL)
303 			SWFOutput_writeMorphFillStyle(out, line1->fill, NULL, line2->fill, NULL);
304 		else
305 		{
306 
307 			SWFOutput_writeUInt8(out, line1->r);
308 			SWFOutput_writeUInt8(out, line1->g);
309 			SWFOutput_writeUInt8(out, line1->b);
310 			SWFOutput_writeUInt8(out, line1->a);
311 			SWFOutput_writeUInt8(out, line2->r);
312 			SWFOutput_writeUInt8(out, line2->g);
313 			SWFOutput_writeUInt8(out, line2->b);
314 			SWFOutput_writeUInt8(out, line2->a);
315 		}
316 	}
317 }
318 
319 
SWFOutput_writeMorphLineStyles(SWFOutput out,SWFLineStyle * lines1,int nLines1,SWFLineStyle * lines2,int nLines2)320 void SWFOutput_writeMorphLineStyles(SWFOutput out,
321 						SWFLineStyle *lines1, int nLines1,
322 						SWFLineStyle *lines2, int nLines2)
323 {
324 	SWFLineStyle line1, line2;
325 	int i;
326 
327 	SWF_assert(nLines1 == nLines2);
328 
329 	if(nLines1<255)
330 		SWFOutput_writeUInt8(out, nLines1);
331 	else
332 	{
333 		SWFOutput_writeUInt8(out, 255);
334 		SWFOutput_writeUInt16(out, nLines1);
335 	}
336 
337 	for(i=0; i<nLines1; ++i)
338 	{
339 		line1 = lines1[i];
340 		line2 = lines2[i];
341 
342 		SWFOutput_writeUInt16(out, line1->width);
343 		SWFOutput_writeUInt16(out, line2->width);
344 		SWFOutput_writeUInt8(out, line1->r);
345 		SWFOutput_writeUInt8(out, line1->g);
346 		SWFOutput_writeUInt8(out, line1->b);
347 		SWFOutput_writeUInt8(out, line1->a);
348 		SWFOutput_writeUInt8(out, line2->r);
349 		SWFOutput_writeUInt8(out, line2->g);
350 		SWFOutput_writeUInt8(out, line2->b);
351 		SWFOutput_writeUInt8(out, line2->a);
352 	}
353 }
354 
355 
356 /*
357  * Local variables:
358  * tab-width: 2
359  * c-basic-offset: 2
360  * End:
361  */
362