1 /* Pango
2 * pangowin32.c: Routines for handling Windows fonts
3 *
4 * Copyright (C) 1999 Red Hat Software
5 * Copyright (C) 2000 Tor Lillqvist
6 * Copyright (C) 2001 Alexander Larsson
7 * Copyright (C) 2007 Novell, 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
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
23 */
24
25 #include "config.h"
26
27 #include <string.h>
28 #include <stdlib.h>
29 #include <glib.h>
30 #include <hb.h>
31
32 #include "pango-impl-utils.h"
33 #include "pangowin32.h"
34 #include "pangowin32-private.h"
35
36 #define MAX_FREED_FONTS 256
37
38 gboolean _pango_win32_debug = FALSE;
39
40 static void pango_win32_font_dispose (GObject *object);
41 static void pango_win32_font_finalize (GObject *object);
42
43 static PangoFontDescription *pango_win32_font_describe (PangoFont *font);
44 static PangoFontDescription *pango_win32_font_describe_absolute (PangoFont *font);
45 static PangoCoverage *pango_win32_font_get_coverage (PangoFont *font,
46 PangoLanguage *lang);
47 static void pango_win32_font_get_glyph_extents (PangoFont *font,
48 PangoGlyph glyph,
49 PangoRectangle *ink_rect,
50 PangoRectangle *logical_rect);
51 static PangoFontMetrics * pango_win32_font_get_metrics (PangoFont *font,
52 PangoLanguage *lang);
53 static PangoFontMap * pango_win32_font_get_font_map (PangoFont *font);
54
55 static gboolean pango_win32_font_real_select_font (PangoFont *font,
56 HDC hdc);
57 static void pango_win32_font_real_done_font (PangoFont *font);
58 static double pango_win32_font_real_get_metrics_factor (PangoFont *font);
59
60 static void pango_win32_get_item_properties (PangoItem *item,
61 PangoUnderline *uline,
62 PangoAttrColor *uline_color,
63 gboolean *uline_set,
64 PangoAttrColor *fg_color,
65 gboolean *fg_set,
66 PangoAttrColor *bg_color,
67 gboolean *bg_set);
68
69 static hb_font_t * pango_win32_font_create_hb_font (PangoFont *font);
70
71 HFONT
_pango_win32_font_get_hfont(PangoFont * font)72 _pango_win32_font_get_hfont (PangoFont *font)
73 {
74 PangoWin32Font *win32font = (PangoWin32Font *)font;
75 PangoWin32FontCache *cache;
76
77 if (!win32font)
78 return NULL;
79
80 if (!win32font->hfont)
81 {
82 cache = pango_win32_font_map_get_font_cache (win32font->fontmap);
83 if (G_UNLIKELY (!cache))
84 return NULL;
85
86 win32font->hfont = pango_win32_font_cache_loadw (cache, &win32font->logfontw);
87 if (!win32font->hfont)
88 {
89 gchar *face_utf8 = g_utf16_to_utf8 (win32font->logfontw.lfFaceName,
90 -1, NULL, NULL, NULL);
91 g_warning ("Cannot load font '%s\n", face_utf8);
92 g_free (face_utf8);
93 return NULL;
94 }
95 }
96
97 return win32font->hfont;
98 }
99
100 /**
101 * pango_win32_get_context:
102 *
103 * Retrieves a `PangoContext` appropriate for rendering with Windows fonts.
104 *
105 * Return value: the new `PangoContext`
106 *
107 * Deprecated: 1.22: Use [func@Pango.Win32FontMap.for_display] followed by
108 * [method@Pango.FontMap.create_context] instead.
109 */
110 PangoContext *
pango_win32_get_context(void)111 pango_win32_get_context (void)
112 {
113 return pango_font_map_create_context (pango_win32_font_map_for_display ());
114 }
115
G_DEFINE_TYPE(PangoWin32Font,_pango_win32_font,PANGO_TYPE_FONT)116 G_DEFINE_TYPE (PangoWin32Font, _pango_win32_font, PANGO_TYPE_FONT)
117
118 static void
119 _pango_win32_font_init (PangoWin32Font *win32font)
120 {
121 win32font->size = -1;
122
123 win32font->metrics_by_lang = NULL;
124
125 win32font->glyph_info = g_hash_table_new_full (NULL, NULL, NULL, g_free);
126 }
127
128 static GPrivate display_dc_key = G_PRIVATE_INIT ((GDestroyNotify) DeleteDC);
129
130 HDC
_pango_win32_get_display_dc(void)131 _pango_win32_get_display_dc (void)
132 {
133 HDC hdc = g_private_get (&display_dc_key);
134
135 if (hdc == NULL)
136 {
137 hdc = CreateDC ("DISPLAY", NULL, NULL, NULL);
138
139 if (G_UNLIKELY (hdc == NULL))
140 g_warning ("CreateDC() failed");
141
142 g_private_set (&display_dc_key, hdc);
143
144 /* Also do some generic pangowin32 initialisations... this function
145 * is a suitable place for those as it is called from a couple
146 * of class_init functions.
147 */
148 #ifdef PANGO_WIN32_DEBUGGING
149 if (getenv ("PANGO_WIN32_DEBUG") != NULL)
150 _pango_win32_debug = TRUE;
151 #endif
152 }
153
154 return hdc;
155 }
156
157 /**
158 * pango_win32_get_dc:
159 *
160 * Obtains a handle to the Windows device context that is used by Pango.
161 *
162 * Return value: A handle to the Windows device context that is used by Pango.
163 **/
164 HDC
pango_win32_get_dc(void)165 pango_win32_get_dc (void)
166 {
167 return _pango_win32_get_display_dc ();
168 }
169
170 /**
171 * pango_win32_get_debug_flag:
172 *
173 * Returns whether debugging is turned on.
174 *
175 * Return value: %TRUE if debugging is turned on.
176 *
177 * Since: 1.2
178 */
179 gboolean
pango_win32_get_debug_flag(void)180 pango_win32_get_debug_flag (void)
181 {
182 return _pango_win32_debug;
183 }
184
185 static void
_pango_win32_font_class_init(PangoWin32FontClass * class)186 _pango_win32_font_class_init (PangoWin32FontClass *class)
187 {
188 GObjectClass *object_class = G_OBJECT_CLASS (class);
189 PangoFontClass *font_class = PANGO_FONT_CLASS (class);
190
191 object_class->finalize = pango_win32_font_finalize;
192 object_class->dispose = pango_win32_font_dispose;
193
194 font_class->describe = pango_win32_font_describe;
195 font_class->describe_absolute = pango_win32_font_describe_absolute;
196 font_class->get_coverage = pango_win32_font_get_coverage;
197 font_class->get_glyph_extents = pango_win32_font_get_glyph_extents;
198 font_class->get_metrics = pango_win32_font_get_metrics;
199 font_class->get_font_map = pango_win32_font_get_font_map;
200 font_class->create_hb_font = pango_win32_font_create_hb_font;
201
202 class->select_font = pango_win32_font_real_select_font;
203 class->done_font = pango_win32_font_real_done_font;
204 class->get_metrics_factor = pango_win32_font_real_get_metrics_factor;
205
206 _pango_win32_get_display_dc ();
207 }
208
209 /**
210 * pango_win32_render:
211 * @hdc: the device context
212 * @font: the font in which to draw the string
213 * @glyphs: the glyph string to draw
214 * @x: the x position of start of string (in pixels)
215 * @y: the y position of baseline (in pixels)
216 *
217 * Render a `PangoGlyphString` onto a Windows DC
218 */
219 void
pango_win32_render(HDC hdc,PangoFont * font,PangoGlyphString * glyphs,int x,int y)220 pango_win32_render (HDC hdc,
221 PangoFont *font,
222 PangoGlyphString *glyphs,
223 int x,
224 int y)
225 {
226 HFONT hfont, old_hfont = NULL;
227 int i, j, num_valid_glyphs;
228 guint16 *glyph_indexes;
229 gint *dX;
230 gint this_x;
231 gint start_x_offset, x_offset, next_x_offset, cur_y_offset; /* in Pango units */
232
233 g_return_if_fail (glyphs != NULL);
234
235 #ifdef PANGO_WIN32_DEBUGGING
236 if (_pango_win32_debug)
237 {
238 PING (("num_glyphs:%d", glyphs->num_glyphs));
239 for (i = 0; i < glyphs->num_glyphs; i++)
240 {
241 g_print (" %d:%d", glyphs->glyphs[i].glyph, glyphs->glyphs[i].geometry.width);
242 if (glyphs->glyphs[i].geometry.x_offset != 0 ||
243 glyphs->glyphs[i].geometry.y_offset != 0)
244 g_print (":%d,%d", glyphs->glyphs[i].geometry.x_offset,
245 glyphs->glyphs[i].geometry.y_offset);
246 }
247 g_print ("\n");
248 }
249 #endif
250
251 if (glyphs->num_glyphs == 0)
252 return;
253
254 hfont = _pango_win32_font_get_hfont (font);
255 if (!hfont)
256 return;
257
258 old_hfont = SelectObject (hdc, hfont);
259
260 glyph_indexes = g_new (guint16, glyphs->num_glyphs);
261 dX = g_new (INT, glyphs->num_glyphs);
262
263 /* Render glyphs using one ExtTextOutW() call for each run of glyphs
264 * that have the same y offset. The big majority of glyphs will have
265 * y offset of zero, so in general, the whole glyph string will be
266 * rendered by one call to ExtTextOutW().
267 *
268 * In order to minimize buildup of rounding errors, we keep track of
269 * where the glyphs should be rendered in Pango units, and round
270 * to pixels separately for each glyph,
271 */
272
273 i = 0;
274
275 /* Outer loop through all glyphs in string */
276 while (i < glyphs->num_glyphs)
277 {
278 cur_y_offset = glyphs->glyphs[i].geometry.y_offset;
279 num_valid_glyphs = 0;
280 x_offset = 0;
281 start_x_offset = glyphs->glyphs[i].geometry.x_offset;
282 this_x = PANGO_PIXELS (start_x_offset);
283
284 /* Inner loop through glyphs with the same y offset, or code
285 * point zero (just spacing).
286 */
287 while (i < glyphs->num_glyphs &&
288 (glyphs->glyphs[i].glyph == PANGO_GLYPH_EMPTY ||
289 cur_y_offset == glyphs->glyphs[i].geometry.y_offset))
290 {
291 if (glyphs->glyphs[i].glyph == PANGO_GLYPH_EMPTY)
292 {
293 /* PANGO_GLYPH_EMPTY glyphs should not be rendered, but their
294 * indicated width (set up by PangoLayout) should be taken
295 * into account.
296 */
297
298 /* If the string starts with spacing, must shift the
299 * starting point for the glyphs actually rendered. For
300 * spacing in the middle of the glyph string, add to the dX
301 * of the previous glyph to be rendered.
302 */
303 if (num_valid_glyphs == 0)
304 start_x_offset += glyphs->glyphs[i].geometry.width;
305 else
306 {
307 x_offset += glyphs->glyphs[i].geometry.width;
308 dX[num_valid_glyphs-1] = PANGO_PIXELS (x_offset) - this_x;
309 }
310 }
311 else
312 {
313 if (glyphs->glyphs[i].glyph & PANGO_GLYPH_UNKNOWN_FLAG)
314 {
315 /* Glyph index is actually the char value that doesn't
316 * have any glyph (ORed with the flag). We should really
317 * do the same that pango_xft_real_render() does: render
318 * a box with the char value in hex inside it in a tiny
319 * font. Later. For now, use the TrueType invalid glyph
320 * at 0.
321 */
322 glyph_indexes[num_valid_glyphs] = 0;
323 }
324 else
325 glyph_indexes[num_valid_glyphs] = glyphs->glyphs[i].glyph;
326
327 x_offset += glyphs->glyphs[i].geometry.width;
328
329 /* If the next glyph has an X offset, take that into consideration now */
330 if (i < glyphs->num_glyphs - 1)
331 next_x_offset = glyphs->glyphs[i+1].geometry.x_offset;
332 else
333 next_x_offset = 0;
334
335 dX[num_valid_glyphs] = PANGO_PIXELS (x_offset + next_x_offset) - this_x;
336
337 /* Prepare for next glyph */
338 this_x += dX[num_valid_glyphs];
339 num_valid_glyphs++;
340 }
341 i++;
342 }
343 #ifdef PANGO_WIN32_DEBUGGING
344 if (_pango_win32_debug)
345 {
346 g_print ("ExtTextOutW at %d,%d deltas:",
347 x + PANGO_PIXELS (start_x_offset),
348 y + PANGO_PIXELS (cur_y_offset));
349 for (j = 0; j < num_valid_glyphs; j++)
350 g_print (" %d", dX[j]);
351 g_print ("\n");
352 }
353 #endif
354
355 ExtTextOutW (hdc,
356 x + PANGO_PIXELS (start_x_offset),
357 y + PANGO_PIXELS (cur_y_offset),
358 ETO_GLYPH_INDEX,
359 NULL,
360 glyph_indexes, num_valid_glyphs,
361 dX);
362 x += this_x;
363 }
364
365
366 SelectObject (hdc, old_hfont); /* restore */
367 g_free (glyph_indexes);
368 g_free (dX);
369 }
370
371 /**
372 * pango_win32_render_transformed:
373 * @hdc: a windows device context
374 * @matrix: (nullable): a `PangoMatrix`
375 * @font: the font in which to draw the string
376 * @glyphs: the glyph string to draw
377 * @x: the x position of the start of the string (in Pango
378 * units in user space coordinates)
379 * @y: the y position of the baseline (in Pango units
380 * in user space coordinates)
381 *
382 * Renders a `PangoGlyphString` onto a windows DC, possibly
383 * transforming the layed-out coordinates through a transformation
384 * matrix.
385 *
386 * Note that the transformation matrix for @font is not
387 * changed, so to produce correct rendering results, the @font
388 * must have been loaded using a `PangoContext` with an identical
389 * transformation matrix to that passed in to this function.
390 */
391 void
pango_win32_render_transformed(HDC hdc,const PangoMatrix * matrix,PangoFont * font,PangoGlyphString * glyphs,int x,int y)392 pango_win32_render_transformed (HDC hdc,
393 const PangoMatrix *matrix,
394 PangoFont *font,
395 PangoGlyphString *glyphs,
396 int x,
397 int y)
398 {
399 XFORM xForm;
400 XFORM xFormPrev = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
401 int mode = GetGraphicsMode (hdc);
402
403 if (!SetGraphicsMode (hdc, GM_ADVANCED))
404 g_warning ("SetGraphicsMode() failed");
405 else if (!GetWorldTransform (hdc, &xFormPrev))
406 g_warning ("GetWorldTransform() failed");
407 else if (matrix)
408 {
409 xForm.eM11 = matrix->xx;
410 xForm.eM12 = matrix->yx;
411 xForm.eM21 = matrix->xy;
412 xForm.eM22 = matrix->yy;
413 xForm.eDx = matrix->x0;
414 xForm.eDy = matrix->y0;
415 if (!SetWorldTransform (hdc, &xForm))
416 g_warning ("GetWorldTransform() failed");
417 }
418
419 pango_win32_render (hdc, font, glyphs, x/PANGO_SCALE, y/PANGO_SCALE);
420
421 /* restore */
422 SetWorldTransform (hdc, &xFormPrev);
423 SetGraphicsMode (hdc, mode);
424 }
425
426 static void
pango_win32_font_get_glyph_extents(PangoFont * font,PangoGlyph glyph,PangoRectangle * ink_rect,PangoRectangle * logical_rect)427 pango_win32_font_get_glyph_extents (PangoFont *font,
428 PangoGlyph glyph,
429 PangoRectangle *ink_rect,
430 PangoRectangle *logical_rect)
431 {
432 PangoWin32Font *win32font = (PangoWin32Font *)font;
433 guint16 glyph_index = glyph;
434 GLYPHMETRICS gm;
435 TEXTMETRIC tm;
436 guint32 res;
437 HFONT hfont;
438 MAT2 m = {{0,1}, {0,0}, {0,0}, {0,1}};
439 PangoWin32GlyphInfo *info;
440
441 if (glyph == PANGO_GLYPH_EMPTY)
442 {
443 if (ink_rect)
444 ink_rect->x = ink_rect->width = ink_rect->y = ink_rect->height = 0;
445 if (logical_rect)
446 logical_rect->x = logical_rect->width = logical_rect->y = logical_rect->height = 0;
447 return;
448 }
449
450 if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
451 glyph_index = glyph = 0;
452
453 info = g_hash_table_lookup (win32font->glyph_info, GUINT_TO_POINTER (glyph));
454
455 if (!info)
456 {
457 HDC hdc = _pango_win32_get_display_dc ();
458
459 info = g_new0 (PangoWin32GlyphInfo, 1);
460
461 memset (&gm, 0, sizeof (gm));
462
463 hfont = _pango_win32_font_get_hfont (font);
464 SelectObject (hdc, hfont);
465 res = GetGlyphOutlineA (hdc,
466 glyph_index,
467 GGO_METRICS | GGO_GLYPH_INDEX,
468 &gm,
469 0, NULL,
470 &m);
471
472 if (res == GDI_ERROR)
473 {
474 gchar *error = g_win32_error_message (GetLastError ());
475 g_warning ("GetGlyphOutline(%04X) failed: %s\n",
476 glyph_index, error);
477 g_free (error);
478
479 /* Don't just return now, use the still zeroed out gm */
480 }
481
482 info->ink_rect.x = PANGO_SCALE * gm.gmptGlyphOrigin.x;
483 info->ink_rect.width = PANGO_SCALE * gm.gmBlackBoxX;
484 info->ink_rect.y = - PANGO_SCALE * gm.gmptGlyphOrigin.y;
485 info->ink_rect.height = PANGO_SCALE * gm.gmBlackBoxY;
486
487 GetTextMetrics (hdc, &tm);
488 info->logical_rect.x = 0;
489 info->logical_rect.width = PANGO_SCALE * gm.gmCellIncX;
490 info->logical_rect.y = - PANGO_SCALE * tm.tmAscent;
491 info->logical_rect.height = PANGO_SCALE * (tm.tmAscent + tm.tmDescent);
492
493 g_hash_table_insert (win32font->glyph_info, GUINT_TO_POINTER(glyph), info);
494 }
495
496 if (ink_rect)
497 *ink_rect = info->ink_rect;
498
499 if (logical_rect)
500 *logical_rect = info->logical_rect;
501 }
502
503 static int
max_glyph_width(PangoLayout * layout)504 max_glyph_width (PangoLayout *layout)
505 {
506 int max_width = 0;
507 GSList *l, *r;
508
509 for (l = pango_layout_get_lines_readonly (layout); l; l = l->next)
510 {
511 PangoLayoutLine *line = l->data;
512
513 for (r = line->runs; r; r = r->next)
514 {
515 PangoGlyphString *glyphs = ((PangoGlyphItem *)r->data)->glyphs;
516 int i;
517
518 for (i = 0; i < glyphs->num_glyphs; i++)
519 if (glyphs->glyphs[i].geometry.width > max_width)
520 max_width = glyphs->glyphs[i].geometry.width;
521 }
522 }
523
524 return max_width;
525 }
526
527 static PangoFontMetrics *
pango_win32_font_get_metrics(PangoFont * font,PangoLanguage * language)528 pango_win32_font_get_metrics (PangoFont *font,
529 PangoLanguage *language)
530 {
531 PangoWin32MetricsInfo *info = NULL; /* Quiet gcc */
532 PangoWin32Font *win32font = (PangoWin32Font *)font;
533 GSList *tmp_list;
534
535 const char *sample_str = pango_language_get_sample_string (language);
536
537 tmp_list = win32font->metrics_by_lang;
538 while (tmp_list)
539 {
540 info = tmp_list->data;
541
542 if (info->sample_str == sample_str) /* We _don't_ need strcmp */
543 break;
544
545 tmp_list = tmp_list->next;
546 }
547
548 if (!tmp_list)
549 {
550 HFONT hfont;
551 PangoFontMetrics *metrics;
552
553 info = g_new (PangoWin32MetricsInfo, 1);
554 win32font->metrics_by_lang = g_slist_prepend (win32font->metrics_by_lang, info);
555
556 info->sample_str = sample_str;
557 info->metrics = metrics = pango_font_metrics_new ();
558
559 hfont = _pango_win32_font_get_hfont (font);
560 if (hfont != NULL)
561 {
562 PangoCoverage *coverage;
563 TEXTMETRIC tm;
564 HDC hdc = _pango_win32_get_display_dc ();
565
566 SelectObject (hdc, hfont);
567 GetTextMetrics (hdc, &tm);
568
569 metrics->ascent = tm.tmAscent * PANGO_SCALE;
570 metrics->descent = tm.tmDescent * PANGO_SCALE;
571 metrics->height = (tm.tmHeight + tm.tmInternalLeading + tm.tmExternalLeading) * PANGO_SCALE;
572 metrics->approximate_char_width = tm.tmAveCharWidth * PANGO_SCALE;
573
574 coverage = pango_win32_font_get_coverage (font, language);
575 if (pango_coverage_get (coverage, '0') != PANGO_COVERAGE_NONE &&
576 pango_coverage_get (coverage, '9') != PANGO_COVERAGE_NONE)
577 {
578 PangoContext *context;
579 PangoFontDescription *font_desc;
580 PangoLayout *layout;
581
582 /* Get the average width of the chars in "0123456789" */
583 context = pango_font_map_create_context (pango_win32_font_map_for_display ());
584 pango_context_set_language (context, language);
585 font_desc = pango_font_describe_with_absolute_size (font);
586 pango_context_set_font_description (context, font_desc);
587 layout = pango_layout_new (context);
588 pango_layout_set_text (layout, "0123456789", -1);
589
590 metrics->approximate_digit_width = max_glyph_width (layout);
591
592 pango_font_description_free (font_desc);
593 g_object_unref (layout);
594 g_object_unref (context);
595 }
596 else
597 metrics->approximate_digit_width = metrics->approximate_char_width;
598
599 pango_coverage_unref (coverage);
600
601 /* FIXME: Should get the real values from the TrueType font file */
602 metrics->underline_position = -2 * PANGO_SCALE;
603 metrics->underline_thickness = 1 * PANGO_SCALE;
604 metrics->strikethrough_thickness = metrics->underline_thickness;
605 /* Really really wild guess */
606 metrics->strikethrough_position = metrics->ascent / 3;
607 }
608 }
609
610 return pango_font_metrics_ref (info->metrics);
611 }
612
613 static PangoFontMap *
pango_win32_font_get_font_map(PangoFont * font)614 pango_win32_font_get_font_map (PangoFont *font)
615 {
616 PangoWin32Font *win32font = (PangoWin32Font *)font;
617
618 return win32font->fontmap;
619 }
620
621 static gboolean
pango_win32_font_real_select_font(PangoFont * font,HDC hdc)622 pango_win32_font_real_select_font (PangoFont *font,
623 HDC hdc)
624 {
625 HFONT hfont = _pango_win32_font_get_hfont (font);
626
627 if (!hfont)
628 return FALSE;
629
630 if (!SelectObject (hdc, hfont))
631 {
632 g_warning ("pango_win32_font_real_select_font: Cannot select font\n");
633 return FALSE;
634 }
635
636 return TRUE;
637 }
638
639 static void
pango_win32_font_real_done_font(PangoFont * font)640 pango_win32_font_real_done_font (PangoFont *font)
641 {
642 }
643
644 static double
pango_win32_font_real_get_metrics_factor(PangoFont * font)645 pango_win32_font_real_get_metrics_factor (PangoFont *font)
646 {
647 return PANGO_SCALE;
648 }
649
650 /**
651 * pango_win32_font_logfont:
652 * @font: a `PangoFont` which must be from the Win32 backend
653 *
654 * Determine the LOGFONTA struct for the specified font. Note that
655 * Pango internally uses LOGFONTW structs, so if converting the UTF-16
656 * face name in the LOGFONTW struct to system codepage fails, the
657 * returned LOGFONTA will have an emppty face name. To get the
658 * LOGFONTW of a PangoFont, use pango_win32_font_logfontw(). It
659 * is recommended to do that always even if you don't expect
660 * to come across fonts with odd names.
661 *
662 * Return value: A newly allocated LOGFONTA struct. It must be
663 * freed with g_free().
664 */
665 LOGFONTA *
pango_win32_font_logfont(PangoFont * font)666 pango_win32_font_logfont (PangoFont *font)
667 {
668 PangoWin32Font *win32font = (PangoWin32Font *)font;
669 LOGFONTA *lfp;
670
671 g_return_val_if_fail (font != NULL, NULL);
672 g_return_val_if_fail (PANGO_WIN32_IS_FONT (font), NULL);
673
674 lfp = g_new (LOGFONTA, 1);
675
676 *lfp = *(LOGFONTA*) &win32font->logfontw;
677 if (!WideCharToMultiByte (CP_ACP, 0,
678 win32font->logfontw.lfFaceName, -1,
679 lfp->lfFaceName, G_N_ELEMENTS (lfp->lfFaceName),
680 NULL, NULL))
681 lfp->lfFaceName[0] = '\0';
682
683 return lfp;
684 }
685
686 /**
687 * pango_win32_font_logfontw:
688 * @font: a `PangoFont` which must be from the Win32 backend
689 *
690 * Determine the LOGFONTW struct for the specified font.
691 *
692 * Return value: A newly allocated LOGFONTW struct. It must be
693 * freed with g_free().
694 *
695 * Since: 1.16
696 **/
697 LOGFONTW *
pango_win32_font_logfontw(PangoFont * font)698 pango_win32_font_logfontw (PangoFont *font)
699 {
700 PangoWin32Font *win32font = (PangoWin32Font *)font;
701 LOGFONTW *lfp;
702
703 g_return_val_if_fail (font != NULL, NULL);
704 g_return_val_if_fail (PANGO_WIN32_IS_FONT (font), NULL);
705
706 lfp = g_new (LOGFONTW, 1);
707 *lfp = win32font->logfontw;
708
709 return lfp;
710 }
711
712 /**
713 * pango_win32_font_select_font:
714 * @font: a `PangoFont` from the Win32 backend
715 * @hdc: a windows device context
716 *
717 * Selects the font into the specified DC and changes the mapping mode
718 * and world transformation of the DC appropriately for the font.
719 *
720 * You may want to surround the use of this function with calls
721 * to SaveDC() and RestoreDC(). Call [method@Pango.Win32Font.done_font[ when
722 * you are done using the DC to release allocated resources.
723 *
724 * See [method@Pango.Win32Font.get_metrics_factor] for information about
725 * converting from the coordinate space used by this function
726 * into Pango units.
727 *
728 * Return value: %TRUE if the operation succeeded.
729 */
730 gboolean
pango_win32_font_select_font(PangoFont * font,HDC hdc)731 pango_win32_font_select_font (PangoFont *font,
732 HDC hdc)
733 {
734 g_return_val_if_fail (PANGO_WIN32_IS_FONT (font), FALSE);
735
736 return PANGO_WIN32_FONT_GET_CLASS (font)->select_font (font, hdc);
737 }
738
739 /**
740 * pango_win32_font_done_font:
741 * @font: a `PangoFont` from the win32 backend
742 *
743 * Releases any resources allocated by [method@Pango.Win32Font.select_font].
744 */
745 void
pango_win32_font_done_font(PangoFont * font)746 pango_win32_font_done_font (PangoFont *font)
747 {
748 g_return_if_fail (PANGO_WIN32_IS_FONT (font));
749
750 PANGO_WIN32_FONT_GET_CLASS (font)->done_font (font);
751 }
752
753 /**
754 * pango_win32_font_get_metrics_factor:
755 * @font: a `PangoFont` from the win32 backend
756 *
757 * Returns the scale factor from logical units in the coordinate
758 * space used by [method@Pango.Win32Font.select_font] to Pango
759 * units in user space.
760 *
761 * Return value: factor to multiply logical units by to get Pango
762 * units.
763 */
764 double
pango_win32_font_get_metrics_factor(PangoFont * font)765 pango_win32_font_get_metrics_factor (PangoFont *font)
766 {
767 g_return_val_if_fail (PANGO_WIN32_IS_FONT (font), 1.);
768
769 return PANGO_WIN32_FONT_GET_CLASS (font)->get_metrics_factor (font);
770 }
771
772 static void
pango_win32_fontmap_cache_add(PangoFontMap * fontmap,PangoWin32Font * win32font)773 pango_win32_fontmap_cache_add (PangoFontMap *fontmap,
774 PangoWin32Font *win32font)
775 {
776 PangoWin32FontMap *win32fontmap = PANGO_WIN32_FONT_MAP (fontmap);
777
778 if (win32fontmap->freed_fonts->length == MAX_FREED_FONTS)
779 {
780 PangoWin32Font *old_font = g_queue_pop_tail (win32fontmap->freed_fonts);
781 g_object_unref (old_font);
782 }
783
784 g_object_ref (win32font);
785 g_queue_push_head (win32fontmap->freed_fonts, win32font);
786 win32font->in_cache = TRUE;
787 }
788
789 static void
pango_win32_font_dispose(GObject * object)790 pango_win32_font_dispose (GObject *object)
791 {
792 PangoWin32Font *win32font = PANGO_WIN32_FONT (object);
793
794 /* If the font is not already in the freed-fonts cache, add it,
795 * if it is already there, do nothing and the font will be
796 * freed.
797 */
798 if (!win32font->in_cache && win32font->fontmap)
799 pango_win32_fontmap_cache_add (win32font->fontmap, win32font);
800
801 G_OBJECT_CLASS (_pango_win32_font_parent_class)->dispose (object);
802 }
803
804 static void
free_metrics_info(PangoWin32MetricsInfo * info)805 free_metrics_info (PangoWin32MetricsInfo *info)
806 {
807 pango_font_metrics_unref (info->metrics);
808 g_free (info);
809 }
810
811 static void
pango_win32_font_entry_remove(PangoWin32Face * face,PangoFont * font)812 pango_win32_font_entry_remove (PangoWin32Face *face,
813 PangoFont *font)
814 {
815 face->cached_fonts = g_slist_remove (face->cached_fonts, font);
816 }
817
818 static void
pango_win32_font_finalize(GObject * object)819 pango_win32_font_finalize (GObject *object)
820 {
821 PangoWin32Font *win32font = (PangoWin32Font *)object;
822 PangoWin32FontCache *cache = pango_win32_font_map_get_font_cache (win32font->fontmap);
823 PangoWin32Font *fontmap;
824
825 if (cache != NULL && win32font->hfont != NULL)
826 pango_win32_font_cache_unload (cache, win32font->hfont);
827
828 g_slist_foreach (win32font->metrics_by_lang, (GFunc)free_metrics_info, NULL);
829 g_slist_free (win32font->metrics_by_lang);
830
831 if (win32font->win32face)
832 pango_win32_font_entry_remove (win32font->win32face, PANGO_FONT (win32font));
833
834 g_hash_table_destroy (win32font->glyph_info);
835
836 fontmap = g_weak_ref_get ((GWeakRef *) &win32font->fontmap);
837 if (fontmap)
838 {
839 g_object_remove_weak_pointer (G_OBJECT (win32font->fontmap), (gpointer *) (gpointer) &win32font->fontmap);
840 g_object_unref (fontmap);
841 }
842
843 G_OBJECT_CLASS (_pango_win32_font_parent_class)->finalize (object);
844 }
845
846 static PangoFontDescription *
pango_win32_font_describe(PangoFont * font)847 pango_win32_font_describe (PangoFont *font)
848 {
849 PangoFontDescription *desc;
850 PangoWin32Font *win32font = PANGO_WIN32_FONT (font);
851
852 desc = pango_font_description_copy (win32font->win32face->description);
853 pango_font_description_set_size (desc, win32font->size / (PANGO_SCALE / PANGO_WIN32_FONT_MAP (win32font->fontmap)->resolution));
854
855 return desc;
856 }
857
858 static PangoFontDescription *
pango_win32_font_describe_absolute(PangoFont * font)859 pango_win32_font_describe_absolute (PangoFont *font)
860 {
861 PangoFontDescription *desc;
862 PangoWin32Font *win32font = PANGO_WIN32_FONT (font);
863
864 desc = pango_font_description_copy (win32font->win32face->description);
865 pango_font_description_set_absolute_size (desc, win32font->size);
866
867 return desc;
868 }
869
870 static PangoCoverage *
pango_win32_font_get_coverage(PangoFont * font,PangoLanguage * lang G_GNUC_UNUSED)871 pango_win32_font_get_coverage (PangoFont *font,
872 PangoLanguage *lang G_GNUC_UNUSED)
873 {
874 PangoWin32Face *win32face = ((PangoWin32Font *)font)->win32face;
875
876 if (!win32face->coverage)
877 {
878 PangoCoverage *coverage = pango_coverage_new ();
879 hb_font_t *hb_font = pango_font_get_hb_font (font);
880 hb_face_t *hb_face = hb_font_get_face (hb_font);
881 hb_set_t *chars = hb_set_create ();
882 hb_codepoint_t ch = HB_SET_VALUE_INVALID;
883
884 hb_face_collect_unicodes (hb_face, chars);
885 while (hb_set_next(chars, &ch))
886 pango_coverage_set (coverage, ch, PANGO_COVERAGE_EXACT);
887
888 win32face->coverage = pango_coverage_ref (coverage);
889 }
890
891 return pango_coverage_ref (win32face->coverage);
892 }
893
894 /* Utility functions */
895
896 /**
897 * pango_win32_get_unknown_glyph:
898 * @font: a `PangoFont`
899 * @wc: the Unicode character for which a glyph is needed
900 *
901 * Returns the index of a glyph suitable for drawing @wc as an
902 * unknown character.
903 *
904 * Use PANGO_GET_UNKNOWN_GLYPH() instead.
905 *
906 * Return value: a glyph index into @font
907 */
908 PangoGlyph
pango_win32_get_unknown_glyph(PangoFont * font,gunichar wc)909 pango_win32_get_unknown_glyph (PangoFont *font,
910 gunichar wc)
911 {
912 return PANGO_GET_UNKNOWN_GLYPH (wc);
913 }
914
915 /**
916 * pango_win32_render_layout_line:
917 * @hdc: DC to use for drawing
918 * @line: a `PangoLayoutLine`
919 * @x: the x position of start of string (in pixels)
920 * @y: the y position of baseline (in pixels)
921 *
922 * Render a `PangoLayoutLine` onto a device context.
923 *
924 * For underlining to work property the text alignment
925 * of the DC should have TA_BASELINE and TA_LEFT.
926 */
927 void
pango_win32_render_layout_line(HDC hdc,PangoLayoutLine * line,int x,int y)928 pango_win32_render_layout_line (HDC hdc,
929 PangoLayoutLine *line,
930 int x,
931 int y)
932 {
933 GSList *tmp_list = line->runs;
934 PangoRectangle overall_rect;
935 PangoRectangle logical_rect;
936 PangoRectangle ink_rect;
937 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
938
939 int x_off = 0;
940
941 pango_layout_line_get_extents (line,NULL, &overall_rect);
942
943 while (tmp_list)
944 {
945 COLORREF oldfg = 0;
946 HPEN uline_pen, old_pen;
947 POINT points[2];
948 PangoUnderline uline = PANGO_UNDERLINE_NONE;
949 PangoLayoutRun *run = tmp_list->data;
950 PangoAttrColor fg_color, bg_color, uline_color;
951 gboolean fg_set, bg_set, uline_set;
952
953 tmp_list = tmp_list->next;
954
955 pango_win32_get_item_properties (run->item, &uline, &uline_color, &uline_set, &fg_color, &fg_set, &bg_color, &bg_set);
956 if (!uline_set)
957 uline_color = fg_color;
958
959 if (uline == PANGO_UNDERLINE_NONE)
960 pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
961 NULL, &logical_rect);
962 else
963 pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
964 &ink_rect, &logical_rect);
965
966 if (bg_set)
967 {
968 COLORREF bg_col = RGB ((bg_color.color.red) >> 8,
969 (bg_color.color.green) >> 8,
970 (bg_color.color.blue) >> 8);
971 HBRUSH bg_brush = CreateSolidBrush (bg_col);
972 HBRUSH old_brush = SelectObject (hdc, bg_brush);
973 old_pen = SelectObject (hdc, GetStockObject (NULL_PEN));
974 Rectangle (hdc, x + PANGO_PIXELS (x_off + logical_rect.x),
975 y + PANGO_PIXELS (overall_rect.y),
976 1 + x + PANGO_PIXELS (x_off + logical_rect.x + logical_rect.width),
977 1 + y + PANGO_PIXELS (overall_rect.y + overall_rect.height));
978 SelectObject (hdc, old_brush);
979 DeleteObject (bg_brush);
980 SelectObject (hdc, old_pen);
981 }
982
983 if (fg_set)
984 {
985 COLORREF fg_col = RGB ((fg_color.color.red) >> 8,
986 (fg_color.color.green) >> 8,
987 (fg_color.color.blue) >> 8);
988 oldfg = SetTextColor (hdc, fg_col);
989 }
990
991 pango_win32_render (hdc, run->item->analysis.font, run->glyphs,
992 x + PANGO_PIXELS (x_off), y);
993
994 if (fg_set)
995 SetTextColor (hdc, oldfg);
996
997 if (uline != PANGO_UNDERLINE_NONE)
998 {
999 COLORREF uline_col = RGB ((uline_color.color.red) >> 8,
1000 (uline_color.color.green) >> 8,
1001 (uline_color.color.blue) >> 8);
1002 uline_pen = CreatePen (PS_SOLID, 1, uline_col);
1003 old_pen = SelectObject (hdc, uline_pen);
1004 }
1005
1006 switch (uline)
1007 {
1008 case PANGO_UNDERLINE_NONE:
1009 break;
1010 case PANGO_UNDERLINE_DOUBLE:
1011 points[0].x = x + PANGO_PIXELS (x_off + ink_rect.x) - 1;
1012 points[0].y = points[1].y = y + 4;
1013 points[1].x = x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width);
1014 Polyline (hdc, points, 2);
1015 points[0].y = points[1].y = y + 2;
1016 Polyline (hdc, points, 2);
1017 break;
1018 case PANGO_UNDERLINE_SINGLE:
1019 points[0].x = x + PANGO_PIXELS (x_off + ink_rect.x) - 1;
1020 points[0].y = points[1].y = y + 2;
1021 points[1].x = x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width);
1022 Polyline (hdc, points, 2);
1023 break;
1024 case PANGO_UNDERLINE_ERROR:
1025 {
1026 int point_x;
1027 int counter = 0;
1028 int end_x = x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width);
1029
1030 for (point_x = x + PANGO_PIXELS (x_off + ink_rect.x) - 1;
1031 point_x <= end_x;
1032 point_x += 2)
1033 {
1034 points[0].x = point_x;
1035 points[1].x = MAX (point_x + 1, end_x);
1036
1037 if (counter)
1038 points[0].y = points[1].y = y + 2;
1039 else
1040 points[0].y = points[1].y = y + 3;
1041
1042 Polyline (hdc, points, 2);
1043 counter = (counter + 1) % 2;
1044 }
1045 }
1046 break;
1047 case PANGO_UNDERLINE_LOW:
1048 points[0].x = x + PANGO_PIXELS (x_off + ink_rect.x) - 1;
1049 points[0].y = points[1].y = y + PANGO_PIXELS (ink_rect.y + ink_rect.height) + 2;
1050 points[1].x = x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width);
1051 Polyline (hdc, points, 2);
1052 break;
1053 case PANGO_UNDERLINE_SINGLE_LINE:
1054 case PANGO_UNDERLINE_DOUBLE_LINE:
1055 case PANGO_UNDERLINE_ERROR_LINE:
1056 g_warning ("Underline value %d not implemented", uline);
1057 break;
1058 }
1059
1060 if (uline != PANGO_UNDERLINE_NONE)
1061 {
1062 SelectObject (hdc, old_pen);
1063 DeleteObject (uline_pen);
1064 }
1065
1066 x_off += logical_rect.width;
1067 }
1068
1069 SetBkMode (hdc, oldbkmode);
1070 }
1071
1072 /**
1073 * pango_win32_render_layout:
1074 * @hdc: HDC to use for drawing
1075 * @layout: a `PangoLayout`
1076 * @x: the X position of the left of the layout (in pixels)
1077 * @y: the Y position of the top of the layout (in pixels)
1078 *
1079 * Render a `PangoLayoutLine` onto an HDC.
1080 */
1081 void
pango_win32_render_layout(HDC hdc,PangoLayout * layout,int x,int y)1082 pango_win32_render_layout (HDC hdc,
1083 PangoLayout *layout,
1084 int x,
1085 int y)
1086 {
1087 PangoLayoutIter *iter;
1088
1089 g_return_if_fail (hdc != NULL);
1090 g_return_if_fail (PANGO_IS_LAYOUT (layout));
1091
1092 iter = pango_layout_get_iter (layout);
1093
1094 do
1095 {
1096 PangoRectangle logical_rect;
1097 PangoLayoutLine *line;
1098 int baseline;
1099
1100 line = pango_layout_iter_get_line_readonly (iter);
1101
1102 pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
1103 baseline = pango_layout_iter_get_baseline (iter);
1104
1105 pango_win32_render_layout_line (hdc,
1106 line,
1107 x + PANGO_PIXELS (logical_rect.x),
1108 y + PANGO_PIXELS (baseline));
1109 }
1110 while (pango_layout_iter_next_line (iter));
1111
1112 pango_layout_iter_free (iter);
1113 }
1114
1115 /* This utility function is duplicated here and in pango-layout.c; should it be
1116 * public? Trouble is - what is the appropriate set of properties?
1117 */
1118 static void
pango_win32_get_item_properties(PangoItem * item,PangoUnderline * uline,PangoAttrColor * uline_color,gboolean * uline_set,PangoAttrColor * fg_color,gboolean * fg_set,PangoAttrColor * bg_color,gboolean * bg_set)1119 pango_win32_get_item_properties (PangoItem *item,
1120 PangoUnderline *uline,
1121 PangoAttrColor *uline_color,
1122 gboolean *uline_set,
1123 PangoAttrColor *fg_color,
1124 gboolean *fg_set,
1125 PangoAttrColor *bg_color,
1126 gboolean *bg_set)
1127 {
1128 GSList *tmp_list = item->analysis.extra_attrs;
1129
1130 if (fg_set)
1131 *fg_set = FALSE;
1132
1133 if (bg_set)
1134 *bg_set = FALSE;
1135
1136 while (tmp_list)
1137 {
1138 PangoAttribute *attr = tmp_list->data;
1139
1140 switch (attr->klass->type)
1141 {
1142 case PANGO_ATTR_UNDERLINE:
1143 if (uline)
1144 *uline = ((PangoAttrInt *)attr)->value;
1145 break;
1146
1147 case PANGO_ATTR_UNDERLINE_COLOR:
1148 if (uline_color)
1149 *uline_color = *((PangoAttrColor *)attr);
1150 if (uline_set)
1151 *uline_set = TRUE;
1152
1153 break;
1154
1155 case PANGO_ATTR_FOREGROUND:
1156 if (fg_color)
1157 *fg_color = *((PangoAttrColor *)attr);
1158 if (fg_set)
1159 *fg_set = TRUE;
1160
1161 break;
1162
1163 case PANGO_ATTR_BACKGROUND:
1164 if (bg_color)
1165 *bg_color = *((PangoAttrColor *)attr);
1166 if (bg_set)
1167 *bg_set = TRUE;
1168
1169 break;
1170
1171 default:
1172 break;
1173 }
1174 tmp_list = tmp_list->next;
1175 }
1176 }
1177
1178 /**
1179 * pango_win32_font_get_glyph_index:
1180 * @font: a `PangoFont`
1181 * @wc: a Unicode character
1182 *
1183 * Obtains the index of the glyph for @wc in @font, or 0, if not
1184 * covered.
1185 *
1186 * Return value: the glyph index for @wc.
1187 */
1188 gint
pango_win32_font_get_glyph_index(PangoFont * font,gunichar wc)1189 pango_win32_font_get_glyph_index (PangoFont *font,
1190 gunichar wc)
1191 {
1192 hb_font_t *hb_font = pango_font_get_hb_font (font);
1193 hb_codepoint_t glyph = 0;
1194
1195 hb_font_get_nominal_glyph (hb_font, wc, &glyph);
1196
1197 return glyph;
1198 }
1199
1200 /*
1201 * Swap HarfBuzz-style tags to tags that GetFontData() understands,
1202 * adapted from https://github.com/harfbuzz/harfbuzz/pull/1832,
1203 * by Ebrahim Byagowi.
1204 */
1205
hb_gdi_uint16_swap(const guint16 v)1206 static inline guint16 hb_gdi_uint16_swap (const guint16 v)
1207 { return (v >> 8) | (v << 8); }
hb_gdi_uint32_swap(const guint32 v)1208 static inline guint32 hb_gdi_uint32_swap (const guint32 v)
1209 { return (hb_gdi_uint16_swap (v) << 16) | hb_gdi_uint16_swap (v >> 16); }
1210
1211 /*
1212 * Adapted from https://www.mail-archive.com/harfbuzz@lists.freedesktop.org/msg06538.html
1213 * by Konstantin Ritt.
1214 */
1215 static hb_blob_t *
hfont_reference_table(hb_face_t * face,hb_tag_t tag,void * user_data)1216 hfont_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data)
1217 {
1218 HDC hdc;
1219 HFONT hfont, old_hfont;
1220 gchar *buf = NULL;
1221 DWORD size;
1222
1223 /* We have a common DC for our PangoWin32Font, so let's just use it */
1224 hdc = _pango_win32_get_display_dc ();
1225 hfont = (HFONT) user_data;
1226
1227 /* we want to restore things, just to be safe */
1228 old_hfont = SelectObject (hdc, hfont);
1229 if (old_hfont == NULL)
1230 {
1231 g_warning ("SelectObject() for the PangoWin32Font failed!");
1232 return hb_blob_get_empty ();
1233 }
1234
1235 size = GetFontData (hdc, hb_gdi_uint32_swap (tag), 0, NULL, 0);
1236
1237 /*
1238 * not all tags support retrieving the sizes, so don't warn,
1239 * just return hb_blob_get_empty()
1240 */
1241 if (size == GDI_ERROR)
1242 {
1243 SelectObject (hdc, old_hfont);
1244 return hb_blob_get_empty ();
1245 }
1246
1247 buf = g_malloc (size * sizeof (gchar));
1248
1249 /* This should be quite unlikely to fail if size was not GDI_ERROR */
1250 if (GetFontData (hdc, hb_gdi_uint32_swap (tag), 0, buf, size) == GDI_ERROR)
1251 size = 0;
1252
1253 SelectObject (hdc, old_hfont);
1254 return hb_blob_create (buf, size, HB_MEMORY_MODE_READONLY, buf, g_free);
1255 }
1256
1257 static hb_font_t *
pango_win32_font_create_hb_font(PangoFont * font)1258 pango_win32_font_create_hb_font (PangoFont *font)
1259 {
1260 PangoWin32Font *win32font = (PangoWin32Font *)font;
1261 HFONT hfont;
1262 hb_face_t *face = NULL;
1263 hb_font_t *hb_font = NULL;
1264
1265 g_return_val_if_fail (font != NULL, NULL);
1266
1267 hfont = _pango_win32_font_get_hfont (font);
1268
1269 /* We are *not* allowed to destroy the HFONT here ! */
1270 face = hb_face_create_for_tables (hfont_reference_table, (void *)hfont, NULL);
1271
1272 hb_font = hb_font_create (face);
1273 hb_font_set_scale (hb_font, win32font->size, win32font->size);
1274 hb_face_destroy (face);
1275
1276 return hb_font;
1277 }
1278
1279 gpointer
_pango_win32_copy_cmap(gpointer cmap,guint16 cmap_format)1280 _pango_win32_copy_cmap (gpointer cmap, guint16 cmap_format)
1281 {
1282 if (!cmap)
1283 return NULL;
1284
1285 if (cmap_format == 12)
1286 {
1287 struct format_12_cmap *new_table;
1288 struct format_12_cmap *old_table;
1289 guint32 *tbl, *tbl_end;
1290
1291 old_table = (struct format_12_cmap *) cmap;
1292
1293 new_table = g_malloc (old_table->length);
1294 memcpy (old_table, new_table, sizeof (struct format_12_cmap));
1295
1296 tbl_end = (guint32 *) ((char *) new_table + new_table->length);
1297 tbl = new_table->groups;
1298
1299 while (tbl < tbl_end)
1300 {
1301 *tbl = GUINT32_FROM_BE (*tbl);
1302 tbl++;
1303 }
1304
1305 return new_table;
1306 }
1307 else if (cmap_format == 4)
1308 {
1309 struct format_4_cmap *new_table;
1310 struct format_4_cmap *old_table;
1311 guint16 *tbl, *tbl_end;
1312
1313 old_table = (struct format_4_cmap *) cmap;
1314
1315 new_table = g_malloc (old_table->length);
1316 memcpy (old_table, new_table, sizeof (struct format_4_cmap));
1317
1318 tbl_end = (guint16 *)((char *) new_table + new_table->length);
1319 tbl = &new_table->reserved;
1320
1321 while (tbl < tbl_end)
1322 {
1323 *tbl = GUINT16_FROM_BE (*tbl);
1324 tbl++;
1325 }
1326
1327 return new_table;
1328 }
1329 else
1330 {
1331 /* got non-null cmap but unknown format, it shouldn't happen */
1332 g_assert_not_reached ();
1333 }
1334
1335 return NULL;
1336 }
1337