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 #ifndef __C2MAN__
23 #include <stdlib.h>
24 #include <string.h>
25 #endif
26 
27 #include "libming.h"
28 #include "textfield.h"
29 #include "utf8.h"
30 #include "character.h"
31 #include "browserfont.h"
32 #include "font.h"
33 
34 
35 typedef enum {Unresolved, BrowserFont, Font, FontChar, Imported} FontType;
36 struct SWFTextField_s
37 {
38 	struct SWFCharacter_s character;
39 
40 	SWFOutput out; /* cheap way out */
41 	int flags;
42 	FontType fonttype;
43 
44 	union
45 	{
46 		SWFFont font;
47 		SWFFontCharacter fontchar;
48 		SWFBrowserFont browserFont;
49 	} font;
50 
51 	int nLines;
52 	int fontHeight;
53 	int fieldHeight;
54 	int width;
55 	int padding;
56 
57 	byte r;
58 	byte g;
59 	byte b;
60 	byte a;
61 
62 	short length;
63 	byte alignment;
64 	short leftMargin;
65 	short rightMargin;
66 	short indentation;
67 	short lineSpacing;
68 
69 	char *varName;
70 	char *string;
71 	unsigned short *embeds;
72 	int embedlen;
73 };
74 
75 
76 /* after every metric change, we update the bounds for the
77 	 SWFCharacter_getBounds function */
78 
79 static void
resetBounds(SWFTextField field)80 resetBounds(SWFTextField field)
81 {
82 	int minX, maxX, minY, maxY;
83 
84 	SWFRect_getBounds(CHARACTER(field)->bounds, &minX, &maxX, &minY, &maxY);
85 
86 	minX = -field->padding;
87 	minY = -field->padding;
88 
89 	if ( field->width == 0 )
90 	{
91 		int width = field->fontHeight*(field->string ? strlen(field->string) : 0);
92 		maxX = field->padding + width;
93 	}
94 	else
95 		maxX = field->padding + field->width;
96 
97 	if ( field->fieldHeight == 0 )
98 	{
99 		maxY = field->padding + field->fontHeight*field->nLines +
100 			(field->nLines-1)*field->lineSpacing;
101 	}
102 	else
103 		maxY = field->padding + field->fieldHeight;
104 
105 	SWFRect_setBounds(CHARACTER(field)->bounds, minX, maxX, minY, maxY);
106 }
107 
108 
109 void
writeSWFTextFieldToMethod(SWFBlock block,SWFByteOutputMethod method,void * data)110 writeSWFTextFieldToMethod(SWFBlock block,
111 													SWFByteOutputMethod method, void *data)
112 {
113 	SWFOutput out = SWFBrowserFont_getOutput((SWFBrowserFont)block);
114 	SWFOutput_writeToMethod(out, method, data);
115 }
116 
117 
118 int
completeSWFTextField(SWFBlock block)119 completeSWFTextField(SWFBlock block)
120 {
121 	SWFTextField field = (SWFTextField)block;
122 
123 	/* we're guessing how big the block's going to be.. */
124 	SWFOutput out =
125 		newSizedSWFOutput(42
126 			+ ((field->varName)?strlen(field->varName):0)
127 			+ ((field->string)?strlen(field->string):0));
128 
129 	field->out = out;
130 
131 	resetBounds(field);
132 
133 	SWFOutput_writeUInt16(out, CHARACTERID(field));
134 	SWFOutput_writeRect(out, CHARACTER(field)->bounds);
135 	SWFOutput_writeUInt16(out, field->flags);
136 
137 	if(field->flags & SWFTEXTFIELD_HASFONT)
138 	{
139 		SWFOutput_writeUInt16(out, CHARACTERID(field->font.fontchar));
140 		SWFOutput_writeUInt16(out, field->fontHeight);
141 	}
142 
143 	if(field->flags & SWFTEXTFIELD_HASCOLOR)
144 	{
145 		SWFOutput_writeUInt8(out, field->r);
146 		SWFOutput_writeUInt8(out, field->g);
147 		SWFOutput_writeUInt8(out, field->b);
148 		SWFOutput_writeUInt8(out, field->a);
149 	}
150 
151 	if ( field->flags & SWFTEXTFIELD_HASLENGTH )
152 		SWFOutput_writeUInt16(out, field->length);
153 
154 	if(field->flags & SWFTEXTFIELD_HASLAYOUT)
155 	{
156 		SWFOutput_writeUInt8(out, field->alignment);
157 		SWFOutput_writeUInt16(out, field->leftMargin);
158 		SWFOutput_writeUInt16(out, field->rightMargin);
159 		SWFOutput_writeUInt16(out, field->indentation);
160 		SWFOutput_writeUInt16(out, field->lineSpacing);
161 	}
162 
163 	SWFOutput_writeString(out, (byte*) field->varName);
164 	if ( field->flags & SWFTEXTFIELD_HASTEXT )
165 		SWFOutput_writeString(out, (byte*)field->string);
166 
167 	/*
168 		XXX - if font is a real font, do we need to talk to it?
169 		flash 4 just makes a browser font for (editable) textfields for all fonts
170 	*/
171 
172 	SWFOutput_byteAlign(out);
173 	return SWFOutput_getLength(out);
174 }
175 
176 
177 void
destroySWFTextField(SWFTextField field)178 destroySWFTextField(SWFTextField field)
179 {
180 	destroySWFOutput(field->out);
181 
182 	if ( field->varName != NULL )
183 		free(field->varName);
184 
185 	if ( field->string != NULL )
186 		free(field->string);
187 
188 	if ( field->embeds != NULL )
189 		free(field->embeds);
190 
191 	destroySWFCharacter((SWFCharacter) field);
192 }
193 
194 
195 SWFTextField
newSWFTextField()196 newSWFTextField()
197 {
198 	SWFRect temp_rect;
199 
200 	SWFTextField field = (SWFTextField)malloc(sizeof(struct SWFTextField_s));
201 
202 	/* If malloc failed, return NULL to signify this */
203 	if (NULL == field)
204 		return NULL;
205 
206 	SWFCharacterInit((SWFCharacter)field);
207 
208 	BLOCK(field)->writeBlock = writeSWFTextFieldToMethod;
209 	BLOCK(field)->complete = completeSWFTextField;
210 	BLOCK(field)->dtor = (destroySWFBlockMethod) destroySWFTextField;
211 	BLOCK(field)->type = SWF_DEFINEEDITTEXT;
212 
213 	CHARACTERID(field) = ++SWF_gNumCharacters;
214 	temp_rect = newSWFRect(-40, 280, -40, 280);
215 
216 	/* If newSWFRect() failed, return NULL to signify this */
217 	if (NULL == temp_rect)
218 	{
219 		free(field);
220 		return NULL;
221 	}
222 
223 	CHARACTER(field)->bounds = temp_rect;
224 
225 	field->out = NULL;
226 
227 	field->lineSpacing = 40;
228 	field->padding = 40;
229 	field->fontHeight = 240;
230 	field->fieldHeight = 0;
231 	field->width = 0;
232 	field->a = 0xff;
233 	field->nLines = 1;
234 
235 	field->flags = 0;
236 
237 	field->font.font = NULL;
238 	field->fonttype = Unresolved;
239 	field->varName = NULL;
240 	field->string = NULL;
241 
242 	field->r = 0;
243 	field->g = 0;
244 	field->b = 0;
245 	field->a = 0xff;
246 
247 	field->length = 0;
248 	field->alignment = SWFTEXTFIELD_ALIGN_LEFT;
249 	field->leftMargin = 0;
250 	field->rightMargin = 0;
251 	field->indentation = 0;
252 
253 	field->embeds = NULL;
254 	field->embedlen = 0;
255 
256 	return field;
257 }
258 
checkSWFFontCharacter(SWFFontCharacter fc)259 static inline int checkSWFFontCharacter(SWFFontCharacter fc)
260 {
261 	int font_flags;
262 	int nGlyphs;
263 
264 	SWFFont font = SWFFontCharacter_getFont(fc);
265 	font_flags = SWFFont_getFlags(font);
266 	nGlyphs = SWFFontCharacter_getNGlyphs(fc);
267 
268 	if((font_flags & SWF_FONT_HASLAYOUT) == 0 && nGlyphs == 0)
269 		return -1;
270 
271 	return 0;
272 }
273 
274 /* font machinery:
275 	if a regular font (outlines in fdb) is used, it is added to the textfield
276 	as type Font and later converted to a FontChar
277 	while a Font, characters can be added (embedded)
278 	an Imported font stays as is, so does a BrowserFont
279  */
280 void
SWFTextField_setFont(SWFTextField field,SWFBlock font)281 SWFTextField_setFont(SWFTextField field, SWFBlock font)
282 {
283 	if(font == NULL)
284 		return;
285 	if ( BLOCK(font)->type == SWF_BROWSERFONT )
286 	{
287 		field->fonttype = BrowserFont;
288 		field->font.browserFont = (SWFBrowserFont)font;
289 		SWFCharacter_addDependency((SWFCharacter)field, (SWFCharacter)font);
290 		field->flags |= SWFTEXTFIELD_HASFONT;
291 	}
292 	else if ( BLOCK(font)->type == SWF_DEFINEFONT
293 		|| BLOCK(font)->type == SWF_DEFINEFONT2)
294 	{
295 		SWFFontCharacter fc = (SWFFontCharacter)font;
296 		if(checkSWFFontCharacter(fc))
297 		{
298 			SWF_warn("font is empty or has no layout information\n");
299 			return;
300 		}
301 		field->fonttype = Imported;
302 		field->font.fontchar = fc;
303 		SWFCharacter_addDependency(
304 			(SWFCharacter)field, (SWFCharacter)font);
305 		field->flags |= SWFTEXTFIELD_HASFONT | SWFTEXTFIELD_USEFONT;
306 	}
307 	else if (BLOCK(font)->type == SWF_MINGFONT)
308 	{
309 		if(!(SWFFont_getFlags((SWFFont)font) & SWF_FONT_HASLAYOUT))
310 		{
311 			SWF_warn("font is empty or has no layout information\n");
312 			return;
313 		}
314 		field->fonttype = Font;
315 		field->font.font = (SWFFont)font;
316 		field->flags |= SWFTEXTFIELD_HASFONT | SWFTEXTFIELD_USEFONT;
317 	}
318 	else
319 		SWF_warn("SWFTextField_setFont: not a valid font object\n");
320 }
321 
322 SWFFont
SWFTextField_getUnresolvedFont(SWFTextField field)323 SWFTextField_getUnresolvedFont(SWFTextField field)
324 {
325 	switch(field->fonttype)
326 	{	case Font:
327 			return field->font.font;
328 		default:
329 			return NULL;
330 	}
331 }
332 
333 
334 void
SWFTextField_addChars(SWFTextField field,const char * string)335 SWFTextField_addChars(SWFTextField field, const char *string)
336 {
337 	int n, len = strlen(string);
338 	if(field->fonttype == Font || field->fonttype == FontChar)
339 	{	field->embeds = (unsigned short *)realloc(
340 			field->embeds, (field->embedlen + len) * 2);
341 		for(n = 0 ; n < len  ; n++)
342 			field->embeds[field->embedlen++] = string[n] & 0xff;
343 	}
344 }
345 
346 void
SWFTextField_addUTF8Chars(SWFTextField field,const char * string)347 SWFTextField_addUTF8Chars(SWFTextField field, const char *string)
348 {
349 	unsigned short *widestring;
350 	int n, len;
351 	if(field->fonttype == FontChar || field->fonttype == Font)
352 	{	len = UTF8ExpandString(string, &widestring);
353 		field->embeds = (unsigned short *)realloc(
354 			field->embeds, (field->embedlen + len) * 2);
355 		for(n = 0 ; n < len  ; n++)
356 			field->embeds[field->embedlen++] = widestring[n];
357 		free(widestring);
358 	}
359 }
360 
361 /*
362 	this is called when the textfield is added to the movie,
363 	so no more changes to it from that point
364 	other type may still add characters to the fontchar
365  */
SWFTextField_setFontCharacter(SWFTextField field,SWFFontCharacter fontchar)366 void SWFTextField_setFontCharacter(SWFTextField field, SWFFontCharacter fontchar)
367 {
368 	field->fonttype = FontChar;
369 	field->font.fontchar = fontchar;
370 	if((field->flags & SWFTEXTFIELD_NOEDIT) == 0)
371 		SWFFontCharacter_addAllChars(fontchar);
372 	else
373 		SWFFontCharacter_addWideChars(fontchar,
374 				field->embeds, field->embedlen);
375 }
376 
377 void
SWFTextField_setScaledBounds(SWFTextField field,int width,int height)378 SWFTextField_setScaledBounds(SWFTextField field, int width, int height)
379 {
380 	field->width = width;
381 	field->fieldHeight = height;
382 	resetBounds(field);
383 }
384 
385 
386 void
SWFTextField_setFlags(SWFTextField field,int flags)387 SWFTextField_setFlags(SWFTextField field, int flags)
388 {
389 	field->flags |= flags;
390 }
391 
392 
393 void
SWFTextField_setColor(SWFTextField field,byte r,byte g,byte b,byte a)394 SWFTextField_setColor(SWFTextField field, byte r, byte g, byte b, byte a)
395 {
396 	field->r = r;
397 	field->g = g;
398 	field->b = b;
399 	field->a = a;
400 	field->flags |= SWFTEXTFIELD_HASCOLOR;
401 }
402 
403 
404 void
SWFTextField_setVariableName(SWFTextField field,const char * name)405 SWFTextField_setVariableName(SWFTextField field, const char *name)
406 {
407 	field->varName = strdup(name);
408 }
409 
410 
411 static void
SWFTextField_addStringOnly(SWFTextField field,const char * string)412 SWFTextField_addStringOnly(SWFTextField field, const char *string)
413 {
414 	int l;
415 
416 	for ( l=0; string[l]!='\0'; ++l )
417 	{
418 		if ( string[l] == '\n' )
419 			++field->nLines;
420 	}
421 
422 	if ( field->string )
423 	{
424 		field->string = (char*)realloc(field->string, strlen(field->string)+l+1);
425 		strcat(field->string, string);
426 	}
427 	else
428 		field->string = strdup(string);
429 	field->flags |= SWFTEXTFIELD_HASTEXT;
430 	resetBounds(field);
431 }
432 
433 void
SWFTextField_addString(SWFTextField field,const char * string)434 SWFTextField_addString(SWFTextField field, const char *string)
435 {
436 	int l, n;
437 
438 	l = strlen(string);
439 
440 	SWFTextField_addStringOnly(field, string);
441 	if(field->fonttype == FontChar || field->fonttype == Font)
442 	{	field->embeds = (unsigned short *)realloc(
443 			field->embeds, (field->embedlen + l) * 2);
444 		for(n = 0 ; n < l  ; n++)
445 			field->embeds[field->embedlen++] = string[n] & 0xff;
446 	}
447 }
448 
449 void
SWFTextField_addUTF8String(SWFTextField field,const char * string)450 SWFTextField_addUTF8String(SWFTextField field, const char *string)
451 {
452 	unsigned short *widestring;
453 	int l, n;
454 
455 	SWFTextField_addStringOnly(field, string);
456 	if(field->fonttype == FontChar || field->fonttype == Font)
457 	{	l = UTF8ExpandString(string, &widestring);
458 		field->embeds = (unsigned short *)realloc(
459 			field->embeds, (field->embedlen + l) * 2);
460 		for(n = 0 ; n < l  ; n++)
461 			field->embeds[field->embedlen++] = widestring[n];
462 		free(widestring);
463 	}
464 }
465 
466 
467 void
SWFTextField_setScaledFontHeight(SWFTextField field,int height)468 SWFTextField_setScaledFontHeight(SWFTextField field, int height)
469 {
470 	field->fontHeight = height;
471 	resetBounds(field);
472 }
473 
474 
475 void
SWFTextField_setScaledFieldHeight(SWFTextField field,int height)476 SWFTextField_setScaledFieldHeight(SWFTextField field, int height)
477 {
478 	field->fieldHeight = height;
479 	resetBounds(field);
480 }
481 
482 
483 void
SWFTextField_setScaledWidth(SWFTextField field,int width)484 SWFTextField_setScaledWidth(SWFTextField field, int width)
485 {
486 	field->width = width;
487 	resetBounds(field);
488 }
489 
490 
491 void
SWFTextField_setScaledPadding(SWFTextField field,int padding)492 SWFTextField_setScaledPadding(SWFTextField field, int padding)
493 {
494 	field->padding = padding;
495 	resetBounds(field);
496 }
497 
498 
499 void
SWFTextField_setScaledLeftMargin(SWFTextField field,int leftMargin)500 SWFTextField_setScaledLeftMargin(SWFTextField field, int leftMargin)
501 {
502 	field->leftMargin = leftMargin;
503 	field->flags |= SWFTEXTFIELD_HASLAYOUT;
504 }
505 
506 
507 void
SWFTextField_setScaledRightMargin(SWFTextField field,int rightMargin)508 SWFTextField_setScaledRightMargin(SWFTextField field, int rightMargin)
509 {
510 	field->rightMargin = rightMargin;
511 	field->flags |= SWFTEXTFIELD_HASLAYOUT;
512 }
513 
514 
515 void
SWFTextField_setScaledIndentation(SWFTextField field,int indentation)516 SWFTextField_setScaledIndentation(SWFTextField field, int indentation)
517 {
518 	field->indentation = indentation;
519 	field->flags |= SWFTEXTFIELD_HASLAYOUT;
520 }
521 
522 
523 void
SWFTextField_setScaledLineSpacing(SWFTextField field,int lineSpacing)524 SWFTextField_setScaledLineSpacing(SWFTextField field, int lineSpacing)
525 {
526 	field->lineSpacing = lineSpacing;
527 	field->flags |= SWFTEXTFIELD_HASLAYOUT;
528 	resetBounds(field);
529 }
530 
531 
532 void
SWFTextField_setAlignment(SWFTextField field,SWFTextFieldAlignment alignment)533 SWFTextField_setAlignment(SWFTextField field, SWFTextFieldAlignment alignment)
534 {
535 	field->alignment = alignment;
536 	field->flags |= SWFTEXTFIELD_HASLAYOUT;
537 }
538 
539 
540 void
SWFTextField_setLength(SWFTextField field,int length)541 SWFTextField_setLength(SWFTextField field, int length)
542 {
543 	field->length = length;
544 	field->flags |= SWFTEXTFIELD_HASLENGTH;
545 }
546 
547 
548 /*
549  * Local variables:
550  * tab-width: 2
551  * c-basic-offset: 2
552  * End:
553  */
554