1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* This file is part of the GtkHTML library.
3 *
4 * Copyright (C) 1997 Martin Jones (mjones@kde.org)
5 * Copyright (C) 1997 Torben Weis (weis@kde.org)
6 * Copyright (C) 1999, 2000 Helix Code, Inc.
7 * Copyright (C) 2000, 2001, 2002, 2003 Ximian, Inc.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24
25 #include <config.h>
26 #include <string.h> /* strcmp */
27 #include <stdlib.h>
28 #include "gtkhtml-compat.h"
29
30 #include "htmlcolor.h"
31 #include "htmlcolorset.h"
32 #include "htmlentity.h"
33 #include "htmltext.h"
34 #include "htmltextslave.h"
35 #include "htmlpainter.h"
36
37
38 /* Convenience macro to extract the HTMLPainterClass from a GTK+ object. */
39 #define HP_CLASS(obj) \
40 HTML_PAINTER_CLASS (G_OBJECT_GET_CLASS (obj))
41
42 /* Our parent class. */
43 static GObjectClass *parent_class = NULL;
44
45
46 /* GObject methods. */
47
48 static void
finalize(GObject * object)49 finalize (GObject *object)
50 {
51 HTMLPainter *painter;
52
53 painter = HTML_PAINTER (object);
54 html_font_manager_finalize (&painter->font_manager);
55
56 g_free (painter->font_face);
57
58 if (painter->pango_context)
59 g_object_unref (painter->pango_context);
60
61 /* FIXME ownership of the color set? */
62
63 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
64
65 if (painter->widget) {
66 g_object_unref (painter->widget);
67 painter->widget = NULL;
68 }
69 }
70
71
72 #define DEFINE_UNIMPLEMENTED(method) \
73 static gint \
74 method##_unimplemented (GObject *obj) \
75 { \
76 g_warning ("Class `%s' does not implement `" #method "'\n", \
77 g_type_name (G_TYPE_FROM_INSTANCE (obj))); \
78 return 0; \
79 }
80
81 DEFINE_UNIMPLEMENTED (begin)
DEFINE_UNIMPLEMENTED(end)82 DEFINE_UNIMPLEMENTED (end)
83
84 DEFINE_UNIMPLEMENTED (alloc_color)
85 DEFINE_UNIMPLEMENTED (free_color)
86
87 DEFINE_UNIMPLEMENTED (set_pen)
88 DEFINE_UNIMPLEMENTED (get_black)
89 DEFINE_UNIMPLEMENTED (draw_line)
90 DEFINE_UNIMPLEMENTED (draw_rect)
91 DEFINE_UNIMPLEMENTED (draw_glyphs)
92 DEFINE_UNIMPLEMENTED (draw_spell_error)
93 DEFINE_UNIMPLEMENTED (fill_rect)
94 DEFINE_UNIMPLEMENTED (draw_pixmap)
95 DEFINE_UNIMPLEMENTED (draw_ellipse)
96 DEFINE_UNIMPLEMENTED (clear)
97 DEFINE_UNIMPLEMENTED (set_background_color)
98 DEFINE_UNIMPLEMENTED (draw_shade_line)
99 DEFINE_UNIMPLEMENTED (draw_border)
100
101 DEFINE_UNIMPLEMENTED (set_clip_rectangle)
102 DEFINE_UNIMPLEMENTED (draw_background)
103 DEFINE_UNIMPLEMENTED (draw_embedded)
104
105 DEFINE_UNIMPLEMENTED (get_pixel_size)
106 DEFINE_UNIMPLEMENTED (get_page_width)
107 DEFINE_UNIMPLEMENTED (get_page_height)
108
109 static void
110 html_painter_init (GObject *object,
111 HTMLPainterClass *real_klass)
112 {
113 HTMLPainter *painter;
114
115 painter = HTML_PAINTER (object);
116 html_font_manager_init (&painter->font_manager, painter);
117 painter->font_style = GTK_HTML_FONT_STYLE_DEFAULT;
118 painter->font_face = NULL;
119 painter->widget = NULL;
120 painter->clip_width = painter->clip_height = 0;
121 }
122
123 static void
html_painter_real_set_widget(HTMLPainter * painter,GtkWidget * widget)124 html_painter_real_set_widget (HTMLPainter *painter,
125 GtkWidget *widget)
126 {
127 if (painter->widget)
128 g_object_unref (painter->widget);
129 painter->widget = widget;
130 g_object_ref (widget);
131 }
132
133 static gint
text_width(HTMLPainter * painter,PangoFontDescription * desc,const gchar * text,gint bytes)134 text_width (HTMLPainter *painter,
135 PangoFontDescription *desc,
136 const gchar *text,
137 gint bytes)
138 {
139 HTMLTextPangoInfo *pi;
140 GList *glyphs;
141 gint width = 0;
142
143 pi = html_painter_text_itemize_and_prepare_glyphs (painter, desc, text, bytes, &glyphs, NULL);
144
145 if (pi && glyphs) {
146 GList *list;
147 gint i;
148 for (list = glyphs; list; list = list->next->next) {
149 PangoGlyphString *str = (PangoGlyphString *) list->data;
150 for (i = 0; i < str->num_glyphs; i++)
151 width += str->glyphs[i].geometry.width;
152 }
153 }
154 if (glyphs)
155 html_painter_glyphs_destroy (glyphs);
156 if (pi)
157 html_text_pango_info_destroy (pi);
158 /* printf ("text_width %d\n", PANGO_PIXELS (width)); */
159 return html_painter_pango_to_engine (painter, width);
160 }
161
162 static void
text_size(HTMLPainter * painter,PangoFontDescription * desc,const gchar * text,gint bytes,HTMLTextPangoInfo * pi,GList * glyphs,gint * width_out,gint * ascent_out,gint * descent_out)163 text_size (HTMLPainter *painter,
164 PangoFontDescription *desc,
165 const gchar *text,
166 gint bytes,
167 HTMLTextPangoInfo *pi,
168 GList *glyphs,
169 gint *width_out,
170 gint *ascent_out,
171 gint *descent_out)
172 {
173 gboolean temp_pi = FALSE;
174 gint ascent = 0;
175 gint descent = 0;
176 gint width = 0;
177
178 if (!pi) {
179 pi = html_painter_text_itemize_and_prepare_glyphs (painter, desc, text, bytes, &glyphs, NULL);
180 temp_pi = TRUE;
181 }
182
183 if (pi && pi->n && glyphs) {
184 GList *gl;
185 PangoRectangle log_rect;
186 PangoItem *item;
187 PangoGlyphString *str;
188 const gchar *c_text = text;
189 gint c_bytes, ii;
190
191 c_bytes = 0;
192 for (gl = glyphs; gl && c_bytes < bytes; gl = gl->next) {
193 str = (PangoGlyphString *) gl->data;
194 gl = gl->next;
195 ii = GPOINTER_TO_INT (gl->data);
196 item = pi->entries[ii].glyph_item.item;
197 pango_glyph_string_extents (str, item->analysis.font, NULL, &log_rect);
198 width += log_rect.width;
199
200 if (ascent_out || descent_out) {
201 PangoFontMetrics *pfm;
202
203 pfm = pango_font_get_metrics (item->analysis.font, item->analysis.language);
204 ascent = MAX (ascent, pango_font_metrics_get_ascent (pfm));
205 descent = MAX (descent, pango_font_metrics_get_descent (pfm));
206 pango_font_metrics_unref (pfm);
207 }
208
209 c_text = g_utf8_offset_to_pointer (c_text, str->num_glyphs);
210 if (*text == '\t')
211 c_text++;
212 c_bytes = c_text - text;
213 }
214 }
215
216 if (width_out)
217 *width_out = html_painter_pango_to_engine (painter, width);
218 if (ascent_out)
219 *ascent_out = html_painter_pango_to_engine (painter, ascent);
220 if (descent_out)
221 *descent_out = html_painter_pango_to_engine (painter, descent);
222
223 if (temp_pi) {
224 if (glyphs)
225 html_painter_glyphs_destroy (glyphs);
226 if (pi)
227 html_text_pango_info_destroy (pi);
228 }
229 }
230
231 static void
html_painter_class_init(GObjectClass * object_class)232 html_painter_class_init (GObjectClass *object_class)
233 {
234 HTMLPainterClass *class;
235
236 class = HTML_PAINTER_CLASS (object_class);
237
238 object_class->finalize = finalize;
239 parent_class = g_type_class_ref (G_TYPE_OBJECT);
240
241 class->set_widget = html_painter_real_set_widget;
242 class->begin = (gpointer) begin_unimplemented;
243 class->end = (gpointer) end_unimplemented;
244
245 class->alloc_color = (gpointer) alloc_color_unimplemented;
246 class->free_color = (gpointer) free_color_unimplemented;
247
248 class->set_pen = (gpointer) set_pen_unimplemented;
249 class->get_black = (gpointer) get_black_unimplemented;
250 class->draw_line = (gpointer) draw_line_unimplemented;
251 class->draw_rect = (gpointer) draw_rect_unimplemented;
252 class->draw_glyphs = (gpointer) draw_glyphs_unimplemented;
253 class->draw_spell_error = (gpointer) draw_spell_error_unimplemented;
254 class->fill_rect = (gpointer) fill_rect_unimplemented;
255 class->draw_pixmap = (gpointer) draw_pixmap_unimplemented;
256 class->draw_ellipse = (gpointer) draw_ellipse_unimplemented;
257 class->clear = (gpointer) clear_unimplemented;
258 class->set_background_color = (gpointer) set_background_color_unimplemented;
259 class->draw_shade_line = (gpointer) draw_shade_line_unimplemented;
260 class->draw_border = (gpointer) draw_border_unimplemented;
261
262 class->set_clip_rectangle = (gpointer) set_clip_rectangle_unimplemented;
263 class->draw_background = (gpointer) draw_background_unimplemented;
264 class->draw_embedded = (gpointer) draw_embedded_unimplemented;
265
266 class->get_pixel_size = (gpointer) get_pixel_size_unimplemented;
267
268 class->get_page_width = (gpointer) get_page_width_unimplemented;
269 class->get_page_height = (gpointer) get_page_height_unimplemented;
270 }
271
272 GType
html_painter_get_type(void)273 html_painter_get_type (void)
274 {
275 static GType html_painter_type = 0;
276
277 if (html_painter_type == 0) {
278 static const GTypeInfo html_painter_info = {
279 sizeof (HTMLPainterClass),
280 NULL,
281 NULL,
282 (GClassInitFunc) html_painter_class_init,
283 NULL,
284 NULL,
285 sizeof (HTMLPainter),
286 1,
287 (GInstanceInitFunc) html_painter_init,
288 };
289 html_painter_type = g_type_register_static (G_TYPE_OBJECT, "HTMLPainter", &html_painter_info, 0);
290 }
291
292 return html_painter_type;
293 }
294
295 /* Functions to begin/end a painting process. */
296
297 void
html_painter_begin(HTMLPainter * painter,gint x1,gint y1,gint x2,gint y2)298 html_painter_begin (HTMLPainter *painter,
299 gint x1,
300 gint y1,
301 gint x2,
302 gint y2)
303 {
304 g_return_if_fail (painter != NULL);
305 g_return_if_fail (HTML_IS_PAINTER (painter));
306
307 painter->clip_height = painter->clip_width = 0;
308
309 (* HP_CLASS (painter)->begin) (painter, x1, y1, x2, y2);
310 }
311
312 void
html_painter_end(HTMLPainter * painter)313 html_painter_end (HTMLPainter *painter)
314 {
315 g_return_if_fail (painter != NULL);
316 g_return_if_fail (HTML_IS_PAINTER (painter));
317
318 (* HP_CLASS (painter)->end) (painter);
319 }
320
321
322 /* Color control. */
323 void
html_painter_alloc_color(HTMLPainter * painter,GdkColor * color)324 html_painter_alloc_color (HTMLPainter *painter,
325 GdkColor *color)
326 {
327 g_return_if_fail (painter != NULL);
328 g_return_if_fail (HTML_IS_PAINTER (painter));
329 g_return_if_fail (color != NULL);
330
331 (* HP_CLASS (painter)->alloc_color) (painter, color);
332 }
333
334 void
html_painter_free_color(HTMLPainter * painter,GdkColor * color)335 html_painter_free_color (HTMLPainter *painter,
336 GdkColor *color)
337 {
338 g_return_if_fail (painter != NULL);
339 g_return_if_fail (HTML_IS_PAINTER (painter));
340 g_return_if_fail (color != NULL);
341
342 (* HP_CLASS (painter)->free_color) (painter, color);
343 }
344
345
346 /* Font handling. */
347
348 void
html_painter_set_font_style(HTMLPainter * painter,GtkHTMLFontStyle font_style)349 html_painter_set_font_style (HTMLPainter *painter,
350 GtkHTMLFontStyle font_style)
351 {
352 g_return_if_fail (painter != NULL);
353 g_return_if_fail (HTML_IS_PAINTER (painter));
354 g_return_if_fail (font_style != GTK_HTML_FONT_STYLE_DEFAULT);
355
356 painter->font_style = font_style;
357 }
358
359 GtkHTMLFontStyle
html_painter_get_font_style(HTMLPainter * painter)360 html_painter_get_font_style (HTMLPainter *painter)
361 {
362 g_return_val_if_fail (painter != NULL, GTK_HTML_FONT_STYLE_DEFAULT);
363 g_return_val_if_fail (HTML_IS_PAINTER (painter), GTK_HTML_FONT_STYLE_DEFAULT);
364
365 return painter->font_style;
366 }
367
368 void
html_painter_set_font_face(HTMLPainter * painter,HTMLFontFace * face)369 html_painter_set_font_face (HTMLPainter *painter,
370 HTMLFontFace *face)
371 {
372 g_return_if_fail (painter != NULL);
373 g_return_if_fail (HTML_IS_PAINTER (painter));
374
375 if (!painter->font_face || !face || strcmp (painter->font_face, face)) {
376 g_free (painter->font_face);
377 painter->font_face = g_strdup (face);
378 }
379 }
380
381 gpointer
html_painter_get_font(HTMLPainter * painter,HTMLFontFace * face,GtkHTMLFontStyle style)382 html_painter_get_font (HTMLPainter *painter,
383 HTMLFontFace *face,
384 GtkHTMLFontStyle style)
385 {
386 HTMLFont *font;
387
388 font = html_font_manager_get_font (&painter->font_manager, face, style);
389 return font ? font->data : NULL;
390 }
391
392 static void
get_font_info(HTMLPainter * painter,HTMLTextPangoInfo * pi,HTMLFontFace ** font_face,GtkHTMLFontStyle * font_style)393 get_font_info (HTMLPainter *painter,
394 HTMLTextPangoInfo *pi,
395 HTMLFontFace **font_face,
396 GtkHTMLFontStyle *font_style)
397 {
398 if (pi && pi->have_font) {
399 *font_face = pi->face;
400 *font_style = pi->font_style;
401 } else {
402 *font_face = painter->font_face;
403 *font_style = painter->font_style;
404 }
405 }
406
407 static gint
get_space_width(HTMLPainter * painter,HTMLTextPangoInfo * pi)408 get_space_width (HTMLPainter *painter,
409 HTMLTextPangoInfo *pi)
410 {
411 HTMLFontFace *font_face;
412 GtkHTMLFontStyle font_style;
413
414 get_font_info (painter, pi, &font_face, &font_style);
415
416 return html_painter_get_space_width (painter, font_style, font_face);
417 }
418
419 /**
420 * html_painter_calc_entries_size:
421 * @painter: a #HTMLPainter
422 * @text: text to compute size of
423 * @len: length of text, in characters
424 * @pi: #HTMLTextPangoInfo structure holding information about
425 * the text. (It may be for a larger range of text that includes
426 * the range specified by @text and @len.)
427 * @glyphs: list holding information about segments of text to draw.
428 * There is one segment for each run of non-tab characters. The
429 * list is structure as a series of pairs of PangoGlyphString,
430 * GINT_TO_POINTER(item_index), where item_index is an index
431 * within pi->entries[].
432 * @line_offset: location to store column offset in output, used
433 * for tab display. On entry holds the the column offset for the
434 * first character in @text. On exit, updated to hold the character
435 * offset for the first character after the end of the text.
436 * If %NULL is passed, then tabs are disabled and substituted with spaces.
437 * @width: location to store width of text (in engine coordinates)
438 * @asc: location to store ascent of text (in engine coordinates)
439 * @dsc: location to store descent of text (in engine coordinates)
440 *
441 * Computes size information for a piece of text, using provided Pango
442 * layout information.
443 **/
444 void
html_painter_calc_entries_size(HTMLPainter * painter,const gchar * text,guint len,HTMLTextPangoInfo * pi,GList * glyphs,gint * line_offset,gint * width,gint * asc,gint * dsc)445 html_painter_calc_entries_size (HTMLPainter *painter,
446 const gchar *text,
447 guint len,
448 HTMLTextPangoInfo *pi,
449 GList *glyphs,
450 gint *line_offset,
451 gint *width,
452 gint *asc,
453 gint *dsc)
454 {
455 HTMLFontFace *font_face = NULL;
456 GtkHTMLFontStyle font_style = GTK_HTML_FONT_STYLE_DEFAULT;
457 HTMLFont *font;
458
459 g_return_if_fail (painter != NULL);
460 g_return_if_fail (HTML_IS_PAINTER (painter));
461 g_return_if_fail (text != NULL);
462
463 if (line_offset || !pi) {
464 get_font_info (painter, pi, &font_face, &font_style);
465 font = html_font_manager_get_font (&painter->font_manager, font_face, font_style);
466 } else
467 font = NULL;
468
469 text_size (painter, (PangoFontDescription *) font->data, text, g_utf8_offset_to_pointer (text, len) - text,
470 pi, glyphs, width, asc, dsc);
471 /* g_print ("calc_text_size %s %d %d %d\n", text, *width, asc ? *asc : -1, dsc ? *dsc : -1); */
472
473 if (line_offset) {
474 gint space_width = html_painter_get_space_width (painter, font_style, font_face);
475 gint tabs;
476
477 *width += (html_text_text_line_length (text, line_offset, len, &tabs) - len + tabs)*space_width;
478 }
479 }
480
481 /**
482 * html_painter_calc_text_size:
483 * @painter: a #HTMLPainter
484 * @text: text to compute size of
485 * @len: length of text, in characters
486 * @width: location to store width of text (in engine coordinates)
487 * @asc: location to store ascent of text (in engine coordinates)
488 * @dsc: location to store descent of text (in engine coordinates)
489 *
490 * Computes size information for a piece of text.
491 **/
492 void
html_painter_calc_text_size(HTMLPainter * painter,const gchar * text,guint len,gint * width,gint * asc,gint * dsc)493 html_painter_calc_text_size (HTMLPainter *painter,
494 const gchar *text,
495 guint len,
496 gint *width,
497 gint *asc,
498 gint *dsc)
499 {
500 gint line_offset = 0;
501
502 g_return_if_fail (painter != NULL);
503 g_return_if_fail (HTML_IS_PAINTER (painter));
504 g_return_if_fail (text != NULL);
505
506 html_painter_calc_entries_size (painter, text, len, NULL, NULL, &line_offset,
507 width, asc, dsc);
508 }
509
510 /* The actual paint operations. */
511
512 void
html_painter_set_pen(HTMLPainter * painter,const GdkColor * color)513 html_painter_set_pen (HTMLPainter *painter,
514 const GdkColor *color)
515 {
516 g_return_if_fail (painter != NULL);
517 g_return_if_fail (HTML_IS_PAINTER (painter));
518 g_return_if_fail (color != NULL);
519
520 (* HP_CLASS (painter)->set_pen) (painter, color);
521 }
522
523 void
html_painter_draw_line(HTMLPainter * painter,gint x1,gint y1,gint x2,gint y2)524 html_painter_draw_line (HTMLPainter *painter,
525 gint x1,
526 gint y1,
527 gint x2,
528 gint y2)
529 {
530 g_return_if_fail (painter != NULL);
531 g_return_if_fail (HTML_IS_PAINTER (painter));
532
533 (* HP_CLASS (painter)->draw_line) (painter, x1, y1, x2, y2);
534 }
535
536 void
html_painter_draw_rect(HTMLPainter * painter,gint x,gint y,gint width,gint height)537 html_painter_draw_rect (HTMLPainter *painter,
538 gint x,
539 gint y,
540 gint width,
541 gint height)
542 {
543 g_return_if_fail (painter != NULL);
544 g_return_if_fail (HTML_IS_PAINTER (painter));
545
546 (* HP_CLASS (painter)->draw_rect) (painter, x, y, width, height);
547 }
548
549 void
html_replace_tabs(const gchar * text,gchar * translated,guint bytes)550 html_replace_tabs (const gchar *text,
551 gchar *translated,
552 guint bytes)
553 {
554 const gchar *t, *tab;
555 gchar *tt;
556
557 t = text;
558 tt = translated;
559
560 do {
561 tab = memchr (t, (guchar) '\t', bytes - (t - text));
562 if (tab) {
563 strncpy (tt, t, tab - t);
564 tt += tab - t;
565 *tt = ' ';
566 tt++;
567 t = tab + 1;
568 } else
569 strncpy (tt, t, bytes - (t - text));
570 } while (tab);
571 }
572
573 /**
574 * html_painter_draw_entries:
575 * @painter: a #HTMLPainter
576 * @x: x coordinate at which to draw text, in engine coordinates
577 * @y: x coordinate at which to draw text, in engine coordinates
578 * @text: text to draw
579 * @len: length of text, in characters
580 * @pi: #HTMLTextPangoInfo structure holding information about
581 * the text. (It may be for a larger range of text that includes
582 * the range specified by @text and @len.)
583 * @glyphs: list holding information about segments of text to draw.
584 * There is one segment for each run of non-tab characters. The
585 * list is structure as a series of pairs of PangoGlyphString,
586 * GINT_TO_POINTER(item_index), where item_index is an index
587 * within pi->entries[].
588 * @line_offset: column offset of the first character in @text, used for
589 * tab display. If set to -1, then tabs are disabled and substituted
590 * with spaces.
591 *
592 * Draws a piece of text, using provided Pango layout information.
593 **/
594 void
html_painter_draw_entries(HTMLPainter * painter,gint x,gint y,const gchar * text,gint len,HTMLTextPangoInfo * pi,GList * glyphs,gint line_offset)595 html_painter_draw_entries (HTMLPainter *painter,
596 gint x,
597 gint y,
598 const gchar *text,
599 gint len,
600 HTMLTextPangoInfo *pi,
601 GList *glyphs,
602 gint line_offset)
603 {
604 const gchar *tab, *c_text;
605 gint bytes;
606 GList *gl;
607 gint first_item_offset = -1;
608 gint space_width = -1;
609
610 g_return_if_fail (painter != NULL);
611 g_return_if_fail (HTML_IS_PAINTER (painter));
612
613 c_text = text;
614 bytes = g_utf8_offset_to_pointer (text, len) - text;
615 gl = glyphs;
616 tab = memchr (c_text, (guchar) '\t', bytes);
617
618 /* We iterate through the string by tabs and non-tab segments, skipping over
619 * the tabs and drawing the non-tab segments.
620 *
621 * We have one PangoGlyphString for each non-tab segment within each item.
622 */
623 while (gl) {
624 gint ii = GPOINTER_TO_INT (gl->next->data);
625 PangoItem *item = pi->entries[ii].glyph_item.item;
626 const gchar *item_end;
627 const gchar *next;
628
629 if (first_item_offset < 0)
630 first_item_offset = item->offset;
631
632 item_end = text + item->offset - first_item_offset + item->length;
633
634 if (*c_text == '\t')
635 next = c_text + 1;
636 else if (tab && tab < item_end)
637 next = tab;
638 else
639 next = item_end;
640
641 if (*c_text == '\t') {
642 if (space_width < 0)
643 space_width = get_space_width (painter, pi);
644
645 if (line_offset == -1)
646 x += space_width;
647 else {
648 x += space_width * (8 - (line_offset % 8));
649 line_offset += 8 - (line_offset % 8);
650 }
651
652 tab = memchr (c_text + 1, (guchar) '\t', bytes - 1);
653 } else {
654 x += html_painter_pango_to_engine (painter, (* HP_CLASS (painter)->draw_glyphs) (painter, x, y, item, gl->data, NULL, NULL));
655
656 if (line_offset != -1)
657 line_offset += g_utf8_pointer_to_offset (c_text, next);
658
659 gl = gl->next->next;
660 }
661
662 bytes -= next - c_text;
663 c_text = next;
664 }
665 }
666
667 gint
html_painter_draw_glyphs(HTMLPainter * painter,gint x,gint y,PangoItem * item,PangoGlyphString * glyphs,GdkColor * fg,GdkColor * bg)668 html_painter_draw_glyphs (HTMLPainter *painter,
669 gint x,
670 gint y,
671 PangoItem *item,
672 PangoGlyphString *glyphs,
673 GdkColor *fg,
674 GdkColor *bg)
675 {
676 return (* HP_CLASS (painter)->draw_glyphs) (painter, x, y, item, glyphs, fg, bg);
677 }
678
679 /**
680 * html_painter_draw_text:
681 * @painter: a #HTMLPainter
682 * @x: x coordinate at which to draw text, in engine coordinates
683 * @y: x coordinate at which to draw text, in engine coordinates
684 * @text: text to draw
685 * @len: length of text, in characters
686 *
687 * Draws a piece of text.
688 **/
689 void
html_painter_draw_text(HTMLPainter * painter,gint x,gint y,const gchar * text,gint len)690 html_painter_draw_text (HTMLPainter *painter,
691 gint x,
692 gint y,
693 const gchar *text,
694 gint len)
695 {
696 HTMLTextPangoInfo *pi;
697 GList *glyphs;
698 gint blen;
699
700 g_return_if_fail (painter != NULL);
701 g_return_if_fail (HTML_IS_PAINTER (painter));
702
703 if (len < 0)
704 len = g_utf8_strlen (text, -1);
705
706 blen = g_utf8_offset_to_pointer (text, len) - text;
707
708 pi = html_painter_text_itemize_and_prepare_glyphs (painter, html_painter_get_font (painter, painter->font_face, painter->font_style),
709 text, blen, &glyphs, NULL);
710
711 html_painter_draw_entries (painter, x, y, text, len, pi, glyphs, 0);
712
713 if (glyphs)
714 html_painter_glyphs_destroy (glyphs);
715 if (pi)
716 html_text_pango_info_destroy (pi);
717 }
718
719 void
html_painter_fill_rect(HTMLPainter * painter,gint x,gint y,gint width,gint height)720 html_painter_fill_rect (HTMLPainter *painter,
721 gint x,
722 gint y,
723 gint width,
724 gint height)
725 {
726 g_return_if_fail (painter != NULL);
727 g_return_if_fail (HTML_IS_PAINTER (painter));
728
729 (* HP_CLASS (painter)->fill_rect) (painter, x, y, width, height);
730 }
731
732 void
html_painter_draw_pixmap(HTMLPainter * painter,GdkPixbuf * pixbuf,gint x,gint y,gint scale_width,gint scale_height,const GdkColor * color)733 html_painter_draw_pixmap (HTMLPainter *painter,
734 GdkPixbuf *pixbuf,
735 gint x,
736 gint y,
737 gint scale_width,
738 gint scale_height,
739 const GdkColor *color)
740 {
741 g_return_if_fail (painter != NULL);
742 g_return_if_fail (HTML_IS_PAINTER (painter));
743 g_return_if_fail (pixbuf != NULL);
744
745 (* HP_CLASS (painter)->draw_pixmap) (painter, pixbuf, x, y, scale_width, scale_height, color);
746 }
747
748 void
html_painter_draw_ellipse(HTMLPainter * painter,gint x,gint y,gint width,gint height)749 html_painter_draw_ellipse (HTMLPainter *painter,
750 gint x,
751 gint y,
752 gint width,
753 gint height)
754 {
755 g_return_if_fail (painter != NULL);
756 g_return_if_fail (HTML_IS_PAINTER (painter));
757
758 (* HP_CLASS (painter)->draw_ellipse) (painter, x, y, width, height);
759 }
760
761 void
html_painter_clear(HTMLPainter * painter)762 html_painter_clear (HTMLPainter *painter)
763 {
764 g_return_if_fail (painter != NULL);
765 g_return_if_fail (HTML_IS_PAINTER (painter));
766
767 (* HP_CLASS (painter)->clear) (painter);
768 }
769
770 void
html_painter_set_background_color(HTMLPainter * painter,const GdkColor * color)771 html_painter_set_background_color (HTMLPainter *painter,
772 const GdkColor *color)
773 {
774 g_return_if_fail (painter != NULL);
775 g_return_if_fail (HTML_IS_PAINTER (painter));
776 g_return_if_fail (color != NULL);
777
778 (* HP_CLASS (painter)->set_background_color) (painter, color);
779 }
780
781 void
html_painter_draw_shade_line(HTMLPainter * painter,gint x,gint y,gint width)782 html_painter_draw_shade_line (HTMLPainter *painter,
783 gint x,
784 gint y,
785 gint width)
786 {
787 g_return_if_fail (painter != NULL);
788 g_return_if_fail (HTML_IS_PAINTER (painter));
789
790 (* HP_CLASS (painter)->draw_shade_line) (painter, x, y, width);
791 }
792
793 void
html_painter_draw_border(HTMLPainter * painter,GdkColor * bg,gint x,gint y,gint width,gint height,HTMLBorderStyle style,gint bordersize)794 html_painter_draw_border (HTMLPainter *painter,
795 GdkColor *bg,
796 gint x,
797 gint y,
798 gint width,
799 gint height,
800 HTMLBorderStyle style,
801 gint bordersize)
802 {
803 g_return_if_fail (painter != NULL);
804 g_return_if_fail (HTML_IS_PAINTER (painter));
805
806 (* HP_CLASS (painter)->draw_border) (painter, bg, x, y, width, height, style, bordersize);
807 }
808
809 void
html_painter_draw_embedded(HTMLPainter * painter,HTMLEmbedded * element,gint x,gint y)810 html_painter_draw_embedded (HTMLPainter *painter,
811 HTMLEmbedded *element,
812 gint x,
813 gint y)
814 {
815 g_return_if_fail (painter != NULL);
816 g_return_if_fail (HTML_IS_PAINTER (painter));
817 g_return_if_fail (element != NULL);
818
819 (* HP_CLASS (painter)->draw_embedded) (painter, element, x, y);
820 }
821
822 /* Passing 0 for width/height means remove clip rectangle */
823 void
html_painter_set_clip_rectangle(HTMLPainter * painter,gint x,gint y,gint width,gint height)824 html_painter_set_clip_rectangle (HTMLPainter *painter,
825 gint x,
826 gint y,
827 gint width,
828 gint height)
829 {
830 g_return_if_fail (painter != NULL);
831 g_return_if_fail (HTML_IS_PAINTER (painter));
832
833 painter->clip_x = x;
834 painter->clip_y = y;
835 painter->clip_width = width;
836 painter->clip_height = height;
837
838 /* printf ("clip rect: %d,%d %dx%d\n", x, y, width, height); */
839
840 (* HP_CLASS (painter)->set_clip_rectangle) (painter, x, y, width, height);
841 }
842
843 void
html_painter_get_clip_rectangle(HTMLPainter * painter,gint * x,gint * y,gint * width,gint * height)844 html_painter_get_clip_rectangle (HTMLPainter *painter,
845 gint *x,
846 gint *y,
847 gint *width,
848 gint *height)
849 {
850 *x = painter->clip_x;
851 *y = painter->clip_y;
852 *width = painter->clip_width;
853 *height = painter->clip_height;
854 }
855
856 /* Passing 0 for pix_width / pix_height makes it use the image width */
857 void
html_painter_draw_background(HTMLPainter * painter,GdkColor * color,GdkPixbuf * pixbuf,gint x,gint y,gint width,gint height,gint tile_x,gint tile_y)858 html_painter_draw_background (HTMLPainter *painter,
859 GdkColor *color,
860 GdkPixbuf *pixbuf,
861 gint x,
862 gint y,
863 gint width,
864 gint height,
865 gint tile_x,
866 gint tile_y)
867 {
868 g_return_if_fail (painter != NULL);
869 g_return_if_fail (HTML_IS_PAINTER (painter));
870
871 (* HP_CLASS (painter)->draw_background) (painter, color, pixbuf, x, y, width, height, tile_x, tile_y);
872 }
873
874 guint
html_painter_get_pixel_size(HTMLPainter * painter)875 html_painter_get_pixel_size (HTMLPainter *painter)
876 {
877 g_return_val_if_fail (painter != NULL, 0);
878 g_return_val_if_fail (HTML_IS_PAINTER (painter), 0);
879
880 return (* HP_CLASS (painter)->get_pixel_size) (painter);
881 }
882
883 gint
html_painter_draw_spell_error(HTMLPainter * painter,gint x,gint y,gint width)884 html_painter_draw_spell_error (HTMLPainter *painter,
885 gint x,
886 gint y,
887 gint width)
888 {
889 return (* HP_CLASS (painter)->draw_spell_error) (painter, x, y, width);
890 }
891
892 HTMLFont *
html_painter_alloc_font(HTMLPainter * painter,gchar * face,gdouble size,gboolean points,GtkHTMLFontStyle style)893 html_painter_alloc_font (HTMLPainter *painter,
894 gchar *face,
895 gdouble size,
896 gboolean points,
897 GtkHTMLFontStyle style)
898 {
899 PangoFontDescription *desc = NULL;
900 gint space_width, space_asc, space_dsc;
901
902 if (face) {
903 desc = pango_font_description_from_string (face);
904 if (points)
905 pango_font_description_set_size (desc, (gint) size);
906 else
907 pango_font_description_set_absolute_size (desc, (gint) size);
908 }
909
910 if (!desc || !pango_font_description_get_family (desc)) {
911 GtkStyleContext *style_context;
912 const PangoFontDescription *font_desc;
913
914 if (desc)
915 pango_font_description_free (desc);
916
917 style_context = gtk_widget_get_style_context (painter->widget);
918 font_desc = gtk_style_context_get_font (style_context, GTK_STATE_FLAG_NORMAL);
919 desc = pango_font_description_copy (font_desc);
920 }
921
922 if (points)
923 pango_font_description_set_size (desc, size);
924 else
925 pango_font_description_set_absolute_size (desc, (gint) size);
926
927 pango_font_description_set_style (desc, style & GTK_HTML_FONT_STYLE_ITALIC ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
928 pango_font_description_set_weight (desc, style & GTK_HTML_FONT_STYLE_BOLD ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL);
929
930 text_size (painter, desc, " ", 1, NULL, NULL, &space_width, &space_asc, &space_dsc);
931
932 return html_font_new (desc,
933 space_width,
934 space_asc, space_dsc,
935 text_width (painter, desc, "\xc2\xa0", 2),
936 text_width (painter, desc, "\t", 1),
937 text_width (painter, desc, "e", 1),
938 text_width (painter, desc, HTML_BLOCK_INDENT, strlen (HTML_BLOCK_INDENT)),
939 text_width (painter, desc, HTML_BLOCK_CITE_LTR, strlen (HTML_BLOCK_CITE_LTR)),
940 text_width (painter, desc, HTML_BLOCK_CITE_RTL, strlen (HTML_BLOCK_CITE_RTL)));
941 }
942
943 void
html_painter_ref_font(HTMLPainter * painter,HTMLFont * font)944 html_painter_ref_font (HTMLPainter *painter,
945 HTMLFont *font)
946 {
947 }
948
949 void
html_painter_unref_font(HTMLPainter * painter,HTMLFont * font)950 html_painter_unref_font (HTMLPainter *painter,
951 HTMLFont *font)
952 {
953 if (font->ref_count < 1) {
954 pango_font_description_free (font->data);
955 font->data = NULL;
956 }
957 }
958
959 guint
html_painter_get_space_width(HTMLPainter * painter,GtkHTMLFontStyle style,HTMLFontFace * face)960 html_painter_get_space_width (HTMLPainter *painter,
961 GtkHTMLFontStyle style,
962 HTMLFontFace *face)
963 {
964 return html_font_manager_get_font (&painter->font_manager, face, style)->space_width;
965 }
966
967 guint
html_painter_get_space_asc(HTMLPainter * painter,GtkHTMLFontStyle style,HTMLFontFace * face)968 html_painter_get_space_asc (HTMLPainter *painter,
969 GtkHTMLFontStyle style,
970 HTMLFontFace *face)
971 {
972 return html_font_manager_get_font (&painter->font_manager, face, style)->space_asc;
973 }
974
975 guint
html_painter_get_space_dsc(HTMLPainter * painter,GtkHTMLFontStyle style,HTMLFontFace * face)976 html_painter_get_space_dsc (HTMLPainter *painter,
977 GtkHTMLFontStyle style,
978 HTMLFontFace *face)
979 {
980 return html_font_manager_get_font (&painter->font_manager, face, style)->space_dsc;
981 }
982
983 guint
html_painter_get_e_width(HTMLPainter * painter,GtkHTMLFontStyle style,HTMLFontFace * face)984 html_painter_get_e_width (HTMLPainter *painter,
985 GtkHTMLFontStyle style,
986 HTMLFontFace *face)
987 {
988 return html_font_manager_get_font (&painter->font_manager, face, style)->e_width;
989 }
990
991 guint
html_painter_get_block_indent_width(HTMLPainter * painter,GtkHTMLFontStyle style,HTMLFontFace * face)992 html_painter_get_block_indent_width (HTMLPainter *painter,
993 GtkHTMLFontStyle style,
994 HTMLFontFace *face)
995 {
996 return html_font_manager_get_font (&painter->font_manager, face, style)->indent_width;
997 }
998
999 guint
html_painter_get_block_cite_width(HTMLPainter * painter,GtkHTMLFontStyle style,HTMLFontFace * face,HTMLDirection dir)1000 html_painter_get_block_cite_width (HTMLPainter *painter,
1001 GtkHTMLFontStyle style,
1002 HTMLFontFace *face,
1003 HTMLDirection dir)
1004 {
1005 HTMLFont *font = html_font_manager_get_font (&painter->font_manager, face, style);
1006 return dir == HTML_DIRECTION_RTL ? font->cite_width_rtl : font->cite_width_ltr;
1007 }
1008
1009 guint
html_painter_get_page_width(HTMLPainter * painter,HTMLEngine * e)1010 html_painter_get_page_width (HTMLPainter *painter,
1011 HTMLEngine *e)
1012 {
1013 return (* HP_CLASS (painter)->get_page_width) (painter, e);
1014 }
1015
1016 guint
html_painter_get_page_height(HTMLPainter * painter,HTMLEngine * e)1017 html_painter_get_page_height (HTMLPainter *painter,
1018 HTMLEngine *e)
1019 {
1020 return (* HP_CLASS (painter)->get_page_height) (painter, e);
1021 }
1022
1023 /**
1024 * html_painter_pango_to_engine:
1025 * @painter: a #HTMLPainter
1026 * @pango_units: distance in Pango units
1027 *
1028 * Convert a distance in Pango units (used for character layout) to
1029 * a distance in engine coordinates. Note that the computation is
1030 * only correct for positive values of @pango_units
1031 *
1032 * Return value: distance converted to engine coordinates.
1033 **/
1034 gint
html_painter_pango_to_engine(HTMLPainter * painter,gint pango_units)1035 html_painter_pango_to_engine (HTMLPainter *painter,
1036 gint pango_units)
1037 {
1038 gdouble tmp = 0.5 + pango_units / painter->engine_to_pango;
1039 return (gint) CLAMP (tmp, G_MININT, G_MAXINT);
1040 }
1041
1042 /**
1043 * html_painter_engine_to_pango:
1044 * @painter: a #HTMLPainter
1045 * @engine_coordiantes: distance in Pango units
1046 *
1047 * Convert a distance in engine coordinates to a distance in Pango
1048 * units (used for character layout). Note that the computation is
1049 * only correct for positive values of @pango_units
1050 *
1051 * Return value: distance converted to Pango units
1052 **/
1053 gint
html_painter_engine_to_pango(HTMLPainter * painter,gint engine_units)1054 html_painter_engine_to_pango (HTMLPainter *painter,
1055 gint engine_units)
1056 {
1057 gdouble tmp = 0.5 + engine_units * painter->engine_to_pango;
1058 return (gint) CLAMP (tmp, G_MININT, G_MAXINT);
1059 }
1060
1061 void
html_painter_set_focus(HTMLPainter * p,gboolean focus)1062 html_painter_set_focus (HTMLPainter *p,
1063 gboolean focus)
1064 {
1065 p->focus = focus;
1066 }
1067
1068 void
html_painter_set_widget(HTMLPainter * painter,GtkWidget * widget)1069 html_painter_set_widget (HTMLPainter *painter,
1070 GtkWidget *widget)
1071 {
1072 (* HP_CLASS (painter)->set_widget) (painter, widget);
1073 }
1074
1075 HTMLTextPangoInfo *
html_painter_text_itemize_and_prepare_glyphs(HTMLPainter * painter,PangoFontDescription * desc,const gchar * text,gint bytes,GList ** glyphs,PangoAttrList * attrs)1076 html_painter_text_itemize_and_prepare_glyphs (HTMLPainter *painter,
1077 PangoFontDescription *desc,
1078 const gchar *text,
1079 gint bytes,
1080 GList **glyphs,
1081 PangoAttrList *attrs)
1082 {
1083 PangoAttribute *attr;
1084 GList *items = NULL;
1085 gboolean empty_attrs = (attrs == NULL);
1086 HTMLTextPangoInfo *pi = NULL;
1087
1088 /* printf ("itemize + glyphs\n"); */
1089
1090 *glyphs = NULL;
1091
1092 if (empty_attrs) {
1093 attrs = pango_attr_list_new ();
1094 attr = pango_attr_font_desc_new (desc);
1095 attr->start_index = 0;
1096 attr->end_index = bytes;
1097 pango_attr_list_insert (attrs, attr);
1098 }
1099
1100 items = pango_itemize (painter->pango_context, text, 0, bytes, attrs, NULL);
1101
1102 if (empty_attrs)
1103 pango_attr_list_unref (attrs);
1104
1105 if (items && items->data) {
1106 PangoItem *item;
1107 GList *il;
1108 const gchar *end;
1109 gint i = 0;
1110
1111 pi = html_text_pango_info_new (g_list_length (items));
1112
1113 for (il = items; il; il = il->next) {
1114 item = (PangoItem *) il->data;
1115 pi->entries[i].glyph_item.item = item;
1116 end = g_utf8_offset_to_pointer (text, item->num_chars);
1117 *glyphs = html_get_glyphs_non_tab (*glyphs, item, i, text, end - text, item->num_chars);
1118 text = end;
1119 i++;
1120 }
1121 *glyphs = g_list_reverse (*glyphs);
1122 g_list_free (items);
1123 }
1124
1125 return pi;
1126 }
1127
1128 void
html_painter_glyphs_destroy(GList * glyphs)1129 html_painter_glyphs_destroy (GList *glyphs)
1130 {
1131 GList *l;
1132
1133 for (l = glyphs; l; l = l->next->next)
1134 pango_glyph_string_free ((PangoGlyphString *) l->data);
1135 g_list_free (glyphs);
1136 }
1137
1138 /**
1139 * html_pango_get_item_properties:
1140 * @item: a #PangoItem
1141 * @properties: a #HTMLPangoProperties structure
1142 *
1143 * Converts the list of extra attributes from @item into a more convenient
1144 * structure form.
1145 **/
1146 void
html_pango_get_item_properties(PangoItem * item,HTMLPangoProperties * properties)1147 html_pango_get_item_properties (PangoItem *item,
1148 HTMLPangoProperties *properties)
1149 {
1150 GSList *tmp_list = item->analysis.extra_attrs;
1151
1152 properties->underline = FALSE;
1153 properties->strikethrough = FALSE;
1154 properties->fg_color = NULL;
1155 properties->bg_color = NULL;
1156
1157 while (tmp_list) {
1158 PangoAttribute *attr = tmp_list->data;
1159
1160 switch (attr->klass->type) {
1161 case PANGO_ATTR_UNDERLINE:
1162 properties->underline = ((PangoAttrInt *) attr)->value != PANGO_UNDERLINE_NONE;
1163 break;
1164
1165 case PANGO_ATTR_STRIKETHROUGH:
1166 properties->strikethrough = ((PangoAttrInt *) attr)->value;
1167 break;
1168
1169 case PANGO_ATTR_FOREGROUND:
1170 properties->fg_color = &((PangoAttrColor *) attr)->color;
1171 break;
1172
1173 case PANGO_ATTR_BACKGROUND:
1174 properties->bg_color = &((PangoAttrColor *) attr)->color;
1175 break;
1176
1177 default:
1178 break;
1179 }
1180 tmp_list = tmp_list->next;
1181 }
1182 }
1183