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