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