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