1 /*
2  * Copyright (C) 2003,2008 Red Hat, Inc.
3  *
4  * This is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU Library General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 
19 
20 #include <config.h>
21 
22 #include <sys/param.h>
23 #include <string.h>
24 #include <gtk/gtk.h>
25 #include <glib.h>
26 #include "debug.h"
27 #include "vtebg.h"
28 #include "vtedraw.h"
29 #include "vte-private.h"
30 
31 #include <pango/pangocairo.h>
32 
33 
34 /* Overview:
35  *
36  *
37  * This file implements vte rendering using pangocairo.  Note that this does
38  * NOT implement any kind of complex text rendering.  That's not currently a
39  * goal.
40  *
41  * The aim is to be super-fast and avoid unneeded work as much as possible.
42  * Here is an overview of how that is accomplished:
43  *
44  *   - We attach a font_info to the draw.  A font_info has all the information
45  *     to quickly draw text.
46  *
47  *   - A font_info keeps uses unistr_font_info structs that represent all
48  *     information needed to quickly draw a single vteunistr.  The font_info
49  *     creates those unistr_font_info structs on demand and caches them
50  *     indefinitely.  It uses a direct array for the ASCII range and a hash
51  *     table for the rest.
52  *
53  *
54  * Fast rendering of unistrs:
55  *
56  * A unistr_font_info (uinfo) calls Pango to set text for the unistr upon
57  * initialization and then caches information needed to draw the results
58  * later.  It uses three different internal representations and respectively
59  * three drawing paths:
60  *
61  *   - COVERAGE_USE_CAIRO_GLYPH:
62  *     Keeping a single glyph index and a cairo scaled-font.  This is the
63  *     fastest way to draw text as it bypasses Pango completely and allows
64  *     for stuffing multiple glyphs into a single cairo_show_glyphs() request
65  *     (if scaled-fonts match).  This method is used if the glyphs used for
66  *     the vteunistr as determined by Pango consists of a single regular glyph
67  *     positioned at 0,0 using a regular font.  This method is used for more
68  *     than 99% of the cases.  Only exceptional cases fall through to the
69  *     other two methods.
70  *
71  *   - COVERAGE_USE_PANGO_GLYPH_STRING:
72  *     Keeping a pango glyphstring and a pango font.  This is slightly slower
73  *     than the previous case as drawing each glyph goes through pango
74  *     separately and causes a separate cairo_show_glyphs() call.  This method
75  *     is used when the previous method cannot be used but the glyphs for the
76  *     character all use a single font.  This is the method used for hexboxes
77  *     and "empty" characters like U+200C ZERO WIDTH NON-JOINER for example.
78  *
79  *   - COVERAGE_USE_PANGO_LAYOUT_LINE:
80  *     Keeping a pango layout line.  This method is used only in the very
81  *     weird and exceptional case that a single vteunistr uses more than one
82  *     font to be drawn.  This happens for example if some diacretics is not
83  *     available in the font chosen for the base character.
84  *
85  *
86  * Caching of font infos:
87  *
88  * To avoid recreating font info structs for the same font again and again we
89  * do the following:
90  *
91  *   - Use a global cache to share font info structs across different widgets.
92  *     We use pango language, cairo font options, resolution, and font description
93  *     as the key for our hash table.
94  *
95  *   - When a font info struct is no longer used by any widget, we delay
96  *     destroying it for a while (FONT_CACHE_TIMEOUT seconds).  This is
97  *     supposed to serve two purposes:
98  *
99  *       * Destroying a terminal widget and creating it again right after will
100  *         reuse the font info struct from the previous widget.
101  *
102  *       * Zooming in and out a terminal reuses the font info structs.
103  *
104  *
105  * Pre-caching ASCII letters:
106  *
107  * When initializing a font info struct we measure a string consisting of all
108  * ASCII letters and some other ASCII characters.  Since we have a shaped pango
109  * layout at hand, we walk over it and cache unistr font info for the ASCII
110  * letters if we can do that easily using COVERAGE_USE_CAIRO_GLYPH.  This
111  * means that we precache all ASCII letters without any extra pango shaping
112  * involved.
113  */
114 
115 
116 
117 #define FONT_CACHE_TIMEOUT (30) /* seconds */
118 
119 
120 /* All shared data structures are implicitly protected by GDK mutex, because
121  * that's how vte.c works and we only get called from there. */
122 
123 
124 /* cairo_show_glyphs accepts runs up to 102 glyphs before it allocates a
125  * temporary array.
126  *
127  * Setting this to a large value can cause dramatic slow-downs for some
128  * xservers (notably fglrx), see bug #410534.
129  *
130  * Moreover, setting it larger than %VTE_DRAW_MAX_LENGTH is nonsensical,
131  * as the higher layers will not submit runs longer than that value.
132  */
133 #define MAX_RUN_LENGTH 100
134 
135 
136 enum unistr_coverage {
137 	/* in increasing order of speed */
138 	COVERAGE_UNKNOWN = 0,		/* we don't know about the character yet */
139 	COVERAGE_USE_PANGO_LAYOUT_LINE,	/* use a PangoLayoutLine for the character */
140 	COVERAGE_USE_PANGO_GLYPH_STRING,	/* use a PangoGlyphString for the character */
141 	COVERAGE_USE_CAIRO_GLYPH	/* use a cairo_glyph_t for the character */
142 };
143 
144 union unistr_font_info {
145 	/* COVERAGE_USE_PANGO_LAYOUT_LINE */
146 	struct {
147 		PangoLayoutLine *line;
148 	} using_pango_layout_line;
149 	/* COVERAGE_USE_PANGO_GLYPH_STRING */
150 	struct {
151 		PangoFont *font;
152 		PangoGlyphString *glyph_string;
153 	} using_pango_glyph_string;
154 	/* COVERAGE_USE_CAIRO_GLYPH */
155 	struct {
156 		cairo_scaled_font_t *scaled_font;
157 		unsigned int glyph_index;
158 	} using_cairo_glyph;
159 };
160 
161 struct unistr_info {
162 	guchar coverage;
163 	guchar has_unknown_chars;
164 	guint16 width;
165 	union unistr_font_info ufi;
166 };
167 
168 static struct unistr_info *
unistr_info_create(void)169 unistr_info_create (void)
170 {
171 	return g_slice_new0 (struct unistr_info);
172 }
173 
174 static void
unistr_info_finish(struct unistr_info * uinfo)175 unistr_info_finish (struct unistr_info *uinfo)
176 {
177 	union unistr_font_info *ufi = &uinfo->ufi;
178 
179 	switch (uinfo->coverage) {
180 	default:
181 	case COVERAGE_UNKNOWN:
182 		break;
183 	case COVERAGE_USE_PANGO_LAYOUT_LINE:
184 		/* we hold a manual reference on layout */
185 		g_object_unref (ufi->using_pango_layout_line.line->layout);
186 		ufi->using_pango_layout_line.line->layout = NULL;
187 		pango_layout_line_unref (ufi->using_pango_layout_line.line);
188 		ufi->using_pango_layout_line.line = NULL;
189 		break;
190 	case COVERAGE_USE_PANGO_GLYPH_STRING:
191 		if (ufi->using_pango_glyph_string.font)
192 			g_object_unref (ufi->using_pango_glyph_string.font);
193 		ufi->using_pango_glyph_string.font = NULL;
194 		pango_glyph_string_free (ufi->using_pango_glyph_string.glyph_string);
195 		ufi->using_pango_glyph_string.glyph_string = NULL;
196 		break;
197 	case COVERAGE_USE_CAIRO_GLYPH:
198 		cairo_scaled_font_destroy (ufi->using_cairo_glyph.scaled_font);
199 		ufi->using_cairo_glyph.scaled_font = NULL;
200 		break;
201 	}
202 }
203 
204 static void
unistr_info_destroy(struct unistr_info * uinfo)205 unistr_info_destroy (struct unistr_info *uinfo)
206 {
207 	unistr_info_finish (uinfo);
208 	g_slice_free (struct unistr_info, uinfo);
209 }
210 
211 struct font_info {
212 	/* lifecycle */
213 	int ref_count;
214 	guint destroy_timeout; /* only used when ref_count == 0 */
215 
216 	/* reusable layout set with font and everything set */
217 	PangoLayout *layout;
218 
219 	/* cache of character info */
220 	struct unistr_info ascii_unistr_info[128];
221 	GHashTable *other_unistr_info;
222 
223 	/* cell metrics */
224 	gint width, height, ascent;
225 
226 	/* reusable string for UTF-8 conversion */
227 	GString *string;
228 
229 #ifdef VTE_DEBUG
230 	/* profiling info */
231 	int coverage_count[4];
232 #endif
233 };
234 
235 
236 static struct unistr_info *
font_info_find_unistr_info(struct font_info * info,vteunistr c)237 font_info_find_unistr_info (struct font_info    *info,
238 			    vteunistr            c)
239 {
240 	struct unistr_info *uinfo;
241 
242 	if (G_LIKELY (c < G_N_ELEMENTS (info->ascii_unistr_info)))
243 		return &info->ascii_unistr_info[c];
244 
245 	if (G_UNLIKELY (info->other_unistr_info == NULL))
246 		info->other_unistr_info = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) unistr_info_destroy);
247 
248 	uinfo = g_hash_table_lookup (info->other_unistr_info, GINT_TO_POINTER (c));
249 	if (G_LIKELY (uinfo))
250 		return uinfo;
251 
252 	uinfo = unistr_info_create ();
253 	g_hash_table_insert (info->other_unistr_info, GINT_TO_POINTER (c), uinfo);
254 	return uinfo;
255 }
256 
257 
258 static void
font_info_cache_ascii(struct font_info * info)259 font_info_cache_ascii (struct font_info *info)
260 {
261 	PangoLayoutLine *line;
262 	PangoGlyphItemIter iter;
263 	PangoGlyphItem *glyph_item;
264 	PangoGlyphString *glyph_string;
265 	PangoFont *pango_font;
266 	cairo_scaled_font_t *scaled_font;
267 	const char *text;
268 	gboolean more;
269 	PangoLanguage *language;
270 	gboolean latin_uses_default_language;
271 
272 	/* We have info->layout holding most ASCII characters.  We want to
273 	 * cache as much info as we can about the ASCII letters so we don't
274 	 * have to look them up again later */
275 
276 	/* Don't cache if unknown glyphs found in layout */
277 	if (pango_layout_get_unknown_glyphs_count (info->layout) != 0)
278 		return;
279 
280 	language = pango_context_get_language (pango_layout_get_context (info->layout));
281 	if (language == NULL)
282 		language = pango_language_get_default ();
283 	latin_uses_default_language = pango_language_includes_script (language, PANGO_SCRIPT_LATIN);
284 
285 	text = pango_layout_get_text (info->layout);
286 
287 	line = pango_layout_get_line_readonly (info->layout, 0);
288 
289 	/* Don't cache if more than one font used for the line */
290 	if (G_UNLIKELY (!line || !line->runs || line->runs->next))
291 		return;
292 
293 	glyph_item = line->runs->data;
294 	glyph_string = glyph_item->glyphs;
295 	pango_font = glyph_item->item->analysis.font;
296 	if (!pango_font)
297 		return;
298 	scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *) pango_font);
299 	if (!scaled_font)
300 		return;
301 
302 	for (more = pango_glyph_item_iter_init_start (&iter, glyph_item, text);
303 	     more;
304 	     more = pango_glyph_item_iter_next_cluster (&iter))
305 	{
306 		struct unistr_info *uinfo;
307 		union unistr_font_info *ufi;
308 	 	PangoGlyphGeometry *geometry;
309 		PangoGlyph glyph;
310 		vteunistr c;
311 
312 		/* Only cache simple clusters */
313 		if (iter.start_char +1 != iter.end_char  ||
314 		    iter.start_index+1 != iter.end_index ||
315 		    iter.start_glyph+1 != iter.end_glyph)
316 			continue;
317 
318 		c = text[iter.start_index];
319 		glyph = glyph_string->glyphs[iter.start_glyph].glyph;
320 		geometry = &glyph_string->glyphs[iter.start_glyph].geometry;
321 
322 		/* If not using the default locale language, only cache non-common
323 		 * characters as common characters get their font from their neighbors
324 		 * and we don't want to force Latin on them. */
325 		if (!latin_uses_default_language &&
326 		    pango_script_for_unichar (c) <= PANGO_SCRIPT_INHERITED)
327 			continue;
328 
329 		/* Only cache simple glyphs */
330 		if (!(glyph <= 0xFFFF) || (geometry->x_offset | geometry->y_offset) != 0)
331 			continue;
332 
333 		uinfo = font_info_find_unistr_info (info, c);
334 		if (G_UNLIKELY (uinfo->coverage != COVERAGE_UNKNOWN))
335 			continue;
336 
337 		ufi = &uinfo->ufi;
338 
339 		uinfo->width = PANGO_PIXELS_CEIL (geometry->width);
340 		uinfo->has_unknown_chars = FALSE;
341 
342 		uinfo->coverage = COVERAGE_USE_CAIRO_GLYPH;
343 
344 		ufi->using_cairo_glyph.scaled_font = cairo_scaled_font_reference (scaled_font);
345 		ufi->using_cairo_glyph.glyph_index = glyph;
346 
347 #ifdef VTE_DEBUG
348 		info->coverage_count[0]++;
349 		info->coverage_count[uinfo->coverage]++;
350 #endif
351 	}
352 
353 #ifdef VTE_DEBUG
354 	_vte_debug_print (VTE_DEBUG_PANGOCAIRO,
355 			  "vtepangocairo: %p cached %d ASCII letters\n",
356 			  info, info->coverage_count[0]);
357 #endif
358 }
359 
360 static void
font_info_measure_font(struct font_info * info)361 font_info_measure_font (struct font_info *info)
362 {
363 	PangoRectangle logical;
364 
365 	/* Estimate for ASCII characters. */
366 	pango_layout_set_text (info->layout, VTE_DRAW_SINGLE_WIDE_CHARACTERS, -1);
367 	pango_layout_get_extents (info->layout, NULL, &logical);
368 	/* We don't do CEIL for width since we are averaging;
369 	 * rounding is more accurate */
370 	info->width  = PANGO_PIXELS (howmany (logical.width, strlen(VTE_DRAW_SINGLE_WIDE_CHARACTERS)));
371 	info->height = PANGO_PIXELS_CEIL (logical.height);
372 	info->ascent = PANGO_PIXELS_CEIL (pango_layout_get_baseline (info->layout));
373 
374 	/* Now that we shaped the entire ASCII character string, cache glyph
375 	 * info for them */
376 	font_info_cache_ascii (info);
377 
378 
379 	if (info->height == 0) {
380 		info->height = PANGO_PIXELS_CEIL (logical.height);
381 	}
382 	if (info->ascent == 0) {
383 		info->ascent = PANGO_PIXELS_CEIL (pango_layout_get_baseline (info->layout));
384 	}
385 
386 	_vte_debug_print (VTE_DEBUG_MISC,
387 			  "vtepangocairo: %p font metrics = %dx%d (%d)\n",
388 			  info, info->width, info->height, info->ascent);
389 }
390 
391 
392 static struct font_info *
font_info_allocate(PangoContext * context)393 font_info_allocate (PangoContext *context)
394 {
395 	struct font_info *info;
396 	PangoTabArray *tabs;
397 
398 	info = g_slice_new0 (struct font_info);
399 
400 	_vte_debug_print (VTE_DEBUG_PANGOCAIRO,
401 			  "vtepangocairo: %p allocating font_info\n",
402 			  info);
403 
404 	info->layout = pango_layout_new (context);
405 	tabs = pango_tab_array_new_with_positions (1, FALSE, PANGO_TAB_LEFT, 1);
406 	pango_layout_set_tabs (info->layout, tabs);
407 	pango_tab_array_free (tabs);
408 
409 	info->string = g_string_sized_new (VTE_UTF8_BPC+1);
410 
411 	font_info_measure_font (info);
412 
413 	return info;
414 }
415 
416 static void
font_info_free(struct font_info * info)417 font_info_free (struct font_info *info)
418 {
419 	vteunistr i;
420 
421 #ifdef VTE_DEBUG
422 	_vte_debug_print (VTE_DEBUG_PANGOCAIRO,
423 			  "vtepangocairo: %p freeing font_info.  coverages %d = %d + %d + %d\n",
424 			  info,
425 			  info->coverage_count[0],
426 			  info->coverage_count[1],
427 			  info->coverage_count[2],
428 			  info->coverage_count[3]);
429 #endif
430 
431 	g_string_free (info->string, TRUE);
432 	g_object_unref (info->layout);
433 
434 	for (i = 0; i < G_N_ELEMENTS (info->ascii_unistr_info); i++)
435 		unistr_info_finish (&info->ascii_unistr_info[i]);
436 
437 	if (info->other_unistr_info) {
438 		g_hash_table_destroy (info->other_unistr_info);
439 	}
440 
441 	g_slice_free (struct font_info, info);
442 }
443 
444 
445 static GHashTable *font_info_for_context;
446 
447 static struct font_info *
font_info_register(struct font_info * info)448 font_info_register (struct font_info *info)
449 {
450 	g_hash_table_insert (font_info_for_context,
451 			     pango_layout_get_context (info->layout),
452 			     info);
453 
454 	return info;
455 }
456 
457 static void
font_info_unregister(struct font_info * info)458 font_info_unregister (struct font_info *info)
459 {
460 	g_hash_table_remove (font_info_for_context,
461 			     pango_layout_get_context (info->layout));
462 }
463 
464 
465 static struct font_info *
font_info_reference(struct font_info * info)466 font_info_reference (struct font_info *info)
467 {
468 	if (!info)
469 		return info;
470 
471 	g_return_val_if_fail (info->ref_count >= 0, info);
472 
473 	if (info->destroy_timeout) {
474 		g_source_remove (info->destroy_timeout);
475 		info->destroy_timeout = 0;
476 	}
477 
478 	info->ref_count++;
479 
480 	return info;
481 }
482 
483 static gboolean
font_info_destroy_delayed(struct font_info * info)484 font_info_destroy_delayed (struct font_info *info)
485 {
486 	info->destroy_timeout = 0;
487 
488 	font_info_unregister (info);
489 	font_info_free (info);
490 
491 	return FALSE;
492 }
493 
494 static void
font_info_destroy(struct font_info * info)495 font_info_destroy (struct font_info *info)
496 {
497 	if (!info)
498 		return;
499 
500 	g_return_if_fail (info->ref_count > 0);
501 
502 	info->ref_count--;
503 	if (info->ref_count)
504 		return;
505 
506 	/* Delay destruction by a few seconds, in case we need it again */
507 	info->destroy_timeout = gdk_threads_add_timeout_seconds (FONT_CACHE_TIMEOUT,
508 								 (GSourceFunc) font_info_destroy_delayed,
509 								 info);
510 }
511 
512 static GQuark
fontconfig_timestamp_quark(void)513 fontconfig_timestamp_quark (void)
514 {
515 	static GQuark quark;
516 
517 	if (G_UNLIKELY (!quark))
518 		quark = g_quark_from_static_string ("vte-fontconfig-timestamp");
519 
520 	return quark;
521 }
522 
523 static void
vte_pango_context_set_fontconfig_timestamp(PangoContext * context,guint fontconfig_timestamp)524 vte_pango_context_set_fontconfig_timestamp (PangoContext *context,
525 					    guint         fontconfig_timestamp)
526 {
527 	g_object_set_qdata ((GObject *) context,
528 			    fontconfig_timestamp_quark (),
529 			    GUINT_TO_POINTER (fontconfig_timestamp));
530 }
531 
532 static guint
vte_pango_context_get_fontconfig_timestamp(PangoContext * context)533 vte_pango_context_get_fontconfig_timestamp (PangoContext *context)
534 {
535 	return GPOINTER_TO_UINT (g_object_get_qdata ((GObject *) context,
536 						     fontconfig_timestamp_quark ()));
537 }
538 
539 static guint
context_hash(PangoContext * context)540 context_hash (PangoContext *context)
541 {
542 	return pango_units_from_double (pango_cairo_context_get_resolution (context))
543 	     ^ pango_font_description_hash (pango_context_get_font_description (context))
544 	     ^ cairo_font_options_hash (pango_cairo_context_get_font_options (context))
545 	     ^ GPOINTER_TO_UINT (pango_context_get_language (context))
546 	     ^ vte_pango_context_get_fontconfig_timestamp (context);
547 }
548 
549 static gboolean
context_equal(PangoContext * a,PangoContext * b)550 context_equal (PangoContext *a,
551 	       PangoContext *b)
552 {
553 	return pango_cairo_context_get_resolution (a) == pango_cairo_context_get_resolution (b)
554 	    && pango_font_description_equal (pango_context_get_font_description (a), pango_context_get_font_description (b))
555 	    && cairo_font_options_equal (pango_cairo_context_get_font_options (a), pango_cairo_context_get_font_options (b))
556 	    && pango_context_get_language (a) == pango_context_get_language (b)
557 	    && vte_pango_context_get_fontconfig_timestamp (a) == vte_pango_context_get_fontconfig_timestamp (b);
558 }
559 
560 static struct font_info *
font_info_find_for_context(PangoContext * context)561 font_info_find_for_context (PangoContext *context)
562 {
563 	struct font_info *info;
564 
565 	if (G_UNLIKELY (font_info_for_context == NULL))
566 		font_info_for_context = g_hash_table_new ((GHashFunc) context_hash, (GEqualFunc) context_equal);
567 
568 	info = g_hash_table_lookup (font_info_for_context, context);
569 	if (G_LIKELY (info)) {
570 		_vte_debug_print (VTE_DEBUG_PANGOCAIRO,
571 				  "vtepangocairo: %p found font_info in cache\n",
572 				  info);
573 		return font_info_reference (info);
574 	}
575 
576 	info = font_info_allocate (context);
577 	info->ref_count = 1;
578 	font_info_register (info);
579 
580 	g_object_unref (context);
581 
582 	return info;
583 }
584 
585 /* assumes ownership/reference of context */
586 static struct font_info *
font_info_create_for_context(PangoContext * context,const PangoFontDescription * desc,VteTerminalAntiAlias antialias,PangoLanguage * language,guint fontconfig_timestamp)587 font_info_create_for_context (PangoContext               *context,
588 			      const PangoFontDescription *desc,
589 			      VteTerminalAntiAlias        antialias,
590 			      PangoLanguage              *language,
591 			      guint                       fontconfig_timestamp)
592 {
593 	if (!PANGO_IS_CAIRO_FONT_MAP (pango_context_get_font_map (context))) {
594 		/* Ouch, Gtk+ switched over to some drawing system?
595 		 * Lets just create one from the default font map.
596 		 */
597 		g_object_unref (context);
598 		context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
599 	}
600 
601 	vte_pango_context_set_fontconfig_timestamp (context, fontconfig_timestamp);
602 
603 	pango_context_set_base_dir (context, PANGO_DIRECTION_LTR);
604 
605 	if (desc)
606 		pango_context_set_font_description (context, desc);
607 
608 	pango_context_set_language (context, language);
609 
610 	switch (antialias) {
611 		cairo_font_options_t *font_options;
612 		cairo_antialias_t cr_aa;
613 
614 	case VTE_ANTI_ALIAS_FORCE_ENABLE:
615 	case VTE_ANTI_ALIAS_FORCE_DISABLE:
616 
617 		if (antialias == VTE_ANTI_ALIAS_FORCE_ENABLE)
618 			cr_aa = CAIRO_ANTIALIAS_DEFAULT; /* let surface decide between gray and subpixel */
619 		else
620 			cr_aa = CAIRO_ANTIALIAS_NONE;
621 
622 		font_options = cairo_font_options_copy (pango_cairo_context_get_font_options (context));
623 		cairo_font_options_set_antialias (font_options, cr_aa);
624 		pango_cairo_context_set_font_options (context, font_options);
625 		cairo_font_options_destroy (font_options);
626 
627 		break;
628 
629 	default:
630 	case VTE_ANTI_ALIAS_USE_DEFAULT:
631 		/* Make sure our contexts have a font_options set.  We use
632 		 * this invariant in our context hash and equal functions.
633 		 */
634 		if (!pango_cairo_context_get_font_options (context)) {
635 			font_options = cairo_font_options_create ();
636 			pango_cairo_context_set_font_options (context, font_options);
637 			cairo_font_options_destroy (font_options);
638 		}
639 		break;
640 	}
641 
642 	return font_info_find_for_context (context);
643 }
644 
645 static struct font_info *
font_info_create_for_screen(GdkScreen * screen,const PangoFontDescription * desc,VteTerminalAntiAlias antialias,PangoLanguage * language)646 font_info_create_for_screen (GdkScreen                  *screen,
647 			     const PangoFontDescription *desc,
648 			     VteTerminalAntiAlias        antialias,
649 			     PangoLanguage              *language)
650 {
651 	GtkSettings *settings = gtk_settings_get_for_screen (screen);
652 	int fontconfig_timestamp;
653 	g_object_get (settings, "gtk-fontconfig-timestamp", &fontconfig_timestamp, NULL);
654 	return font_info_create_for_context (gdk_pango_context_get_for_screen (screen),
655 					     desc, antialias, language, fontconfig_timestamp);
656 }
657 
658 static struct font_info *
font_info_create_for_widget(GtkWidget * widget,const PangoFontDescription * desc,VteTerminalAntiAlias antialias)659 font_info_create_for_widget (GtkWidget                  *widget,
660 			     const PangoFontDescription *desc,
661 			     VteTerminalAntiAlias        antialias)
662 {
663 	GdkScreen *screen = gtk_widget_get_screen (widget);
664 	PangoLanguage *language = pango_context_get_language (gtk_widget_get_pango_context (widget));
665 
666 	return font_info_create_for_screen (screen, desc, antialias, language);
667 }
668 
669 static struct unistr_info *
font_info_get_unistr_info(struct font_info * info,vteunistr c)670 font_info_get_unistr_info (struct font_info *info,
671 			   vteunistr c)
672 {
673 	struct unistr_info *uinfo;
674 	union unistr_font_info *ufi;
675 	PangoRectangle logical;
676 	PangoLayoutLine *line;
677 
678 	uinfo = font_info_find_unistr_info (info, c);
679 	if (G_LIKELY (uinfo->coverage != COVERAGE_UNKNOWN))
680 		return uinfo;
681 
682 	ufi = &uinfo->ufi;
683 
684 	g_string_set_size (info->string, 0);
685 	_vte_unistr_append_to_string (c, info->string);
686 	pango_layout_set_text (info->layout, info->string->str, -1);
687 	pango_layout_get_extents (info->layout, NULL, &logical);
688 
689 	uinfo->width = PANGO_PIXELS_CEIL (logical.width);
690 
691 	line = pango_layout_get_line_readonly (info->layout, 0);
692 
693 	uinfo->has_unknown_chars = pango_layout_get_unknown_glyphs_count (info->layout) != 0;
694 	/* we use PangoLayoutRun rendering unless there is exactly one run in the line. */
695 	if (G_UNLIKELY (!line || !line->runs || line->runs->next))
696 	{
697 		uinfo->coverage = COVERAGE_USE_PANGO_LAYOUT_LINE;
698 
699 		ufi->using_pango_layout_line.line = pango_layout_line_ref (line);
700 		/* we hold a manual reference on layout.  pango currently
701 		 * doesn't work if line->layout is NULL.  ugh! */
702 		pango_layout_set_text (info->layout, "", -1); /* make layout disassociate from the line */
703 		ufi->using_pango_layout_line.line->layout = g_object_ref (info->layout);
704 
705 	} else {
706 		PangoGlyphItem *glyph_item = line->runs->data;
707 		PangoFont *pango_font = glyph_item->item->analysis.font;
708 		PangoGlyphString *glyph_string = glyph_item->glyphs;
709 
710 		/* we use fast cairo path if glyph string has only one real
711 		 * glyph and at origin */
712 		if (!uinfo->has_unknown_chars &&
713 		    glyph_string->num_glyphs == 1 && glyph_string->glyphs[0].glyph <= 0xFFFF &&
714 		    (glyph_string->glyphs[0].geometry.x_offset |
715 		     glyph_string->glyphs[0].geometry.y_offset) == 0)
716 		{
717 			cairo_scaled_font_t *scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *) pango_font);
718 
719 			if (scaled_font) {
720 				uinfo->coverage = COVERAGE_USE_CAIRO_GLYPH;
721 
722 				ufi->using_cairo_glyph.scaled_font = cairo_scaled_font_reference (scaled_font);
723 				ufi->using_cairo_glyph.glyph_index = glyph_string->glyphs[0].glyph;
724 			}
725 		}
726 
727 		/* use pango fast path otherwise */
728 		if (G_UNLIKELY (uinfo->coverage == COVERAGE_UNKNOWN)) {
729 			uinfo->coverage = COVERAGE_USE_PANGO_GLYPH_STRING;
730 
731 			ufi->using_pango_glyph_string.font = pango_font ? g_object_ref (pango_font) : NULL;
732 			ufi->using_pango_glyph_string.glyph_string = pango_glyph_string_copy (glyph_string);
733 		}
734 	}
735 
736 	/* release internal layout resources */
737 	pango_layout_set_text (info->layout, "", -1);
738 
739 #ifdef VTE_DEBUG
740 	info->coverage_count[0]++;
741 	info->coverage_count[uinfo->coverage]++;
742 #endif
743 
744 	return uinfo;
745 }
746 
747 struct _vte_draw {
748 	GtkWidget *widget;
749 
750 	gint started;
751 
752 	struct font_info *font;
753 	struct font_info *font_bold;
754 	cairo_pattern_t *bg_pattern;
755 
756 	cairo_t *cr;
757 };
758 
759 struct _vte_draw *
_vte_draw_new(GtkWidget * widget)760 _vte_draw_new (GtkWidget *widget)
761 {
762 	struct _vte_draw *draw;
763 
764 	/* Create the structure. */
765 	draw = g_slice_new0 (struct _vte_draw);
766 	draw->widget = g_object_ref (widget);
767 
768 	_vte_debug_print (VTE_DEBUG_DRAW, "draw_new\n");
769 
770 	return draw;
771 }
772 
773 void
_vte_draw_free(struct _vte_draw * draw)774 _vte_draw_free (struct _vte_draw *draw)
775 {
776 	_vte_debug_print (VTE_DEBUG_DRAW, "draw_free\n");
777 
778 	if (draw->bg_pattern != NULL) {
779 		cairo_pattern_destroy (draw->bg_pattern);
780 		draw->bg_pattern = NULL;
781 	}
782 
783 	if (draw->font != NULL) {
784 		font_info_destroy (draw->font);
785 		draw->font = NULL;
786 	}
787 
788 	if (draw->widget != NULL) {
789 		g_object_unref (draw->widget);
790 	}
791 
792 	g_slice_free (struct _vte_draw, draw);
793 }
794 
795 void
_vte_draw_start(struct _vte_draw * draw)796 _vte_draw_start (struct _vte_draw *draw)
797 {
798 	GdkWindow *window;
799 
800 	g_return_if_fail (gtk_widget_get_realized (draw->widget));
801 
802 	_vte_debug_print (VTE_DEBUG_DRAW, "draw_start\n");
803 
804 	if (draw->started == 0) {
805 		window = gtk_widget_get_window(draw->widget);
806 		g_object_ref (window);
807 		draw->cr = gdk_cairo_create (window);
808 	}
809 
810 	draw->started++;
811 }
812 
813 void
_vte_draw_end(struct _vte_draw * draw)814 _vte_draw_end (struct _vte_draw *draw)
815 {
816 	g_return_if_fail (draw->started);
817 
818 	draw->started--;
819 	if (draw->started == 0) {
820 		cairo_destroy (draw->cr);
821 		draw->cr = NULL;
822 		g_object_unref (gtk_widget_get_window(draw->widget));
823  	}
824 
825 	_vte_debug_print (VTE_DEBUG_DRAW, "draw_end\n");
826 }
827 
828 void
_vte_draw_set_background_solid(struct _vte_draw * draw,double red,double green,double blue,double opacity)829 _vte_draw_set_background_solid(struct _vte_draw *draw,
830 			       double red,
831 			       double green,
832 			       double blue,
833 			       double opacity)
834 {
835 	if (draw->bg_pattern)
836 		cairo_pattern_destroy (draw->bg_pattern);
837 
838 	draw->bg_pattern = cairo_pattern_create_rgba (red,
839 						      green,
840 						      blue,
841 						      opacity);
842 }
843 
844 void
_vte_draw_set_background_image(struct _vte_draw * draw,VteBgSourceType type,GdkPixbuf * pixbuf,const char * filename,const PangoColor * color,double saturation)845 _vte_draw_set_background_image (struct _vte_draw *draw,
846 			        VteBgSourceType type,
847 			        GdkPixbuf *pixbuf,
848 			        const char *filename,
849 			        const PangoColor *color,
850 			        double saturation)
851 {
852 	cairo_surface_t *surface;
853 
854 	/* Need a valid draw->cr for cairo_get_target () */
855 	_vte_draw_start (draw);
856 
857 	surface = vte_bg_get_surface (vte_bg_get_for_screen (gtk_widget_get_screen (draw->widget)),
858 				     type, pixbuf, filename,
859 				     color, saturation,
860 				     cairo_get_target(draw->cr));
861 
862 	_vte_draw_end (draw);
863 
864 	if (!surface)
865 		return;
866 
867 	if (draw->bg_pattern)
868 		cairo_pattern_destroy (draw->bg_pattern);
869 
870 	draw->bg_pattern = cairo_pattern_create_for_surface (surface);
871 	cairo_surface_destroy (surface);
872 	cairo_pattern_set_extend (draw->bg_pattern, CAIRO_EXTEND_REPEAT);
873 }
874 
875 void
_vte_draw_set_background_scroll(struct _vte_draw * draw,gint x,gint y)876 _vte_draw_set_background_scroll (struct _vte_draw *draw,
877 				 gint x, gint y)
878 {
879 	cairo_matrix_t matrix;
880 
881 	_vte_debug_print (VTE_DEBUG_DRAW,
882 			"draw_set_scroll (%d, %d)\n",
883 			x, y);
884 
885 	g_return_if_fail (draw->bg_pattern != NULL);
886 
887 	cairo_matrix_init_translate (&matrix, x, y);
888 	cairo_pattern_set_matrix (draw->bg_pattern, &matrix);
889 }
890 
891 void
_vte_draw_clip(struct _vte_draw * draw,GdkRegion * region)892 _vte_draw_clip (struct _vte_draw *draw, GdkRegion *region)
893 {
894 	_vte_debug_print (VTE_DEBUG_DRAW, "draw_clip\n");
895 	gdk_cairo_region(draw->cr, region);
896 	cairo_clip (draw->cr);
897 }
898 
899 void
_vte_draw_clear(struct _vte_draw * draw,gint x,gint y,gint width,gint height)900 _vte_draw_clear (struct _vte_draw *draw, gint x, gint y, gint width, gint height)
901 {
902 	g_return_if_fail (draw->bg_pattern != NULL);
903 
904 	_vte_debug_print (VTE_DEBUG_DRAW, "draw_clear (%d, %d, %d, %d)\n",
905 			  x,y,width, height);
906 
907 	cairo_rectangle (draw->cr, x, y, width, height);
908 	cairo_set_operator (draw->cr, CAIRO_OPERATOR_SOURCE);
909 	cairo_set_source (draw->cr, draw->bg_pattern);
910 	cairo_fill (draw->cr);
911 }
912 
913 void
_vte_draw_set_text_font(struct _vte_draw * draw,const PangoFontDescription * fontdesc,VteTerminalAntiAlias antialias)914 _vte_draw_set_text_font (struct _vte_draw *draw,
915 			const PangoFontDescription *fontdesc,
916 			VteTerminalAntiAlias antialias)
917 {
918 	PangoFontDescription *bolddesc = NULL;
919 
920 	_vte_debug_print (VTE_DEBUG_DRAW, "draw_set_text_font (aa=%d)\n",
921 			  antialias);
922 
923 	if (draw->font_bold != draw->font)
924 		font_info_destroy (draw->font_bold);
925 	font_info_destroy (draw->font);
926 	draw->font = font_info_create_for_widget (draw->widget, fontdesc, antialias);
927 
928 	/* calculate bold font desc */
929 	bolddesc = pango_font_description_copy (fontdesc);
930 	pango_font_description_set_weight (bolddesc, PANGO_WEIGHT_BOLD);
931 
932 	draw->font_bold = font_info_create_for_widget (draw->widget, bolddesc, antialias);
933 	pango_font_description_free (bolddesc);
934 
935 	/* Decide if we should keep this bold font face, per bug 54926:
936 	 *  - reject bold font if it is not within 10% of normal font width
937 	 */
938 	if ( abs((draw->font_bold->width * 100 / draw->font->width) - 100) > 10 ) {
939 		font_info_destroy (draw->font_bold);
940 		draw->font_bold = draw->font;
941 	}
942 }
943 
944 void
_vte_draw_get_text_metrics(struct _vte_draw * draw,gint * width,gint * height,gint * ascent)945 _vte_draw_get_text_metrics(struct _vte_draw *draw,
946 			   gint *width, gint *height, gint *ascent)
947 {
948 	g_return_if_fail (draw->font != NULL);
949 
950 	if (width)
951 		*width  = draw->font->width;
952 	if (height)
953 		*height = draw->font->height;
954 	if (ascent)
955 		*ascent = draw->font->ascent;
956 }
957 
958 
959 int
_vte_draw_get_char_width(struct _vte_draw * draw,vteunistr c,int columns,gboolean bold)960 _vte_draw_get_char_width (struct _vte_draw *draw, vteunistr c, int columns,
961 			  gboolean bold)
962 {
963 	struct unistr_info *uinfo;
964 
965 	g_return_val_if_fail (draw->font != NULL, 0);
966 
967 	uinfo = font_info_get_unistr_info (bold ? draw->font_bold : draw->font, c);
968 	return uinfo->width;
969 }
970 
971 static gboolean
_vte_draw_has_bold(struct _vte_draw * draw)972 _vte_draw_has_bold (struct _vte_draw *draw)
973 {
974 	return (draw->font != draw->font_bold);
975 }
976 
977 static void
set_source_color_alpha(cairo_t * cr,const PangoColor * color,guchar alpha)978 set_source_color_alpha (cairo_t        *cr,
979 			const PangoColor *color,
980 			guchar alpha)
981 {
982 	cairo_set_source_rgba (cr,
983 			      color->red / 65535.,
984 			      color->green / 65535.,
985 			      color->blue / 65535.,
986 			      alpha / 255.);
987 }
988 
989 static void
_vte_draw_text_internal(struct _vte_draw * draw,struct _vte_draw_text_request * requests,gsize n_requests,const PangoColor * color,guchar alpha,gboolean bold)990 _vte_draw_text_internal (struct _vte_draw *draw,
991 			 struct _vte_draw_text_request *requests, gsize n_requests,
992 			 const PangoColor *color, guchar alpha, gboolean bold)
993 {
994 	gsize i;
995 	cairo_scaled_font_t *last_scaled_font = NULL;
996 	int n_cr_glyphs = 0;
997 	cairo_glyph_t cr_glyphs[MAX_RUN_LENGTH];
998 	struct font_info *font = bold ? draw->font_bold : draw->font;
999 
1000 	g_return_if_fail (font != NULL);
1001 
1002 	set_source_color_alpha (draw->cr, color, alpha);
1003 	cairo_set_operator (draw->cr, CAIRO_OPERATOR_OVER);
1004 
1005 	for (i = 0; i < n_requests; i++) {
1006 		vteunistr c = requests[i].c;
1007 		int x = requests[i].x;
1008 		int y = requests[i].y + font->ascent;
1009 		struct unistr_info *uinfo = font_info_get_unistr_info (font, c);
1010 		union unistr_font_info *ufi = &uinfo->ufi;
1011 
1012 		switch (uinfo->coverage) {
1013 		default:
1014 		case COVERAGE_UNKNOWN:
1015 			g_assert_not_reached ();
1016 			break;
1017 		case COVERAGE_USE_PANGO_LAYOUT_LINE:
1018 			cairo_move_to (draw->cr, x, y);
1019 			pango_cairo_show_layout_line (draw->cr,
1020 						      ufi->using_pango_layout_line.line);
1021 			break;
1022 		case COVERAGE_USE_PANGO_GLYPH_STRING:
1023 			cairo_move_to (draw->cr, x, y);
1024 			pango_cairo_show_glyph_string (draw->cr,
1025 						       ufi->using_pango_glyph_string.font,
1026 						       ufi->using_pango_glyph_string.glyph_string);
1027 			break;
1028 		case COVERAGE_USE_CAIRO_GLYPH:
1029 			if (last_scaled_font != ufi->using_cairo_glyph.scaled_font || n_cr_glyphs == MAX_RUN_LENGTH) {
1030 				if (n_cr_glyphs) {
1031 					cairo_set_scaled_font (draw->cr, last_scaled_font);
1032 					cairo_show_glyphs (draw->cr,
1033 							   cr_glyphs,
1034 							   n_cr_glyphs);
1035 					n_cr_glyphs = 0;
1036 				}
1037 				last_scaled_font = ufi->using_cairo_glyph.scaled_font;
1038 			}
1039 			cr_glyphs[n_cr_glyphs].index = ufi->using_cairo_glyph.glyph_index;
1040 			cr_glyphs[n_cr_glyphs].x = x;
1041 			cr_glyphs[n_cr_glyphs].y = y;
1042 			n_cr_glyphs++;
1043 			break;
1044 		}
1045 	}
1046 	if (n_cr_glyphs) {
1047 		cairo_set_scaled_font (draw->cr, last_scaled_font);
1048 		cairo_show_glyphs (draw->cr,
1049 				   cr_glyphs,
1050 				   n_cr_glyphs);
1051 		n_cr_glyphs = 0;
1052 	}
1053 }
1054 
1055 void
_vte_draw_text(struct _vte_draw * draw,struct _vte_draw_text_request * requests,gsize n_requests,const PangoColor * color,guchar alpha,gboolean bold)1056 _vte_draw_text (struct _vte_draw *draw,
1057 	       struct _vte_draw_text_request *requests, gsize n_requests,
1058 	       const PangoColor *color, guchar alpha, gboolean bold)
1059 {
1060 	g_return_if_fail (draw->started);
1061 
1062 	if (_vte_debug_on (VTE_DEBUG_DRAW)) {
1063 		GString *string = g_string_new ("");
1064 		gchar *str;
1065 		gsize n;
1066 		for (n = 0; n < n_requests; n++) {
1067 			g_string_append_unichar (string, requests[n].c);
1068 		}
1069 		str = g_string_free (string, FALSE);
1070 		g_printerr ("draw_text (\"%s\", len=%"G_GSIZE_FORMAT", color=(%d,%d,%d,%d), %s)\n",
1071 				str, n_requests, color->red, color->green, color->blue,
1072 				alpha, bold ? "bold" : "normal");
1073 		g_free (str);
1074 	}
1075 
1076 	_vte_draw_text_internal (draw, requests, n_requests, color, alpha, bold);
1077 
1078 	/* handle fonts that lack a bold face by double-striking */
1079 	if (bold && !_vte_draw_has_bold (draw)) {
1080 		gsize i;
1081 
1082 		/* Take a step to the right. */
1083 		for (i = 0; i < n_requests; i++) {
1084 			requests[i].x++;
1085 		}
1086 		_vte_draw_text_internal (draw, requests,
1087 					   n_requests, color, alpha, FALSE);
1088 		/* Now take a step back. */
1089 		for (i = 0; i < n_requests; i++) {
1090 			requests[i].x--;
1091 		}
1092 	}
1093 }
1094 
1095 gboolean
_vte_draw_has_char(struct _vte_draw * draw,vteunistr c,gboolean bold)1096 _vte_draw_has_char (struct _vte_draw *draw, vteunistr c, gboolean bold)
1097 {
1098 	struct unistr_info *uinfo;
1099 
1100 	_vte_debug_print (VTE_DEBUG_DRAW, "draw_has_char ('0x%04X', %s)\n", c,
1101 			  bold ? "bold" : "normal");
1102 
1103 	g_return_val_if_fail (draw->font != NULL, FALSE);
1104 
1105 	uinfo = font_info_get_unistr_info (bold ? draw->font_bold : draw->font, c);
1106 	return !uinfo->has_unknown_chars;
1107 }
1108 
1109 gboolean
_vte_draw_char(struct _vte_draw * draw,struct _vte_draw_text_request * request,const PangoColor * color,guchar alpha,gboolean bold)1110 _vte_draw_char (struct _vte_draw *draw,
1111 	       struct _vte_draw_text_request *request,
1112 	       const PangoColor *color, guchar alpha, gboolean bold)
1113 {
1114 	gboolean has_char;
1115 
1116 	_vte_debug_print (VTE_DEBUG_DRAW,
1117 			"draw_char ('%c', color=(%d,%d,%d,%d), %s)\n",
1118 			request->c,
1119 			color->red, color->green, color->blue,
1120 			alpha, bold ? "bold" : "normal");
1121 
1122 	has_char =_vte_draw_has_char (draw, request->c, bold);
1123 	if (has_char)
1124 		_vte_draw_text (draw, request, 1, color, alpha, bold);
1125 
1126 	return has_char;
1127 }
1128 
1129 void
_vte_draw_draw_rectangle(struct _vte_draw * draw,gint x,gint y,gint width,gint height,const PangoColor * color,guchar alpha)1130 _vte_draw_draw_rectangle (struct _vte_draw *draw,
1131 			 gint x, gint y, gint width, gint height,
1132 			 const PangoColor *color, guchar alpha)
1133 {
1134 	g_return_if_fail (draw->started);
1135 
1136 	_vte_debug_print (VTE_DEBUG_DRAW,
1137 			"draw_rectangle (%d, %d, %d, %d, color=(%d,%d,%d,%d))\n",
1138 			x,y,width,height,
1139 			color->red, color->green, color->blue,
1140 			alpha);
1141 
1142 	cairo_set_operator (draw->cr, CAIRO_OPERATOR_OVER);
1143 	cairo_rectangle (draw->cr, x+VTE_LINE_WIDTH/2., y+VTE_LINE_WIDTH/2., width-VTE_LINE_WIDTH, height-VTE_LINE_WIDTH);
1144 	set_source_color_alpha (draw->cr, color, alpha);
1145 	cairo_set_line_width (draw->cr, VTE_LINE_WIDTH);
1146 	cairo_stroke (draw->cr);
1147 }
1148 
1149 void
_vte_draw_fill_rectangle(struct _vte_draw * draw,gint x,gint y,gint width,gint height,const PangoColor * color,guchar alpha)1150 _vte_draw_fill_rectangle (struct _vte_draw *draw,
1151 			 gint x, gint y, gint width, gint height,
1152 			 const PangoColor *color, guchar alpha)
1153 {
1154 	g_return_if_fail (draw->started);
1155 
1156 	_vte_debug_print (VTE_DEBUG_DRAW,
1157 			"draw_fill_rectangle (%d, %d, %d, %d, color=(%d,%d,%d,%d))\n",
1158 			x,y,width,height,
1159 			color->red, color->green, color->blue,
1160 			alpha);
1161 
1162 	cairo_set_operator (draw->cr, CAIRO_OPERATOR_OVER);
1163 	cairo_rectangle (draw->cr, x, y, width, height);
1164 	set_source_color_alpha (draw->cr, color, alpha);
1165 	cairo_fill (draw->cr);
1166 }
1167