1 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 /* cairo - a vector graphics library with display and print output
3  *
4  * Copyright © 2005 Red Hat, Inc
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it either under the terms of the GNU Lesser General Public
8  * License version 2.1 as published by the Free Software Foundation
9  * (the "LGPL") or, at your option, under the terms of the Mozilla
10  * Public License Version 1.1 (the "MPL"). If you do not alter this
11  * notice, a recipient may use your version of this file under either
12  * the MPL or the LGPL.
13  *
14  * You should have received a copy of the LGPL along with this library
15  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17  * You should have received a copy of the MPL along with this library
18  * in the file COPYING-MPL-1.1
19  *
20  * The contents of this file are subject to the Mozilla Public License
21  * Version 1.1 (the "License"); you may not use this file except in
22  * compliance with the License. You may obtain a copy of the License at
23  * http://www.mozilla.org/MPL/
24  *
25  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27  * the specific language governing rights and limitations.
28  *
29  * The Original Code is the cairo graphics library.
30  *
31  * The Initial Developer of the Original Code is Red Hat, Inc.
32  *
33  * Contributor(s):
34  */
35 
36 #define WIN32_LEAN_AND_MEAN
37 /* We require Windows 2000 features such as GetGlyphIndices */
38 #if !defined(WINVER) || (WINVER < 0x0500)
39 # define WINVER 0x0500
40 #endif
41 #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
42 # define _WIN32_WINNT 0x0500
43 #endif
44 
45 #include "cairoint.h"
46 
47 #include "cairo-win32-private.h"
48 #include "cairo-error-private.h"
49 
50 #include <wchar.h>
51 
52 #ifndef SPI_GETFONTSMOOTHINGTYPE
53 #define SPI_GETFONTSMOOTHINGTYPE 0x200a
54 #endif
55 #ifndef FE_FONTSMOOTHINGCLEARTYPE
56 #define FE_FONTSMOOTHINGCLEARTYPE 2
57 #endif
58 #ifndef CLEARTYPE_QUALITY
59 #define CLEARTYPE_QUALITY 5
60 #endif
61 #ifndef TT_PRIM_CSPLINE
62 #define TT_PRIM_CSPLINE 3
63 #endif
64 
65 #define CMAP_TAG 0x70616d63
66 
67 /**
68  * SECTION:cairo-win32-fonts
69  * @Title: Win32 Fonts
70  * @Short_Description: Font support for Microsoft Windows
71  * @See_Also: #cairo_font_face_t
72  *
73  * The Microsoft Windows font backend is primarily used to render text on
74  * Microsoft Windows systems.
75  */
76 
77 /**
78  * CAIRO_HAS_WIN32_FONT:
79  *
80  * Defined if the Microsoft Windows font backend is available.
81  * This macro can be used to conditionally compile backend-specific code.
82  */
83 
84 const cairo_scaled_font_backend_t _cairo_win32_scaled_font_backend;
85 
86 typedef struct {
87     cairo_scaled_font_t base;
88 
89     LOGFONTW logfont;
90 
91     BYTE quality;
92 
93     /* We do drawing and metrics computation in a "logical space" which
94      * is similar to font space, except that it is scaled by a factor
95      * of the (desired font size) * (WIN32_FONT_LOGICAL_SCALE). The multiplication
96      * by WIN32_FONT_LOGICAL_SCALE allows for sub-pixel precision.
97      */
98     double logical_scale;
99 
100     /* The size we should actually request the font at from Windows; differs
101      * from the logical_scale because it is quantized for orthogonal
102      * transformations
103      */
104     double logical_size;
105 
106     /* Transformations from device <=> logical space
107      */
108     cairo_matrix_t logical_to_device;
109     cairo_matrix_t device_to_logical;
110 
111     /* We special case combinations of 90-degree-rotations, scales and
112      * flips ... that is transformations that take the axes to the
113      * axes. If preserve_axes is true, then swap_axes/swap_x/swap_y
114      * encode the 8 possibilities for orientation (4 rotation angles with
115      * and without a flip), and scale_x, scale_y the scale components.
116      */
117     cairo_bool_t preserve_axes;
118     cairo_bool_t swap_axes;
119     cairo_bool_t swap_x;
120     cairo_bool_t swap_y;
121     double x_scale;
122     double y_scale;
123 
124     /* The size of the design unit of the font
125      */
126     int em_square;
127 
128     HFONT scaled_hfont;
129     HFONT unscaled_hfont;
130 
131     cairo_bool_t is_bitmap;
132     cairo_bool_t is_type1;
133     cairo_bool_t delete_scaled_hfont;
134 } cairo_win32_scaled_font_t;
135 
136 static cairo_status_t
137 _cairo_win32_scaled_font_set_metrics (cairo_win32_scaled_font_t *scaled_font);
138 
139 static cairo_status_t
140 _cairo_win32_scaled_font_init_glyph_metrics (cairo_win32_scaled_font_t *scaled_font,
141 					     cairo_scaled_glyph_t      *scaled_glyph);
142 
143 static cairo_status_t
144 _cairo_win32_scaled_font_init_glyph_surface (cairo_win32_scaled_font_t *scaled_font,
145                                              cairo_scaled_glyph_t      *scaled_glyph);
146 
147 static cairo_status_t
148 _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font,
149 					  cairo_scaled_glyph_t      *scaled_glyph);
150 
151 #define NEARLY_ZERO(d) (fabs(d) < (1. / 65536.))
152 
153 static HDC
_get_global_font_dc(void)154 _get_global_font_dc (void)
155 {
156     static HDC hdc;
157 
158     if (!hdc) {
159 	hdc = CreateCompatibleDC (NULL);
160 	if (!hdc) {
161 	    _cairo_win32_print_gdi_error ("_get_global_font_dc");
162 	    return NULL;
163 	}
164 
165 	if (!SetGraphicsMode (hdc, GM_ADVANCED)) {
166 	    _cairo_win32_print_gdi_error ("_get_global_font_dc");
167 	    DeleteDC (hdc);
168 	    return NULL;
169 	}
170     }
171 
172     return hdc;
173 }
174 
175 static cairo_status_t
_compute_transform(cairo_win32_scaled_font_t * scaled_font,cairo_matrix_t * sc)176 _compute_transform (cairo_win32_scaled_font_t *scaled_font,
177 		    cairo_matrix_t            *sc)
178 {
179     cairo_status_t status;
180 
181     if (NEARLY_ZERO (sc->yx) && NEARLY_ZERO (sc->xy) &&
182 	    !NEARLY_ZERO(sc->xx) && !NEARLY_ZERO(sc->yy)) {
183 	scaled_font->preserve_axes = TRUE;
184 	scaled_font->x_scale = sc->xx;
185 	scaled_font->swap_x = (sc->xx < 0);
186 	scaled_font->y_scale = sc->yy;
187 	scaled_font->swap_y = (sc->yy < 0);
188 	scaled_font->swap_axes = FALSE;
189 
190     } else if (NEARLY_ZERO (sc->xx) && NEARLY_ZERO (sc->yy) &&
191 	    !NEARLY_ZERO(sc->yx) && !NEARLY_ZERO(sc->xy)) {
192 	scaled_font->preserve_axes = TRUE;
193 	scaled_font->x_scale = sc->yx;
194 	scaled_font->swap_x = (sc->yx < 0);
195 	scaled_font->y_scale = sc->xy;
196 	scaled_font->swap_y = (sc->xy < 0);
197 	scaled_font->swap_axes = TRUE;
198 
199     } else {
200 	scaled_font->preserve_axes = FALSE;
201 	scaled_font->swap_x = scaled_font->swap_y = scaled_font->swap_axes = FALSE;
202     }
203 
204     if (scaled_font->preserve_axes) {
205 	if (scaled_font->swap_x)
206 	    scaled_font->x_scale = - scaled_font->x_scale;
207 	if (scaled_font->swap_y)
208 	    scaled_font->y_scale = - scaled_font->y_scale;
209 
210 	scaled_font->logical_scale = WIN32_FONT_LOGICAL_SCALE * scaled_font->y_scale;
211 	scaled_font->logical_size = WIN32_FONT_LOGICAL_SCALE *
212                                     _cairo_lround (scaled_font->y_scale);
213     }
214 
215     /* The font matrix has x and y "scale" components which we extract and
216      * use as character scale values.
217      */
218     cairo_matrix_init (&scaled_font->logical_to_device,
219 		       sc->xx, sc->yx, sc->xy, sc->yy, 0, 0);
220 
221     if (!scaled_font->preserve_axes) {
222 	status = _cairo_matrix_compute_basis_scale_factors (&scaled_font->logical_to_device,
223 						      &scaled_font->x_scale, &scaled_font->y_scale,
224 						      TRUE);	/* XXX: Handle vertical text */
225 	if (status)
226 	    return status;
227 
228 	scaled_font->logical_size = _cairo_lround (WIN32_FONT_LOGICAL_SCALE *
229                                                    scaled_font->y_scale);
230 	scaled_font->logical_scale = WIN32_FONT_LOGICAL_SCALE * scaled_font->y_scale;
231     }
232 
233     cairo_matrix_scale (&scaled_font->logical_to_device,
234 			1.0 / scaled_font->logical_scale, 1.0 / scaled_font->logical_scale);
235 
236     scaled_font->device_to_logical = scaled_font->logical_to_device;
237 
238     status = cairo_matrix_invert (&scaled_font->device_to_logical);
239     if (status)
240 	cairo_matrix_init_identity (&scaled_font->device_to_logical);
241 
242     return CAIRO_STATUS_SUCCESS;
243 }
244 
245 static cairo_bool_t
_have_cleartype_quality(void)246 _have_cleartype_quality (void)
247 {
248     OSVERSIONINFO version_info;
249 
250     version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
251 
252     if (!GetVersionEx (&version_info)) {
253 	_cairo_win32_print_gdi_error ("_have_cleartype_quality");
254 	return FALSE;
255     }
256 
257     return (version_info.dwMajorVersion > 5 ||
258 	    (version_info.dwMajorVersion == 5 &&
259 	     version_info.dwMinorVersion >= 1));	/* XP or newer */
260 }
261 
262 BYTE
cairo_win32_get_system_text_quality(void)263 cairo_win32_get_system_text_quality (void)
264 {
265     BOOL font_smoothing;
266     UINT smoothing_type;
267 
268     if (!SystemParametersInfo (SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) {
269 	_cairo_win32_print_gdi_error ("_cairo_win32_get_system_text_quality");
270 	return DEFAULT_QUALITY;
271     }
272 
273     if (font_smoothing) {
274 	if (_have_cleartype_quality ()) {
275 	    if (!SystemParametersInfo (SPI_GETFONTSMOOTHINGTYPE,
276 				       0, &smoothing_type, 0)) {
277 		_cairo_win32_print_gdi_error ("_cairo_win32_get_system_text_quality");
278 		return DEFAULT_QUALITY;
279 	    }
280 
281 	    if (smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
282 		return CLEARTYPE_QUALITY;
283 	}
284 
285 	return ANTIALIASED_QUALITY;
286     } else {
287 	return DEFAULT_QUALITY;
288     }
289 }
290 
291 /* If face_hfont is non-%NULL then font_matrix must be a simple scale by some
292  * factor S, ctm must be the identity, logfont->lfHeight must be -S,
293  * logfont->lfWidth, logfont->lfEscapement, logfont->lfOrientation must
294  * all be 0, and face_hfont is the result of calling CreateFontIndirectW on
295  * logfont.
296  */
297 static cairo_status_t
_win32_scaled_font_create(LOGFONTW * logfont,HFONT face_hfont,cairo_font_face_t * font_face,const cairo_matrix_t * font_matrix,const cairo_matrix_t * ctm,const cairo_font_options_t * options,cairo_scaled_font_t ** font_out)298 _win32_scaled_font_create (LOGFONTW                   *logfont,
299 			   HFONT                      face_hfont,
300 			   cairo_font_face_t	      *font_face,
301 			   const cairo_matrix_t       *font_matrix,
302 			   const cairo_matrix_t       *ctm,
303 			   const cairo_font_options_t *options,
304 			   cairo_scaled_font_t       **font_out)
305 {
306     HDC hdc;
307     cairo_win32_scaled_font_t *f;
308     cairo_matrix_t scale;
309     cairo_status_t status;
310 
311     hdc = _get_global_font_dc ();
312     if (hdc == NULL)
313 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
314 
315     f = malloc (sizeof(cairo_win32_scaled_font_t));
316     if (f == NULL)
317 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
318 
319     f->logfont = *logfont;
320 
321     /* We don't have any control over the hinting style or subpixel
322      * order in the Win32 font API, so we ignore those parts of
323      * cairo_font_options_t. We use the 'antialias' field to set
324      * the 'quality'.
325      *
326      * XXX: The other option we could pay attention to, but don't
327      *      here is the hint_metrics options.
328      */
329     if (options->antialias == CAIRO_ANTIALIAS_DEFAULT)
330 	f->quality = cairo_win32_get_system_text_quality ();
331     else {
332 	switch (options->antialias) {
333 	case CAIRO_ANTIALIAS_NONE:
334 	    f->quality = NONANTIALIASED_QUALITY;
335 	    break;
336 	case CAIRO_ANTIALIAS_GRAY:
337 	    f->quality = ANTIALIASED_QUALITY;
338 	    break;
339 	case CAIRO_ANTIALIAS_SUBPIXEL:
340 	    if (_have_cleartype_quality ())
341 		f->quality = CLEARTYPE_QUALITY;
342 	    else
343 		f->quality = ANTIALIASED_QUALITY;
344 	    break;
345 	case CAIRO_ANTIALIAS_DEFAULT:
346 	    ASSERT_NOT_REACHED;
347 	}
348     }
349 
350     f->em_square = 0;
351     f->scaled_hfont = NULL;
352     f->unscaled_hfont = NULL;
353 
354     if (f->quality == logfont->lfQuality ||
355         (logfont->lfQuality == DEFAULT_QUALITY &&
356          options->antialias == CAIRO_ANTIALIAS_DEFAULT)) {
357         /* If face_hfont is non-NULL, then we can use it to avoid creating our
358          * own --- because the constraints on face_hfont mentioned above
359          * guarantee it was created in exactly the same way that
360          * _win32_scaled_font_get_scaled_hfont would create it.
361          */
362         f->scaled_hfont = face_hfont;
363     }
364     /* don't delete the hfont if we're using the one passed in to us */
365     f->delete_scaled_hfont = !f->scaled_hfont;
366 
367     cairo_matrix_multiply (&scale, font_matrix, ctm);
368     status = _compute_transform (f, &scale);
369     if (status)
370 	goto FAIL;
371 
372     status = _cairo_scaled_font_init (&f->base, font_face,
373 				      font_matrix, ctm, options,
374 				      &_cairo_win32_scaled_font_backend);
375     if (status)
376 	goto FAIL;
377 
378     status = _cairo_win32_scaled_font_set_metrics (f);
379     if (status) {
380 	_cairo_scaled_font_fini (&f->base);
381 	goto FAIL;
382     }
383 
384     *font_out = &f->base;
385     return CAIRO_STATUS_SUCCESS;
386 
387  FAIL:
388     free (f);
389     return status;
390 }
391 
392 static cairo_status_t
_win32_scaled_font_set_world_transform(cairo_win32_scaled_font_t * scaled_font,HDC hdc)393 _win32_scaled_font_set_world_transform (cairo_win32_scaled_font_t *scaled_font,
394 					HDC                        hdc)
395 {
396     XFORM xform;
397 
398     _cairo_matrix_to_win32_xform (&scaled_font->logical_to_device, &xform);
399 
400     if (!SetWorldTransform (hdc, &xform))
401 	return _cairo_win32_print_gdi_error ("_win32_scaled_font_set_world_transform");
402 
403     return CAIRO_STATUS_SUCCESS;
404 }
405 
406 static cairo_status_t
_win32_scaled_font_set_identity_transform(HDC hdc)407 _win32_scaled_font_set_identity_transform (HDC hdc)
408 {
409     if (!ModifyWorldTransform (hdc, NULL, MWT_IDENTITY))
410 	return _cairo_win32_print_gdi_error ("_win32_scaled_font_set_identity_transform");
411 
412     return CAIRO_STATUS_SUCCESS;
413 }
414 
415 static cairo_status_t
_win32_scaled_font_get_scaled_hfont(cairo_win32_scaled_font_t * scaled_font,HFONT * hfont_out)416 _win32_scaled_font_get_scaled_hfont (cairo_win32_scaled_font_t *scaled_font,
417 				     HFONT *hfont_out)
418 {
419     if (!scaled_font->scaled_hfont) {
420 	LOGFONTW logfont = scaled_font->logfont;
421 	logfont.lfHeight = -scaled_font->logical_size;
422 	logfont.lfWidth = 0;
423 	logfont.lfEscapement = 0;
424 	logfont.lfOrientation = 0;
425 	logfont.lfQuality = scaled_font->quality;
426 
427 	scaled_font->scaled_hfont = CreateFontIndirectW (&logfont);
428 	if (!scaled_font->scaled_hfont)
429 	    return _cairo_win32_print_gdi_error ("_win32_scaled_font_get_scaled_hfont");
430     }
431 
432     *hfont_out = scaled_font->scaled_hfont;
433     return CAIRO_STATUS_SUCCESS;
434 }
435 
436 static cairo_status_t
_win32_scaled_font_get_unscaled_hfont(cairo_win32_scaled_font_t * scaled_font,HDC hdc,HFONT * hfont_out)437 _win32_scaled_font_get_unscaled_hfont (cairo_win32_scaled_font_t *scaled_font,
438 				       HDC                        hdc,
439 				       HFONT			 *hfont_out)
440 {
441     if (scaled_font->unscaled_hfont == NULL) {
442 	OUTLINETEXTMETRIC *otm;
443 	unsigned int otm_size;
444 	HFONT scaled_hfont;
445 	LOGFONTW logfont;
446 	cairo_status_t status;
447 
448 	status = _win32_scaled_font_get_scaled_hfont (scaled_font,
449 						      &scaled_hfont);
450 	if (status)
451 	    return status;
452 
453 	if (! SelectObject (hdc, scaled_hfont))
454 	    return _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:SelectObject");
455 
456 	otm_size = GetOutlineTextMetrics (hdc, 0, NULL);
457 	if (! otm_size)
458 	    return _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:GetOutlineTextMetrics");
459 
460 	otm = malloc (otm_size);
461 	if (otm == NULL)
462 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
463 
464 	if (! GetOutlineTextMetrics (hdc, otm_size, otm)) {
465 	    status = _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:GetOutlineTextMetrics");
466 	    free (otm);
467 	    return status;
468 	}
469 
470 	scaled_font->em_square = otm->otmEMSquare;
471 	free (otm);
472 
473 	logfont = scaled_font->logfont;
474 	logfont.lfHeight = -scaled_font->em_square;
475 	logfont.lfWidth = 0;
476 	logfont.lfEscapement = 0;
477 	logfont.lfOrientation = 0;
478 	logfont.lfQuality = scaled_font->quality;
479 
480 	scaled_font->unscaled_hfont = CreateFontIndirectW (&logfont);
481 	if (! scaled_font->unscaled_hfont)
482 	    return _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:CreateIndirect");
483     }
484 
485     *hfont_out = scaled_font->unscaled_hfont;
486     return CAIRO_STATUS_SUCCESS;
487 }
488 
489 static cairo_status_t
_cairo_win32_scaled_font_select_unscaled_font(cairo_scaled_font_t * scaled_font,HDC hdc)490 _cairo_win32_scaled_font_select_unscaled_font (cairo_scaled_font_t *scaled_font,
491 					       HDC                  hdc)
492 {
493     cairo_status_t status;
494     HFONT hfont;
495     HFONT old_hfont = NULL;
496 
497     status = _win32_scaled_font_get_unscaled_hfont ((cairo_win32_scaled_font_t *)scaled_font, hdc, &hfont);
498     if (status)
499 	return status;
500 
501     old_hfont = SelectObject (hdc, hfont);
502     if (!old_hfont)
503 	return _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_select_unscaled_font");
504 
505     status = _win32_scaled_font_set_identity_transform (hdc);
506     if (status) {
507 	SelectObject (hdc, old_hfont);
508 	return status;
509     }
510 
511     SetMapMode (hdc, MM_TEXT);
512 
513     return CAIRO_STATUS_SUCCESS;
514 }
515 
516 cairo_bool_t
_cairo_win32_scaled_font_is_type1(cairo_scaled_font_t * scaled_font)517 _cairo_win32_scaled_font_is_type1 (cairo_scaled_font_t *scaled_font)
518 {
519     cairo_win32_scaled_font_t *win32_scaled_font;
520 
521     win32_scaled_font = (cairo_win32_scaled_font_t *) scaled_font;
522 
523     return win32_scaled_font->is_type1;
524 }
525 
526 cairo_bool_t
_cairo_win32_scaled_font_is_bitmap(cairo_scaled_font_t * scaled_font)527 _cairo_win32_scaled_font_is_bitmap (cairo_scaled_font_t *scaled_font)
528 {
529     cairo_win32_scaled_font_t *win32_scaled_font;
530 
531     win32_scaled_font = (cairo_win32_scaled_font_t *) scaled_font;
532 
533     return win32_scaled_font->is_bitmap;
534 }
535 
536 static void
_cairo_win32_scaled_font_done_unscaled_font(cairo_scaled_font_t * scaled_font)537 _cairo_win32_scaled_font_done_unscaled_font (cairo_scaled_font_t *scaled_font)
538 {
539 }
540 
541 /* implement the font backend interface */
542 
543 static cairo_status_t
_cairo_win32_font_face_create_for_toy(cairo_toy_font_face_t * toy_face,cairo_font_face_t ** font_face)544 _cairo_win32_font_face_create_for_toy (cairo_toy_font_face_t   *toy_face,
545 				       cairo_font_face_t      **font_face)
546 {
547     LOGFONTW logfont;
548     uint16_t *face_name;
549     int face_name_len;
550     cairo_status_t status;
551 
552     status = _cairo_utf8_to_utf16 (toy_face->family, -1,
553 				   &face_name, &face_name_len);
554     if (status)
555 	return status;
556 
557     if (face_name_len > LF_FACESIZE - 1)
558 	face_name_len = LF_FACESIZE - 1;
559 
560     memcpy (logfont.lfFaceName, face_name, sizeof (uint16_t) * face_name_len);
561     logfont.lfFaceName[face_name_len] = 0;
562     free (face_name);
563 
564     logfont.lfHeight = 0;	/* filled in later */
565     logfont.lfWidth = 0;	/* filled in later */
566     logfont.lfEscapement = 0;	/* filled in later */
567     logfont.lfOrientation = 0;	/* filled in later */
568 
569     switch (toy_face->weight) {
570     case CAIRO_FONT_WEIGHT_NORMAL:
571     default:
572 	logfont.lfWeight = FW_NORMAL;
573 	break;
574     case CAIRO_FONT_WEIGHT_BOLD:
575 	logfont.lfWeight = FW_BOLD;
576 	break;
577     }
578 
579     switch (toy_face->slant) {
580     case CAIRO_FONT_SLANT_NORMAL:
581     default:
582 	logfont.lfItalic = FALSE;
583 	break;
584     case CAIRO_FONT_SLANT_ITALIC:
585     case CAIRO_FONT_SLANT_OBLIQUE:
586 	logfont.lfItalic = TRUE;
587 	break;
588     }
589 
590     logfont.lfUnderline = FALSE;
591     logfont.lfStrikeOut = FALSE;
592     /* The docs for LOGFONT discourage using this, since the
593      * interpretation is locale-specific, but it's not clear what
594      * would be a better alternative.
595      */
596     logfont.lfCharSet = DEFAULT_CHARSET;
597     logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
598     logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
599     logfont.lfQuality = DEFAULT_QUALITY; /* filled in later */
600     logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
601 
602     *font_face = cairo_win32_font_face_create_for_logfontw (&logfont);
603 
604     return CAIRO_STATUS_SUCCESS;
605 }
606 
607 static void
_cairo_win32_scaled_font_fini(void * abstract_font)608 _cairo_win32_scaled_font_fini (void *abstract_font)
609 {
610     cairo_win32_scaled_font_t *scaled_font = abstract_font;
611 
612     if (scaled_font == NULL)
613 	return;
614 
615     if (scaled_font->scaled_hfont && scaled_font->delete_scaled_hfont)
616 	DeleteObject (scaled_font->scaled_hfont);
617 
618     if (scaled_font->unscaled_hfont)
619 	DeleteObject (scaled_font->unscaled_hfont);
620 }
621 
622 static cairo_int_status_t
_cairo_win32_scaled_font_type1_text_to_glyphs(cairo_win32_scaled_font_t * scaled_font,double x,double y,const char * utf8,cairo_glyph_t ** glyphs,int * num_glyphs)623 _cairo_win32_scaled_font_type1_text_to_glyphs (cairo_win32_scaled_font_t *scaled_font,
624 					       double		          x,
625 					       double		          y,
626 					       const char	         *utf8,
627 					       cairo_glyph_t            **glyphs,
628 					       int		         *num_glyphs)
629 {
630     uint16_t *utf16;
631     int n16;
632     int i;
633     WORD *glyph_indices = NULL;
634     cairo_status_t status;
635     double x_pos, y_pos;
636     HDC hdc = NULL;
637     cairo_matrix_t mat;
638 
639     status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &n16);
640     if (status)
641 	return status;
642 
643     glyph_indices = _cairo_malloc_ab (n16 + 1, sizeof (WORD));
644     if (!glyph_indices) {
645 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
646 	goto FAIL1;
647     }
648 
649     hdc = _get_global_font_dc ();
650     assert (hdc != NULL);
651 
652     status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
653     if (status)
654 	goto FAIL2;
655 
656     if (GetGlyphIndicesW (hdc, utf16, n16, glyph_indices, 0) == GDI_ERROR) {
657 	status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_type1_text_to_glyphs:GetGlyphIndicesW");
658 	goto FAIL3;
659     }
660 
661     *num_glyphs = n16;
662     *glyphs = _cairo_malloc_ab (n16, sizeof (cairo_glyph_t));
663     if (!*glyphs) {
664 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
665 	goto FAIL3;
666     }
667 
668     x_pos = x;
669     y_pos = y;
670 
671     mat = scaled_font->base.ctm;
672     status = cairo_matrix_invert (&mat);
673     assert (status == CAIRO_STATUS_SUCCESS);
674 
675     _cairo_scaled_font_freeze_cache (&scaled_font->base);
676 
677     for (i = 0; i < n16; i++) {
678 	cairo_scaled_glyph_t *scaled_glyph;
679 
680 	(*glyphs)[i].index = glyph_indices[i];
681 	(*glyphs)[i].x = x_pos;
682 	(*glyphs)[i].y = y_pos;
683 
684 	status = _cairo_scaled_glyph_lookup (&scaled_font->base,
685 					     glyph_indices[i],
686 					     CAIRO_SCALED_GLYPH_INFO_METRICS,
687 					     &scaled_glyph);
688 	if (status) {
689 	    free (*glyphs);
690 	    *glyphs = NULL;
691 	    break;
692 	}
693 
694 	x = scaled_glyph->x_advance;
695 	y = scaled_glyph->y_advance;
696 	cairo_matrix_transform_distance (&mat, &x, &y);
697 	x_pos += x;
698 	y_pos += y;
699     }
700 
701     _cairo_scaled_font_thaw_cache (&scaled_font->base);
702 
703 FAIL3:
704     cairo_win32_scaled_font_done_font (&scaled_font->base);
705 FAIL2:
706     free (glyph_indices);
707 FAIL1:
708     free (utf16);
709 
710     return status;
711 }
712 
713 static cairo_int_status_t
_cairo_win32_scaled_font_text_to_glyphs(void * abstract_font,double x,double y,const char * utf8,cairo_glyph_t ** glyphs,int * num_glyphs)714 _cairo_win32_scaled_font_text_to_glyphs (void		*abstract_font,
715 					 double		x,
716 					 double		y,
717 					 const char	*utf8,
718 					 cairo_glyph_t **glyphs,
719 					 int		*num_glyphs)
720 {
721     cairo_win32_scaled_font_t *scaled_font = abstract_font;
722     uint16_t *utf16;
723     int n16;
724     GCP_RESULTSW gcp_results;
725     unsigned int buffer_size, i;
726     WCHAR *glyph_indices = NULL;
727     int *dx = NULL;
728     cairo_status_t status;
729     double x_pos, y_pos;
730     double x_incr, y_incr;
731     HDC hdc = NULL;
732 
733     /* GetCharacterPlacement() returns utf16 instead of glyph indices
734      * for Type 1 fonts. Use GetGlyphIndices for Type 1 fonts. */
735     if (scaled_font->is_type1)
736 	 return _cairo_win32_scaled_font_type1_text_to_glyphs (scaled_font,
737 							       x,
738 							       y,
739 							       utf8,
740 							       glyphs,
741 							       num_glyphs);
742 
743     /* Compute a vector in user space along the baseline of length one logical space unit */
744     x_incr = 1;
745     y_incr = 0;
746     cairo_matrix_transform_distance (&scaled_font->base.font_matrix, &x_incr, &y_incr);
747     x_incr /= scaled_font->logical_scale;
748     y_incr /= scaled_font->logical_scale;
749 
750     status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &n16);
751     if (status)
752 	return status;
753 
754     gcp_results.lStructSize = sizeof (GCP_RESULTS);
755     gcp_results.lpOutString = NULL;
756     gcp_results.lpOrder = NULL;
757     gcp_results.lpCaretPos = NULL;
758     gcp_results.lpClass = NULL;
759 
760     buffer_size = MAX (n16 * 1.2, 16);		/* Initially guess number of chars plus a few */
761     if (buffer_size > INT_MAX) {
762 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
763 	goto FAIL1;
764     }
765 
766     hdc = _get_global_font_dc ();
767     assert (hdc != NULL);
768 
769     status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
770     if (status)
771 	goto FAIL1;
772 
773     while (TRUE) {
774 	if (glyph_indices) {
775 	    free (glyph_indices);
776 	    glyph_indices = NULL;
777 	}
778 	if (dx) {
779 	    free (dx);
780 	    dx = NULL;
781 	}
782 
783 	glyph_indices = _cairo_malloc_ab (buffer_size, sizeof (WCHAR));
784 	dx = _cairo_malloc_ab (buffer_size, sizeof (int));
785 	if (!glyph_indices || !dx) {
786 	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
787 	    goto FAIL2;
788 	}
789 
790 	gcp_results.nGlyphs = buffer_size;
791 	gcp_results.lpDx = dx;
792 	gcp_results.lpGlyphs = glyph_indices;
793 
794 	if (!GetCharacterPlacementW (hdc, utf16, n16,
795 				     0,
796 				     &gcp_results,
797 				     GCP_DIACRITIC | GCP_LIGATE | GCP_GLYPHSHAPE | GCP_REORDER)) {
798 	    status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_text_to_glyphs");
799 	    goto FAIL2;
800 	}
801 
802 	if (gcp_results.lpDx && gcp_results.lpGlyphs)
803 	    break;
804 
805 	/* Too small a buffer, try again */
806 
807 	buffer_size += buffer_size / 2;
808 	if (buffer_size > INT_MAX) {
809 	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
810 	    goto FAIL2;
811 	}
812     }
813 
814     *num_glyphs = gcp_results.nGlyphs;
815     *glyphs = _cairo_malloc_ab (gcp_results.nGlyphs, sizeof (cairo_glyph_t));
816     if (!*glyphs) {
817 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
818 	goto FAIL2;
819     }
820 
821     x_pos = x;
822     y_pos = y;
823 
824     for (i = 0; i < gcp_results.nGlyphs; i++) {
825 	(*glyphs)[i].index = glyph_indices[i];
826 	(*glyphs)[i].x = x_pos ;
827 	(*glyphs)[i].y = y_pos;
828 
829 	x_pos += x_incr * dx[i];
830 	y_pos += y_incr * dx[i];
831     }
832 
833  FAIL2:
834     if (glyph_indices)
835 	free (glyph_indices);
836     if (dx)
837 	free (dx);
838 
839     cairo_win32_scaled_font_done_font (&scaled_font->base);
840 
841  FAIL1:
842     free (utf16);
843 
844     return status;
845 }
846 
847 static unsigned long
_cairo_win32_scaled_font_ucs4_to_index(void * abstract_font,uint32_t ucs4)848 _cairo_win32_scaled_font_ucs4_to_index (void		*abstract_font,
849 					uint32_t	 ucs4)
850 {
851     cairo_win32_scaled_font_t *scaled_font = abstract_font;
852     wchar_t unicode[2];
853     WORD glyph_index;
854     HDC hdc = NULL;
855     cairo_status_t status;
856 
857     hdc = _get_global_font_dc ();
858     assert (hdc != NULL);
859 
860     status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
861     if (status)
862 	return 0;
863 
864     unicode[0] = ucs4;
865     unicode[1] = 0;
866     if (GetGlyphIndicesW (hdc, unicode, 1, &glyph_index, 0) == GDI_ERROR) {
867 	_cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_ucs4_to_index:GetGlyphIndicesW");
868 	glyph_index = 0;
869     }
870 
871     cairo_win32_scaled_font_done_font (&scaled_font->base);
872 
873     return glyph_index;
874 }
875 
876 static cairo_status_t
_cairo_win32_scaled_font_set_metrics(cairo_win32_scaled_font_t * scaled_font)877 _cairo_win32_scaled_font_set_metrics (cairo_win32_scaled_font_t *scaled_font)
878 {
879     cairo_status_t status;
880     cairo_font_extents_t extents;
881 
882     TEXTMETRIC metrics;
883     HDC hdc;
884 
885     hdc = _get_global_font_dc ();
886     assert (hdc != NULL);
887 
888     if (scaled_font->preserve_axes || scaled_font->base.options.hint_metrics == CAIRO_HINT_METRICS_OFF) {
889 	/* For 90-degree rotations (including 0), we get the metrics
890 	 * from the GDI in logical space, then convert back to font space
891 	 */
892 	status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
893 	if (status)
894 	    return status;
895 	GetTextMetrics (hdc, &metrics);
896 	cairo_win32_scaled_font_done_font (&scaled_font->base);
897 
898 	extents.ascent = metrics.tmAscent / scaled_font->logical_scale;
899 	extents.descent = metrics.tmDescent / scaled_font->logical_scale;
900 
901 	extents.height = (metrics.tmHeight + metrics.tmExternalLeading) / scaled_font->logical_scale;
902 	extents.max_x_advance = metrics.tmMaxCharWidth / scaled_font->logical_scale;
903 	extents.max_y_advance = 0;
904 
905     } else {
906 	/* For all other transformations, we use the design metrics
907 	 * of the font. The GDI results from GetTextMetrics() on a
908 	 * transformed font are inexplicably large and we want to
909 	 * avoid them.
910 	 */
911 	status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc);
912 	if (status)
913 	    return status;
914 	GetTextMetrics (hdc, &metrics);
915 	_cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base);
916 
917 	extents.ascent = (double)metrics.tmAscent / scaled_font->em_square;
918 	extents.descent = (double)metrics.tmDescent / scaled_font->em_square;
919 	extents.height = (double)(metrics.tmHeight + metrics.tmExternalLeading) / scaled_font->em_square;
920 	extents.max_x_advance = (double)(metrics.tmMaxCharWidth) / scaled_font->em_square;
921 	extents.max_y_advance = 0;
922 
923     }
924 
925     scaled_font->is_bitmap = !(metrics.tmPitchAndFamily & TMPF_VECTOR);
926 
927     /* Need to determine if this is a Type 1 font for the special
928      * handling in _text_to_glyphs.  Unlike TrueType or OpenType,
929      * Type1 fonts do not have a "cmap" table (or any other table).
930      * However GetFontData() will retrieve a Type1 font when
931      * requesting that GetFontData() retrieve data from the start of
932      * the file. This is to distinguish Type1 from stroke fonts such
933      * as "Script" and "Modern". The TMPF_TRUETYPE test is redundant
934      * but improves performance for the most common fonts.
935      */
936     scaled_font->is_type1 = FALSE;
937     if (!(metrics.tmPitchAndFamily & TMPF_TRUETYPE) &&
938 	(metrics.tmPitchAndFamily & TMPF_VECTOR))
939     {
940 	 if ((GetFontData (hdc, CMAP_TAG, 0, NULL, 0) == GDI_ERROR) &&
941 	     (GetFontData (hdc, 0, 0, NULL, 0) != GDI_ERROR))
942 	 {
943 	      scaled_font->is_type1 = TRUE;
944 	 }
945     }
946 
947     return _cairo_scaled_font_set_metrics (&scaled_font->base, &extents);
948 }
949 
950 static cairo_status_t
_cairo_win32_scaled_font_init_glyph_metrics(cairo_win32_scaled_font_t * scaled_font,cairo_scaled_glyph_t * scaled_glyph)951 _cairo_win32_scaled_font_init_glyph_metrics (cairo_win32_scaled_font_t *scaled_font,
952 					     cairo_scaled_glyph_t      *scaled_glyph)
953 {
954     static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
955     GLYPHMETRICS metrics;
956     cairo_status_t status;
957     cairo_text_extents_t extents;
958     HDC hdc;
959 
960     hdc = _get_global_font_dc ();
961     assert (hdc != NULL);
962 
963     if (scaled_font->is_bitmap) {
964 	/* GetGlyphOutline will not work. Assume that the glyph does not extend outside the font box. */
965 	cairo_font_extents_t font_extents;
966 	INT width = 0;
967 	UINT charIndex = _cairo_scaled_glyph_index (scaled_glyph);
968 
969 	cairo_scaled_font_extents (&scaled_font->base, &font_extents);
970 
971 	status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
972 	if (status)
973 	    return status;
974 
975 	if (!GetCharWidth32(hdc, charIndex, charIndex, &width)) {
976 	    status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_init_glyph_metrics:GetCharWidth32");
977 	    width = 0;
978 	}
979 	cairo_win32_scaled_font_done_font (&scaled_font->base);
980 	if (status)
981 	    return status;
982 
983 	extents.x_bearing = 0;
984 	extents.y_bearing = scaled_font->base.ctm.yy * (-font_extents.ascent / scaled_font->y_scale);
985 	extents.width = width / (WIN32_FONT_LOGICAL_SCALE * scaled_font->x_scale);
986 	extents.height = scaled_font->base.ctm.yy * (font_extents.ascent + font_extents.descent) / scaled_font->y_scale;
987 	extents.x_advance = extents.width;
988 	extents.y_advance = 0;
989     } else if (scaled_font->preserve_axes && scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) {
990 	/* If we aren't rotating / skewing the axes, then we get the metrics
991 	 * from the GDI in device space and convert to font space.
992 	 */
993 	status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
994 	if (status)
995 	    return status;
996 
997 	if (GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph),
998 			      GGO_METRICS | GGO_GLYPH_INDEX,
999 			      &metrics, 0, NULL, &matrix) == GDI_ERROR) {
1000 	    memset (&metrics, 0, sizeof (GLYPHMETRICS));
1001 	} else {
1002             if (metrics.gmBlackBoxX == 1 && metrics.gmBlackBoxY == 1 &&
1003                 GetGlyphOutlineW (hdc,
1004                                   _cairo_scaled_glyph_index (scaled_glyph),
1005                                   GGO_NATIVE | GGO_GLYPH_INDEX,
1006                                   &metrics, 0, NULL, &matrix) == 0) {
1007                 /* Workaround for GetGlyphOutline returning 1x1 bounding box
1008                  * for <space> glyph that is in fact empty.
1009                  */
1010                 metrics.gmBlackBoxX = metrics.gmBlackBoxY = 0;
1011             }
1012 	    else if (metrics.gmBlackBoxX > 0 &&
1013                      scaled_font->base.options.antialias != CAIRO_ANTIALIAS_NONE) {
1014 		/* The bounding box reported by Windows supposedly contains the glyph's "black" area;
1015 		 * however, antialiasing (especially with ClearType) means that the actual image that
1016 		 * needs to be rendered may "bleed" into the adjacent pixels, mainly on the right side.
1017 		 * To avoid clipping the glyphs when drawn by _cairo_surface_fallback_show_glyphs,
1018 		 * for example, or other code that uses glyph extents to determine the area to update,
1019 		 * we add a pixel of "slop" to left side of the nominal "black" area returned by GDI,
1020 		 * and two pixels to the right (as tests show some glyphs bleed into this column).
1021 		 */
1022 		metrics.gmptGlyphOrigin.x -= 1;
1023 		metrics.gmBlackBoxX += 3;
1024 	    }
1025 	}
1026 	cairo_win32_scaled_font_done_font (&scaled_font->base);
1027 
1028 	if (scaled_font->swap_axes) {
1029 	    extents.x_bearing = - metrics.gmptGlyphOrigin.y / scaled_font->y_scale;
1030 	    extents.y_bearing = metrics.gmptGlyphOrigin.x / scaled_font->x_scale;
1031 	    extents.width = metrics.gmBlackBoxY / scaled_font->y_scale;
1032 	    extents.height = metrics.gmBlackBoxX / scaled_font->x_scale;
1033 	    extents.x_advance = metrics.gmCellIncY / scaled_font->x_scale;
1034 	    extents.y_advance = metrics.gmCellIncX / scaled_font->y_scale;
1035 	} else {
1036 	    extents.x_bearing = metrics.gmptGlyphOrigin.x / scaled_font->x_scale;
1037 	    extents.y_bearing = - metrics.gmptGlyphOrigin.y / scaled_font->y_scale;
1038 	    extents.width = metrics.gmBlackBoxX / scaled_font->x_scale;
1039 	    extents.height = metrics.gmBlackBoxY / scaled_font->y_scale;
1040 	    extents.x_advance = metrics.gmCellIncX / scaled_font->x_scale;
1041 	    extents.y_advance = metrics.gmCellIncY / scaled_font->y_scale;
1042 	}
1043 
1044 	if (scaled_font->swap_x) {
1045 	    extents.x_bearing = (- extents.x_bearing - extents.width);
1046 	    extents.x_advance = - extents.x_advance;
1047 	}
1048 
1049 	if (scaled_font->swap_y) {
1050 	    extents.y_bearing = (- extents.y_bearing - extents.height);
1051 	    extents.y_advance = - extents.y_advance;
1052 	}
1053 
1054     } else {
1055 	/* For all other transformations, we use the design metrics
1056 	 * of the font.
1057 	 */
1058 	status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc);
1059 	if (status)
1060 	    return status;
1061 
1062 	if (GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph),
1063 	                      GGO_METRICS | GGO_GLYPH_INDEX,
1064 			      &metrics, 0, NULL, &matrix) == GDI_ERROR) {
1065 	    memset (&metrics, 0, sizeof (GLYPHMETRICS));
1066 	}
1067 	_cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base);
1068 
1069 	extents.x_bearing = (double)metrics.gmptGlyphOrigin.x / scaled_font->em_square;
1070 	extents.y_bearing = - (double)metrics.gmptGlyphOrigin.y / scaled_font->em_square;
1071 	extents.width = (double)metrics.gmBlackBoxX / scaled_font->em_square;
1072 	extents.height = (double)metrics.gmBlackBoxY / scaled_font->em_square;
1073 	extents.x_advance = (double)metrics.gmCellIncX / scaled_font->em_square;
1074 	extents.y_advance = (double)metrics.gmCellIncY / scaled_font->em_square;
1075     }
1076 
1077     _cairo_scaled_glyph_set_metrics (scaled_glyph,
1078 				     &scaled_font->base,
1079 				     &extents);
1080 
1081     return CAIRO_STATUS_SUCCESS;
1082 }
1083 
1084 /* Not currently used code, but may be useful in the future if we add
1085  * back the capability to the scaled font backend interface to get the
1086  * actual device space bbox rather than computing it from the
1087  * font-space metrics.
1088  */
1089 #if 0
1090 static cairo_status_t
1091 _cairo_win32_scaled_font_glyph_bbox (void		 *abstract_font,
1092 				     const cairo_glyph_t *glyphs,
1093 				     int                  num_glyphs,
1094 				     cairo_box_t         *bbox)
1095 {
1096     static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
1097     cairo_win32_scaled_font_t *scaled_font = abstract_font;
1098     int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
1099 
1100     if (num_glyphs > 0) {
1101 	HDC hdc;
1102 	GLYPHMETRICS metrics;
1103 	cairo_status_t status;
1104 	int i;
1105 
1106 	hdc = _get_global_font_dc ();
1107 	assert (hdc != NULL);
1108 
1109 	status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
1110 	if (status)
1111 	    return status;
1112 
1113 	for (i = 0; i < num_glyphs; i++) {
1114 	    int x = _cairo_lround (glyphs[i].x);
1115 	    int y = _cairo_lround (glyphs[i].y);
1116 
1117 	    GetGlyphOutlineW (hdc, glyphs[i].index, GGO_METRICS | GGO_GLYPH_INDEX,
1118 			     &metrics, 0, NULL, &matrix);
1119 
1120 	    if (i == 0 || x1 > x + metrics.gmptGlyphOrigin.x)
1121 		x1 = x + metrics.gmptGlyphOrigin.x;
1122 	    if (i == 0 || y1 > y - metrics.gmptGlyphOrigin.y)
1123 		y1 = y - metrics.gmptGlyphOrigin.y;
1124 	    if (i == 0 || x2 < x + metrics.gmptGlyphOrigin.x + (int)metrics.gmBlackBoxX)
1125 		x2 = x + metrics.gmptGlyphOrigin.x + (int)metrics.gmBlackBoxX;
1126 	    if (i == 0 || y2 < y - metrics.gmptGlyphOrigin.y + (int)metrics.gmBlackBoxY)
1127 		y2 = y - metrics.gmptGlyphOrigin.y + (int)metrics.gmBlackBoxY;
1128 	}
1129 
1130 	cairo_win32_scaled_font_done_font (&scaled_font->base);
1131     }
1132 
1133     bbox->p1.x = _cairo_fixed_from_int (x1);
1134     bbox->p1.y = _cairo_fixed_from_int (y1);
1135     bbox->p2.x = _cairo_fixed_from_int (x2);
1136     bbox->p2.y = _cairo_fixed_from_int (y2);
1137 
1138     return CAIRO_STATUS_SUCCESS;
1139 }
1140 #endif
1141 
1142 typedef struct {
1143     cairo_win32_scaled_font_t *scaled_font;
1144     HDC hdc;
1145 
1146     cairo_array_t glyphs;
1147     cairo_array_t dx;
1148 
1149     int start_x;
1150     int last_x;
1151     int last_y;
1152 } cairo_glyph_state_t;
1153 
1154 static void
_start_glyphs(cairo_glyph_state_t * state,cairo_win32_scaled_font_t * scaled_font,HDC hdc)1155 _start_glyphs (cairo_glyph_state_t        *state,
1156 	       cairo_win32_scaled_font_t  *scaled_font,
1157 	       HDC                         hdc)
1158 {
1159     state->hdc = hdc;
1160     state->scaled_font = scaled_font;
1161 
1162     _cairo_array_init (&state->glyphs, sizeof (WCHAR));
1163     _cairo_array_init (&state->dx, sizeof (int));
1164 }
1165 
1166 static cairo_status_t
_flush_glyphs(cairo_glyph_state_t * state)1167 _flush_glyphs (cairo_glyph_state_t *state)
1168 {
1169     cairo_status_t status;
1170     int dx = 0;
1171     WCHAR * elements;
1172     int * dx_elements;
1173 
1174     status = _cairo_array_append (&state->dx, &dx);
1175     if (status)
1176 	return status;
1177 
1178     elements = _cairo_array_index (&state->glyphs, 0);
1179     dx_elements = _cairo_array_index (&state->dx, 0);
1180     if (!ExtTextOutW (state->hdc,
1181 		      state->start_x, state->last_y,
1182 		      ETO_GLYPH_INDEX,
1183 		      NULL,
1184 		      elements,
1185 		      state->glyphs.num_elements,
1186 		      dx_elements)) {
1187 	return _cairo_win32_print_gdi_error ("_flush_glyphs");
1188     }
1189 
1190     _cairo_array_truncate (&state->glyphs, 0);
1191     _cairo_array_truncate (&state->dx, 0);
1192 
1193     return CAIRO_STATUS_SUCCESS;
1194 }
1195 
1196 static cairo_status_t
_add_glyph(cairo_glyph_state_t * state,unsigned long index,double device_x,double device_y)1197 _add_glyph (cairo_glyph_state_t *state,
1198 	    unsigned long        index,
1199 	    double               device_x,
1200 	    double               device_y)
1201 {
1202     cairo_status_t status;
1203     double user_x = device_x;
1204     double user_y = device_y;
1205     WCHAR glyph_index = index;
1206     int logical_x, logical_y;
1207 
1208     cairo_matrix_transform_point (&state->scaled_font->device_to_logical, &user_x, &user_y);
1209 
1210     logical_x = _cairo_lround (user_x);
1211     logical_y = _cairo_lround (user_y);
1212 
1213     if (state->glyphs.num_elements > 0) {
1214 	int dx;
1215 
1216 	if (logical_y != state->last_y) {
1217 	    status = _flush_glyphs (state);
1218 	    if (status)
1219 		return status;
1220 	    state->start_x = logical_x;
1221 	} else {
1222 	    dx = logical_x - state->last_x;
1223 	    status = _cairo_array_append (&state->dx, &dx);
1224 	    if (status)
1225 		return status;
1226 	}
1227     } else {
1228 	state->start_x = logical_x;
1229     }
1230 
1231     state->last_x = logical_x;
1232     state->last_y = logical_y;
1233 
1234     status = _cairo_array_append (&state->glyphs, &glyph_index);
1235     if (status)
1236 	return status;
1237 
1238     return CAIRO_STATUS_SUCCESS;
1239 }
1240 
1241 static cairo_status_t
_finish_glyphs(cairo_glyph_state_t * state)1242 _finish_glyphs (cairo_glyph_state_t *state)
1243 {
1244     cairo_status_t status;
1245 
1246     status = _flush_glyphs (state);
1247 
1248     _cairo_array_fini (&state->glyphs);
1249     _cairo_array_fini (&state->dx);
1250 
1251     return status;
1252 }
1253 
1254 static cairo_status_t
_draw_glyphs_on_surface(cairo_win32_surface_t * surface,cairo_win32_scaled_font_t * scaled_font,COLORREF color,int x_offset,int y_offset,const cairo_glyph_t * glyphs,int num_glyphs)1255 _draw_glyphs_on_surface (cairo_win32_surface_t     *surface,
1256 			 cairo_win32_scaled_font_t *scaled_font,
1257 			 COLORREF                   color,
1258 			 int                        x_offset,
1259 			 int                        y_offset,
1260 			 const cairo_glyph_t       *glyphs,
1261 			 int			    num_glyphs)
1262 {
1263     cairo_glyph_state_t state;
1264     cairo_status_t status, status2;
1265     int i;
1266 
1267     if (!SaveDC (surface->dc))
1268 	return _cairo_win32_print_gdi_error ("_draw_glyphs_on_surface:SaveDC");
1269 
1270     status = cairo_win32_scaled_font_select_font (&scaled_font->base, surface->dc);
1271     if (status)
1272 	goto FAIL1;
1273 
1274     SetTextColor (surface->dc, color);
1275     SetTextAlign (surface->dc, TA_BASELINE | TA_LEFT);
1276     SetBkMode (surface->dc, TRANSPARENT);
1277 
1278     _start_glyphs (&state, scaled_font, surface->dc);
1279 
1280     for (i = 0; i < num_glyphs; i++) {
1281 	status = _add_glyph (&state, glyphs[i].index,
1282 			     glyphs[i].x - x_offset, glyphs[i].y - y_offset);
1283 	if (status)
1284 	    goto FAIL2;
1285     }
1286 
1287  FAIL2:
1288     status2 = _finish_glyphs (&state);
1289     if (status == CAIRO_STATUS_SUCCESS)
1290 	status = status2;
1291 
1292     cairo_win32_scaled_font_done_font (&scaled_font->base);
1293  FAIL1:
1294     RestoreDC (surface->dc, -1);
1295 
1296     return status;
1297 }
1298 
1299 /* Duplicate the green channel of a 4-channel mask in the alpha channel, then
1300  * invert the whole mask.
1301  */
1302 static void
_compute_argb32_mask_alpha(cairo_win32_surface_t * mask_surface)1303 _compute_argb32_mask_alpha (cairo_win32_surface_t *mask_surface)
1304 {
1305     cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->image;
1306     int i, j;
1307 
1308     for (i = 0; i < image->height; i++) {
1309 	uint32_t *p = (uint32_t *) (image->data + i * image->stride);
1310 	for (j = 0; j < image->width; j++) {
1311 	    *p = 0xffffffff ^ (*p | ((*p & 0x0000ff00) << 16));
1312 	    p++;
1313 	}
1314     }
1315 }
1316 
1317 /* Invert a mask
1318  */
1319 static void
_invert_argb32_mask(cairo_win32_surface_t * mask_surface)1320 _invert_argb32_mask (cairo_win32_surface_t *mask_surface)
1321 {
1322     cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->image;
1323     int i, j;
1324 
1325     for (i = 0; i < image->height; i++) {
1326 	uint32_t *p = (uint32_t *) (image->data + i * image->stride);
1327 	for (j = 0; j < image->width; j++) {
1328 	    *p = 0xffffffff ^ *p;
1329 	    p++;
1330 	}
1331     }
1332 }
1333 
1334 /* Compute an alpha-mask from a monochrome RGB24 image
1335  */
1336 static cairo_surface_t *
_compute_a8_mask(cairo_win32_surface_t * mask_surface)1337 _compute_a8_mask (cairo_win32_surface_t *mask_surface)
1338 {
1339     cairo_image_surface_t *image24 = (cairo_image_surface_t *)mask_surface->image;
1340     cairo_image_surface_t *image8;
1341     int i, j;
1342 
1343     if (image24->base.status)
1344 	return cairo_surface_reference (&image24->base);
1345 
1346     image8 = (cairo_image_surface_t *)cairo_image_surface_create (CAIRO_FORMAT_A8,
1347 								  image24->width, image24->height);
1348     if (image8->base.status)
1349 	return &image8->base;
1350 
1351     for (i = 0; i < image24->height; i++) {
1352 	uint32_t *p = (uint32_t *) (image24->data + i * image24->stride);
1353 	unsigned char *q = (unsigned char *) (image8->data + i * image8->stride);
1354 
1355 	for (j = 0; j < image24->width; j++) {
1356 	    *q = 255 - ((*p & 0x0000ff00) >> 8);
1357 	    p++;
1358 	    q++;
1359 	}
1360     }
1361 
1362     return &image8->base;
1363 }
1364 
1365 static cairo_int_status_t
_cairo_win32_scaled_font_glyph_init(void * abstract_font,cairo_scaled_glyph_t * scaled_glyph,cairo_scaled_glyph_info_t info)1366 _cairo_win32_scaled_font_glyph_init (void		       *abstract_font,
1367 				     cairo_scaled_glyph_t      *scaled_glyph,
1368 				     cairo_scaled_glyph_info_t  info)
1369 {
1370     cairo_win32_scaled_font_t *scaled_font = abstract_font;
1371     cairo_status_t status;
1372 
1373     if ((info & CAIRO_SCALED_GLYPH_INFO_METRICS) != 0) {
1374 	status = _cairo_win32_scaled_font_init_glyph_metrics (scaled_font, scaled_glyph);
1375 	if (status)
1376 	    return status;
1377     }
1378 
1379     if (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) {
1380 	status = _cairo_win32_scaled_font_init_glyph_surface (scaled_font, scaled_glyph);
1381 	if (status)
1382 	    return status;
1383     }
1384 
1385     if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0) {
1386 	status = _cairo_win32_scaled_font_init_glyph_path (scaled_font, scaled_glyph);
1387 	if (status)
1388 	    return status;
1389     }
1390 
1391     return CAIRO_STATUS_SUCCESS;
1392 }
1393 
1394 static cairo_int_status_t
_cairo_win32_scaled_font_show_glyphs(void * abstract_font,cairo_operator_t op,const cairo_pattern_t * pattern,cairo_surface_t * generic_surface,int source_x,int source_y,int dest_x,int dest_y,unsigned int width,unsigned int height,cairo_glyph_t * glyphs,int num_glyphs,cairo_region_t * clip_region,int * remaining_glyphs)1395 _cairo_win32_scaled_font_show_glyphs (void			*abstract_font,
1396 				      cairo_operator_t		 op,
1397 				      const cairo_pattern_t	*pattern,
1398 				      cairo_surface_t		*generic_surface,
1399 				      int			 source_x,
1400 				      int			 source_y,
1401 				      int			 dest_x,
1402 				      int			 dest_y,
1403 				      unsigned int		 width,
1404 				      unsigned int		 height,
1405 				      cairo_glyph_t		*glyphs,
1406 				      int			 num_glyphs,
1407 				      cairo_region_t		*clip_region,
1408 				      int			*remaining_glyphs)
1409 {
1410     cairo_win32_scaled_font_t *scaled_font = abstract_font;
1411     cairo_win32_surface_t *surface = (cairo_win32_surface_t *)generic_surface;
1412     cairo_status_t status;
1413 
1414     if (width == 0 || height == 0)
1415 	return CAIRO_STATUS_SUCCESS;
1416 
1417     if (_cairo_surface_is_win32 (generic_surface) &&
1418 	surface->format == CAIRO_FORMAT_RGB24 &&
1419 	(generic_surface->permit_subpixel_antialiasing || scaled_font->quality != CLEARTYPE_QUALITY) &&
1420 	op == CAIRO_OPERATOR_OVER &&
1421 	_cairo_pattern_is_opaque_solid (pattern)) {
1422 
1423 	cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)pattern;
1424 
1425 	/* When compositing OVER on a GDI-understood surface, with a
1426 	 * solid opaque color, we can just call ExtTextOut directly.
1427 	 */
1428 	COLORREF new_color;
1429 
1430 	status = _cairo_win32_surface_set_clip_region (surface, clip_region);
1431 	if (unlikely (status))
1432 	    return status;
1433 
1434 	new_color = RGB (((int)solid_pattern->color.red_short) >> 8,
1435 			 ((int)solid_pattern->color.green_short) >> 8,
1436 			 ((int)solid_pattern->color.blue_short) >> 8);
1437 
1438 	return _draw_glyphs_on_surface (surface, scaled_font, new_color,
1439 					0, 0,
1440 					glyphs, num_glyphs);
1441     } else {
1442 	/* Otherwise, we need to draw using software fallbacks. We create a mask
1443 	 * surface by drawing the the glyphs onto a DIB, black-on-white then
1444 	 * inverting. GDI outputs gamma-corrected images so inverted black-on-white
1445 	 * is very different from white-on-black. We favor the more common
1446 	 * case where the final output is dark-on-light.
1447 	 */
1448 	cairo_win32_surface_t *tmp_surface;
1449 	cairo_surface_t *mask_surface;
1450 	cairo_surface_pattern_t mask;
1451 	cairo_bool_t use_subpixel_antialiasing =
1452 	    scaled_font->quality == CLEARTYPE_QUALITY && generic_surface->permit_subpixel_antialiasing;
1453 	RECT r;
1454 
1455 	tmp_surface = (cairo_win32_surface_t *)cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, width, height);
1456 	if (tmp_surface->base.status)
1457 	    return tmp_surface->base.status;
1458 
1459 	r.left = 0;
1460 	r.top = 0;
1461 	r.right = width;
1462 	r.bottom = height;
1463 	FillRect (tmp_surface->dc, &r, GetStockObject (WHITE_BRUSH));
1464 
1465 	status = _draw_glyphs_on_surface (tmp_surface,
1466 		                          scaled_font, RGB (0, 0, 0),
1467 					  dest_x, dest_y,
1468 					  glyphs, num_glyphs);
1469 	if (status) {
1470 	    cairo_surface_destroy (&tmp_surface->base);
1471 	    return status;
1472 	}
1473 
1474 	if (use_subpixel_antialiasing) {
1475 	    /* For ClearType, we need a 4-channel mask. If we are compositing on
1476 	     * a surface with alpha, we need to compute the alpha channel of
1477 	     * the mask (we just copy the green channel). But for a destination
1478 	     * surface without alpha the alpha channel of the mask is ignored
1479 	     */
1480 
1481 	    if (surface->format != CAIRO_FORMAT_RGB24)
1482 		_compute_argb32_mask_alpha (tmp_surface);
1483 	    else
1484 		_invert_argb32_mask (tmp_surface);
1485 
1486 	    mask_surface = &tmp_surface->base;
1487 	} else {
1488 	    mask_surface = _compute_a8_mask (tmp_surface);
1489 	    cairo_surface_destroy (&tmp_surface->base);
1490 	    status = mask_surface->status;
1491 	    if (status)
1492 		return status;
1493 	}
1494 
1495 	/* For op == OVER, no-cleartype, a possible optimization here is to
1496 	 * draw onto an intermediate ARGB32 surface and alpha-blend that with the
1497 	 * destination
1498 	 */
1499 	_cairo_pattern_init_for_surface (&mask, mask_surface);
1500 	cairo_surface_destroy (mask_surface);
1501 
1502 	if (use_subpixel_antialiasing)
1503 	    mask.base.has_component_alpha = TRUE;
1504 
1505 	status = _cairo_surface_composite (op, pattern,
1506 					   &mask.base,
1507 					   &surface->base,
1508 					   source_x, source_y,
1509 					   0, 0,
1510 					   dest_x, dest_y,
1511 					   width, height,
1512 					   clip_region);
1513 
1514 	_cairo_pattern_fini (&mask.base);
1515 
1516 	return status;
1517     }
1518 }
1519 
1520 static cairo_int_status_t
_cairo_win32_scaled_font_load_truetype_table(void * abstract_font,unsigned long tag,long offset,unsigned char * buffer,unsigned long * length)1521 _cairo_win32_scaled_font_load_truetype_table (void	       *abstract_font,
1522                                              unsigned long      tag,
1523                                              long               offset,
1524                                              unsigned char     *buffer,
1525                                              unsigned long     *length)
1526 {
1527     cairo_win32_scaled_font_t *scaled_font = abstract_font;
1528     HDC hdc;
1529     cairo_status_t status;
1530 
1531     hdc = _get_global_font_dc ();
1532     assert (hdc != NULL);
1533 
1534     tag = (tag&0x000000ff)<<24 | (tag&0x0000ff00)<<8 | (tag&0x00ff0000)>>8 | (tag&0xff000000)>>24;
1535     status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
1536     if (status)
1537 	return status;
1538 
1539     *length = GetFontData (hdc, tag, offset, buffer, *length);
1540     if (*length == GDI_ERROR)
1541         status = CAIRO_INT_STATUS_UNSUPPORTED;
1542 
1543     cairo_win32_scaled_font_done_font (&scaled_font->base);
1544 
1545     return status;
1546 }
1547 
1548 static cairo_int_status_t
_cairo_win32_scaled_font_index_to_ucs4(void * abstract_font,unsigned long index,uint32_t * ucs4)1549 _cairo_win32_scaled_font_index_to_ucs4 (void		*abstract_font,
1550 					unsigned long    index,
1551 					uint32_t	*ucs4)
1552 {
1553     cairo_win32_scaled_font_t *scaled_font = abstract_font;
1554     GLYPHSET *glyph_set;
1555     uint16_t *utf16 = NULL;
1556     WORD *glyph_indices = NULL;
1557     HDC hdc = NULL;
1558     int res;
1559     unsigned int i, j, num_glyphs;
1560     cairo_status_t status;
1561 
1562     hdc = _get_global_font_dc ();
1563     assert (hdc != NULL);
1564 
1565     status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
1566     if (status)
1567 	return status;
1568 
1569     res = GetFontUnicodeRanges(hdc, NULL);
1570     if (res == 0) {
1571 	status = _cairo_win32_print_gdi_error (
1572 	    "_cairo_win32_scaled_font_index_to_ucs4:GetFontUnicodeRanges");
1573 	goto exit1;
1574     }
1575 
1576     glyph_set = malloc (res);
1577     if (glyph_set == NULL) {
1578 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1579 	goto exit1;
1580     }
1581 
1582     res = GetFontUnicodeRanges(hdc, glyph_set);
1583     if (res == 0) {
1584 	status = _cairo_win32_print_gdi_error (
1585 	    "_cairo_win32_scaled_font_index_to_ucs4:GetFontUnicodeRanges");
1586 	goto exit1;
1587     }
1588 
1589     *ucs4 = (uint32_t) -1;
1590     for (i = 0; i < glyph_set->cRanges; i++) {
1591 	num_glyphs = glyph_set->ranges[i].cGlyphs;
1592 
1593 	utf16 = _cairo_malloc_ab (num_glyphs + 1, sizeof (uint16_t));
1594 	if (utf16 == NULL) {
1595 	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1596 	    goto exit1;
1597 	}
1598 
1599 	glyph_indices = _cairo_malloc_ab (num_glyphs + 1, sizeof (WORD));
1600 	if (glyph_indices == NULL) {
1601 	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1602 	    goto exit2;
1603 	}
1604 
1605 	for (j = 0; j < num_glyphs; j++)
1606 	    utf16[j] = glyph_set->ranges[i].wcLow + j;
1607 	utf16[j] = 0;
1608 
1609 	if (GetGlyphIndicesW (hdc, utf16, num_glyphs, glyph_indices, 0) == GDI_ERROR) {
1610 	    status = _cairo_win32_print_gdi_error (
1611 		"_cairo_win32_scaled_font_index_to_ucs4:GetGlyphIndicesW");
1612 	    goto exit2;
1613 	}
1614 
1615 	for (j = 0; j < num_glyphs; j++) {
1616 	    if (glyph_indices[j] == index) {
1617 		*ucs4 = utf16[j];
1618 		goto exit2;
1619 	    }
1620 	}
1621 
1622 	free (glyph_indices);
1623 	glyph_indices = NULL;
1624 	free (utf16);
1625 	utf16 = NULL;
1626     }
1627 
1628 exit2:
1629     if (glyph_indices)
1630 	free (glyph_indices);
1631     if (utf16)
1632 	free (utf16);
1633     free (glyph_set);
1634 exit1:
1635     cairo_win32_scaled_font_done_font (&scaled_font->base);
1636 
1637     return status;
1638 }
1639 
1640 static cairo_status_t
_cairo_win32_scaled_font_init_glyph_surface(cairo_win32_scaled_font_t * scaled_font,cairo_scaled_glyph_t * scaled_glyph)1641 _cairo_win32_scaled_font_init_glyph_surface (cairo_win32_scaled_font_t *scaled_font,
1642                                              cairo_scaled_glyph_t      *scaled_glyph)
1643 {
1644     cairo_status_t status;
1645     cairo_glyph_t glyph;
1646     cairo_win32_surface_t *surface;
1647     cairo_t *cr;
1648     cairo_surface_t *image;
1649     int width, height;
1650     int x1, y1, x2, y2;
1651 
1652     x1 = _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
1653     y1 = _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
1654     x2 = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x);
1655     y2 = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y);
1656     width = x2 - x1;
1657     height = y2 - y1;
1658 
1659     surface = (cairo_win32_surface_t *)
1660 	cairo_win32_surface_create_with_dib (CAIRO_FORMAT_RGB24, width, height);
1661 
1662     cr = cairo_create (&surface->base);
1663     cairo_set_source_rgb (cr, 1, 1, 1);
1664     cairo_paint (cr);
1665     status = cairo_status (cr);
1666     cairo_destroy(cr);
1667     if (status)
1668 	goto FAIL;
1669 
1670     glyph.index = _cairo_scaled_glyph_index (scaled_glyph);
1671     glyph.x = -x1;
1672     glyph.y = -y1;
1673     status = _draw_glyphs_on_surface (surface, scaled_font, RGB(0,0,0),
1674                                       0, 0, &glyph, 1);
1675     if (status)
1676 	goto FAIL;
1677 
1678     GdiFlush();
1679 
1680     image = _compute_a8_mask (surface);
1681     status = image->status;
1682     if (status)
1683 	goto FAIL;
1684 
1685     cairo_surface_set_device_offset (image, -x1, -y1);
1686     _cairo_scaled_glyph_set_surface (scaled_glyph,
1687                                      &scaled_font->base,
1688                                      (cairo_image_surface_t *) image);
1689 
1690   FAIL:
1691     cairo_surface_destroy (&surface->base);
1692 
1693     return status;
1694 }
1695 
1696 static void
_cairo_win32_transform_FIXED_to_fixed(cairo_matrix_t * matrix,FIXED Fx,FIXED Fy,cairo_fixed_t * fx,cairo_fixed_t * fy)1697 _cairo_win32_transform_FIXED_to_fixed (cairo_matrix_t *matrix,
1698                                        FIXED Fx, FIXED Fy,
1699                                        cairo_fixed_t *fx, cairo_fixed_t *fy)
1700 {
1701     double x = Fx.value + Fx.fract / 65536.0;
1702     double y = Fy.value + Fy.fract / 65536.0;
1703     cairo_matrix_transform_point (matrix, &x, &y);
1704     *fx = _cairo_fixed_from_double (x);
1705     *fy = _cairo_fixed_from_double (y);
1706 }
1707 
1708 static cairo_status_t
_cairo_win32_scaled_font_init_glyph_path(cairo_win32_scaled_font_t * scaled_font,cairo_scaled_glyph_t * scaled_glyph)1709 _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font,
1710 					  cairo_scaled_glyph_t      *scaled_glyph)
1711 {
1712     static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, -1 } };
1713     cairo_status_t status;
1714     GLYPHMETRICS metrics;
1715     HDC hdc;
1716     DWORD bytesGlyph;
1717     unsigned char *buffer, *ptr;
1718     cairo_path_fixed_t *path;
1719     cairo_matrix_t transform;
1720     cairo_fixed_t x, y;
1721 
1722     if (scaled_font->is_bitmap)
1723 	return CAIRO_INT_STATUS_UNSUPPORTED;
1724 
1725     hdc = _get_global_font_dc ();
1726     assert (hdc != NULL);
1727 
1728     path = _cairo_path_fixed_create ();
1729     if (!path)
1730 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1731 
1732     if (scaled_font->base.options.hint_style == CAIRO_HINT_STYLE_NONE) {
1733         status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc);
1734         transform = scaled_font->base.scale;
1735         cairo_matrix_scale (&transform, 1.0/scaled_font->em_square, 1.0/scaled_font->em_square);
1736     } else {
1737         status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
1738         cairo_matrix_init_identity(&transform);
1739     }
1740     if (status)
1741         goto CLEANUP_PATH;
1742 
1743     bytesGlyph = GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph),
1744 				   GGO_NATIVE | GGO_GLYPH_INDEX,
1745 				   &metrics, 0, NULL, &matrix);
1746 
1747     if (bytesGlyph == GDI_ERROR) {
1748 	status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_glyph_path");
1749 	goto CLEANUP_FONT;
1750     }
1751 
1752     ptr = buffer = malloc (bytesGlyph);
1753     if (!buffer) {
1754 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1755 	goto CLEANUP_FONT;
1756     }
1757 
1758     if (GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph),
1759 			  GGO_NATIVE | GGO_GLYPH_INDEX,
1760 			  &metrics, bytesGlyph, buffer, &matrix) == GDI_ERROR) {
1761 	status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_glyph_path");
1762 	goto CLEANUP_BUFFER;
1763     }
1764 
1765     while (ptr < buffer + bytesGlyph) {
1766 	TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)ptr;
1767 	unsigned char *endPoly = ptr + header->cb;
1768 
1769 	ptr += sizeof (TTPOLYGONHEADER);
1770 
1771         _cairo_win32_transform_FIXED_to_fixed (&transform,
1772                                                header->pfxStart.x,
1773                                                header->pfxStart.y,
1774                                                &x, &y);
1775         status = _cairo_path_fixed_move_to (path, x, y);
1776 	if (status)
1777 	    goto CLEANUP_BUFFER;
1778 
1779 	while (ptr < endPoly) {
1780 	    TTPOLYCURVE *curve = (TTPOLYCURVE *)ptr;
1781 	    POINTFX *points = curve->apfx;
1782 	    int i;
1783 	    switch (curve->wType) {
1784 	    case TT_PRIM_LINE:
1785 		for (i = 0; i < curve->cpfx; i++) {
1786                     _cairo_win32_transform_FIXED_to_fixed (&transform,
1787                                                            points[i].x,
1788                                                            points[i].y,
1789                                                            &x, &y);
1790 		    status = _cairo_path_fixed_line_to (path, x, y);
1791 		    if (status)
1792 			goto CLEANUP_BUFFER;
1793 		}
1794 		break;
1795 	    case TT_PRIM_QSPLINE:
1796 		for (i = 0; i < curve->cpfx - 1; i++) {
1797 		    cairo_fixed_t p1x, p1y, p2x, p2y, cx, cy, c1x, c1y, c2x, c2y;
1798 		    if (! _cairo_path_fixed_get_current_point (path, &p1x, &p1y))
1799 			goto CLEANUP_BUFFER;
1800                     _cairo_win32_transform_FIXED_to_fixed (&transform,
1801                                                            points[i].x,
1802                                                            points[i].y,
1803                                                            &cx, &cy);
1804 
1805 		    if (i + 1 == curve->cpfx - 1) {
1806                         _cairo_win32_transform_FIXED_to_fixed (&transform,
1807                                                                points[i + 1].x,
1808                                                                points[i + 1].y,
1809                                                                &p2x, &p2y);
1810 		    } else {
1811 			/* records with more than one curve use interpolation for
1812 			   control points, per http://support.microsoft.com/kb/q87115/ */
1813                         _cairo_win32_transform_FIXED_to_fixed (&transform,
1814                                                                points[i + 1].x,
1815                                                                points[i + 1].y,
1816                                                                &x, &y);
1817                         p2x = (cx + x) / 2;
1818 			p2y = (cy + y) / 2;
1819 		    }
1820 
1821 		    c1x = 2 * cx / 3 + p1x / 3;
1822 		    c1y = 2 * cy / 3 + p1y / 3;
1823 		    c2x = 2 * cx / 3 + p2x / 3;
1824 		    c2y = 2 * cy / 3 + p2y / 3;
1825 
1826 		    status = _cairo_path_fixed_curve_to (path, c1x, c1y, c2x, c2y, p2x, p2y);
1827 		    if (status)
1828 			goto CLEANUP_BUFFER;
1829 		}
1830 		break;
1831 	    case TT_PRIM_CSPLINE:
1832 		for (i = 0; i < curve->cpfx - 2; i += 2) {
1833 		    cairo_fixed_t x1, y1, x2, y2;
1834                     _cairo_win32_transform_FIXED_to_fixed (&transform,
1835                                                            points[i].x,
1836                                                            points[i].y,
1837                                                            &x, &y);
1838                     _cairo_win32_transform_FIXED_to_fixed (&transform,
1839                                                            points[i + 1].x,
1840                                                            points[i + 1].y,
1841                                                            &x1, &y1);
1842                     _cairo_win32_transform_FIXED_to_fixed (&transform,
1843                                                            points[i + 2].x,
1844                                                            points[i + 2].y,
1845                                                            &x2, &y2);
1846 		    status = _cairo_path_fixed_curve_to (path, x, y, x1, y1, x2, y2);
1847 		    if (status)
1848 			goto CLEANUP_BUFFER;
1849 		}
1850 		break;
1851 	    }
1852 	    ptr += sizeof(TTPOLYCURVE) + sizeof (POINTFX) * (curve->cpfx - 1);
1853 	}
1854 	status = _cairo_path_fixed_close_path (path);
1855 	if (status)
1856 	    goto CLEANUP_BUFFER;
1857     }
1858 
1859     _cairo_scaled_glyph_set_path (scaled_glyph,
1860 				  &scaled_font->base,
1861 				  path);
1862 
1863  CLEANUP_BUFFER:
1864     free (buffer);
1865 
1866  CLEANUP_FONT:
1867     if (scaled_font->base.options.hint_style == CAIRO_HINT_STYLE_NONE)
1868 	_cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base);
1869     else
1870 	cairo_win32_scaled_font_done_font (&scaled_font->base);
1871 
1872  CLEANUP_PATH:
1873     if (status != CAIRO_STATUS_SUCCESS)
1874 	_cairo_path_fixed_destroy (path);
1875 
1876     return status;
1877 }
1878 
1879 const cairo_scaled_font_backend_t _cairo_win32_scaled_font_backend = {
1880     CAIRO_FONT_TYPE_WIN32,
1881     _cairo_win32_scaled_font_fini,
1882     _cairo_win32_scaled_font_glyph_init,
1883     NULL, /* _cairo_win32_scaled_font_text_to_glyphs, FIXME */
1884     _cairo_win32_scaled_font_ucs4_to_index,
1885     _cairo_win32_scaled_font_show_glyphs,
1886     _cairo_win32_scaled_font_load_truetype_table,
1887     _cairo_win32_scaled_font_index_to_ucs4,
1888 };
1889 
1890 /* #cairo_win32_font_face_t */
1891 
1892 typedef struct _cairo_win32_font_face cairo_win32_font_face_t;
1893 
1894 /* If hfont is non-%NULL then logfont->lfHeight must be -S for some S,
1895  * logfont->lfWidth, logfont->lfEscapement, logfont->lfOrientation must
1896  * all be 0, and hfont is the result of calling CreateFontIndirectW on
1897  * logfont.
1898  */
1899 struct _cairo_win32_font_face {
1900     cairo_font_face_t base;
1901     LOGFONTW logfont;
1902     HFONT hfont;
1903 };
1904 
1905 /* implement the platform-specific interface */
1906 
1907 static void
1908 _cairo_win32_font_face_destroy (void *abstract_face);
1909 
1910 static cairo_bool_t
_is_scale(const cairo_matrix_t * matrix,double scale)1911 _is_scale (const cairo_matrix_t *matrix, double scale)
1912 {
1913     return matrix->xx == scale && matrix->yy == scale &&
1914            matrix->xy == 0. && matrix->yx == 0. &&
1915            matrix->x0 == 0. && matrix->y0 == 0.;
1916 }
1917 
1918 static cairo_status_t
_cairo_win32_font_face_scaled_font_create(void * abstract_face,const cairo_matrix_t * font_matrix,const cairo_matrix_t * ctm,const cairo_font_options_t * options,cairo_scaled_font_t ** font)1919 _cairo_win32_font_face_scaled_font_create (void			*abstract_face,
1920 					   const cairo_matrix_t	*font_matrix,
1921 					   const cairo_matrix_t	*ctm,
1922 					   const cairo_font_options_t *options,
1923 					   cairo_scaled_font_t **font)
1924 {
1925     HFONT hfont = NULL;
1926 
1927     cairo_win32_font_face_t *font_face = abstract_face;
1928 
1929     if (font_face->hfont) {
1930         /* Check whether it's OK to go ahead and use the font-face's HFONT. */
1931         if (_is_scale (ctm, 1.) &&
1932             _is_scale (font_matrix, -font_face->logfont.lfHeight)) {
1933             hfont = font_face->hfont;
1934         }
1935     }
1936 
1937     return _win32_scaled_font_create (&font_face->logfont,
1938 				      hfont,
1939 				      &font_face->base,
1940 				      font_matrix, ctm, options,
1941 				      font);
1942 }
1943 
1944 const cairo_font_face_backend_t _cairo_win32_font_face_backend = {
1945     CAIRO_FONT_TYPE_WIN32,
1946     _cairo_win32_font_face_create_for_toy,
1947     _cairo_win32_font_face_destroy,
1948     _cairo_win32_font_face_scaled_font_create
1949 };
1950 
1951 /* We maintain a hash table from LOGFONT,HFONT => #cairo_font_face_t.
1952  * The primary purpose of this mapping is to provide unique
1953  * #cairo_font_face_t values so that our cache and mapping from
1954  * #cairo_font_face_t => #cairo_scaled_font_t works. Once the
1955  * corresponding #cairo_font_face_t objects fall out of downstream
1956  * caches, we don't need them in this hash table anymore.
1957  *
1958  * Modifications to this hash table are protected by
1959  * _cairo_win32_font_face_mutex.
1960  *
1961  * Only #cairo_font_face_t values with null 'hfont' (no
1962  * HFONT preallocated by caller) are stored in this table. We rely
1963  * on callers to manage the lifetime of the HFONT, and they can't
1964  * do that if we share #cairo_font_face_t values with other callers.
1965  */
1966 
1967 static cairo_hash_table_t *cairo_win32_font_face_hash_table = NULL;
1968 
1969 static int
1970 _cairo_win32_font_face_keys_equal (const void *key_a,
1971 				   const void *key_b);
1972 
1973 static void
_cairo_win32_font_face_hash_table_destroy(void)1974 _cairo_win32_font_face_hash_table_destroy (void)
1975 {
1976     cairo_hash_table_t *hash_table;
1977 
1978     /* We manually acquire the lock rather than calling
1979      * _cairo_win32_font_face_hash_table_lock simply to avoid creating
1980      * the table only to destroy it again. */
1981     CAIRO_MUTEX_LOCK (_cairo_win32_font_face_mutex);
1982     hash_table = cairo_win32_font_face_hash_table;
1983     cairo_win32_font_face_hash_table = NULL;
1984     CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex);
1985 
1986     if (hash_table != NULL)
1987 	_cairo_hash_table_destroy (hash_table);
1988 }
1989 
1990 static cairo_hash_table_t *
_cairo_win32_font_face_hash_table_lock(void)1991 _cairo_win32_font_face_hash_table_lock (void)
1992 {
1993     CAIRO_MUTEX_LOCK (_cairo_win32_font_face_mutex);
1994 
1995     if (unlikely (cairo_win32_font_face_hash_table == NULL))
1996     {
1997 	cairo_win32_font_face_hash_table =
1998 	_cairo_hash_table_create (_cairo_win32_font_face_keys_equal);
1999 
2000 	if (unlikely (cairo_win32_font_face_hash_table == NULL)) {
2001 	    CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex);
2002 	    _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
2003 	    return NULL;
2004 	}
2005     }
2006 
2007     return cairo_win32_font_face_hash_table;
2008 }
2009 
2010 static void
_cairo_win32_font_face_hash_table_unlock(void)2011 _cairo_win32_font_face_hash_table_unlock (void)
2012 {
2013     CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex);
2014 }
2015 
2016 static void
_cairo_win32_font_face_init_key(cairo_win32_font_face_t * key,LOGFONTW * logfont,HFONT font)2017 _cairo_win32_font_face_init_key (cairo_win32_font_face_t *key,
2018 				 LOGFONTW                *logfont,
2019 				 HFONT                    font)
2020 {
2021     unsigned long hash = _CAIRO_HASH_INIT_VALUE;
2022 
2023     key->logfont = *logfont;
2024     key->hfont = font;
2025 
2026     hash = _cairo_hash_bytes (0, logfont->lfFaceName, 2*wcslen(logfont->lfFaceName));
2027     hash = _cairo_hash_bytes (hash, &logfont->lfWeight, sizeof(logfont->lfWeight));
2028     hash = _cairo_hash_bytes (hash, &logfont->lfItalic, sizeof(logfont->lfItalic));
2029 
2030     key->base.hash_entry.hash = hash;
2031 }
2032 
2033 static int
_cairo_win32_font_face_keys_equal(const void * key_a,const void * key_b)2034 _cairo_win32_font_face_keys_equal (const void *key_a,
2035 				   const void *key_b)
2036 {
2037     const cairo_win32_font_face_t *face_a = key_a;
2038     const cairo_win32_font_face_t *face_b = key_b;
2039 
2040     if (face_a->logfont.lfWeight         == face_b->logfont.lfWeight &&
2041 	face_a->logfont.lfItalic         == face_b->logfont.lfItalic &&
2042 	face_a->logfont.lfUnderline      == face_b->logfont.lfUnderline &&
2043 	face_a->logfont.lfStrikeOut      == face_b->logfont.lfStrikeOut &&
2044 	face_a->logfont.lfCharSet        == face_b->logfont.lfCharSet &&
2045 	face_a->logfont.lfOutPrecision   == face_b->logfont.lfOutPrecision &&
2046 	face_a->logfont.lfClipPrecision  == face_b->logfont.lfClipPrecision &&
2047 	face_a->logfont.lfPitchAndFamily == face_b->logfont.lfPitchAndFamily &&
2048 	(wcscmp (face_a->logfont.lfFaceName, face_b->logfont.lfFaceName) == 0))
2049 	return TRUE;
2050     else
2051 	return FALSE;
2052 }
2053 
2054 static void
_cairo_win32_font_face_destroy(void * abstract_face)2055 _cairo_win32_font_face_destroy (void *abstract_face)
2056 {
2057     cairo_hash_table_t *hash_table;
2058     cairo_win32_font_face_t *font_face = abstract_face;
2059 
2060     if (!font_face->hfont) {
2061         hash_table = _cairo_win32_font_face_hash_table_lock ();
2062         if (unlikely (hash_table == NULL)) {
2063             return;
2064         }
2065         _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry);
2066         _cairo_win32_font_face_hash_table_unlock ();
2067     }
2068 }
2069 
2070 /**
2071  * cairo_win32_font_face_create_for_logfontw_hfont:
2072  * @logfont: A #LOGFONTW structure specifying the font to use.
2073  *   If @font is %NULL then the lfHeight, lfWidth, lfOrientation and lfEscapement
2074  *   fields of this structure are ignored. Otherwise lfWidth, lfOrientation and
2075  *   lfEscapement must be zero.
2076  * @font: An #HFONT that can be used when the font matrix is a scale by
2077  *   -lfHeight and the CTM is identity.
2078  *
2079  * Creates a new font for the Win32 font backend based on a
2080  * #LOGFONT. This font can then be used with
2081  * cairo_set_font_face() or cairo_scaled_font_create().
2082  * The #cairo_scaled_font_t
2083  * returned from cairo_scaled_font_create() is also for the Win32 backend
2084  * and can be used with functions such as cairo_win32_scaled_font_select_font().
2085  *
2086  * Return value: a newly created #cairo_font_face_t. Free with
2087  *  cairo_font_face_destroy() when you are done using it.
2088  **/
2089 cairo_font_face_t *
cairo_win32_font_face_create_for_logfontw_hfont(LOGFONTW * logfont,HFONT font)2090 cairo_win32_font_face_create_for_logfontw_hfont (LOGFONTW *logfont, HFONT font)
2091 {
2092     cairo_win32_font_face_t *font_face, key;
2093     cairo_hash_table_t *hash_table;
2094     cairo_status_t status;
2095 
2096     if (!font) {
2097         hash_table = _cairo_win32_font_face_hash_table_lock ();
2098         if (unlikely (hash_table == NULL)) {
2099             _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
2100 	    return (cairo_font_face_t *)&_cairo_font_face_nil;
2101         }
2102 
2103         _cairo_win32_font_face_init_key (&key, logfont, font);
2104 
2105         /* Return existing unscaled font if it exists in the hash table. */
2106         font_face = _cairo_hash_table_lookup (hash_table,
2107                                               &key.base.hash_entry);
2108         if (font_face != NULL) {
2109 	    cairo_font_face_reference (&font_face->base);
2110 	    goto DONE;
2111         }
2112     }
2113 
2114     /* Otherwise create it and insert into hash table. */
2115     font_face = malloc (sizeof (cairo_win32_font_face_t));
2116     if (!font_face) {
2117         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
2118 	goto FAIL;
2119     }
2120 
2121     _cairo_win32_font_face_init_key (font_face, logfont, font);
2122     _cairo_font_face_init (&font_face->base, &_cairo_win32_font_face_backend);
2123 
2124     if (!font) {
2125         assert (font_face->base.hash_entry.hash == key.base.hash_entry.hash);
2126         status = _cairo_hash_table_insert (hash_table,
2127                                            &font_face->base.hash_entry);
2128         if (unlikely (status))
2129 	    goto FAIL;
2130     }
2131 
2132 DONE:
2133     if (!font) {
2134         _cairo_win32_font_face_hash_table_unlock ();
2135     }
2136 
2137     return &font_face->base;
2138 
2139 FAIL:
2140     if (!font) {
2141         _cairo_win32_font_face_hash_table_unlock ();
2142     }
2143 
2144     return (cairo_font_face_t *)&_cairo_font_face_nil;
2145 }
2146 
2147 /**
2148  * cairo_win32_font_face_create_for_logfontw:
2149  * @logfont: A #LOGFONTW structure specifying the font to use.
2150  *   The lfHeight, lfWidth, lfOrientation and lfEscapement
2151  *   fields of this structure are ignored.
2152  *
2153  * Creates a new font for the Win32 font backend based on a
2154  * #LOGFONT. This font can then be used with
2155  * cairo_set_font_face() or cairo_scaled_font_create().
2156  * The #cairo_scaled_font_t
2157  * returned from cairo_scaled_font_create() is also for the Win32 backend
2158  * and can be used with functions such as cairo_win32_scaled_font_select_font().
2159  *
2160  * Return value: a newly created #cairo_font_face_t. Free with
2161  *  cairo_font_face_destroy() when you are done using it.
2162  **/
2163 cairo_font_face_t *
cairo_win32_font_face_create_for_logfontw(LOGFONTW * logfont)2164 cairo_win32_font_face_create_for_logfontw (LOGFONTW *logfont)
2165 {
2166     return cairo_win32_font_face_create_for_logfontw_hfont (logfont, NULL);
2167 }
2168 
2169 /**
2170  * cairo_win32_font_face_create_for_hfont:
2171  * @font: An #HFONT structure specifying the font to use.
2172  *
2173  * Creates a new font for the Win32 font backend based on a
2174  * #HFONT. This font can then be used with
2175  * cairo_set_font_face() or cairo_scaled_font_create().
2176  * The #cairo_scaled_font_t
2177  * returned from cairo_scaled_font_create() is also for the Win32 backend
2178  * and can be used with functions such as cairo_win32_scaled_font_select_font().
2179  *
2180  * Return value: a newly created #cairo_font_face_t. Free with
2181  *  cairo_font_face_destroy() when you are done using it.
2182  **/
2183 cairo_font_face_t *
cairo_win32_font_face_create_for_hfont(HFONT font)2184 cairo_win32_font_face_create_for_hfont (HFONT font)
2185 {
2186     LOGFONTW logfont;
2187     GetObjectW (font, sizeof(logfont), &logfont);
2188 
2189     if (logfont.lfEscapement != 0 || logfont.lfOrientation != 0 ||
2190         logfont.lfWidth != 0) {
2191         /* We can't use this font because that optimization requires that
2192          * lfEscapement, lfOrientation and lfWidth be zero. */
2193         font = NULL;
2194     }
2195 
2196     return cairo_win32_font_face_create_for_logfontw_hfont (&logfont, font);
2197 }
2198 
2199 static cairo_bool_t
_cairo_scaled_font_is_win32(cairo_scaled_font_t * scaled_font)2200 _cairo_scaled_font_is_win32 (cairo_scaled_font_t *scaled_font)
2201 {
2202     return scaled_font->backend == &_cairo_win32_scaled_font_backend;
2203 }
2204 
2205 /**
2206  * cairo_win32_scaled_font_select_font:
2207  * @scaled_font: A #cairo_scaled_font_t from the Win32 font backend. Such an
2208  *   object can be created with cairo_win32_scaled_font_create_for_logfontw().
2209  * @hdc: a device context
2210  *
2211  * Selects the font into the given device context and changes the
2212  * map mode and world transformation of the device context to match
2213  * that of the font. This function is intended for use when using
2214  * layout APIs such as Uniscribe to do text layout with the
2215  * cairo font. After finishing using the device context, you must call
2216  * cairo_win32_scaled_font_done_font() to release any resources allocated
2217  * by this function.
2218  *
2219  * See cairo_win32_scaled_font_get_metrics_factor() for converting logical
2220  * coordinates from the device context to font space.
2221  *
2222  * Normally, calls to SaveDC() and RestoreDC() would be made around
2223  * the use of this function to preserve the original graphics state.
2224  *
2225  * Return value: %CAIRO_STATUS_SUCCESS if the operation succeeded.
2226  *   otherwise an error such as %CAIRO_STATUS_NO_MEMORY and
2227  *   the device context is unchanged.
2228  **/
2229 cairo_status_t
cairo_win32_scaled_font_select_font(cairo_scaled_font_t * scaled_font,HDC hdc)2230 cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font,
2231 				     HDC                  hdc)
2232 {
2233     cairo_status_t status;
2234     HFONT hfont;
2235     HFONT old_hfont = NULL;
2236     int old_mode;
2237 
2238     if (! _cairo_scaled_font_is_win32 (scaled_font)) {
2239 	return _cairo_error (CAIRO_STATUS_FONT_TYPE_MISMATCH);
2240     }
2241 
2242     if (scaled_font->status)
2243 	return scaled_font->status;
2244 
2245     status = _win32_scaled_font_get_scaled_hfont ((cairo_win32_scaled_font_t *)scaled_font, &hfont);
2246     if (status)
2247 	return status;
2248 
2249     old_hfont = SelectObject (hdc, hfont);
2250     if (!old_hfont)
2251 	return _cairo_win32_print_gdi_error ("cairo_win32_scaled_font_select_font:SelectObject");
2252 
2253     old_mode = SetGraphicsMode (hdc, GM_ADVANCED);
2254     if (!old_mode) {
2255 	status = _cairo_win32_print_gdi_error ("cairo_win32_scaled_font_select_font:SetGraphicsMode");
2256 	SelectObject (hdc, old_hfont);
2257 	return status;
2258     }
2259 
2260     status = _win32_scaled_font_set_world_transform ((cairo_win32_scaled_font_t *)scaled_font, hdc);
2261     if (status) {
2262 	SetGraphicsMode (hdc, old_mode);
2263 	SelectObject (hdc, old_hfont);
2264 	return status;
2265     }
2266 
2267     SetMapMode (hdc, MM_TEXT);
2268 
2269     return CAIRO_STATUS_SUCCESS;
2270 }
2271 
2272 /**
2273  * cairo_win32_scaled_font_done_font:
2274  * @scaled_font: A scaled font from the Win32 font backend.
2275  *
2276  * Releases any resources allocated by cairo_win32_scaled_font_select_font()
2277  **/
2278 void
cairo_win32_scaled_font_done_font(cairo_scaled_font_t * scaled_font)2279 cairo_win32_scaled_font_done_font (cairo_scaled_font_t *scaled_font)
2280 {
2281     if (! _cairo_scaled_font_is_win32 (scaled_font)) {
2282 	_cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH);
2283     }
2284 }
2285 
2286 /**
2287  * cairo_win32_scaled_font_get_metrics_factor:
2288  * @scaled_font: a scaled font from the Win32 font backend
2289  *
2290  * Gets a scale factor between logical coordinates in the coordinate
2291  * space used by cairo_win32_scaled_font_select_font() (that is, the
2292  * coordinate system used by the Windows functions to return metrics) and
2293  * font space coordinates.
2294  *
2295  * Return value: factor to multiply logical units by to get font space
2296  *               coordinates.
2297  **/
2298 double
cairo_win32_scaled_font_get_metrics_factor(cairo_scaled_font_t * scaled_font)2299 cairo_win32_scaled_font_get_metrics_factor (cairo_scaled_font_t *scaled_font)
2300 {
2301     if (! _cairo_scaled_font_is_win32 (scaled_font)) {
2302 	_cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH);
2303 	return 1.;
2304     }
2305     return 1. / ((cairo_win32_scaled_font_t *)scaled_font)->logical_scale;
2306 }
2307 
2308 /**
2309  * cairo_win32_scaled_font_get_logical_to_device:
2310  * @scaled_font: a scaled font from the Win32 font backend
2311  * @logical_to_device: matrix to return
2312  *
2313  * Gets the transformation mapping the logical space used by @scaled_font
2314  * to device space.
2315  *
2316  * Since: 1.4
2317  **/
2318 void
cairo_win32_scaled_font_get_logical_to_device(cairo_scaled_font_t * scaled_font,cairo_matrix_t * logical_to_device)2319 cairo_win32_scaled_font_get_logical_to_device (cairo_scaled_font_t *scaled_font,
2320 					       cairo_matrix_t *logical_to_device)
2321 {
2322     cairo_win32_scaled_font_t *win_font = (cairo_win32_scaled_font_t *)scaled_font;
2323     if (! _cairo_scaled_font_is_win32 (scaled_font)) {
2324 	_cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH);
2325 	cairo_matrix_init_identity (logical_to_device);
2326 	return;
2327     }
2328     *logical_to_device = win_font->logical_to_device;
2329 }
2330 
2331 /**
2332  * cairo_win32_scaled_font_get_device_to_logical:
2333  * @scaled_font: a scaled font from the Win32 font backend
2334  * @device_to_logical: matrix to return
2335  *
2336  * Gets the transformation mapping device space to the logical space
2337  * used by @scaled_font.
2338  *
2339  * Since: 1.4
2340  **/
2341 void
cairo_win32_scaled_font_get_device_to_logical(cairo_scaled_font_t * scaled_font,cairo_matrix_t * device_to_logical)2342 cairo_win32_scaled_font_get_device_to_logical (cairo_scaled_font_t *scaled_font,
2343 					       cairo_matrix_t *device_to_logical)
2344 {
2345     cairo_win32_scaled_font_t *win_font = (cairo_win32_scaled_font_t *)scaled_font;
2346     if (! _cairo_scaled_font_is_win32 (scaled_font)) {
2347 	_cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH);
2348 	cairo_matrix_init_identity (device_to_logical);
2349 	return;
2350     }
2351     *device_to_logical = win_font->device_to_logical;
2352 }
2353 
2354 void
_cairo_win32_font_reset_static_data(void)2355 _cairo_win32_font_reset_static_data (void)
2356 {
2357     _cairo_win32_font_face_hash_table_destroy ();
2358 }
2359