2 * Copyright (C) 2007 Pekka Lampila <pekka.lampila@iki.fi>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
27 #include "swfdec_text_field_movie.h"
28 #include "swfdec_as_strings.h"
29 #include "swfdec_style_sheet.h"
30 #include "swfdec_xml.h"
31 #include "swfdec_debug.h"
41 SwfdecTextFormat
* format
;
47 gboolean condense_white
;
48 SwfdecStyleSheet
* style_sheet
;
49 SwfdecTextBuffer
* text
;
55 swfdec_text_field_movie_html_parse_close_tag (ParserData
*data
, ParserTag
*tag
,
58 g_return_if_fail (data
!= NULL
);
59 g_return_if_fail (tag
!= NULL
);
61 if (data
->multiline
&& !end
&&
62 ((tag
->name_length
== 1 && !g_strncasecmp (tag
->name
, "p", 1)) ||
63 (tag
->name_length
== 2 && !g_strncasecmp (tag
->name
, "li", 2))))
67 for (iter
= data
->tags_closed
; iter
!= NULL
; iter
= iter
->next
) {
68 ParserTag
*f
= iter
->data
;
69 if (f
->end_index
< tag
->index
)
71 if (f
->name_length
== 4 && !g_strncasecmp (f
->name
, "font", 4)) {
72 ParserTag
*n
= g_new0 (ParserTag
, 1);
74 n
->name_length
= f
->name_length
;
75 n
->index
= swfdec_text_buffer_get_length (data
->text
);
76 n
->end_index
= n
->index
+ 1;
77 if (f
->format
!= NULL
) {
78 n
->format
= swfdec_text_format_copy (f
->format
);
82 data
->tags_closed
= g_slist_prepend (data
->tags_closed
, n
);
86 swfdec_text_buffer_append_text (data
->text
, "\n");
89 tag
->end_index
= swfdec_text_buffer_get_length (data
->text
);
91 data
->tags_open
= g_slist_remove (data
->tags_open
, tag
);
92 data
->tags_closed
= g_slist_prepend (data
->tags_closed
, tag
);
96 swfdec_text_field_movie_html_parse_comment (ParserData
*data
, const char *p
)
100 g_return_val_if_fail (data
!= NULL
, NULL
);
101 g_return_val_if_fail (p
!= NULL
, NULL
);
102 g_return_val_if_fail (strncmp (p
, "<!--", strlen ("<!--")) == 0, NULL
);
104 end
= strstr (p
+ strlen ("<!--"), "-->");
106 end
+= strlen("-->");
108 // return NULL if no end found
113 swfdec_text_field_movie_html_tag_set_attribute (ParserData
*data
,
114 ParserTag
*tag
, const char *name
, int name_length
, const char *value
,
118 SwfdecAsObject
*object
;
120 g_return_if_fail (data
!= NULL
);
121 g_return_if_fail (tag
!= NULL
);
122 g_return_if_fail (name
!= NULL
);
123 g_return_if_fail (name_length
>= 0);
124 g_return_if_fail (value
!= NULL
);
125 g_return_if_fail (value_length
>= 0);
130 object
= SWFDEC_AS_OBJECT (tag
->format
);
131 SWFDEC_AS_VALUE_SET_STRING (&val
, swfdec_as_context_give_string (
132 swfdec_gc_object_get_context (object
), g_strndup (value
, value_length
)));
134 if (tag
->name_length
== 10 && !g_strncasecmp (tag
->name
, "textformat", 10))
136 if (name_length
== 10 && !g_strncasecmp (name
, "leftmargin", 10))
138 swfdec_as_object_set_variable (object
, SWFDEC_AS_STR_leftMargin
, &val
);
140 else if (name_length
== 11 && !g_strncasecmp (name
, "rightmargin", 11))
142 swfdec_as_object_set_variable (object
, SWFDEC_AS_STR_rightMargin
, &val
);
144 else if (name_length
== 6 && !g_strncasecmp (name
, "indent", 6))
146 swfdec_as_object_set_variable (object
, SWFDEC_AS_STR_indent
, &val
);
148 else if (name_length
== 11 && !g_strncasecmp (name
, "blockindent", 11))
150 swfdec_as_object_set_variable (object
, SWFDEC_AS_STR_blockIndent
, &val
);
152 else if (name_length
== 8 && !g_strncasecmp (name
, "tabstops", 8))
155 swfdec_as_object_set_variable (object
, SWFDEC_AS_STR_tabStops
, &val
);
158 else if (tag
->name_length
== 1 && !g_strncasecmp (tag
->name
, "p", 1))
160 if (name_length
== 5 && !g_strncasecmp (name
, "align", 5))
162 swfdec_as_object_set_variable (object
, SWFDEC_AS_STR_align
, &val
);
165 else if (tag
->name_length
== 4 && !g_strncasecmp (tag
->name
, "font", 4))
167 if (name_length
== 4 && !g_strncasecmp (name
, "face", 4))
169 swfdec_as_object_set_variable (object
, SWFDEC_AS_STR_font
, &val
);
171 else if (name_length
== 4 && !g_strncasecmp (name
, "size", 4))
173 swfdec_as_object_set_variable (object
, SWFDEC_AS_STR_size
, &val
);
175 else if (name_length
== 5 && !g_strncasecmp (name
, "color", 5))
177 SwfdecAsValue val_number
;
179 if (value_length
!= 7 || *value
!= '#') {
180 SWFDEC_AS_VALUE_SET_NUMBER (&val_number
, 0);
185 number
= g_ascii_strtoll (value
+ 1, &tail
, 16);
186 if (tail
!= value
+ 7)
188 SWFDEC_AS_VALUE_SET_NUMBER (&val_number
, number
);
191 swfdec_as_object_set_variable (object
, SWFDEC_AS_STR_color
, &val_number
);
193 else if (name_length
== 13 && !g_strncasecmp (name
, "letterspacing", 13))
195 swfdec_as_object_set_variable (object
, SWFDEC_AS_STR_letterSpacing
,
198 // special case: Don't parse kerning
200 else if (tag
->name_length
== 1 && !g_strncasecmp (tag
->name
, "a", 1))
202 if (name_length
== 4 && !g_strncasecmp (name
, "href", 4))
204 swfdec_as_object_set_variable (object
, SWFDEC_AS_STR_url
, &val
);
206 else if (name_length
== 6 && !g_strncasecmp (name
, "target", 6))
208 swfdec_as_object_set_variable (object
, SWFDEC_AS_STR_target
, &val
);
212 if (data
->style_sheet
&&
213 ((tag
->name_length
== 2 && !g_strncasecmp (tag
->name
, "li", 2)) ||
214 (tag
->name_length
== 4 && !g_strncasecmp (tag
->name
, "span", 4)) ||
215 (tag
->name_length
== 1 && !g_strncasecmp (tag
->name
, "p", 1))))
217 if (name_length
== 5 && !g_strncasecmp (name
, "class", 5)) {
218 SwfdecTextFormat
*format
= swfdec_style_sheet_get_class_format (
219 data
->style_sheet
, swfdec_as_context_give_string (data
->cx
,
220 g_strndup (value
, value_length
)));
222 swfdec_text_format_add (tag
->format
, format
);
228 swfdec_text_field_movie_html_parse_attribute (ParserData
*data
, ParserTag
*tag
,
231 const char *end
, *name
, *value
;
232 int name_length
, value_length
;
234 g_return_val_if_fail (data
!= NULL
, NULL
);
235 g_return_val_if_fail (tag
!= NULL
, NULL
);
236 g_return_val_if_fail ((*p
!= '>' && *p
!= '\0'), NULL
);
238 end
= p
+ strcspn (p
, "=> \r\n\t");
240 return NULL
; // Correct?
243 name_length
= end
- p
;
245 p
= end
+ strspn (end
, " \r\n\t");
247 return NULL
; // FIXME: Correct?
249 p
= p
+ strspn (p
, " \r\n\t");
251 if (*p
!= '"' && *p
!= '\'')
252 return NULL
; // FIXME: Correct?
256 end
= strchr (end
, *p
);
257 } while (end
!= NULL
&& *(end
- 1) == '\\');
260 return NULL
; // FIXME: Correct?
263 value_length
= end
- (p
+ 1);
266 swfdec_text_field_movie_html_tag_set_attribute (data
, tag
, name
,
267 name_length
, value
, value_length
);
270 g_return_val_if_fail (end
+ 1 > p
, NULL
);
276 swfdec_text_field_movie_html_parse_tag (ParserData
*data
, const char *p
)
279 const char *name
, *end
;
283 g_return_val_if_fail (data
!= NULL
, NULL
);
284 g_return_val_if_fail (p
!= NULL
, NULL
);
285 g_return_val_if_fail (*p
== '<', NULL
);
289 // closing tag or opening tag?
297 // find the end of the name
298 end
= p
+ strcspn (p
, "> \r\n\t");
303 // don't count trailing / as part of the name if it's followed by >
304 // we still act like it's a normal opening tag even if it has /
305 if (*end
== '>' && *(end
- 1) == '/')
308 if (end
== p
) // empty name
312 name_length
= end
- p
;
316 if (name_length
== 1 && !g_strncasecmp (name
, "p", 1)) {
317 GSList
*iter
, *found
;
320 iter
= data
->tags_open
;
321 while (iter
!= NULL
) {
323 if (tag
->name_length
== 1 && !g_strncasecmp (tag
->name
, "p", 1))
329 iter
= data
->tags_open
;
330 while (iter
!= found
) {
333 if ((tag
->name_length
== 2 && !g_strncasecmp (tag
->name
, "li", 2)) ||
334 (tag
->name_length
== 10 &&
335 !g_strncasecmp (tag
->name
, "textformat", 10)))
337 swfdec_text_field_movie_html_parse_close_tag (data
, tag
, TRUE
);
340 swfdec_text_buffer_append_text (data
->text
, "\n");
341 swfdec_text_field_movie_html_parse_close_tag (data
, found
->data
,
345 if (data
->tags_open
!= NULL
) {
346 tag
= data
->tags_open
->data
;
347 if (name_length
== tag
->name_length
&&
348 !g_strncasecmp (name
, tag
->name
, name_length
))
349 swfdec_text_field_movie_html_parse_close_tag (data
, tag
, FALSE
);
353 end
= strchr (end
, '>');
359 SwfdecAsObject
*object
;
362 if (name_length
== 3 && !g_strncasecmp (name
, "tab", 3))
363 swfdec_text_buffer_append_text (data
->text
, "\t");
365 if (data
->multiline
) {
366 if (name_length
== 2 && !g_strncasecmp (name
, "br", 2))
368 swfdec_text_buffer_append_text (data
->text
, "\n");
370 else if (name_length
== 2 && !g_strncasecmp (name
, "li", 1))
372 gsize length
= swfdec_text_buffer_get_length (data
->text
);
373 const char *s
= swfdec_text_buffer_get_text (data
->text
);
374 if (length
> 0 && s
[length
-1] != '\n' && s
[length
-1] != '\r')
375 swfdec_text_buffer_append_text (data
->text
, "\n");
379 tag
= g_new0 (ParserTag
, 1);
381 tag
->name_length
= name_length
;
382 tag
->format
= SWFDEC_TEXT_FORMAT (swfdec_text_format_new (data
->cx
));
383 tag
->index
= swfdec_text_buffer_get_length (data
->text
);
385 data
->tags_open
= g_slist_prepend (data
->tags_open
, tag
);
387 // set format based on tag
388 if (tag
->format
!= NULL
) {
389 object
= SWFDEC_AS_OBJECT (tag
->format
);
390 SWFDEC_AS_VALUE_SET_BOOLEAN (&val
, TRUE
);
392 if (tag
->name_length
== 2 && !g_strncasecmp (tag
->name
, "li", 2)) {
393 swfdec_as_object_set_variable (object
, SWFDEC_AS_STR_bullet
, &val
);
394 } else if (tag
->name_length
== 1 && !g_strncasecmp (tag
->name
, "b", 1)) {
395 swfdec_as_object_set_variable (object
, SWFDEC_AS_STR_bold
, &val
);
396 } else if (tag
->name_length
== 1 && !g_strncasecmp (tag
->name
, "i", 1)) {
397 swfdec_as_object_set_variable (object
, SWFDEC_AS_STR_italic
, &val
);
398 } else if (tag
->name_length
== 1 && !g_strncasecmp (tag
->name
, "u", 1)) {
399 swfdec_as_object_set_variable (object
, SWFDEC_AS_STR_underline
, &val
);
401 else if (tag
->name_length
== 3 && !g_strncasecmp (tag
->name
, "img", 3))
403 SWFDEC_FIXME ("IMG tag support for TextField's HTML input missing");
407 if (data
->style_sheet
&&
408 ((tag
->name_length
== 2 && !g_strncasecmp (tag
->name
, "li", 2)) ||
409 (tag
->name_length
== 1 && !g_strncasecmp (tag
->name
, "p", 1)))) {
410 SwfdecTextFormat
*format
= swfdec_style_sheet_get_tag_format (
411 data
->style_sheet
, swfdec_as_context_give_string (data
->cx
,
412 g_strndup (tag
->name
, tag
->name_length
)));
414 swfdec_text_format_add (tag
->format
, format
);
418 end
= end
+ strspn (end
, " \r\n\t");
419 while (*end
!= '\0' && *end
!= '>' && (*end
!= '/' || *(end
+ 1) != '>')) {
420 end
= swfdec_text_field_movie_html_parse_attribute (data
, tag
, end
);
423 end
= end
+ strspn (end
, " \r\n\t");
437 swfdec_text_field_movie_html_parse_text (ParserData
*data
, const char *p
)
442 g_return_val_if_fail (data
!= NULL
, NULL
);
443 g_return_val_if_fail (p
!= NULL
, NULL
);
444 g_return_val_if_fail (*p
!= '\0' && *p
!= '<', NULL
);
446 // condense the whitespace with previous text
447 // also skip any whitespace that would be preceding first actual text
448 if (data
->condense_white
&& data
->cx
->version
>= 8) {
449 gsize length
= swfdec_text_buffer_get_length (data
->text
);
450 const char *s
= swfdec_text_buffer_get_text (data
->text
);
451 if (length
== 0 || g_ascii_isspace (s
[length
- 1]))
452 p
+= strspn (p
, " \n\r\t");
455 // if it's only whitespace, don't add it
456 if (data
->cx
->version
< 8) {
457 end
= p
+ strspn (p
, " \n\r\t");
458 if (*end
== '\0' || *end
== '<')
463 // if condense_white: all whitespace blocks are converted to a single space
464 while (*p
!= '\0' && *p
!= '<') {
465 if (data
->condense_white
) {
466 end
= p
+ strcspn (p
, "< \n\r\t");
468 end
= strchr (p
, '<');
470 end
= strchr (p
, '\0');
473 unescaped
= swfdec_xml_unescape_len (data
->cx
, p
, end
- p
, TRUE
);
474 swfdec_text_buffer_append_text (data
->text
, unescaped
);
477 if (data
->condense_white
&& g_ascii_isspace (*end
)) {
478 swfdec_text_buffer_append_text (data
->text
, " ");
479 p
= end
+ strspn (end
, " \n\r\t");
489 swfdec_text_field_movie_html_parse (SwfdecTextFieldMovie
*text
, const char *str
)
494 g_return_if_fail (SWFDEC_IS_TEXT_FIELD_MOVIE (text
));
495 g_return_if_fail (str
!= NULL
);
497 data
.cx
= swfdec_gc_object_get_context (text
);
498 data
.multiline
= (data
.cx
->version
< 7 || text
->multiline
);
499 data
.condense_white
= text
->condense_white
;
500 if (text
->style_sheet
!= NULL
&& SWFDEC_IS_STYLESHEET (text
->style_sheet
)) {
501 data
.style_sheet
= SWFDEC_STYLESHEET (text
->style_sheet
);
503 data
.style_sheet
= NULL
;
505 data
.text
= text
->text
;
506 data
.tags_open
= NULL
;
507 data
.tags_closed
= NULL
;
510 while (p
!= NULL
&& *p
!= '\0') {
512 if (strncmp (p
+ 1, "!--", strlen ("!--")) == 0) {
513 p
= swfdec_text_field_movie_html_parse_comment (&data
, p
);
515 p
= swfdec_text_field_movie_html_parse_tag (&data
, p
);
518 p
= swfdec_text_field_movie_html_parse_text (&data
, p
);
522 // close remaining tags
523 while (data
.tags_open
!= NULL
) {
524 /* yes, this really appends to the default format */
525 swfdec_text_buffer_set_default_attributes (text
->text
,
526 &((ParserTag
*)data
.tags_open
->data
)->format
->attr
,
527 ((ParserTag
*)data
.tags_open
->data
)->format
->values_set
);
528 swfdec_text_field_movie_html_parse_close_tag (&data
,
529 (ParserTag
*)data
.tags_open
->data
, TRUE
);
533 while (data
.tags_closed
!= NULL
) {
534 ParserTag
*tag
= (ParserTag
*)data
.tags_closed
->data
;
536 if (tag
->index
!= tag
->end_index
&& tag
->format
!= NULL
) {
537 swfdec_text_buffer_set_attributes (text
->text
, tag
->index
,
538 tag
->end_index
- tag
->index
, &tag
->format
->attr
, tag
->format
->values_set
);
542 data
.tags_closed
= g_slist_remove (data
.tags_closed
, tag
);
550 swfdec_text_field_movie_html_text_align_to_string (SwfdecTextAlign align
)
553 case SWFDEC_TEXT_ALIGN_LEFT
:
555 case SWFDEC_TEXT_ALIGN_RIGHT
:
557 case SWFDEC_TEXT_ALIGN_CENTER
:
559 case SWFDEC_TEXT_ALIGN_JUSTIFY
:
562 g_assert_not_reached ();
569 * TEXTFORMAT / P or LI / FONT / A / B / I / U
571 * Order of attributes:
573 * LEFTMARGIN / RIGHTMARGIN / INDENT / LEADING / BLOCKINDENT / TABSTOPS
576 * FONT: FACE / SIZE / COLOR / LETTERSPACING / KERNING
583 swfdec_text_field_movie_html_text_append_paragraph (SwfdecTextFieldMovie
*text
,
584 GString
*string
, guint start_index
, guint end_index
)
586 const SwfdecTextAttributes
*attr
, *attr_prev
, *attr_font
;
587 SwfdecTextBufferIter
*iter
;
588 GSList
*fonts
, *iter_font
;
589 guint index_
, index_prev
;
590 gboolean textformat
, bullet
, font
= FALSE
;
593 g_return_val_if_fail (SWFDEC_IS_TEXT_FIELD_MOVIE (text
), string
);
594 g_return_val_if_fail (string
!= NULL
, string
);
595 g_return_val_if_fail (start_index
<= end_index
, string
);
597 iter
= swfdec_text_buffer_get_iter (text
->text
, start_index
);
598 index_
= start_index
;
599 attr
= swfdec_text_buffer_iter_get_attributes (text
->text
, iter
);
601 if (attr
->left_margin
!= 0 || attr
->right_margin
!= 0 ||
602 attr
->indent
!= 0 || attr
->leading
!= 0 ||
603 attr
->block_indent
!= 0 ||
604 attr
->n_tab_stops
> 0)
606 string
= g_string_append (string
, "<TEXTFORMAT");
607 if (attr
->left_margin
) {
608 g_string_append_printf (string
, " LEFTMARGIN=\"%i\"",
611 if (attr
->right_margin
) {
612 g_string_append_printf (string
, " RIGHTMARGIN=\"%i\"",
616 g_string_append_printf (string
, " INDENT=\"%i\"", attr
->indent
);
618 g_string_append_printf (string
, " LEADING=\"%i\"", attr
->leading
);
619 if (attr
->block_indent
) {
620 g_string_append_printf (string
, " BLOCKINDENT=\"%i\"",
623 if (attr
->n_tab_stops
> 0) {
625 g_string_append (string
, " TABSTOPS=\"\"");
626 for (i
= 0; i
< attr
->n_tab_stops
; i
++) {
627 g_string_append_printf (string
, "%d,", attr
->tab_stops
[i
]);
629 string
->str
[string
->len
- 1] = '\"';
631 string
= g_string_append (string
, ">");
641 string
= g_string_append (string
, "<LI>");
644 g_string_append_printf (string
, "<P ALIGN=\"%s\">",
645 swfdec_text_field_movie_html_text_align_to_string (attr
->align
));
649 // note we don't escape attr->font, even thought it can have evil chars
650 g_string_append_printf (string
, "<FONT FACE=\"%s\" SIZE=\"%i\" COLOR=\"#%06X\" LETTERSPACING=\"%i\" KERNING=\"%i\">",
651 attr
->font
, attr
->size
, attr
->color
, (int)attr
->letter_spacing
,
652 (attr
->kerning
? 1 : 0));
653 fonts
= g_slist_prepend (NULL
, (gpointer
) attr
);
655 if (attr
->url
!= SWFDEC_AS_STR_EMPTY
)
656 g_string_append_printf (string
, "<A HREF=\"%s\" TARGET=\"%s\">",
657 attr
->url
, attr
->target
);
659 string
= g_string_append (string
, "<B>");
661 string
= g_string_append (string
, "<I>");
663 string
= g_string_append (string
, "<U>");
665 // special case: use <= instead of < to add some extra markup
666 for (iter
= swfdec_text_buffer_iter_next (text
->text
, iter
);
667 iter
!= NULL
&& swfdec_text_buffer_iter_get_start (text
->text
, iter
) <= end_index
;
668 iter
= swfdec_text_buffer_iter_next (text
->text
, iter
))
672 index_
= swfdec_text_buffer_iter_get_start (text
->text
, iter
);
673 attr
= swfdec_text_buffer_iter_get_attributes (text
->text
, iter
);
675 escaped
= swfdec_xml_escape_len (swfdec_text_buffer_get_text (text
->text
) + index_prev
,
676 index_
- index_prev
);
677 string
= g_string_append (string
, escaped
);
681 // Figure out what tags need to be rewritten
682 if (attr
->font
!= attr_prev
->font
||
683 attr
->size
!= attr_prev
->size
||
684 attr
->color
!= attr_prev
->color
||
685 (int)attr
->letter_spacing
!= (int)attr_prev
->letter_spacing
||
686 attr
->kerning
!= attr_prev
->kerning
) {
688 } else if (attr
->url
== attr_prev
->url
&&
689 attr
->target
== attr_prev
->target
&&
690 attr
->bold
== attr_prev
->bold
&&
691 attr
->italic
== attr_prev
->italic
&&
692 attr
->underline
== attr_prev
->underline
) {
697 for (iter_font
= fonts
; iter_font
!= NULL
; iter_font
= iter_font
->next
)
699 attr_font
= iter_font
->data
;
700 if (attr
->font
== attr_font
->font
&&
701 attr
->size
== attr_font
->size
&&
702 attr
->color
== attr_font
->color
&&
703 (int)attr
->letter_spacing
== (int)attr_font
->letter_spacing
&&
704 attr
->kerning
== attr_font
->kerning
) {
708 if (attr_prev
->underline
)
709 string
= g_string_append (string
, "</U>");
710 if (attr_prev
->italic
)
711 string
= g_string_append (string
, "</I>");
713 string
= g_string_append (string
, "</B>");
714 if (attr_prev
->url
!= SWFDEC_AS_STR_EMPTY
)
715 string
= g_string_append (string
, "</A>");
716 if (iter_font
!= NULL
) {
717 while (fonts
!= iter_font
) {
718 string
= g_string_append (string
, "</FONT>");
719 fonts
= g_slist_remove (fonts
, fonts
->data
);
724 attr_font
= fonts
->data
;
725 if (font
&& (attr
->font
!= attr_font
->font
||
726 attr
->size
!= attr_font
->size
||
727 attr
->color
!= attr_font
->color
||
728 (int)attr
->letter_spacing
!= (int)attr_font
->letter_spacing
||
729 attr
->kerning
!= attr_font
->kerning
))
731 fonts
= g_slist_prepend (fonts
, (gpointer
) attr
);
733 string
= g_string_append (string
, "<FONT");
734 // note we don't escape attr->font, even thought it can have evil chars
735 if (attr
->font
!= attr_font
->font
)
736 g_string_append_printf (string
, " FACE=\"%s\"", attr
->font
);
737 if (attr
->size
!= attr_font
->size
)
738 g_string_append_printf (string
, " SIZE=\"%i\"", attr
->size
);
739 if (attr
->color
!= attr_font
->color
)
740 g_string_append_printf (string
, " COLOR=\"#%06X\"", attr
->color
);
741 if ((int)attr
->letter_spacing
!= (int)attr_font
->letter_spacing
) {
742 g_string_append_printf (string
, " LETTERSPACING=\"%i\"",
743 (int)attr
->letter_spacing
);
745 if (attr
->kerning
!= attr_font
->kerning
) {
746 g_string_append_printf (string
, " KERNING=\"%i\"",
747 (attr
->kerning
? 1 : 0));
749 string
= g_string_append (string
, ">");
751 if (attr
->url
!= SWFDEC_AS_STR_EMPTY
) {
752 g_string_append_printf (string
, "<A HREF=\"%s\" TARGET=\"%s\">",
753 attr
->url
, attr
->target
);
756 string
= g_string_append (string
, "<B>");
758 string
= g_string_append (string
, "<I>");
760 string
= g_string_append (string
, "<U>");
763 escaped
= swfdec_xml_escape_len (swfdec_text_buffer_get_text (text
->text
) + index_
,
765 string
= g_string_append (string
, escaped
);
769 string
= g_string_append (string
, "</U>");
771 string
= g_string_append (string
, "</I>");
773 string
= g_string_append (string
, "</B>");
774 if (attr
->url
!= SWFDEC_AS_STR_EMPTY
)
775 string
= g_string_append (string
, "</A>");
776 for (iter_font
= fonts
; iter_font
!= NULL
; iter_font
= iter_font
->next
)
777 string
= g_string_append (string
, "</FONT>");
778 g_slist_free (fonts
);
780 string
= g_string_append (string
, "</LI>");
782 string
= g_string_append (string
, "</P>");
785 string
= g_string_append (string
, "</TEXTFORMAT>");
791 swfdec_text_field_movie_get_html_text (SwfdecTextFieldMovie
*text
)
793 const char *p
, *end
, *start
;
796 g_return_val_if_fail (SWFDEC_IS_TEXT_FIELD_MOVIE (text
),
797 SWFDEC_AS_STR_EMPTY
);
799 string
= g_string_new ("");
800 p
= start
= swfdec_text_buffer_get_text (text
->text
);
803 end
= strpbrk (p
, "\r\n");
805 end
= strchr (p
, '\0');
807 string
= swfdec_text_field_movie_html_text_append_paragraph (text
, string
,
808 p
- start
, end
- start
);
814 return swfdec_as_context_give_string (swfdec_gc_object_get_context (text
),
815 g_string_free (string
, FALSE
));