fix build for --disable-gtk-doc
[swfdec.git] / swfdec / swfdec_text_format.c
blob7ca201236fa5595f4949d89cdda31c0fa9847b00
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_array.h"
31 #include "swfdec_as_internal.h"
32 #include "swfdec_as_native_function.h"
33 #include "swfdec_as_object.h"
34 #include "swfdec_as_strings.h"
35 #include "swfdec_debug.h"
36 #include "swfdec_internal.h"
37 #include "swfdec_as_internal.h"
38 #include "swfdec_player_internal.h"
39 /* for getTextExtent */
40 #include "swfdec_text_buffer.h"
41 #include "swfdec_text_layout.h"
43 G_DEFINE_TYPE (SwfdecTextFormat, swfdec_text_format, SWFDEC_TYPE_AS_RELAY)
45 static int property_offsets[] = {
46 G_STRUCT_OFFSET (SwfdecTextFormat, attr.align),
47 G_STRUCT_OFFSET (SwfdecTextFormat, attr.block_indent),
48 G_STRUCT_OFFSET (SwfdecTextFormat, attr.bold),
49 G_STRUCT_OFFSET (SwfdecTextFormat, attr.bullet),
50 G_STRUCT_OFFSET (SwfdecTextFormat, attr.color),
51 G_STRUCT_OFFSET (SwfdecTextFormat, attr.display),
52 G_STRUCT_OFFSET (SwfdecTextFormat, attr.font),
53 G_STRUCT_OFFSET (SwfdecTextFormat, attr.indent),
54 G_STRUCT_OFFSET (SwfdecTextFormat, attr.italic),
55 G_STRUCT_OFFSET (SwfdecTextFormat, attr.kerning),
56 G_STRUCT_OFFSET (SwfdecTextFormat, attr.leading),
57 G_STRUCT_OFFSET (SwfdecTextFormat, attr.left_margin),
58 G_STRUCT_OFFSET (SwfdecTextFormat, attr.letter_spacing),
59 G_STRUCT_OFFSET (SwfdecTextFormat, attr.right_margin),
60 G_STRUCT_OFFSET (SwfdecTextFormat, attr.size),
61 G_STRUCT_OFFSET (SwfdecTextFormat, attr.tab_stops),
62 G_STRUCT_OFFSET (SwfdecTextFormat, attr.target),
63 G_STRUCT_OFFSET (SwfdecTextFormat, attr.underline),
64 G_STRUCT_OFFSET (SwfdecTextFormat, attr.url)
67 static void
68 swfdec_text_format_mark (SwfdecGcObject *object)
70 SwfdecTextFormat *format = SWFDEC_TEXT_FORMAT (object);
72 swfdec_text_attributes_mark (&format->attr);
74 SWFDEC_GC_OBJECT_CLASS (swfdec_text_format_parent_class)->mark (object);
77 static void
78 swfdec_text_format_dispose (GObject *object)
80 SwfdecTextFormat *format = SWFDEC_TEXT_FORMAT (object);
82 swfdec_text_attributes_reset (&format->attr);
84 G_OBJECT_CLASS (swfdec_text_format_parent_class)->dispose (object);
87 static void
88 swfdec_text_format_class_init (SwfdecTextFormatClass *klass)
90 GObjectClass *object_class = G_OBJECT_CLASS (klass);
91 SwfdecGcObjectClass *gc_class = SWFDEC_GC_OBJECT_CLASS (klass);
93 object_class->dispose = swfdec_text_format_dispose;
95 gc_class->mark = swfdec_text_format_mark;
98 static void
99 swfdec_text_format_init (SwfdecTextFormat *format)
101 swfdec_text_attributes_reset (&format->attr);
104 static void
105 swfdec_text_format_get_string (SwfdecAsObject *object,
106 SwfdecTextAttribute property, SwfdecAsValue *ret)
108 SwfdecTextFormat *format;
110 if (object == NULL || !SWFDEC_IS_TEXT_FORMAT (object->relay))
111 return;
112 format = SWFDEC_TEXT_FORMAT (object->relay);
114 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, property)) {
115 SWFDEC_AS_VALUE_SET_NULL (ret);
116 return;
119 SWFDEC_AS_VALUE_SET_STRING (ret,
120 G_STRUCT_MEMBER (const char *, format, property_offsets[property]));
123 static void
124 swfdec_text_format_set_string (SwfdecAsObject *object,
125 SwfdecTextAttribute property, guint argc, SwfdecAsValue *argv)
127 SwfdecTextFormat *format;
128 SwfdecAsContext *context;
129 const char *s;
131 if (object == NULL || !SWFDEC_IS_TEXT_FORMAT (object->relay))
132 return;
133 format = SWFDEC_TEXT_FORMAT (object->relay);
135 if (argc < 1)
136 return;
138 context = swfdec_gc_object_get_context (format);
139 swfdec_as_value_to_integer (context, argv[0]);
140 swfdec_as_value_to_number (context, argv[0]);
141 s = swfdec_as_value_to_string (context, argv[0]);
143 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0]) ||
144 SWFDEC_AS_VALUE_IS_NULL (argv[0])) {
145 /* FIXME: reset to defaults here? */
146 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set, property);
147 } else {
148 G_STRUCT_MEMBER (const char *, format, property_offsets[property]) = s;
149 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, property);
151 /* FIXME: figure out what to do here */
154 static void
155 swfdec_text_format_get_boolean (SwfdecAsObject *object,
156 SwfdecTextAttribute property, SwfdecAsValue *ret)
158 SwfdecTextFormat *format;
160 if (object == NULL || !SWFDEC_IS_TEXT_FORMAT (object->relay))
161 return;
162 format = SWFDEC_TEXT_FORMAT (object->relay);
164 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, property)) {
165 SWFDEC_AS_VALUE_SET_NULL (ret);
166 return;
169 if (G_STRUCT_MEMBER (gboolean, format, property_offsets[property])) {
170 SWFDEC_AS_VALUE_SET_BOOLEAN (ret, TRUE);
171 } else {
172 SWFDEC_AS_VALUE_SET_BOOLEAN (ret, FALSE);
176 static void
177 swfdec_text_format_set_boolean (SwfdecAsObject *object,
178 SwfdecTextAttribute property, guint argc, SwfdecAsValue *argv)
180 SwfdecTextFormat *format;
181 SwfdecAsContext *context;
183 if (object == NULL || !SWFDEC_IS_TEXT_FORMAT (object->relay))
184 return;
185 format = SWFDEC_TEXT_FORMAT (object->relay);
187 if (argc < 1)
188 return;
190 context = swfdec_gc_object_get_context (format);
191 swfdec_as_value_to_integer (context, argv[0]);
192 swfdec_as_value_to_number (context, argv[0]);
193 swfdec_as_value_to_string (context, argv[0]);
195 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0]) ||
196 SWFDEC_AS_VALUE_IS_NULL (argv[0])) {
197 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set, property);
198 } else {
199 G_STRUCT_MEMBER (gboolean, format, property_offsets[property]) =
200 swfdec_as_value_to_boolean (context, argv[0]);
201 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, property);
205 static void
206 swfdec_text_format_get_integer (SwfdecAsObject *object,
207 SwfdecTextAttribute property, SwfdecAsValue *ret)
209 SwfdecTextFormat *format;
211 if (object == NULL || !SWFDEC_IS_TEXT_FORMAT (object->relay))
212 return;
213 format = SWFDEC_TEXT_FORMAT (object->relay);
215 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, property)) {
216 SWFDEC_AS_VALUE_SET_NULL (ret);
217 return;
220 *ret = swfdec_as_value_from_number (object->context,
221 (double)G_STRUCT_MEMBER (int, format, property_offsets[property]));
224 static int
225 swfdec_text_format_value_to_integer (SwfdecAsContext *cx, SwfdecAsValue *val,
226 gboolean allow_negative)
228 double d;
229 int n;
231 n = swfdec_as_value_to_integer (cx, *val);
232 d = swfdec_as_value_to_number (cx, *val);
233 swfdec_as_value_to_string (cx, *val);
235 if (cx->version >= 8) {
236 if (isnan (d))
237 return (allow_negative ? G_MININT32 : 0);
239 if (!isfinite (d)) {
240 if (d > 0) {
241 return G_MININT32;
242 } else {
243 return (allow_negative ? G_MININT32 : 0);
246 if (d > (double)G_MAXINT32)
247 return G_MININT32;
249 n = (int)d;
250 if (!allow_negative && n < 0) {
251 return 0;
252 } else {
253 return n;
255 } else {
256 if (!allow_negative && n < 0) {
257 return 0;
258 } else {
259 return n;
264 static void
265 swfdec_text_format_set_integer (SwfdecAsObject *object,
266 SwfdecTextAttribute property, guint argc, SwfdecAsValue *argv,
267 gboolean allow_negative)
269 SwfdecTextFormat *format;
271 if (object == NULL || !SWFDEC_IS_TEXT_FORMAT (object->relay))
272 return;
273 format = SWFDEC_TEXT_FORMAT (object->relay);
275 if (argc < 1)
276 return;
278 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0]) ||
279 SWFDEC_AS_VALUE_IS_NULL (argv[0])) {
280 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set, property);
281 } else {
282 G_STRUCT_MEMBER (int, format, property_offsets[property]) =
283 swfdec_text_format_value_to_integer (swfdec_gc_object_get_context (format),
284 &argv[0], allow_negative);
285 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, property);
289 static void
290 swfdec_text_format_do_get_align (SwfdecAsContext *cx, SwfdecAsObject *object,
291 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
293 SwfdecTextFormat *format;
295 if (object == NULL || !SWFDEC_IS_TEXT_FORMAT (object->relay))
296 return;
297 format = SWFDEC_TEXT_FORMAT (object->relay);
299 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_ALIGN)) {
300 SWFDEC_AS_VALUE_SET_NULL (ret);
301 return;
304 switch (format->attr.align) {
305 case SWFDEC_TEXT_ALIGN_LEFT:
306 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_left);
307 break;
308 case SWFDEC_TEXT_ALIGN_RIGHT:
309 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_right);
310 break;
311 case SWFDEC_TEXT_ALIGN_CENTER:
312 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_center);
313 break;
314 case SWFDEC_TEXT_ALIGN_JUSTIFY:
315 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_justify);
316 break;
317 default:
318 g_assert_not_reached ();
322 static void
323 swfdec_text_format_do_set_align (SwfdecAsContext *cx, SwfdecAsObject *object,
324 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
326 SwfdecTextFormat *format;
327 const char *s;
329 if (object == NULL || !SWFDEC_IS_TEXT_FORMAT (object->relay))
330 return;
331 format = SWFDEC_TEXT_FORMAT (object->relay);
333 if (argc < 1)
334 return;
336 swfdec_as_value_to_integer (cx, argv[0]);
337 swfdec_as_value_to_number (cx, argv[0]);
338 s = swfdec_as_value_to_string (cx, argv[0]);
340 if (!g_ascii_strcasecmp (s, "left")) {
341 format->attr.align = SWFDEC_TEXT_ALIGN_LEFT;
342 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_ALIGN);
343 } else if (!g_ascii_strcasecmp (s, "right")) {
344 format->attr.align = SWFDEC_TEXT_ALIGN_RIGHT;
345 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_ALIGN);
346 } else if (!g_ascii_strcasecmp (s, "center")) {
347 format->attr.align = SWFDEC_TEXT_ALIGN_CENTER;
348 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_ALIGN);
349 } else if (!g_ascii_strcasecmp (s, "justify")) {
350 format->attr.align = SWFDEC_TEXT_ALIGN_JUSTIFY;
351 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_ALIGN);
355 static void
356 swfdec_text_format_do_get_block_indent (SwfdecAsContext *cx,
357 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
358 SwfdecAsValue *ret)
360 swfdec_text_format_get_integer (object, SWFDEC_TEXT_ATTRIBUTE_BLOCK_INDENT, ret);
363 static void
364 swfdec_text_format_do_set_block_indent (SwfdecAsContext *cx,
365 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
366 SwfdecAsValue *ret)
368 swfdec_text_format_set_integer (object, SWFDEC_TEXT_ATTRIBUTE_BLOCK_INDENT, argc, argv,
369 cx->version >= 8);
372 static void
373 swfdec_text_format_do_get_bold (SwfdecAsContext *cx, SwfdecAsObject *object,
374 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
376 swfdec_text_format_get_boolean (object, SWFDEC_TEXT_ATTRIBUTE_BOLD, ret);
379 static void
380 swfdec_text_format_do_set_bold (SwfdecAsContext *cx, SwfdecAsObject *object,
381 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
383 swfdec_text_format_set_boolean (object, SWFDEC_TEXT_ATTRIBUTE_BOLD, argc, argv);
386 static void
387 swfdec_text_format_do_get_bullet (SwfdecAsContext *cx, SwfdecAsObject *object,
388 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
390 swfdec_text_format_get_boolean (object, SWFDEC_TEXT_ATTRIBUTE_BULLET, ret);
393 static void
394 swfdec_text_format_do_set_bullet (SwfdecAsContext *cx, SwfdecAsObject *object,
395 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
397 swfdec_text_format_set_boolean (object, SWFDEC_TEXT_ATTRIBUTE_BULLET, argc, argv);
400 static void
401 swfdec_text_format_do_get_color (SwfdecAsContext *cx, SwfdecAsObject *object,
402 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
404 SwfdecTextFormat *format;
406 if (object == NULL || !SWFDEC_IS_TEXT_FORMAT (object->relay))
407 return;
408 format = SWFDEC_TEXT_FORMAT (object->relay);
410 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_COLOR)) {
411 SWFDEC_AS_VALUE_SET_NULL (ret);
412 return;
415 *ret = swfdec_as_value_from_number (cx, format->attr.color);
418 static void
419 swfdec_text_format_do_set_color (SwfdecAsContext *cx, SwfdecAsObject *object,
420 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
422 SwfdecTextFormat *format;
424 if (object == NULL || !SWFDEC_IS_TEXT_FORMAT (object->relay))
425 return;
426 format = SWFDEC_TEXT_FORMAT (object->relay);
428 if (argc < 1)
429 return;
431 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0]) ||
432 SWFDEC_AS_VALUE_IS_NULL (argv[0])) {
433 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_COLOR);
434 } else {
435 format->attr.color = (unsigned) swfdec_as_value_to_integer (cx, argv[0]);
436 swfdec_as_value_to_integer (cx, argv[0]);
437 swfdec_as_value_to_string (cx, argv[0]);
439 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_COLOR);
443 static void
444 swfdec_text_format_do_get_display (SwfdecAsContext *cx, SwfdecAsObject *object,
445 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
447 SwfdecTextFormat *format;
449 if (object == NULL || !SWFDEC_IS_TEXT_FORMAT (object->relay))
450 return;
451 format = SWFDEC_TEXT_FORMAT (object->relay);
453 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_DISPLAY))
455 SWFDEC_AS_VALUE_SET_NULL (ret);
456 return;
459 switch (format->attr.display) {
460 case SWFDEC_TEXT_DISPLAY_NONE:
461 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_none);
462 break;
463 case SWFDEC_TEXT_DISPLAY_INLINE:
464 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_inline);
465 break;
466 case SWFDEC_TEXT_DISPLAY_BLOCK:
467 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_block);
468 break;
469 default:
470 g_assert_not_reached ();
474 static void
475 swfdec_text_format_do_set_display (SwfdecAsContext *cx, SwfdecAsObject *object,
476 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
478 SwfdecTextFormat *format;
479 const char *s;
481 if (object == NULL || !SWFDEC_IS_TEXT_FORMAT (object->relay))
482 return;
483 format = SWFDEC_TEXT_FORMAT (object->relay);
485 swfdec_as_value_to_integer (cx, argv[0]);
486 swfdec_as_value_to_number (cx, argv[0]);
487 swfdec_as_value_to_string (cx, argv[0]);
488 s = swfdec_as_value_to_string (cx, argv[0]); // oh yes, let's call it twice
490 if (!g_ascii_strcasecmp (s, "none")) {
491 format->attr.display = SWFDEC_TEXT_DISPLAY_NONE;
492 } else if (!g_ascii_strcasecmp (s, "inline")) {
493 format->attr.display = SWFDEC_TEXT_DISPLAY_INLINE;
494 } else {
495 format->attr.display = SWFDEC_TEXT_DISPLAY_BLOCK;
498 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_DISPLAY);
501 static void
502 swfdec_text_format_do_get_font (SwfdecAsContext *cx, SwfdecAsObject *object,
503 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
505 swfdec_text_format_get_string (object, SWFDEC_TEXT_ATTRIBUTE_FONT, ret);
508 static void
509 swfdec_text_format_do_set_font (SwfdecAsContext *cx, SwfdecAsObject *object,
510 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
512 swfdec_text_format_set_string (object, SWFDEC_TEXT_ATTRIBUTE_FONT, argc, argv);
515 static void
516 swfdec_text_format_do_get_indent (SwfdecAsContext *cx, SwfdecAsObject *object,
517 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
519 swfdec_text_format_get_integer (object, SWFDEC_TEXT_ATTRIBUTE_INDENT, ret);
522 static void
523 swfdec_text_format_do_set_indent (SwfdecAsContext *cx, SwfdecAsObject *object,
524 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
526 swfdec_text_format_set_integer (object, SWFDEC_TEXT_ATTRIBUTE_INDENT, argc, argv,
527 cx->version >= 8);
530 static void
531 swfdec_text_format_do_get_italic (SwfdecAsContext *cx, SwfdecAsObject *object,
532 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
534 swfdec_text_format_get_boolean (object, SWFDEC_TEXT_ATTRIBUTE_ITALIC, ret);
537 static void
538 swfdec_text_format_do_set_italic (SwfdecAsContext *cx, SwfdecAsObject *object,
539 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
541 swfdec_text_format_set_boolean (object, SWFDEC_TEXT_ATTRIBUTE_ITALIC, argc, argv);
544 static void
545 swfdec_text_format_do_get_kerning (SwfdecAsContext *cx, SwfdecAsObject *object,
546 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
548 swfdec_text_format_get_boolean (object, SWFDEC_TEXT_ATTRIBUTE_KERNING, ret);
551 static void
552 swfdec_text_format_do_set_kerning (SwfdecAsContext *cx, SwfdecAsObject *object,
553 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
555 swfdec_text_format_set_boolean (object, SWFDEC_TEXT_ATTRIBUTE_KERNING, argc, argv);
558 static void
559 swfdec_text_format_do_get_leading (SwfdecAsContext *cx, SwfdecAsObject *object,
560 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
562 swfdec_text_format_get_integer (object, SWFDEC_TEXT_ATTRIBUTE_LEADING, ret);
565 static void
566 swfdec_text_format_do_set_leading (SwfdecAsContext *cx, SwfdecAsObject *object,
567 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
569 swfdec_text_format_set_integer (object, SWFDEC_TEXT_ATTRIBUTE_LEADING, argc, argv,
570 cx->version >= 8);
573 static void
574 swfdec_text_format_do_get_left_margin (SwfdecAsContext *cx,
575 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
576 SwfdecAsValue *ret)
578 swfdec_text_format_get_integer (object, SWFDEC_TEXT_ATTRIBUTE_LEFT_MARGIN, ret);
581 static void
582 swfdec_text_format_do_set_left_margin (SwfdecAsContext *cx,
583 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
584 SwfdecAsValue *ret)
586 swfdec_text_format_set_integer (object, SWFDEC_TEXT_ATTRIBUTE_LEFT_MARGIN, argc, argv, FALSE);
589 static void
590 swfdec_text_format_do_get_letter_spacing (SwfdecAsContext *cx,
591 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
592 SwfdecAsValue *ret)
594 SwfdecTextFormat *format;
596 if (object == NULL || !SWFDEC_IS_TEXT_FORMAT (object->relay))
597 return;
598 format = SWFDEC_TEXT_FORMAT (object->relay);
600 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_LETTER_SPACING)) {
601 SWFDEC_AS_VALUE_SET_NULL (ret);
602 return;
605 *ret = swfdec_as_value_from_number (cx, format->attr.letter_spacing);
608 static void
609 swfdec_text_format_do_set_letter_spacing (SwfdecAsContext *cx,
610 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
611 SwfdecAsValue *ret)
613 SwfdecTextFormat *format;
614 double d;
616 if (object == NULL || !SWFDEC_IS_TEXT_FORMAT (object->relay))
617 return;
618 format = SWFDEC_TEXT_FORMAT (object->relay);
620 if (argc < 1)
621 return;
623 swfdec_as_value_to_integer (cx, argv[0]);
624 d = swfdec_as_value_to_number (cx, argv[0]);
625 swfdec_as_value_to_string (cx, argv[0]);
627 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0]) ||
628 SWFDEC_AS_VALUE_IS_NULL (argv[0]))
630 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set,
631 SWFDEC_TEXT_ATTRIBUTE_LETTER_SPACING);
633 else
635 format->attr.letter_spacing = d;
636 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set,
637 SWFDEC_TEXT_ATTRIBUTE_LETTER_SPACING);
641 static void
642 swfdec_text_format_do_get_right_margin (SwfdecAsContext *cx,
643 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
644 SwfdecAsValue *ret)
646 swfdec_text_format_get_integer (object, SWFDEC_TEXT_ATTRIBUTE_RIGHT_MARGIN, ret);
649 static void
650 swfdec_text_format_do_set_right_margin (SwfdecAsContext *cx,
651 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
652 SwfdecAsValue *ret)
654 swfdec_text_format_set_integer (object, SWFDEC_TEXT_ATTRIBUTE_RIGHT_MARGIN, argc, argv,
655 FALSE);
658 static void
659 swfdec_text_format_do_get_size (SwfdecAsContext *cx, SwfdecAsObject *object,
660 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
662 swfdec_text_format_get_integer (object, SWFDEC_TEXT_ATTRIBUTE_SIZE, ret);
665 static void
666 swfdec_text_format_do_set_size (SwfdecAsContext *cx, SwfdecAsObject *object,
667 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
669 swfdec_text_format_set_integer (object, SWFDEC_TEXT_ATTRIBUTE_SIZE, argc, argv, TRUE);
672 static void
673 swfdec_text_format_do_get_tab_stops (SwfdecAsContext *cx,
674 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
675 SwfdecAsValue *ret)
677 SwfdecTextFormat *format;
678 guint i;
679 SwfdecAsValue val;
680 SwfdecAsObject *array;
682 if (object == NULL || !SWFDEC_IS_TEXT_FORMAT (object->relay))
683 return;
684 format = SWFDEC_TEXT_FORMAT (object->relay);
686 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_TAB_STOPS)) {
687 SWFDEC_AS_VALUE_SET_NULL (ret);
688 return;
691 array = swfdec_as_array_new (cx);
692 for (i = 0; i < format->attr.n_tab_stops; i++) {
693 val = swfdec_as_value_from_integer (cx, format->attr.tab_stops[i]);
694 swfdec_as_array_push (array, &val);
696 SWFDEC_AS_VALUE_SET_OBJECT (ret, array);
699 static void
700 swfdec_text_format_do_set_tab_stops (SwfdecAsContext *cx,
701 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
702 SwfdecAsValue *ret)
704 SwfdecTextFormat *format;
706 if (object == NULL || !SWFDEC_IS_TEXT_FORMAT (object->relay))
707 return;
708 format = SWFDEC_TEXT_FORMAT (object->relay);
710 if (argc < 1)
711 return;
713 swfdec_as_value_to_integer (cx, argv[0]);
714 swfdec_as_value_to_number (cx, argv[0]);
715 swfdec_as_value_to_string (cx, argv[0]);
717 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0]) ||
718 SWFDEC_AS_VALUE_IS_NULL (argv[0]))
720 g_free (format->attr.tab_stops);
721 format->attr.tab_stops = NULL;
722 format->attr.n_tab_stops = 0;
723 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_TAB_STOPS);
725 else if (SWFDEC_AS_VALUE_IS_OBJECT (argv[0]) &&
726 SWFDEC_AS_VALUE_GET_OBJECT (argv[0])->array)
728 SwfdecAsObject *array;
729 SwfdecAsValue val;
730 guint i;
731 int len;
733 array = SWFDEC_AS_VALUE_GET_OBJECT (argv[0]);
734 len = swfdec_as_array_get_length (array);
736 if (!SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_TAB_STOPS)) {
737 // special case, if we have null and array is empty, keep it at null
738 if (len == 0)
739 return;
740 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_TAB_STOPS);
743 g_free (format->attr.tab_stops);
744 format->attr.n_tab_stops = MAX (0, len);
745 format->attr.tab_stops = g_new (guint, format->attr.n_tab_stops);
746 for (i = 0; i < format->attr.n_tab_stops; i++) {
747 swfdec_as_array_get_value (array, i, &val);
748 format->attr.tab_stops[i] = swfdec_text_format_value_to_integer (cx, &val, TRUE);
751 else if (SWFDEC_AS_VALUE_IS_STRING (argv[0]))
753 gsize i;
755 // special case: empty strings mean null
756 if (SWFDEC_AS_VALUE_GET_STRING (argv[0]) == SWFDEC_AS_STR_EMPTY) {
757 g_free (format->attr.tab_stops);
758 format->attr.tab_stops = NULL;
759 format->attr.n_tab_stops = 0;
760 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_TAB_STOPS);
761 } else {
762 int n = cx->version >= 8 ? G_MININT : 0;
763 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_TAB_STOPS);
764 format->attr.n_tab_stops = strlen (SWFDEC_AS_VALUE_GET_STRING (argv[0]));
765 format->attr.tab_stops = g_new (guint, format->attr.n_tab_stops);
766 for (i = 0; i < format->attr.n_tab_stops; i++) {
767 format->attr.tab_stops[i] = n;
771 else if (SWFDEC_TEXT_ATTRIBUTE_IS_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_TAB_STOPS))
773 format->attr.n_tab_stops = 0;
774 g_free (format->attr.tab_stops);
775 format->attr.tab_stops = NULL;
779 static void
780 swfdec_text_format_do_get_target (SwfdecAsContext *cx, SwfdecAsObject *object,
781 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
783 swfdec_text_format_get_string (object, SWFDEC_TEXT_ATTRIBUTE_TARGET, ret);
786 static void
787 swfdec_text_format_do_set_target (SwfdecAsContext *cx, SwfdecAsObject *object,
788 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
790 swfdec_text_format_set_string (object, SWFDEC_TEXT_ATTRIBUTE_TARGET, argc, argv);
793 static void
794 swfdec_text_format_do_get_underline (SwfdecAsContext *cx,
795 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
796 SwfdecAsValue *ret)
798 swfdec_text_format_get_boolean (object, SWFDEC_TEXT_ATTRIBUTE_UNDERLINE, ret);
801 static void
802 swfdec_text_format_do_set_underline (SwfdecAsContext *cx,
803 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv,
804 SwfdecAsValue *ret)
806 swfdec_text_format_set_boolean (object, SWFDEC_TEXT_ATTRIBUTE_UNDERLINE, argc, argv);
809 static void
810 swfdec_text_format_do_get_url (SwfdecAsContext *cx, SwfdecAsObject *object,
811 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
813 swfdec_text_format_get_string (object, SWFDEC_TEXT_ATTRIBUTE_URL, ret);
816 static void
817 swfdec_text_format_do_set_url (SwfdecAsContext *cx, SwfdecAsObject *object,
818 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
820 swfdec_text_format_set_string (object, SWFDEC_TEXT_ATTRIBUTE_URL, argc, argv);
823 static void
824 swfdec_text_format_getTextExtent (SwfdecAsContext *cx, SwfdecAsObject *object,
825 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
827 SwfdecTextFormat *format;
828 SwfdecTextBuffer *buffer;
829 SwfdecTextLayout *layout;
830 SwfdecAsObject *obj;
831 SwfdecAsValue val;
832 const char* text;
833 int i, j;
835 SWFDEC_AS_CHECK (SWFDEC_TYPE_TEXT_FORMAT, &format, "s", &text);
837 obj = swfdec_as_object_new_empty (cx);
839 buffer = swfdec_text_buffer_new ();
840 swfdec_text_buffer_set_default_attributes (buffer,
841 &format->attr, format->values_set);
842 swfdec_text_buffer_append_text (buffer, text);
843 layout = swfdec_text_layout_new (buffer);
845 i = swfdec_text_layout_get_width (layout);
846 val = swfdec_as_value_from_integer (cx, i);
847 swfdec_as_object_set_variable (obj, SWFDEC_AS_STR_width, &val);
848 if (i)
849 i += 4;
850 val = swfdec_as_value_from_integer (cx, i);
851 swfdec_as_object_set_variable (obj, SWFDEC_AS_STR_textFieldWidth, &val);
853 i = swfdec_text_layout_get_height (layout);
854 val = swfdec_as_value_from_integer (cx, i);
855 swfdec_as_object_set_variable (obj, SWFDEC_AS_STR_height, &val);
856 if (i)
857 i += 4;
858 val = swfdec_as_value_from_integer (cx, i);
859 swfdec_as_object_set_variable (obj, SWFDEC_AS_STR_textFieldHeight, &val);
861 swfdec_text_layout_get_ascent_descent (layout, &i, &j);
862 val = swfdec_as_value_from_integer (cx, i);
863 swfdec_as_object_set_variable (obj, SWFDEC_AS_STR_ascent, &val);
864 val = swfdec_as_value_from_integer (cx, j);
865 swfdec_as_object_set_variable (obj, SWFDEC_AS_STR_descent, &val);
867 SWFDEC_AS_VALUE_SET_OBJECT (ret, obj);
868 g_object_unref (layout);
869 g_object_unref (buffer);
872 void
873 swfdec_text_format_add (SwfdecTextFormat *format, const SwfdecTextFormat *from)
875 g_return_if_fail (SWFDEC_IS_TEXT_FORMAT (format));
876 g_return_if_fail (SWFDEC_IS_TEXT_FORMAT (from));
878 swfdec_text_attributes_copy (&format->attr, &from->attr, from->values_set);
879 format->values_set |= from->values_set;
882 void
883 swfdec_text_format_remove_different (SwfdecTextFormat *format,
884 const SwfdecTextFormat *from)
886 g_return_if_fail (SWFDEC_IS_TEXT_FORMAT (format));
887 g_return_if_fail (SWFDEC_IS_TEXT_FORMAT (from));
889 format->values_set &= ~swfdec_text_attributes_diff (&format->attr, &from->attr);
892 gboolean
893 swfdec_text_format_equal_or_undefined (const SwfdecTextFormat *a,
894 const SwfdecTextFormat *b)
896 int set, diff;
898 g_return_val_if_fail (SWFDEC_IS_TEXT_FORMAT (a), FALSE);
899 g_return_val_if_fail (SWFDEC_IS_TEXT_FORMAT (b), FALSE);
901 set = a->values_set & b->values_set;
902 diff = swfdec_text_attributes_diff (&a->attr, &b->attr);
904 return (set & diff) == 0;
907 gboolean
908 swfdec_text_format_equal (const SwfdecTextFormat *a, const SwfdecTextFormat *b)
910 g_return_val_if_fail (SWFDEC_IS_TEXT_FORMAT (a), FALSE);
911 g_return_val_if_fail (SWFDEC_IS_TEXT_FORMAT (b), FALSE);
913 if (a->values_set != b->values_set)
914 return FALSE;
916 return (a->values_set & swfdec_text_attributes_diff (&a->attr, &b->attr)) == 0;
919 void
920 swfdec_text_format_set_defaults (SwfdecTextFormat *format)
922 swfdec_text_attributes_reset (&format->attr);
923 format->values_set = SWFDEC_TEXT_ATTRIBUTES_MASK;
925 if (swfdec_gc_object_get_context (format)->version < 8) {
926 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_KERNING);
927 SWFDEC_TEXT_ATTRIBUTE_UNSET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_LETTER_SPACING);
931 static void
932 swfdec_text_format_clear (SwfdecTextFormat *format)
934 format->values_set = 0;
936 format->attr.display = SWFDEC_TEXT_DISPLAY_BLOCK;
937 SWFDEC_TEXT_ATTRIBUTE_SET (format->values_set, SWFDEC_TEXT_ATTRIBUTE_DISPLAY);
940 void
941 swfdec_text_format_init_properties (SwfdecAsContext *cx)
943 SwfdecAsValue val;
944 SwfdecAsObject *proto;
946 // FIXME: We should only initialize if the prototype Object has not been
947 // initialized by any object's constructor with native properties
948 // (TextField, TextFormat, XML, XMLNode at least)
950 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (cx));
952 swfdec_as_object_get_variable (cx->global, SWFDEC_AS_STR_TextFormat, &val);
953 if (!SWFDEC_AS_VALUE_IS_OBJECT (val))
954 return;
955 proto = SWFDEC_AS_VALUE_GET_OBJECT (val);
956 swfdec_as_object_get_variable (proto, SWFDEC_AS_STR_prototype, &val);
957 if (!SWFDEC_AS_VALUE_IS_OBJECT (val))
958 return;
959 proto = SWFDEC_AS_VALUE_GET_OBJECT (val);
961 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_align,
962 swfdec_text_format_do_get_align, swfdec_text_format_do_set_align);
963 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_blockIndent,
964 swfdec_text_format_do_get_block_indent,
965 swfdec_text_format_do_set_block_indent);
966 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_bold,
967 swfdec_text_format_do_get_bold, swfdec_text_format_do_set_bold);
968 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_bullet,
969 swfdec_text_format_do_get_bullet, swfdec_text_format_do_set_bullet);
970 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_color,
971 swfdec_text_format_do_get_color, swfdec_text_format_do_set_color);
972 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_display,
973 swfdec_text_format_do_get_display, swfdec_text_format_do_set_display);
974 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_font,
975 swfdec_text_format_do_get_font, swfdec_text_format_do_set_font);
976 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_indent,
977 swfdec_text_format_do_get_indent, swfdec_text_format_do_set_indent);
978 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_italic,
979 swfdec_text_format_do_get_italic, swfdec_text_format_do_set_italic);
980 if (cx->version >= 8) {
981 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_kerning,
982 swfdec_text_format_do_get_kerning, swfdec_text_format_do_set_kerning);
984 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_leading,
985 swfdec_text_format_do_get_leading, swfdec_text_format_do_set_leading);
986 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_leftMargin,
987 swfdec_text_format_do_get_left_margin,
988 swfdec_text_format_do_set_left_margin);
989 if (cx->version >= 8) {
990 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_letterSpacing,
991 swfdec_text_format_do_get_letter_spacing,
992 swfdec_text_format_do_set_letter_spacing);
994 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_rightMargin,
995 swfdec_text_format_do_get_right_margin,
996 swfdec_text_format_do_set_right_margin);
997 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_size,
998 swfdec_text_format_do_get_size, swfdec_text_format_do_set_size);
999 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_tabStops,
1000 swfdec_text_format_do_get_tab_stops,
1001 swfdec_text_format_do_set_tab_stops);
1002 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_target,
1003 swfdec_text_format_do_get_target, swfdec_text_format_do_set_target);
1004 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_underline,
1005 swfdec_text_format_do_get_underline,
1006 swfdec_text_format_do_set_underline);
1007 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_url,
1008 swfdec_text_format_do_get_url, swfdec_text_format_do_set_url);
1011 SWFDEC_AS_NATIVE (110, 0, swfdec_text_format_construct)
1012 void
1013 swfdec_text_format_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
1014 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
1016 static const char *arguments[] = {
1017 SWFDEC_AS_STR_font,
1018 SWFDEC_AS_STR_size,
1019 SWFDEC_AS_STR_color,
1020 SWFDEC_AS_STR_bold,
1021 SWFDEC_AS_STR_italic,
1022 SWFDEC_AS_STR_underline,
1023 SWFDEC_AS_STR_url,
1024 SWFDEC_AS_STR_target,
1025 SWFDEC_AS_STR_align,
1026 SWFDEC_AS_STR_leftMargin,
1027 SWFDEC_AS_STR_rightMargin,
1028 SWFDEC_AS_STR_indent,
1029 SWFDEC_AS_STR_leading,
1030 NULL
1032 SwfdecTextFormat *format;
1033 SwfdecAsFunction *function;
1034 SwfdecAsValue val;
1035 guint i;
1037 if (!swfdec_as_context_is_constructing (cx)) {
1038 SWFDEC_FIXME ("What do we do if not constructing?");
1039 return;
1042 swfdec_text_format_init_properties (cx);
1044 format = g_object_new (SWFDEC_TYPE_TEXT_FORMAT, "context", cx, NULL);
1045 swfdec_text_format_clear (format);
1046 swfdec_as_object_set_relay (object, SWFDEC_AS_RELAY (format));
1048 function = swfdec_as_native_function_new_bare (cx,
1049 SWFDEC_AS_STR_getTextExtent, swfdec_text_format_getTextExtent);
1050 SWFDEC_AS_VALUE_SET_OBJECT (&val, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (function)));
1051 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_getTextExtent, &val);
1053 for (i = 0; i < argc && arguments[i] != NULL; i++) {
1054 swfdec_as_object_set_variable (object, arguments[i], &argv[i]);
1058 SwfdecTextFormat *
1059 swfdec_text_format_copy (SwfdecTextFormat *copy_from)
1061 SwfdecTextFormat *copy_to;
1063 g_return_val_if_fail (SWFDEC_IS_TEXT_FORMAT (copy_from), NULL);
1065 copy_to = swfdec_text_format_new_no_properties (
1066 swfdec_gc_object_get_context (copy_from));
1068 swfdec_text_attributes_copy (&copy_to->attr, &copy_from->attr, -1);
1069 copy_to->values_set = copy_from->values_set;
1071 return copy_to;
1074 SwfdecTextFormat *
1075 swfdec_text_format_new_no_properties (SwfdecAsContext *context)
1077 SwfdecAsObject *object;
1078 SwfdecTextFormat *ret;
1079 SwfdecAsFunction *function;
1080 SwfdecAsValue val;
1082 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), NULL);
1084 ret = g_object_new (SWFDEC_TYPE_TEXT_FORMAT, "context", context, NULL);
1086 swfdec_text_format_clear (ret);
1087 object = swfdec_as_object_new (context, NULL);
1088 swfdec_as_object_set_constructor_by_name (object, SWFDEC_AS_STR_TextFormat, NULL);
1089 swfdec_as_object_set_relay (object, SWFDEC_AS_RELAY (ret));
1091 // FIXME: Need better way to create function without prototype/constructor
1092 function = swfdec_as_native_function_new_bare (context,
1093 SWFDEC_AS_STR_getTextExtent, swfdec_text_format_getTextExtent);
1094 SWFDEC_AS_VALUE_SET_OBJECT (&val, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (function)));
1095 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_getTextExtent, &val);
1097 return ret;
1100 SwfdecTextFormat *
1101 swfdec_text_format_new (SwfdecAsContext *context)
1103 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), NULL);
1105 swfdec_text_format_init_properties (context);
1107 return swfdec_text_format_new_no_properties (context);