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.
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
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
)
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
);
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
);
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
;
99 swfdec_text_format_init (SwfdecTextFormat
*format
)
101 swfdec_text_attributes_reset (&format
->attr
);
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
))
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
);
119 SWFDEC_AS_VALUE_SET_STRING (ret
,
120 G_STRUCT_MEMBER (const char *, format
, property_offsets
[property
]));
124 swfdec_text_format_set_string (SwfdecAsObject
*object
,
125 SwfdecTextAttribute property
, guint argc
, SwfdecAsValue
*argv
)
127 SwfdecTextFormat
*format
;
128 SwfdecAsContext
*context
;
131 if (object
== NULL
|| !SWFDEC_IS_TEXT_FORMAT (object
->relay
))
133 format
= SWFDEC_TEXT_FORMAT (object
->relay
);
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
);
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 */
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
))
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
);
169 if (G_STRUCT_MEMBER (gboolean
, format
, property_offsets
[property
])) {
170 SWFDEC_AS_VALUE_SET_BOOLEAN (ret
, TRUE
);
172 SWFDEC_AS_VALUE_SET_BOOLEAN (ret
, FALSE
);
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
))
185 format
= SWFDEC_TEXT_FORMAT (object
->relay
);
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
);
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
);
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
))
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
);
220 swfdec_as_value_set_number (swfdec_gc_object_get_context (object
), ret
,
221 (double)G_STRUCT_MEMBER (int, format
, property_offsets
[property
]));
225 swfdec_text_format_value_to_integer (SwfdecAsContext
*cx
, SwfdecAsValue
*val
,
226 gboolean allow_negative
)
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) {
237 return (allow_negative
? G_MININT32
: 0);
243 return (allow_negative
? G_MININT32
: 0);
246 if (d
> (double)G_MAXINT32
)
250 if (!allow_negative
&& n
< 0) {
256 if (!allow_negative
&& n
< 0) {
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
))
273 format
= SWFDEC_TEXT_FORMAT (object
->relay
);
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
);
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
);
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
))
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
);
304 switch (format
->attr
.align
) {
305 case SWFDEC_TEXT_ALIGN_LEFT
:
306 SWFDEC_AS_VALUE_SET_STRING (ret
, SWFDEC_AS_STR_left
);
308 case SWFDEC_TEXT_ALIGN_RIGHT
:
309 SWFDEC_AS_VALUE_SET_STRING (ret
, SWFDEC_AS_STR_right
);
311 case SWFDEC_TEXT_ALIGN_CENTER
:
312 SWFDEC_AS_VALUE_SET_STRING (ret
, SWFDEC_AS_STR_center
);
314 case SWFDEC_TEXT_ALIGN_JUSTIFY
:
315 SWFDEC_AS_VALUE_SET_STRING (ret
, SWFDEC_AS_STR_justify
);
318 g_assert_not_reached ();
323 swfdec_text_format_do_set_align (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
324 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*ret
)
326 SwfdecTextFormat
*format
;
329 if (object
== NULL
|| !SWFDEC_IS_TEXT_FORMAT (object
->relay
))
331 format
= SWFDEC_TEXT_FORMAT (object
->relay
);
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
);
356 swfdec_text_format_do_get_block_indent (SwfdecAsContext
*cx
,
357 SwfdecAsObject
*object
, guint argc
, SwfdecAsValue
*argv
,
360 swfdec_text_format_get_integer (object
, SWFDEC_TEXT_ATTRIBUTE_BLOCK_INDENT
, ret
);
364 swfdec_text_format_do_set_block_indent (SwfdecAsContext
*cx
,
365 SwfdecAsObject
*object
, guint argc
, SwfdecAsValue
*argv
,
368 swfdec_text_format_set_integer (object
, SWFDEC_TEXT_ATTRIBUTE_BLOCK_INDENT
, argc
, argv
,
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
);
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
);
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
);
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
);
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
))
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
);
415 swfdec_as_value_set_number (cx
, ret
, format
->attr
.color
);
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
))
426 format
= SWFDEC_TEXT_FORMAT (object
->relay
);
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
);
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
);
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
))
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
);
459 switch (format
->attr
.display
) {
460 case SWFDEC_TEXT_DISPLAY_NONE
:
461 SWFDEC_AS_VALUE_SET_STRING (ret
, SWFDEC_AS_STR_none
);
463 case SWFDEC_TEXT_DISPLAY_INLINE
:
464 SWFDEC_AS_VALUE_SET_STRING (ret
, SWFDEC_AS_STR_inline
);
466 case SWFDEC_TEXT_DISPLAY_BLOCK
:
467 SWFDEC_AS_VALUE_SET_STRING (ret
, SWFDEC_AS_STR_block
);
470 g_assert_not_reached ();
475 swfdec_text_format_do_set_display (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
476 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*ret
)
478 SwfdecTextFormat
*format
;
481 if (object
== NULL
|| !SWFDEC_IS_TEXT_FORMAT (object
->relay
))
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
;
495 format
->attr
.display
= SWFDEC_TEXT_DISPLAY_BLOCK
;
498 SWFDEC_TEXT_ATTRIBUTE_SET (format
->values_set
, SWFDEC_TEXT_ATTRIBUTE_DISPLAY
);
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
);
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
);
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
);
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
,
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
);
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
);
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
);
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
);
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
);
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
,
574 swfdec_text_format_do_get_left_margin (SwfdecAsContext
*cx
,
575 SwfdecAsObject
*object
, guint argc
, SwfdecAsValue
*argv
,
578 swfdec_text_format_get_integer (object
, SWFDEC_TEXT_ATTRIBUTE_LEFT_MARGIN
, ret
);
582 swfdec_text_format_do_set_left_margin (SwfdecAsContext
*cx
,
583 SwfdecAsObject
*object
, guint argc
, SwfdecAsValue
*argv
,
586 swfdec_text_format_set_integer (object
, SWFDEC_TEXT_ATTRIBUTE_LEFT_MARGIN
, argc
, argv
, FALSE
);
590 swfdec_text_format_do_get_letter_spacing (SwfdecAsContext
*cx
,
591 SwfdecAsObject
*object
, guint argc
, SwfdecAsValue
*argv
,
594 SwfdecTextFormat
*format
;
596 if (object
== NULL
|| !SWFDEC_IS_TEXT_FORMAT (object
->relay
))
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
);
605 swfdec_as_value_set_number (cx
, ret
, format
->attr
.letter_spacing
);
609 swfdec_text_format_do_set_letter_spacing (SwfdecAsContext
*cx
,
610 SwfdecAsObject
*object
, guint argc
, SwfdecAsValue
*argv
,
613 SwfdecTextFormat
*format
;
616 if (object
== NULL
|| !SWFDEC_IS_TEXT_FORMAT (object
->relay
))
618 format
= SWFDEC_TEXT_FORMAT (object
->relay
);
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
);
635 format
->attr
.letter_spacing
= d
;
636 SWFDEC_TEXT_ATTRIBUTE_SET (format
->values_set
,
637 SWFDEC_TEXT_ATTRIBUTE_LETTER_SPACING
);
642 swfdec_text_format_do_get_right_margin (SwfdecAsContext
*cx
,
643 SwfdecAsObject
*object
, guint argc
, SwfdecAsValue
*argv
,
646 swfdec_text_format_get_integer (object
, SWFDEC_TEXT_ATTRIBUTE_RIGHT_MARGIN
, ret
);
650 swfdec_text_format_do_set_right_margin (SwfdecAsContext
*cx
,
651 SwfdecAsObject
*object
, guint argc
, SwfdecAsValue
*argv
,
654 swfdec_text_format_set_integer (object
, SWFDEC_TEXT_ATTRIBUTE_RIGHT_MARGIN
, argc
, argv
,
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
);
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
);
673 swfdec_text_format_do_get_tab_stops (SwfdecAsContext
*cx
,
674 SwfdecAsObject
*object
, guint argc
, SwfdecAsValue
*argv
,
677 SwfdecTextFormat
*format
;
680 SwfdecAsObject
*array
;
682 if (object
== NULL
|| !SWFDEC_IS_TEXT_FORMAT (object
->relay
))
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
);
691 array
= swfdec_as_array_new (cx
);
692 for (i
= 0; i
< format
->attr
.n_tab_stops
; i
++) {
693 swfdec_as_value_set_integer (cx
, &val
, format
->attr
.tab_stops
[i
]);
694 swfdec_as_array_push (array
, &val
);
696 SWFDEC_AS_VALUE_SET_OBJECT (ret
, array
);
700 swfdec_text_format_do_set_tab_stops (SwfdecAsContext
*cx
,
701 SwfdecAsObject
*object
, guint argc
, SwfdecAsValue
*argv
,
704 SwfdecTextFormat
*format
;
706 if (object
== NULL
|| !SWFDEC_IS_TEXT_FORMAT (object
->relay
))
708 format
= SWFDEC_TEXT_FORMAT (object
->relay
);
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
;
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
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]))
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
);
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
;
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
);
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
);
794 swfdec_text_format_do_get_underline (SwfdecAsContext
*cx
,
795 SwfdecAsObject
*object
, guint argc
, SwfdecAsValue
*argv
,
798 swfdec_text_format_get_boolean (object
, SWFDEC_TEXT_ATTRIBUTE_UNDERLINE
, ret
);
802 swfdec_text_format_do_set_underline (SwfdecAsContext
*cx
,
803 SwfdecAsObject
*object
, guint argc
, SwfdecAsValue
*argv
,
806 swfdec_text_format_set_boolean (object
, SWFDEC_TEXT_ATTRIBUTE_UNDERLINE
, argc
, argv
);
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
);
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
);
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
;
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 swfdec_as_value_set_integer (cx
, &val
, i
);
847 swfdec_as_object_set_variable (obj
, SWFDEC_AS_STR_width
, &val
);
850 swfdec_as_value_set_integer (cx
, &val
, i
);
851 swfdec_as_object_set_variable (obj
, SWFDEC_AS_STR_textFieldWidth
, &val
);
853 i
= swfdec_text_layout_get_height (layout
);
854 swfdec_as_value_set_integer (cx
, &val
, i
);
855 swfdec_as_object_set_variable (obj
, SWFDEC_AS_STR_height
, &val
);
858 swfdec_as_value_set_integer (cx
, &val
, i
);
859 swfdec_as_object_set_variable (obj
, SWFDEC_AS_STR_textFieldHeight
, &val
);
861 swfdec_text_layout_get_ascent_descent (layout
, &i
, &j
);
862 swfdec_as_value_set_integer (cx
, &val
, i
);
863 swfdec_as_object_set_variable (obj
, SWFDEC_AS_STR_ascent
, &val
);
864 swfdec_as_value_set_integer (cx
, &val
, 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
);
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
;
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
);
893 swfdec_text_format_equal_or_undefined (const SwfdecTextFormat
*a
,
894 const SwfdecTextFormat
*b
)
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;
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
)
916 return (a
->values_set
& swfdec_text_attributes_diff (&a
->attr
, &b
->attr
)) == 0;
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
);
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
);
941 swfdec_text_format_init_properties (SwfdecAsContext
*cx
)
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
))
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
))
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
)
1013 swfdec_text_format_construct (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
1014 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*ret
)
1016 static const char *arguments
[] = {
1019 SWFDEC_AS_STR_color
,
1021 SWFDEC_AS_STR_italic
,
1022 SWFDEC_AS_STR_underline
,
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
,
1032 SwfdecTextFormat
*format
;
1033 SwfdecAsObject
*function
;
1037 if (!swfdec_as_context_is_constructing (cx
)) {
1038 SWFDEC_FIXME ("What do we do if not constructing?");
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_OBJECT (swfdec_as_native_function_new_bare (cx
,
1049 SWFDEC_AS_STR_getTextExtent
, swfdec_text_format_getTextExtent
, NULL
));
1050 SWFDEC_AS_VALUE_SET_OBJECT (&val
, 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
]);
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 (©_to
->attr
, ©_from
->attr
, -1);
1069 copy_to
->values_set
= copy_from
->values_set
;
1075 swfdec_text_format_new_no_properties (SwfdecAsContext
*context
)
1077 SwfdecAsObject
*object
;
1078 SwfdecTextFormat
*ret
;
1079 SwfdecAsObject
*function
;
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_OBJECT (swfdec_as_native_function_new (context
,
1093 SWFDEC_AS_STR_getTextExtent
, swfdec_text_format_getTextExtent
, NULL
));
1094 swfdec_as_object_unset_variable_flags (function
, SWFDEC_AS_STR_constructor
, SWFDEC_AS_VARIABLE_PERMANENT
);
1095 swfdec_as_object_unset_variable_flags (function
, SWFDEC_AS_STR___proto__
, SWFDEC_AS_VARIABLE_PERMANENT
);
1096 swfdec_as_object_delete_variable (function
, SWFDEC_AS_STR_constructor
);
1097 swfdec_as_object_delete_variable (function
, SWFDEC_AS_STR___proto__
);
1098 if (function
!= NULL
) {
1099 SWFDEC_AS_VALUE_SET_OBJECT (&val
, SWFDEC_AS_OBJECT (function
));
1100 swfdec_as_object_set_variable (object
, SWFDEC_AS_STR_getTextExtent
, &val
);
1107 swfdec_text_format_new (SwfdecAsContext
*context
)
1109 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context
), NULL
);
1111 swfdec_text_format_init_properties (context
);
1113 return swfdec_text_format_new_no_properties (context
);