release 0.8.0
[swfdec.git] / swfdec / swfdec_text_format.c
blob7442a0d00420d472afe800828b92433f3ac48f4d
1 /* Swfdec
2 * Copyright (C) 2007-2008 Benjamin Otte <otte@gnome.org>
3 * 2007 Pekka Lampila <pekka.lampila@iki.fi>
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.
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., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301 USA
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
25 #include <math.h>
26 #include <string.h>
27 #include <pango/pangocairo.h>
29 #include "swfdec_text_format.h"
30 #include "swfdec_as_native_function.h"
31 #include "swfdec_as_array.h"
32 #include "swfdec_as_object.h"
33 #include "swfdec_as_strings.h"
34 #include "swfdec_debug.h"
35 #include "swfdec_internal.h"
36 #include "swfdec_as_internal.h"
37 #include "swfdec_player_internal.h"
38 /* for getTextExtent */
39 #include "swfdec_text_buffer.h"
40 #include "swfdec_text_layout.h"
42 G_DEFINE_TYPE (SwfdecTextFormat, swfdec_text_format, SWFDEC_TYPE_AS_OBJECT)
44 static int property_offsets[] = {
45 G_STRUCT_OFFSET (SwfdecTextFormat, attr.align),
46 G_STRUCT_OFFSET (SwfdecTextFormat, attr.block_indent),
47 G_STRUCT_OFFSET (SwfdecTextFormat, attr.bold),
48 G_STRUCT_OFFSET (SwfdecTextFormat, attr.bullet),
49 G_STRUCT_OFFSET (SwfdecTextFormat, attr.color),
50 G_STRUCT_OFFSET (SwfdecTextFormat, attr.display),
51 G_STRUCT_OFFSET (SwfdecTextFormat, attr.font),
52 G_STRUCT_OFFSET (SwfdecTextFormat, attr.indent),
53 G_STRUCT_OFFSET (SwfdecTextFormat, attr.italic),
54 G_STRUCT_OFFSET (SwfdecTextFormat, attr.kerning),
55 G_STRUCT_OFFSET (SwfdecTextFormat, attr.leading),
56 G_STRUCT_OFFSET (SwfdecTextFormat, attr.left_margin),
57 G_STRUCT_OFFSET (SwfdecTextFormat, attr.letter_spacing),
58 G_STRUCT_OFFSET (SwfdecTextFormat, attr.right_margin),
59 G_STRUCT_OFFSET (SwfdecTextFormat, attr.size),
60 G_STRUCT_OFFSET (SwfdecTextFormat, attr.tab_stops),
61 G_STRUCT_OFFSET (SwfdecTextFormat, attr.target),
62 G_STRUCT_OFFSET (SwfdecTextFormat, attr.underline),
63 G_STRUCT_OFFSET (SwfdecTextFormat, attr.url)
66 static void
67 swfdec_text_format_mark (SwfdecGcObject *object)
69 SwfdecTextFormat *format = SWFDEC_TEXT_FORMAT (object);
71 swfdec_text_attributes_mark (&format->attr);
73 SWFDEC_GC_OBJECT_CLASS (swfdec_text_format_parent_class)->mark (object);
76 static void
77 swfdec_text_format_class_init (SwfdecTextFormatClass *klass)
79 SwfdecGcObjectClass *gc_class = SWFDEC_GC_OBJECT_CLASS (klass);
81 gc_class->mark = swfdec_text_format_mark;
84 static void
85 swfdec_text_format_init (SwfdecTextFormat *format)
87 swfdec_text_attributes_reset (&format->attr);
90 static void
91 swfdec_text_format_get_string (SwfdecAsObject *object,
92 SwfdecTextAttribute property, SwfdecAsValue *ret)
94 SwfdecTextFormat *format;
96 if (!SWFDEC_IS_TEXT_FORMAT (object))
97 return;
98 format = SWFDEC_TEXT_FORMAT (object);
100 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, property)) {
101 SWFDEC_AS_VALUE_SET_NULL (ret);
102 return;
105 SWFDEC_AS_VALUE_SET_STRING (ret,
106 G_STRUCT_MEMBER (const char *, format, property_offsets[property]));
109 static void
110 swfdec_text_format_set_string (SwfdecAsObject *object,
111 SwfdecTextAttribute property, guint argc, SwfdecAsValue *argv)
113 SwfdecTextFormat *format;
114 SwfdecAsContext *context;
115 const char *s;
117 if (!SWFDEC_IS_TEXT_FORMAT (object))
118 return;
119 format = SWFDEC_TEXT_FORMAT (object);
121 if (argc < 1)
122 return;
124 context = swfdec_gc_object_get_context (format);
125 swfdec_as_value_to_integer (context, &argv[0]);
126 swfdec_as_value_to_number (context, &argv[0]);
127 s = swfdec_as_value_to_string (context, &argv[0]);
129 if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0]) ||
130 SWFDEC_AS_VALUE_IS_NULL (&argv[0])) {
131 /* FIXME: reset to defaults here? */
132 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set, property);
133 } else {
134 G_STRUCT_MEMBER (const char *, format, property_offsets[property]) = s;
135 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, property);
137 /* FIXME: figure out what to do here */
140 static void
141 swfdec_text_format_get_boolean (SwfdecAsObject *object,
142 SwfdecTextAttribute property, SwfdecAsValue *ret)
144 SwfdecTextFormat *format;
146 if (!SWFDEC_IS_TEXT_FORMAT (object))
147 return;
148 format = SWFDEC_TEXT_FORMAT (object);
150 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, property)) {
151 SWFDEC_AS_VALUE_SET_NULL (ret);
152 return;
155 if (G_STRUCT_MEMBER (gboolean, format, property_offsets[property])) {
156 SWFDEC_AS_VALUE_SET_BOOLEAN (ret, TRUE);
157 } else {
158 SWFDEC_AS_VALUE_SET_BOOLEAN (ret, FALSE);
162 static void
163 swfdec_text_format_set_boolean (SwfdecAsObject *object,
164 SwfdecTextAttribute property, guint argc, SwfdecAsValue *argv)
166 SwfdecTextFormat *format;
167 SwfdecAsContext *context;
169 if (!SWFDEC_IS_TEXT_FORMAT (object))
170 return;
171 format = SWFDEC_TEXT_FORMAT (object);
173 if (argc < 1)
174 return;
176 context = swfdec_gc_object_get_context (format);
177 swfdec_as_value_to_integer (context, &argv[0]);
178 swfdec_as_value_to_number (context, &argv[0]);
179 swfdec_as_value_to_string (context, &argv[0]);
181 if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0]) ||
182 SWFDEC_AS_VALUE_IS_NULL (&argv[0])) {
183 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set, property);
184 } else {
185 G_STRUCT_MEMBER (gboolean, format, property_offsets[property]) =
186 swfdec_as_value_to_boolean (context, &argv[0]);
187 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, property);
191 static void
192 swfdec_text_format_get_integer (SwfdecAsObject *object,
193 SwfdecTextAttribute property, SwfdecAsValue *ret)
195 SwfdecTextFormat *format;
197 if (!SWFDEC_IS_TEXT_FORMAT (object))
198 return;
199 format = SWFDEC_TEXT_FORMAT (object);
201 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, property)) {
202 SWFDEC_AS_VALUE_SET_NULL (ret);
203 return;
206 SWFDEC_AS_VALUE_SET_NUMBER (ret,
207 (double)G_STRUCT_MEMBER (int, format, property_offsets[property]));
210 static int
211 swfdec_text_format_value_to_integer (SwfdecAsContext *cx, SwfdecAsValue *val,
212 gboolean allow_negative)
214 double d;
215 int n;
217 n = swfdec_as_value_to_integer (cx, val);
218 d = swfdec_as_value_to_number (cx, val);
219 swfdec_as_value_to_string (cx, val);
221 if (cx->version >= 8) {
222 if (isnan (d))
223 return (allow_negative ? G_MININT32 : 0);
225 if (!isfinite (d)) {
226 if (d > 0) {
227 return G_MININT32;
228 } else {
229 return (allow_negative ? G_MININT32 : 0);
232 if (d > (double)G_MAXINT32)
233 return G_MININT32;
235 n = (int)d;
236 if (!allow_negative && n < 0) {
237 return 0;
238 } else {
239 return n;
241 } else {
242 if (!allow_negative && n < 0) {
243 return 0;
244 } else {
245 return n;
250 static void
251 swfdec_text_format_set_integer (SwfdecAsObject *object,
252 SwfdecTextAttribute property, guint argc, SwfdecAsValue *argv,
253 gboolean allow_negative)
255 SwfdecTextFormat *format;
257 if (!SWFDEC_IS_TEXT_FORMAT (object))
258 return;
259 format = SWFDEC_TEXT_FORMAT (object);
261 if (argc < 1)
262 return;
264 if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0]) ||
265 SWFDEC_AS_VALUE_IS_NULL (&argv[0])) {
266 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set, property);
267 } else {
268 G_STRUCT_MEMBER (int, format, property_offsets[property]) =
269 swfdec_text_format_value_to_integer (swfdec_gc_object_get_context (format),
270 &argv[0], allow_negative);
271 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, property);
275 static void
276 swfdec_text_format_do_get_align (SwfdecAsContext *cx, SwfdecAsObject *object,
277 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
279 SwfdecTextFormat *format;
281 if (!SWFDEC_IS_TEXT_FORMAT (object))
282 return;
283 format = SWFDEC_TEXT_FORMAT (object);
285 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_ALIGN)) {
286 SWFDEC_AS_VALUE_SET_NULL (ret);
287 return;
290 switch (format->attr.align) {
291 case SWFDEC_TEXT_ALIGN_LEFT:
292 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_left);
293 break;
294 case SWFDEC_TEXT_ALIGN_RIGHT:
295 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_right);
296 break;
297 case SWFDEC_TEXT_ALIGN_CENTER:
298 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_center);
299 break;
300 case SWFDEC_TEXT_ALIGN_JUSTIFY:
301 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_justify);
302 break;
303 default:
304 g_assert_not_reached ();
308 static void
309 swfdec_text_format_do_set_align (SwfdecAsContext *cx, SwfdecAsObject *object,
310 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
312 SwfdecTextFormat *format;
313 const char *s;
315 if (!SWFDEC_IS_TEXT_FORMAT (object))
316 return;
317 format = SWFDEC_TEXT_FORMAT (object);
319 if (argc < 1)
320 return;
322 swfdec_as_value_to_integer (cx, &argv[0]);
323 swfdec_as_value_to_number (cx, &argv[0]);
324 s = swfdec_as_value_to_string (cx, &argv[0]);
326 if (!g_ascii_strcasecmp (s, "left")) {
327 format->attr.align = SWFDEC_TEXT_ALIGN_LEFT;
328 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_ALIGN);
329 } else if (!g_ascii_strcasecmp (s, "right")) {
330 format->attr.align = SWFDEC_TEXT_ALIGN_RIGHT;
331 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_ALIGN);
332 } else if (!g_ascii_strcasecmp (s, "center")) {
333 format->attr.align = SWFDEC_TEXT_ALIGN_CENTER;
334 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_ALIGN);
335 } else if (!g_ascii_strcasecmp (s, "justify")) {
336 format->attr.align = SWFDEC_TEXT_ALIGN_JUSTIFY;
337 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_ALIGN);
341 static void
342 swfdec_text_format_do_get_block_indent (SwfdecAsContext *cx,
343 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
344 SwfdecAsValue *ret)
346 swfdec_text_format_get_integer (object, SWFDEC_TEXT_ATTRIBUTE_BLOCK_INDENT, ret);
349 static void
350 swfdec_text_format_do_set_block_indent (SwfdecAsContext *cx,
351 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
352 SwfdecAsValue *ret)
354 swfdec_text_format_set_integer (object, SWFDEC_TEXT_ATTRIBUTE_BLOCK_INDENT, argc, argv,
355 cx->version >= 8);
358 static void
359 swfdec_text_format_do_get_bold (SwfdecAsContext *cx, SwfdecAsObject *object,
360 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
362 swfdec_text_format_get_boolean (object, SWFDEC_TEXT_ATTRIBUTE_BOLD, ret);
365 static void
366 swfdec_text_format_do_set_bold (SwfdecAsContext *cx, SwfdecAsObject *object,
367 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
369 swfdec_text_format_set_boolean (object, SWFDEC_TEXT_ATTRIBUTE_BOLD, argc, argv);
372 static void
373 swfdec_text_format_do_get_bullet (SwfdecAsContext *cx, SwfdecAsObject *object,
374 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
376 swfdec_text_format_get_boolean (object, SWFDEC_TEXT_ATTRIBUTE_BULLET, ret);
379 static void
380 swfdec_text_format_do_set_bullet (SwfdecAsContext *cx, SwfdecAsObject *object,
381 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
383 swfdec_text_format_set_boolean (object, SWFDEC_TEXT_ATTRIBUTE_BULLET, argc, argv);
386 static void
387 swfdec_text_format_do_get_color (SwfdecAsContext *cx, SwfdecAsObject *object,
388 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
390 SwfdecTextFormat *format;
392 if (!SWFDEC_IS_TEXT_FORMAT (object))
393 return;
394 format = SWFDEC_TEXT_FORMAT (object);
396 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_COLOR)) {
397 SWFDEC_AS_VALUE_SET_NULL (ret);
398 return;
401 SWFDEC_AS_VALUE_SET_NUMBER (ret, format->attr.color);
404 static void
405 swfdec_text_format_do_set_color (SwfdecAsContext *cx, SwfdecAsObject *object,
406 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
408 SwfdecTextFormat *format;
410 if (!SWFDEC_IS_TEXT_FORMAT (object))
411 return;
412 format = SWFDEC_TEXT_FORMAT (object);
414 if (argc < 1)
415 return;
417 if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0]) ||
418 SWFDEC_AS_VALUE_IS_NULL (&argv[0])) {
419 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_COLOR);
420 } else {
421 format->attr.color = (unsigned) swfdec_as_value_to_integer (cx, &argv[0]);
422 swfdec_as_value_to_integer (cx, &argv[0]);
423 swfdec_as_value_to_string (cx, &argv[0]);
425 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_COLOR);
429 static void
430 swfdec_text_format_do_get_display (SwfdecAsContext *cx, SwfdecAsObject *object,
431 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
433 SwfdecTextFormat *format;
435 if (!SWFDEC_IS_TEXT_FORMAT (object))
436 return;
437 format = SWFDEC_TEXT_FORMAT (object);
439 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_DISPLAY))
441 SWFDEC_AS_VALUE_SET_NULL (ret);
442 return;
445 switch (format->attr.display) {
446 case SWFDEC_TEXT_DISPLAY_NONE:
447 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_none);
448 break;
449 case SWFDEC_TEXT_DISPLAY_INLINE:
450 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_inline);
451 break;
452 case SWFDEC_TEXT_DISPLAY_BLOCK:
453 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_block);
454 break;
455 default:
456 g_assert_not_reached ();
460 static void
461 swfdec_text_format_do_set_display (SwfdecAsContext *cx, SwfdecAsObject *object,
462 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
464 SwfdecTextFormat *format;
465 const char *s;
467 if (!SWFDEC_IS_TEXT_FORMAT (object))
468 return;
469 format = SWFDEC_TEXT_FORMAT (object);
471 swfdec_as_value_to_integer (cx, &argv[0]);
472 swfdec_as_value_to_number (cx, &argv[0]);
473 swfdec_as_value_to_string (cx, &argv[0]);
474 s = swfdec_as_value_to_string (cx, &argv[0]); // oh yes, let's call it twice
476 if (!g_ascii_strcasecmp (s, "none")) {
477 format->attr.display = SWFDEC_TEXT_DISPLAY_NONE;
478 } else if (!g_ascii_strcasecmp (s, "inline")) {
479 format->attr.display = SWFDEC_TEXT_DISPLAY_INLINE;
480 } else {
481 format->attr.display = SWFDEC_TEXT_DISPLAY_BLOCK;
484 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_DISPLAY);
487 static void
488 swfdec_text_format_do_get_font (SwfdecAsContext *cx, SwfdecAsObject *object,
489 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
491 swfdec_text_format_get_string (object, SWFDEC_TEXT_ATTRIBUTE_FONT, ret);
494 static void
495 swfdec_text_format_do_set_font (SwfdecAsContext *cx, SwfdecAsObject *object,
496 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
498 swfdec_text_format_set_string (object, SWFDEC_TEXT_ATTRIBUTE_FONT, argc, argv);
501 static void
502 swfdec_text_format_do_get_indent (SwfdecAsContext *cx, SwfdecAsObject *object,
503 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
505 swfdec_text_format_get_integer (object, SWFDEC_TEXT_ATTRIBUTE_INDENT, ret);
508 static void
509 swfdec_text_format_do_set_indent (SwfdecAsContext *cx, SwfdecAsObject *object,
510 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
512 swfdec_text_format_set_integer (object, SWFDEC_TEXT_ATTRIBUTE_INDENT, argc, argv,
513 cx->version >= 8);
516 static void
517 swfdec_text_format_do_get_italic (SwfdecAsContext *cx, SwfdecAsObject *object,
518 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
520 swfdec_text_format_get_boolean (object, SWFDEC_TEXT_ATTRIBUTE_ITALIC, ret);
523 static void
524 swfdec_text_format_do_set_italic (SwfdecAsContext *cx, SwfdecAsObject *object,
525 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
527 swfdec_text_format_set_boolean (object, SWFDEC_TEXT_ATTRIBUTE_ITALIC, argc, argv);
530 static void
531 swfdec_text_format_do_get_kerning (SwfdecAsContext *cx, SwfdecAsObject *object,
532 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
534 swfdec_text_format_get_boolean (object, SWFDEC_TEXT_ATTRIBUTE_KERNING, ret);
537 static void
538 swfdec_text_format_do_set_kerning (SwfdecAsContext *cx, SwfdecAsObject *object,
539 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
541 swfdec_text_format_set_boolean (object, SWFDEC_TEXT_ATTRIBUTE_KERNING, argc, argv);
544 static void
545 swfdec_text_format_do_get_leading (SwfdecAsContext *cx, SwfdecAsObject *object,
546 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
548 swfdec_text_format_get_integer (object, SWFDEC_TEXT_ATTRIBUTE_LEADING, ret);
551 static void
552 swfdec_text_format_do_set_leading (SwfdecAsContext *cx, SwfdecAsObject *object,
553 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
555 swfdec_text_format_set_integer (object, SWFDEC_TEXT_ATTRIBUTE_LEADING, argc, argv,
556 cx->version >= 8);
559 static void
560 swfdec_text_format_do_get_left_margin (SwfdecAsContext *cx,
561 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
562 SwfdecAsValue *ret)
564 swfdec_text_format_get_integer (object, SWFDEC_TEXT_ATTRIBUTE_LEFT_MARGIN, ret);
567 static void
568 swfdec_text_format_do_set_left_margin (SwfdecAsContext *cx,
569 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
570 SwfdecAsValue *ret)
572 swfdec_text_format_set_integer (object, SWFDEC_TEXT_ATTRIBUTE_LEFT_MARGIN, argc, argv, FALSE);
575 static void
576 swfdec_text_format_do_get_letter_spacing (SwfdecAsContext *cx,
577 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
578 SwfdecAsValue *ret)
580 SwfdecTextFormat *format;
582 if (!SWFDEC_IS_TEXT_FORMAT (object))
583 return;
584 format = SWFDEC_TEXT_FORMAT (object);
586 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_LETTER_SPACING)) {
587 SWFDEC_AS_VALUE_SET_NULL (ret);
588 return;
591 SWFDEC_AS_VALUE_SET_NUMBER (ret, format->attr.letter_spacing);
594 static void
595 swfdec_text_format_do_set_letter_spacing (SwfdecAsContext *cx,
596 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
597 SwfdecAsValue *ret)
599 SwfdecTextFormat *format;
600 double d;
602 if (!SWFDEC_IS_TEXT_FORMAT (object))
603 return;
604 format = SWFDEC_TEXT_FORMAT (object);
606 if (argc < 1)
607 return;
609 swfdec_as_value_to_integer (cx, &argv[0]);
610 d = swfdec_as_value_to_number (cx, &argv[0]);
611 swfdec_as_value_to_string (cx, &argv[0]);
613 if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0]) ||
614 SWFDEC_AS_VALUE_IS_NULL (&argv[0]))
616 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set,
617 SWFDEC_TEXT_ATTRIBUTE_LETTER_SPACING);
619 else
621 format->attr.letter_spacing = d;
622 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set,
623 SWFDEC_TEXT_ATTRIBUTE_LETTER_SPACING);
627 static void
628 swfdec_text_format_do_get_right_margin (SwfdecAsContext *cx,
629 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
630 SwfdecAsValue *ret)
632 swfdec_text_format_get_integer (object, SWFDEC_TEXT_ATTRIBUTE_RIGHT_MARGIN, ret);
635 static void
636 swfdec_text_format_do_set_right_margin (SwfdecAsContext *cx,
637 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
638 SwfdecAsValue *ret)
640 swfdec_text_format_set_integer (object, SWFDEC_TEXT_ATTRIBUTE_RIGHT_MARGIN, argc, argv,
641 FALSE);
644 static void
645 swfdec_text_format_do_get_size (SwfdecAsContext *cx, SwfdecAsObject *object,
646 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
648 swfdec_text_format_get_integer (object, SWFDEC_TEXT_ATTRIBUTE_SIZE, ret);
651 static void
652 swfdec_text_format_do_set_size (SwfdecAsContext *cx, SwfdecAsObject *object,
653 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
655 swfdec_text_format_set_integer (object, SWFDEC_TEXT_ATTRIBUTE_SIZE, argc, argv, TRUE);
658 static void
659 swfdec_text_format_do_get_tab_stops (SwfdecAsContext *cx,
660 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
661 SwfdecAsValue *ret)
663 SwfdecTextFormat *format;
664 guint i;
665 SwfdecAsValue val;
666 SwfdecAsObject *array;
668 if (!SWFDEC_IS_TEXT_FORMAT (object))
669 return;
670 format = SWFDEC_TEXT_FORMAT (object);
672 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_TAB_STOPS)) {
673 SWFDEC_AS_VALUE_SET_NULL (ret);
674 return;
677 array = swfdec_as_array_new (cx);
678 for (i = 0; i < format->attr.n_tab_stops; i++) {
679 SWFDEC_AS_VALUE_SET_INT (&val, format->attr.tab_stops[i]);
680 swfdec_as_array_push (SWFDEC_AS_ARRAY (array), &val);
682 SWFDEC_AS_VALUE_SET_OBJECT (ret, array);
685 static void
686 swfdec_text_format_do_set_tab_stops (SwfdecAsContext *cx,
687 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
688 SwfdecAsValue *ret)
690 SwfdecTextFormat *format;
692 if (!SWFDEC_IS_TEXT_FORMAT (object))
693 return;
694 format = SWFDEC_TEXT_FORMAT (object);
696 if (argc < 1)
697 return;
699 swfdec_as_value_to_integer (cx, &argv[0]);
700 swfdec_as_value_to_number (cx, &argv[0]);
701 swfdec_as_value_to_string (cx, &argv[0]);
703 if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0]) ||
704 SWFDEC_AS_VALUE_IS_NULL (&argv[0]))
706 g_free (format->attr.tab_stops);
707 format->attr.tab_stops = NULL;
708 format->attr.n_tab_stops = 0;
709 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_TAB_STOPS);
711 else if (SWFDEC_AS_VALUE_IS_OBJECT (&argv[0]) &&
712 SWFDEC_IS_AS_ARRAY (SWFDEC_AS_VALUE_GET_OBJECT (&argv[0])))
714 SwfdecAsArray *array;
715 SwfdecAsValue val;
716 guint i;
717 int len;
719 array = SWFDEC_AS_ARRAY (SWFDEC_AS_VALUE_GET_OBJECT (&argv[0]));
720 len = swfdec_as_array_get_length (array);
722 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_TAB_STOPS)) {
723 // special case, if we have null and array is empty, keep it at null
724 if (len == 0)
725 return;
726 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_TAB_STOPS);
729 g_free (format->attr.tab_stops);
730 format->attr.n_tab_stops = MAX (0, len);
731 format->attr.tab_stops = g_new (guint, format->attr.n_tab_stops);
732 for (i = 0; i < format->attr.n_tab_stops; i++) {
733 swfdec_as_array_get_value (array, i, &val);
734 format->attr.tab_stops[i] = swfdec_text_format_value_to_integer (cx, &val, TRUE);
737 else if (SWFDEC_AS_VALUE_IS_STRING (&argv[0]))
739 gsize i;
741 // special case: empty strings mean null
742 if (SWFDEC_AS_VALUE_GET_STRING (&argv[0]) == SWFDEC_AS_STR_EMPTY) {
743 g_free (format->attr.tab_stops);
744 format->attr.tab_stops = NULL;
745 format->attr.n_tab_stops = 0;
746 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_TAB_STOPS);
747 } else {
748 int n = cx->version >= 8 ? G_MININT : 0;
749 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_TAB_STOPS);
750 format->attr.n_tab_stops = strlen (SWFDEC_AS_VALUE_GET_STRING (&argv[0]));
751 format->attr.tab_stops = g_new (guint, format->attr.n_tab_stops);
752 for (i = 0; i < format->attr.n_tab_stops; i++) {
753 format->attr.tab_stops[i] = n;
757 else if (SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_TAB_STOPS))
759 format->attr.n_tab_stops = 0;
760 g_free (format->attr.tab_stops);
761 format->attr.tab_stops = NULL;
765 static void
766 swfdec_text_format_do_get_target (SwfdecAsContext *cx, SwfdecAsObject *object,
767 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
769 swfdec_text_format_get_string (object, SWFDEC_TEXT_ATTRIBUTE_TARGET, ret);
772 static void
773 swfdec_text_format_do_set_target (SwfdecAsContext *cx, SwfdecAsObject *object,
774 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
776 swfdec_text_format_set_string (object, SWFDEC_TEXT_ATTRIBUTE_TARGET, argc, argv);
779 static void
780 swfdec_text_format_do_get_underline (SwfdecAsContext *cx,
781 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
782 SwfdecAsValue *ret)
784 swfdec_text_format_get_boolean (object, SWFDEC_TEXT_ATTRIBUTE_UNDERLINE, ret);
787 static void
788 swfdec_text_format_do_set_underline (SwfdecAsContext *cx,
789 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
790 SwfdecAsValue *ret)
792 swfdec_text_format_set_boolean (object, SWFDEC_TEXT_ATTRIBUTE_UNDERLINE, argc, argv);
795 static void
796 swfdec_text_format_do_get_url (SwfdecAsContext *cx, SwfdecAsObject *object,
797 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
799 swfdec_text_format_get_string (object, SWFDEC_TEXT_ATTRIBUTE_URL, ret);
802 static void
803 swfdec_text_format_do_set_url (SwfdecAsContext *cx, SwfdecAsObject *object,
804 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
806 swfdec_text_format_set_string (object, SWFDEC_TEXT_ATTRIBUTE_URL, argc, argv);
809 static void
810 swfdec_text_format_getTextExtent (SwfdecAsContext *cx, SwfdecAsObject *object,
811 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
813 SwfdecTextFormat *format;
814 SwfdecTextBuffer *buffer;
815 SwfdecTextLayout *layout;
816 SwfdecAsObject *obj;
817 SwfdecAsValue val;
818 const char* text;
819 int i, j;
821 SWFDEC_AS_CHECK (SWFDEC_TYPE_TEXT_FORMAT, &format, "s", &text);
823 obj = swfdec_as_object_new_empty (cx);
825 buffer = swfdec_text_buffer_new ();
826 swfdec_text_buffer_set_default_attributes (buffer,
827 &format->attr, format->values_set);
828 swfdec_text_buffer_append_text (buffer, text);
829 layout = swfdec_text_layout_new (buffer);
831 i = swfdec_text_layout_get_width (layout);
832 SWFDEC_AS_VALUE_SET_INT (&val, i);
833 swfdec_as_object_set_variable (obj, SWFDEC_AS_STR_width, &val);
834 if (i)
835 i += 4;
836 SWFDEC_AS_VALUE_SET_INT (&val, i);
837 swfdec_as_object_set_variable (obj, SWFDEC_AS_STR_textFieldWidth, &val);
839 i = swfdec_text_layout_get_height (layout);
840 SWFDEC_AS_VALUE_SET_INT (&val, i);
841 swfdec_as_object_set_variable (obj, SWFDEC_AS_STR_height, &val);
842 if (i)
843 i += 4;
844 SWFDEC_AS_VALUE_SET_INT (&val, i);
845 swfdec_as_object_set_variable (obj, SWFDEC_AS_STR_textFieldHeight, &val);
847 swfdec_text_layout_get_ascent_descent (layout, &i, &j);
848 SWFDEC_AS_VALUE_SET_INT (&val, i);
849 swfdec_as_object_set_variable (obj, SWFDEC_AS_STR_ascent, &val);
850 SWFDEC_AS_VALUE_SET_INT (&val, j);
851 swfdec_as_object_set_variable (obj, SWFDEC_AS_STR_descent, &val);
853 SWFDEC_AS_VALUE_SET_OBJECT (ret, obj);
854 g_object_unref (layout);
855 g_object_unref (buffer);
858 void
859 swfdec_text_format_add (SwfdecTextFormat *format, const SwfdecTextFormat *from)
861 g_return_if_fail (SWFDEC_IS_TEXT_FORMAT (format));
862 g_return_if_fail (SWFDEC_IS_TEXT_FORMAT (from));
864 swfdec_text_attributes_copy (&format->attr, &from->attr, from->values_set);
865 format->values_set |= from->values_set;
868 void
869 swfdec_text_format_remove_different (SwfdecTextFormat *format,
870 const SwfdecTextFormat *from)
872 g_return_if_fail (SWFDEC_IS_TEXT_FORMAT (format));
873 g_return_if_fail (SWFDEC_IS_TEXT_FORMAT (from));
875 format->values_set &= ~swfdec_text_attributes_diff (&format->attr, &from->attr);
878 gboolean
879 swfdec_text_format_equal_or_undefined (const SwfdecTextFormat *a,
880 const SwfdecTextFormat *b)
882 int set, diff;
884 g_return_val_if_fail (SWFDEC_IS_TEXT_FORMAT (a), FALSE);
885 g_return_val_if_fail (SWFDEC_IS_TEXT_FORMAT (b), FALSE);
887 set = a->values_set & b->values_set;
888 diff = swfdec_text_attributes_diff (&a->attr, &b->attr);
890 return (set & diff) == 0;
893 gboolean
894 swfdec_text_format_equal (const SwfdecTextFormat *a, const SwfdecTextFormat *b)
896 g_return_val_if_fail (SWFDEC_IS_TEXT_FORMAT (a), FALSE);
897 g_return_val_if_fail (SWFDEC_IS_TEXT_FORMAT (b), FALSE);
899 if (a->values_set != b->values_set)
900 return FALSE;
902 return (a->values_set & swfdec_text_attributes_diff (&a->attr, &b->attr)) == 0;
905 void
906 swfdec_text_format_set_defaults (SwfdecTextFormat *format)
908 swfdec_text_attributes_reset (&format->attr);
909 format->values_set = SWFDEC_TEXT_ATTRIBUTES_MASK;
911 if (swfdec_gc_object_get_context (format)->version < 8) {
912 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_KERNING);
913 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_LETTER_SPACING);
917 static void
918 swfdec_text_format_clear (SwfdecTextFormat *format)
920 format->values_set = 0;
922 format->attr.display = SWFDEC_TEXT_DISPLAY_BLOCK;
923 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_DISPLAY);
926 void
927 swfdec_text_format_init_properties (SwfdecAsContext *cx)
929 SwfdecAsValue val;
930 SwfdecAsObject *proto;
932 // FIXME: We should only initialize if the prototype Object has not been
933 // initialized by any object's constructor with native properties
934 // (TextField, TextFormat, XML, XMLNode at least)
936 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (cx));
938 swfdec_as_object_get_variable (cx->global, SWFDEC_AS_STR_TextFormat, &val);
939 if (!SWFDEC_AS_VALUE_IS_OBJECT (&val))
940 return;
941 proto = SWFDEC_AS_VALUE_GET_OBJECT (&val);
942 swfdec_as_object_get_variable (proto, SWFDEC_AS_STR_prototype, &val);
943 if (!SWFDEC_AS_VALUE_IS_OBJECT (&val))
944 return;
945 proto = SWFDEC_AS_VALUE_GET_OBJECT (&val);
947 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_align,
948 swfdec_text_format_do_get_align, swfdec_text_format_do_set_align);
949 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_blockIndent,
950 swfdec_text_format_do_get_block_indent,
951 swfdec_text_format_do_set_block_indent);
952 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_bold,
953 swfdec_text_format_do_get_bold, swfdec_text_format_do_set_bold);
954 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_bullet,
955 swfdec_text_format_do_get_bullet, swfdec_text_format_do_set_bullet);
956 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_color,
957 swfdec_text_format_do_get_color, swfdec_text_format_do_set_color);
958 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_display,
959 swfdec_text_format_do_get_display, swfdec_text_format_do_set_display);
960 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_font,
961 swfdec_text_format_do_get_font, swfdec_text_format_do_set_font);
962 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_indent,
963 swfdec_text_format_do_get_indent, swfdec_text_format_do_set_indent);
964 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_italic,
965 swfdec_text_format_do_get_italic, swfdec_text_format_do_set_italic);
966 if (cx->version >= 8) {
967 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_kerning,
968 swfdec_text_format_do_get_kerning, swfdec_text_format_do_set_kerning);
970 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_leading,
971 swfdec_text_format_do_get_leading, swfdec_text_format_do_set_leading);
972 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_leftMargin,
973 swfdec_text_format_do_get_left_margin,
974 swfdec_text_format_do_set_left_margin);
975 if (cx->version >= 8) {
976 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_letterSpacing,
977 swfdec_text_format_do_get_letter_spacing,
978 swfdec_text_format_do_set_letter_spacing);
980 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_rightMargin,
981 swfdec_text_format_do_get_right_margin,
982 swfdec_text_format_do_set_right_margin);
983 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_size,
984 swfdec_text_format_do_get_size, swfdec_text_format_do_set_size);
985 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_tabStops,
986 swfdec_text_format_do_get_tab_stops,
987 swfdec_text_format_do_set_tab_stops);
988 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_target,
989 swfdec_text_format_do_get_target, swfdec_text_format_do_set_target);
990 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_underline,
991 swfdec_text_format_do_get_underline,
992 swfdec_text_format_do_set_underline);
993 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_url,
994 swfdec_text_format_do_get_url, swfdec_text_format_do_set_url);
997 SWFDEC_AS_CONSTRUCTOR (110, 0, swfdec_text_format_construct, swfdec_text_format_get_type)
998 void
999 swfdec_text_format_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
1000 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
1002 static const char *arguments[] = {
1003 SWFDEC_AS_STR_font,
1004 SWFDEC_AS_STR_size,
1005 SWFDEC_AS_STR_color,
1006 SWFDEC_AS_STR_bold,
1007 SWFDEC_AS_STR_italic,
1008 SWFDEC_AS_STR_underline,
1009 SWFDEC_AS_STR_url,
1010 SWFDEC_AS_STR_target,
1011 SWFDEC_AS_STR_align,
1012 SWFDEC_AS_STR_leftMargin,
1013 SWFDEC_AS_STR_rightMargin,
1014 SWFDEC_AS_STR_indent,
1015 SWFDEC_AS_STR_leading,
1016 NULL
1018 SwfdecAsFunction *function;
1019 SwfdecAsObject *tmp;
1020 SwfdecAsValue val;
1021 guint i;
1023 if (!swfdec_as_context_is_constructing (cx)) {
1024 SWFDEC_FIXME ("What do we do if not constructing?");
1025 return;
1028 g_assert (SWFDEC_IS_TEXT_FORMAT (object));
1030 swfdec_text_format_init_properties (cx);
1032 swfdec_text_format_clear (SWFDEC_TEXT_FORMAT (object));
1034 // FIXME: Need better way to create function without prototype/constructor
1035 tmp = cx->Function;
1036 cx->Function = NULL;
1037 function = swfdec_as_native_function_new (cx, SWFDEC_AS_STR_getTextExtent,
1038 swfdec_text_format_getTextExtent, NULL);
1039 cx->Function = tmp;
1040 if (function != NULL) {
1041 SWFDEC_AS_VALUE_SET_OBJECT (&val, SWFDEC_AS_OBJECT (function));
1042 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_getTextExtent, &val);
1045 for (i = 0; i < argc && arguments[i] != NULL; i++) {
1046 swfdec_as_object_set_variable (object, arguments[i], &argv[i]);
1050 SwfdecTextFormat *
1051 swfdec_text_format_copy (SwfdecTextFormat *copy_from)
1053 SwfdecAsObject *object_to;
1054 SwfdecTextFormat *copy_to;
1056 g_return_val_if_fail (SWFDEC_IS_TEXT_FORMAT (copy_from), NULL);
1058 object_to = swfdec_text_format_new_no_properties (
1059 swfdec_gc_object_get_context (copy_from));
1060 if (object_to == NULL)
1061 return NULL;
1062 copy_to = SWFDEC_TEXT_FORMAT (object_to);
1064 swfdec_text_attributes_copy (&copy_to->attr, &copy_from->attr, -1);
1065 copy_to->values_set = copy_from->values_set;
1067 return copy_to;
1070 SwfdecAsObject *
1071 swfdec_text_format_new_no_properties (SwfdecAsContext *context)
1073 SwfdecAsObject *tmp, *ret;
1074 SwfdecAsFunction *function;
1075 SwfdecAsValue val;
1077 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), NULL);
1079 ret = g_object_new (SWFDEC_TYPE_TEXT_FORMAT, "context", context, NULL);
1081 swfdec_text_format_clear (SWFDEC_TEXT_FORMAT (ret));
1082 swfdec_as_object_set_constructor_by_name (ret, SWFDEC_AS_STR_TextFormat, NULL);
1084 // FIXME: Need better way to create function without prototype/constructor
1085 tmp = context->Function;
1086 context->Function = NULL;
1087 function = swfdec_as_native_function_new (context, SWFDEC_AS_STR_getTextExtent,
1088 swfdec_text_format_getTextExtent, NULL);
1089 context->Function = tmp;
1090 if (function != NULL) {
1091 SWFDEC_AS_VALUE_SET_OBJECT (&val, SWFDEC_AS_OBJECT (function));
1092 swfdec_as_object_set_variable (ret, SWFDEC_AS_STR_getTextExtent, &val);
1095 return ret;
1098 SwfdecAsObject *
1099 swfdec_text_format_new (SwfdecAsContext *context)
1101 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), NULL);
1103 swfdec_text_format_init_properties (context);
1105 return swfdec_text_format_new_no_properties (context);