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 � 2010 Mozilla Foundation
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 the Mozilla Foundation
32 *
33 * Contributor(s):
34 * Bas Schouten <bschouten@mozilla.com>
35 */
36
37 #include "cairoint.h"
38
39 #include "cairo-win32-private.h"
40 #include "cairo-surface-private.h"
41 #include "cairo-clip-private.h"
42
43 #include "cairo-d2d-private.h"
44 #include "cairo-dwrite-private.h"
45 #include "cairo-truetype-subset-private.h"
46 #include <float.h>
47
48 typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)(
49 D2D1_FACTORY_TYPE factoryType,
50 REFIID iid,
51 CONST D2D1_FACTORY_OPTIONS *pFactoryOptions,
52 void **factory
53 );
54
55 #define CAIRO_INT_STATUS_SUCCESS (cairo_int_status_t)CAIRO_STATUS_SUCCESS
56
57 // Forward declarations
58 cairo_int_status_t
59 _dwrite_draw_glyphs_to_gdi_surface_d2d(cairo_win32_surface_t *surface,
60 DWRITE_MATRIX *transform,
61 DWRITE_GLYPH_RUN *run,
62 COLORREF color,
63 const RECT &area);
64
65 cairo_int_status_t
66 _dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
67 DWRITE_MATRIX *transform,
68 DWRITE_GLYPH_RUN *run,
69 COLORREF color,
70 cairo_dwrite_scaled_font_t *scaled_font,
71 const RECT &area);
72
73 class D2DFactory
74 {
75 public:
Instance()76 static ID2D1Factory *Instance()
77 {
78 if (!mFactoryInstance) {
79 D2D1CreateFactoryFunc createD2DFactory = (D2D1CreateFactoryFunc)
80 GetProcAddress(LoadLibraryW(L"d2d1.dll"), "D2D1CreateFactory");
81 if (createD2DFactory) {
82 D2D1_FACTORY_OPTIONS options;
83 options.debugLevel = D2D1_DEBUG_LEVEL_NONE;
84 createD2DFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
85 __uuidof(ID2D1Factory),
86 &options,
87 (void**)&mFactoryInstance);
88 }
89 }
90 return mFactoryInstance;
91 }
92
RenderTarget()93 static ID2D1DCRenderTarget *RenderTarget()
94 {
95 if (!mRenderTarget) {
96 if (!Instance()) {
97 return NULL;
98 }
99 // Create a DC render target.
100 D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
101 D2D1_RENDER_TARGET_TYPE_DEFAULT,
102 D2D1::PixelFormat(
103 DXGI_FORMAT_B8G8R8A8_UNORM,
104 D2D1_ALPHA_MODE_PREMULTIPLIED),
105 0,
106 0,
107 D2D1_RENDER_TARGET_USAGE_NONE,
108 D2D1_FEATURE_LEVEL_DEFAULT
109 );
110
111 Instance()->CreateDCRenderTarget(&props, &mRenderTarget);
112 }
113 return mRenderTarget;
114 }
115
116 private:
117 static ID2D1Factory *mFactoryInstance;
118 static ID2D1DCRenderTarget *mRenderTarget;
119 };
120
121 IDWriteFactory *DWriteFactory::mFactoryInstance = NULL;
122 IDWriteFontCollection *DWriteFactory::mSystemCollection = NULL;
123 IDWriteRenderingParams *DWriteFactory::mDefaultRenderingParams = NULL;
124 IDWriteRenderingParams *DWriteFactory::mCustomClearTypeRenderingParams = NULL;
125 IDWriteRenderingParams *DWriteFactory::mForceGDIClassicRenderingParams = NULL;
126 FLOAT DWriteFactory::mGamma = -1.0;
127 FLOAT DWriteFactory::mEnhancedContrast = -1.0;
128 FLOAT DWriteFactory::mClearTypeLevel = -1.0;
129 int DWriteFactory::mPixelGeometry = -1;
130 int DWriteFactory::mRenderingMode = -1;
131
132 ID2D1Factory *D2DFactory::mFactoryInstance = NULL;
133 ID2D1DCRenderTarget *D2DFactory::mRenderTarget = NULL;
134
135 /* Functions cairo_font_face_backend_t */
136 static cairo_status_t
137 _cairo_dwrite_font_face_create_for_toy (cairo_toy_font_face_t *toy_face,
138 cairo_font_face_t **font_face);
139 static void
140 _cairo_dwrite_font_face_destroy (void *font_face);
141
142 static cairo_status_t
143 _cairo_dwrite_font_face_scaled_font_create (void *abstract_face,
144 const cairo_matrix_t *font_matrix,
145 const cairo_matrix_t *ctm,
146 const cairo_font_options_t *options,
147 cairo_scaled_font_t **font);
148
149 const cairo_font_face_backend_t _cairo_dwrite_font_face_backend = {
150 CAIRO_FONT_TYPE_DWRITE,
151 _cairo_dwrite_font_face_create_for_toy,
152 _cairo_dwrite_font_face_destroy,
153 _cairo_dwrite_font_face_scaled_font_create
154 };
155
156 /* Functions cairo_scaled_font_backend_t */
157
158 void _cairo_dwrite_scaled_font_fini(void *scaled_font);
159
160 static cairo_warn cairo_int_status_t
161 _cairo_dwrite_scaled_glyph_init(void *scaled_font,
162 cairo_scaled_glyph_t *scaled_glyph,
163 cairo_scaled_glyph_info_t info);
164
165 cairo_warn cairo_int_status_t
166 _cairo_dwrite_scaled_show_glyphs(void *scaled_font,
167 cairo_operator_t op,
168 const cairo_pattern_t *pattern,
169 cairo_surface_t *surface,
170 int source_x,
171 int source_y,
172 int dest_x,
173 int dest_y,
174 unsigned int width,
175 unsigned int height,
176 cairo_glyph_t *glyphs,
177 int num_glyphs,
178 cairo_region_t *clip_region,
179 int *remaining_glyphs);
180
181 cairo_int_status_t
182 _cairo_dwrite_load_truetype_table(void *scaled_font,
183 unsigned long tag,
184 long offset,
185 unsigned char *buffer,
186 unsigned long *length);
187
188 unsigned long
189 _cairo_dwrite_ucs4_to_index(void *scaled_font,
190 uint32_t ucs4);
191
192 const cairo_scaled_font_backend_t _cairo_dwrite_scaled_font_backend = {
193 CAIRO_FONT_TYPE_DWRITE,
194 _cairo_dwrite_scaled_font_fini,
195 _cairo_dwrite_scaled_glyph_init,
196 NULL,
197 _cairo_dwrite_ucs4_to_index,
198 _cairo_dwrite_scaled_show_glyphs,
199 _cairo_dwrite_load_truetype_table,
200 NULL,
201 };
202
203 /* Helper conversion functions */
204
205 /**
206 * Get a D2D matrix from a cairo matrix. Note that D2D uses row vectors where cairo
207 * uses column vectors. Hence the transposition.
208 *
209 * \param Cairo matrix
210 * \return D2D matrix
211 */
212 static D2D1::Matrix3x2F
_cairo_d2d_matrix_from_matrix(const cairo_matrix_t * matrix)213 _cairo_d2d_matrix_from_matrix(const cairo_matrix_t *matrix)
214 {
215 return D2D1::Matrix3x2F((FLOAT)matrix->xx,
216 (FLOAT)matrix->yx,
217 (FLOAT)matrix->xy,
218 (FLOAT)matrix->yy,
219 (FLOAT)matrix->x0,
220 (FLOAT)matrix->y0);
221 }
222
223
224 /**
225 * Get a DirectWrite matrix from a cairo matrix. Note that DirectWrite uses row
226 * vectors where cairo uses column vectors. Hence the transposition.
227 *
228 * \param Cairo matrix
229 * \return DirectWrite matrix
230 */
231 DWRITE_MATRIX
_cairo_dwrite_matrix_from_matrix(const cairo_matrix_t * matrix)232 _cairo_dwrite_matrix_from_matrix(const cairo_matrix_t *matrix)
233 {
234 DWRITE_MATRIX dwmat;
235 dwmat.m11 = (FLOAT)matrix->xx;
236 dwmat.m12 = (FLOAT)matrix->yx;
237 dwmat.m21 = (FLOAT)matrix->xy;
238 dwmat.m22 = (FLOAT)matrix->yy;
239 dwmat.dx = (FLOAT)matrix->x0;
240 dwmat.dy = (FLOAT)matrix->y0;
241 return dwmat;
242 }
243
244 /* Helper functions for cairo_dwrite_scaled_glyph_init */
245 cairo_int_status_t
246 _cairo_dwrite_scaled_font_init_glyph_metrics
247 (cairo_dwrite_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph);
248
249 cairo_int_status_t
250 _cairo_dwrite_scaled_font_init_glyph_surface
251 (cairo_dwrite_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph);
252
253 cairo_int_status_t
254 _cairo_dwrite_scaled_font_init_glyph_path
255 (cairo_dwrite_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph);
256
257 /* implement the font backend interface */
258
259 static cairo_status_t
_cairo_dwrite_font_face_create_for_toy(cairo_toy_font_face_t * toy_face,cairo_font_face_t ** font_face)260 _cairo_dwrite_font_face_create_for_toy (cairo_toy_font_face_t *toy_face,
261 cairo_font_face_t **font_face)
262 {
263 WCHAR *face_name;
264 int face_name_len;
265
266 if (!DWriteFactory::Instance()) {
267 return (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED;
268 }
269
270 face_name_len = MultiByteToWideChar(CP_UTF8, 0, toy_face->family, -1, NULL, 0);
271 face_name = new WCHAR[face_name_len];
272 MultiByteToWideChar(CP_UTF8, 0, toy_face->family, -1, face_name, face_name_len);
273
274 IDWriteFontFamily *family = DWriteFactory::FindSystemFontFamily(face_name);
275 delete face_name;
276 if (!family) {
277 *font_face = (cairo_font_face_t*)&_cairo_font_face_nil;
278 return CAIRO_STATUS_FONT_TYPE_MISMATCH;
279 }
280
281 DWRITE_FONT_WEIGHT weight;
282 switch (toy_face->weight) {
283 case CAIRO_FONT_WEIGHT_BOLD:
284 weight = DWRITE_FONT_WEIGHT_BOLD;
285 break;
286 case CAIRO_FONT_WEIGHT_NORMAL:
287 default:
288 weight = DWRITE_FONT_WEIGHT_NORMAL;
289 break;
290 }
291
292 DWRITE_FONT_STYLE style;
293 switch (toy_face->slant) {
294 case CAIRO_FONT_SLANT_ITALIC:
295 style = DWRITE_FONT_STYLE_ITALIC;
296 break;
297 case CAIRO_FONT_SLANT_OBLIQUE:
298 style = DWRITE_FONT_STYLE_OBLIQUE;
299 break;
300 case CAIRO_FONT_SLANT_NORMAL:
301 default:
302 style = DWRITE_FONT_STYLE_NORMAL;
303 break;
304 }
305
306 cairo_dwrite_font_face_t *face = (cairo_dwrite_font_face_t*)malloc(sizeof(cairo_dwrite_font_face_t));
307 HRESULT hr = family->GetFirstMatchingFont(weight, DWRITE_FONT_STRETCH_NORMAL, style, &face->font);
308 if (SUCCEEDED(hr)) {
309 // Cannot use C++ style new since cairo deallocates this.
310 *font_face = (cairo_font_face_t*)face;
311 _cairo_font_face_init (&(*(_cairo_dwrite_font_face**)font_face)->base, &_cairo_dwrite_font_face_backend);
312 } else {
313 free(face);
314 }
315
316 return CAIRO_STATUS_SUCCESS;
317 }
318
319 static void
_cairo_dwrite_font_face_destroy(void * font_face)320 _cairo_dwrite_font_face_destroy (void *font_face)
321 {
322 cairo_dwrite_font_face_t *dwrite_font_face = static_cast<cairo_dwrite_font_face_t*>(font_face);
323 if (dwrite_font_face->dwriteface)
324 dwrite_font_face->dwriteface->Release();
325 if (dwrite_font_face->font)
326 dwrite_font_face->font->Release();
327 }
328
329
330 static inline unsigned short
read_short(const char * buf)331 read_short(const char *buf)
332 {
333 return be16_to_cpu(*(unsigned short*)buf);
334 }
335
336 void
_cairo_dwrite_glyph_run_from_glyphs(cairo_glyph_t * glyphs,int num_glyphs,cairo_dwrite_scaled_font_t * scaled_font,AutoDWriteGlyphRun * run,cairo_bool_t * transformed)337 _cairo_dwrite_glyph_run_from_glyphs(cairo_glyph_t *glyphs,
338 int num_glyphs,
339 cairo_dwrite_scaled_font_t *scaled_font,
340 AutoDWriteGlyphRun *run,
341 cairo_bool_t *transformed)
342 {
343 run->allocate(num_glyphs);
344
345 UINT16 *indices = const_cast<UINT16*>(run->glyphIndices);
346 FLOAT *advances = const_cast<FLOAT*>(run->glyphAdvances);
347 DWRITE_GLYPH_OFFSET *offsets = const_cast<DWRITE_GLYPH_OFFSET*>(run->glyphOffsets);
348
349 cairo_dwrite_font_face_t *dwriteff = reinterpret_cast<cairo_dwrite_font_face_t*>(scaled_font->base.font_face);
350
351 run->bidiLevel = 0;
352 run->fontFace = dwriteff->dwriteface;
353 run->glyphCount = num_glyphs;
354 run->isSideways = FALSE;
355
356 if (scaled_font->mat.xy == 0 && scaled_font->mat.yx == 0 &&
357 scaled_font->mat.xx == scaled_font->base.font_matrix.xx &&
358 scaled_font->mat.yy == scaled_font->base.font_matrix.yy) {
359 // Fast route, don't actually use a transform but just
360 // set the correct font size.
361 *transformed = 0;
362
363 run->fontEmSize = (FLOAT)scaled_font->base.font_matrix.yy;
364
365 for (int i = 0; i < num_glyphs; i++) {
366 indices[i] = (WORD) glyphs[i].index;
367
368 offsets[i].ascenderOffset = -(FLOAT)(glyphs[i].y);
369 offsets[i].advanceOffset = (FLOAT)(glyphs[i].x);
370 advances[i] = 0.0;
371 }
372 } else {
373 *transformed = 1;
374 // Transforming positions by the inverse matrix, then by the original
375 // matrix later may introduce small errors, especially because the
376 // D2D matrix is single-precision whereas the cairo one is double.
377 // This is a problem when glyph positions were originally at exactly
378 // half-pixel locations, which eventually round to whole pixels for
379 // GDI rendering - the errors introduced here cause them to round in
380 // unpredictable directions, instead of all rounding in a consistent
381 // way, leading to poor glyph spacing (bug 675383).
382 // To mitigate this, nudge the positions by a tiny amount to try and
383 // ensure that after the two transforms, they'll still round in a
384 // consistent direction.
385 const double EPSILON = 0.0001;
386 for (int i = 0; i < num_glyphs; i++) {
387 indices[i] = (WORD) glyphs[i].index;
388 double x = glyphs[i].x + EPSILON;
389 double y = glyphs[i].y;
390 cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y);
391 // Since we will multiply by our ctm matrix later for rotation effects
392 // and such, adjust positions by the inverse matrix now. Y-axis is
393 // inverted! Therefor the offset is -y.
394 offsets[i].ascenderOffset = -(FLOAT)y;
395 offsets[i].advanceOffset = (FLOAT)x;
396 advances[i] = 0.0;
397 }
398 // The font matrix takes care of the scaling if we have a transform,
399 // emSize should be 1.
400 run->fontEmSize = 1.0f;
401 }
402 }
403
404 #define GASP_TAG 0x70736167
405 #define GASP_DOGRAY 0x2
406
407 static cairo_bool_t
do_grayscale(IDWriteFontFace * dwface,unsigned int ppem)408 do_grayscale(IDWriteFontFace *dwface, unsigned int ppem)
409 {
410 void *tableContext;
411 char *tableData;
412 UINT32 tableSize;
413 BOOL exists;
414 dwface->TryGetFontTable(GASP_TAG, (const void**)&tableData, &tableSize, &tableContext, &exists);
415
416 if (exists) {
417 if (tableSize < 4) {
418 dwface->ReleaseFontTable(tableContext);
419 return true;
420 }
421 struct gaspRange {
422 unsigned short maxPPEM; // Stored big-endian
423 unsigned short behavior; // Stored big-endian
424 };
425 unsigned short numRanges = read_short(tableData + 2);
426 if (tableSize < (UINT)4 + numRanges * 4) {
427 dwface->ReleaseFontTable(tableContext);
428 return true;
429 }
430 gaspRange *ranges = (gaspRange *)(tableData + 4);
431 for (int i = 0; i < numRanges; i++) {
432 if (be16_to_cpu(ranges[i].maxPPEM) > ppem) {
433 if (!(be16_to_cpu(ranges[i].behavior) & GASP_DOGRAY)) {
434 dwface->ReleaseFontTable(tableContext);
435 return false;
436 }
437 break;
438 }
439 }
440 dwface->ReleaseFontTable(tableContext);
441 }
442 return true;
443 }
444
445 static cairo_status_t
_cairo_dwrite_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)446 _cairo_dwrite_font_face_scaled_font_create (void *abstract_face,
447 const cairo_matrix_t *font_matrix,
448 const cairo_matrix_t *ctm,
449 const cairo_font_options_t *options,
450 cairo_scaled_font_t **font)
451 {
452 cairo_dwrite_font_face_t *font_face = static_cast<cairo_dwrite_font_face_t*>(abstract_face);
453
454 // Must do malloc and not C++ new, since Cairo frees this.
455 cairo_dwrite_scaled_font_t *dwriteFont = (cairo_dwrite_scaled_font_t*)malloc(sizeof(cairo_dwrite_scaled_font_t));
456 *font = reinterpret_cast<cairo_scaled_font_t*>(dwriteFont);
457 _cairo_scaled_font_init(&dwriteFont->base, &font_face->base, font_matrix, ctm, options, &_cairo_dwrite_scaled_font_backend);
458
459 cairo_font_extents_t extents;
460
461 DWRITE_FONT_METRICS metrics;
462 font_face->dwriteface->GetMetrics(&metrics);
463
464 extents.ascent = (FLOAT)metrics.ascent / metrics.designUnitsPerEm;
465 extents.descent = (FLOAT)metrics.descent / metrics.designUnitsPerEm;
466 extents.height = (FLOAT)(metrics.ascent + metrics.descent + metrics.lineGap) / metrics.designUnitsPerEm;
467 extents.max_x_advance = 14.0;
468 extents.max_y_advance = 0.0;
469
470 dwriteFont->mat = dwriteFont->base.ctm;
471 cairo_matrix_multiply(&dwriteFont->mat, &dwriteFont->mat, font_matrix);
472 dwriteFont->mat_inverse = dwriteFont->mat;
473 cairo_matrix_invert (&dwriteFont->mat_inverse);
474
475 cairo_antialias_t default_quality = CAIRO_ANTIALIAS_SUBPIXEL;
476
477 dwriteFont->measuring_mode = DWRITE_MEASURING_MODE_NATURAL;
478
479 // The following code detects the system quality at scaled_font creation time,
480 // this means that if cleartype settings are changed but the scaled_fonts
481 // are re-used, they might not adhere to the new system setting until re-
482 // creation.
483 switch (cairo_win32_get_system_text_quality()) {
484 case CLEARTYPE_QUALITY:
485 default_quality = CAIRO_ANTIALIAS_SUBPIXEL;
486 break;
487 case ANTIALIASED_QUALITY:
488 default_quality = CAIRO_ANTIALIAS_GRAY;
489 dwriteFont->measuring_mode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
490 break;
491 case DEFAULT_QUALITY:
492 // _get_system_quality() seems to think aliased is default!
493 default_quality = CAIRO_ANTIALIAS_NONE;
494 dwriteFont->measuring_mode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
495 break;
496 }
497
498 if (default_quality == CAIRO_ANTIALIAS_GRAY) {
499 if (!do_grayscale(font_face->dwriteface, (unsigned int)_cairo_round(font_matrix->yy))) {
500 default_quality = CAIRO_ANTIALIAS_NONE;
501 }
502 }
503
504 if (options->antialias == CAIRO_ANTIALIAS_DEFAULT) {
505 dwriteFont->antialias_mode = default_quality;
506 } else {
507 dwriteFont->antialias_mode = options->antialias;
508 }
509
510 dwriteFont->manual_show_glyphs_allowed = TRUE;
511 dwriteFont->rendering_mode =
512 default_quality == CAIRO_ANTIALIAS_SUBPIXEL ?
513 cairo_d2d_surface_t::TEXT_RENDERING_NORMAL : cairo_d2d_surface_t::TEXT_RENDERING_NO_CLEARTYPE;
514
515 return _cairo_scaled_font_set_metrics (*font, &extents);
516 }
517
518 /* Implementation cairo_dwrite_scaled_font_backend_t */
519 void
_cairo_dwrite_scaled_font_fini(void * scaled_font)520 _cairo_dwrite_scaled_font_fini(void *scaled_font)
521 {
522 }
523
524 static cairo_int_status_t
_cairo_dwrite_scaled_glyph_init(void * scaled_font,cairo_scaled_glyph_t * scaled_glyph,cairo_scaled_glyph_info_t info)525 _cairo_dwrite_scaled_glyph_init(void *scaled_font,
526 cairo_scaled_glyph_t *scaled_glyph,
527 cairo_scaled_glyph_info_t info)
528 {
529 cairo_dwrite_scaled_font_t *scaled_dwrite_font = static_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
530 cairo_int_status_t status;
531
532 if ((info & CAIRO_SCALED_GLYPH_INFO_METRICS) != 0) {
533 status = _cairo_dwrite_scaled_font_init_glyph_metrics (scaled_dwrite_font, scaled_glyph);
534 if (status)
535 return status;
536 }
537
538 if (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) {
539 status = _cairo_dwrite_scaled_font_init_glyph_surface (scaled_dwrite_font, scaled_glyph);
540 if (status)
541 return status;
542 }
543
544 if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0) {
545 status = _cairo_dwrite_scaled_font_init_glyph_path (scaled_dwrite_font, scaled_glyph);
546 if (status)
547 return status;
548 }
549
550 return CAIRO_INT_STATUS_SUCCESS;
551 }
552
553 unsigned long
_cairo_dwrite_ucs4_to_index(void * scaled_font,uint32_t ucs4)554 _cairo_dwrite_ucs4_to_index(void *scaled_font,
555 uint32_t ucs4)
556 {
557 cairo_dwrite_scaled_font_t *dwritesf = static_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
558 cairo_dwrite_font_face_t *face = reinterpret_cast<cairo_dwrite_font_face_t*>(dwritesf->base.font_face);
559
560 UINT16 index;
561 face->dwriteface->GetGlyphIndicesA(&ucs4, 1, &index);
562 return index;
563 }
564
565 cairo_warn cairo_int_status_t
_cairo_dwrite_scaled_show_glyphs(void * scaled_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)566 _cairo_dwrite_scaled_show_glyphs(void *scaled_font,
567 cairo_operator_t op,
568 const cairo_pattern_t *pattern,
569 cairo_surface_t *generic_surface,
570 int source_x,
571 int source_y,
572 int dest_x,
573 int dest_y,
574 unsigned int width,
575 unsigned int height,
576 cairo_glyph_t *glyphs,
577 int num_glyphs,
578 cairo_region_t *clip_region,
579 int *remaining_glyphs)
580 {
581 cairo_win32_surface_t *surface = (cairo_win32_surface_t *)generic_surface;
582 cairo_int_status_t status;
583
584 if (width == 0 || height == 0)
585 return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
586
587 if (_cairo_surface_is_win32 (generic_surface) &&
588 surface->format == CAIRO_FORMAT_RGB24 &&
589 op == CAIRO_OPERATOR_OVER) {
590
591 //XXX: we need to set the clip region here
592
593 status = (cairo_int_status_t)_cairo_dwrite_show_glyphs_on_surface (surface, op, pattern,
594 glyphs, num_glyphs,
595 (cairo_scaled_font_t*)scaled_font, NULL);
596
597 return status;
598 } else {
599 cairo_dwrite_scaled_font_t *dwritesf =
600 static_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
601 BOOL transform = FALSE;
602
603 AutoDWriteGlyphRun run;
604 run.allocate(num_glyphs);
605 UINT16 *indices = const_cast<UINT16*>(run.glyphIndices);
606 FLOAT *advances = const_cast<FLOAT*>(run.glyphAdvances);
607 DWRITE_GLYPH_OFFSET *offsets = const_cast<DWRITE_GLYPH_OFFSET*>(run.glyphOffsets);
608
609 run.bidiLevel = 0;
610 run.fontFace = ((cairo_dwrite_font_face_t*)dwritesf->base.font_face)->dwriteface;
611 run.isSideways = FALSE;
612 IDWriteGlyphRunAnalysis *analysis;
613
614 if (dwritesf->mat.xy == 0 && dwritesf->mat.yx == 0 &&
615 dwritesf->mat.xx == dwritesf->base.font_matrix.xx &&
616 dwritesf->mat.yy == dwritesf->base.font_matrix.yy) {
617
618 for (int i = 0; i < num_glyphs; i++) {
619 indices[i] = (WORD) glyphs[i].index;
620 // Since we will multiply by our ctm matrix later for rotation effects
621 // and such, adjust positions by the inverse matrix now.
622 offsets[i].ascenderOffset = (FLOAT)dest_y - (FLOAT)glyphs[i].y;
623 offsets[i].advanceOffset = (FLOAT)glyphs[i].x - dest_x;
624 advances[i] = 0.0;
625 }
626 run.fontEmSize = (FLOAT)dwritesf->base.font_matrix.yy;
627 } else {
628 transform = TRUE;
629
630 for (int i = 0; i < num_glyphs; i++) {
631 indices[i] = (WORD) glyphs[i].index;
632 double x = glyphs[i].x - dest_x;
633 double y = glyphs[i].y - dest_y;
634 cairo_matrix_transform_point(&dwritesf->mat_inverse, &x, &y);
635 // Since we will multiply by our ctm matrix later for rotation effects
636 // and such, adjust positions by the inverse matrix now.
637 offsets[i].ascenderOffset = -(FLOAT)y;
638 offsets[i].advanceOffset = (FLOAT)x;
639 advances[i] = 0.0;
640 }
641 run.fontEmSize = 1.0f;
642 }
643
644 HRESULT hr;
645 if (!transform) {
646 hr = DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run,
647 1.0f,
648 NULL,
649 DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC,
650 DWRITE_MEASURING_MODE_NATURAL,
651 0,
652 0,
653 &analysis);
654 } else {
655 DWRITE_MATRIX dwmatrix = _cairo_dwrite_matrix_from_matrix(&dwritesf->mat);
656 hr = DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run,
657 1.0f,
658 &dwmatrix,
659 DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC,
660 DWRITE_MEASURING_MODE_NATURAL,
661 0,
662 0,
663 &analysis);
664 }
665
666 if (FAILED(hr) || !analysis) {
667 return CAIRO_INT_STATUS_UNSUPPORTED;
668 }
669
670 RECT r;
671 r.left = 0;
672 r.top = 0;
673 r.right = width;
674 r.bottom = height;
675
676 BYTE *surface = new BYTE[width * height * 3];
677
678 analysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, &r, surface, width * height * 3);
679
680 cairo_image_surface_t *mask_surface =
681 (cairo_image_surface_t*)cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
682
683 cairo_surface_flush(&mask_surface->base);
684
685 for (unsigned int y = 0; y < height; y++) {
686 for (unsigned int x = 0; x < width; x++) {
687 mask_surface->data[y * mask_surface->stride + x * 4] = surface[y * width * 3 + x * 3 + 1];
688 mask_surface->data[y * mask_surface->stride + x * 4 + 1] = surface[y * width * 3 + x * 3 + 1];
689 mask_surface->data[y * mask_surface->stride + x * 4 + 2] = surface[y * width * 3 + x * 3 + 1];
690 mask_surface->data[y * mask_surface->stride + x * 4 + 3] = surface[y * width * 3 + x * 3 + 1];
691 }
692 }
693 cairo_surface_mark_dirty(&mask_surface->base);
694
695 pixman_image_set_component_alpha(mask_surface->pixman_image, 1);
696
697 cairo_surface_pattern_t mask;
698 _cairo_pattern_init_for_surface (&mask, &mask_surface->base);
699
700 status = (cairo_int_status_t)_cairo_surface_composite (op, pattern,
701 &mask.base,
702 generic_surface,
703 source_x, source_y,
704 0, 0,
705 dest_x, dest_y,
706 width, height,
707 clip_region);
708
709 _cairo_pattern_fini (&mask.base);
710
711 analysis->Release();
712 delete [] surface;
713
714 cairo_surface_destroy (&mask_surface->base);
715 *remaining_glyphs = 0;
716
717 return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
718 }
719 }
720
721 /* cairo_dwrite_scaled_glyph_init helper function bodies */
722 cairo_int_status_t
_cairo_dwrite_scaled_font_init_glyph_metrics(cairo_dwrite_scaled_font_t * scaled_font,cairo_scaled_glyph_t * scaled_glyph)723 _cairo_dwrite_scaled_font_init_glyph_metrics(cairo_dwrite_scaled_font_t *scaled_font,
724 cairo_scaled_glyph_t *scaled_glyph)
725 {
726 UINT16 charIndex = (UINT16)_cairo_scaled_glyph_index (scaled_glyph);
727 cairo_dwrite_font_face_t *font_face = (cairo_dwrite_font_face_t*)scaled_font->base.font_face;
728 cairo_text_extents_t extents;
729
730 DWRITE_GLYPH_METRICS metrics;
731 DWRITE_FONT_METRICS fontMetrics;
732 font_face->dwriteface->GetMetrics(&fontMetrics);
733 HRESULT hr = font_face->dwriteface->GetDesignGlyphMetrics(&charIndex, 1, &metrics);
734 if (FAILED(hr)) {
735 return CAIRO_INT_STATUS_UNSUPPORTED;
736 }
737
738 // TODO: Treat swap_xy.
739 extents.width = (FLOAT)(metrics.advanceWidth - metrics.leftSideBearing - metrics.rightSideBearing) /
740 fontMetrics.designUnitsPerEm;
741 extents.height = (FLOAT)(metrics.advanceHeight - metrics.topSideBearing - metrics.bottomSideBearing) /
742 fontMetrics.designUnitsPerEm;
743 extents.x_advance = (FLOAT)metrics.advanceWidth / fontMetrics.designUnitsPerEm;
744 extents.x_bearing = (FLOAT)metrics.leftSideBearing / fontMetrics.designUnitsPerEm;
745 extents.y_advance = 0.0;
746 extents.y_bearing = (FLOAT)(metrics.topSideBearing - metrics.verticalOriginY) /
747 fontMetrics.designUnitsPerEm;
748
749 // We pad the extents here because GetDesignGlyphMetrics returns "ideal" metrics
750 // for the glyph outline, without accounting for hinting/gridfitting/antialiasing,
751 // and therefore it does not always cover all pixels that will actually be touched.
752 if (scaled_font->base.options.antialias != CAIRO_ANTIALIAS_NONE &&
753 extents.width > 0 && extents.height > 0) {
754 extents.width += scaled_font->mat_inverse.xx * 2;
755 extents.x_bearing -= scaled_font->mat_inverse.xx;
756 }
757
758 _cairo_scaled_glyph_set_metrics (scaled_glyph,
759 &scaled_font->base,
760 &extents);
761 return CAIRO_INT_STATUS_SUCCESS;
762 }
763
764 /**
765 * Stack-based helper implementing IDWriteGeometrySink.
766 * Used to determine the path of the glyphs.
767 */
768
769 class GeometryRecorder : public IDWriteGeometrySink
770 {
771 public:
GeometryRecorder(cairo_path_fixed_t * aCairoPath)772 GeometryRecorder(cairo_path_fixed_t *aCairoPath)
773 : mCairoPath(aCairoPath) {}
774
775 // IUnknown interface
IFACEMETHOD(QueryInterface)776 IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
777 {
778 if (iid != __uuidof(IDWriteGeometrySink))
779 return E_NOINTERFACE;
780
781 *ppObject = static_cast<IDWriteGeometrySink*>(this);
782
783 return S_OK;
784 }
785
IFACEMETHOD_(ULONG,AddRef)786 IFACEMETHOD_(ULONG, AddRef)()
787 {
788 return 1;
789 }
790
IFACEMETHOD_(ULONG,Release)791 IFACEMETHOD_(ULONG, Release)()
792 {
793 return 1;
794 }
795
SetFillMode(D2D1_FILL_MODE fillMode)796 IFACEMETHODIMP_(void) SetFillMode(D2D1_FILL_MODE fillMode)
797 {
798 return;
799 }
800
Close()801 STDMETHODIMP Close()
802 {
803 return S_OK;
804 }
805
SetSegmentFlags(D2D1_PATH_SEGMENT vertexFlags)806 IFACEMETHODIMP_(void) SetSegmentFlags(D2D1_PATH_SEGMENT vertexFlags)
807 {
808 return;
809 }
810
GetFixedX(const D2D1_POINT_2F & point)811 cairo_fixed_t GetFixedX(const D2D1_POINT_2F &point)
812 {
813 unsigned int control_word;
814 _controlfp_s(&control_word, _CW_DEFAULT, MCW_PC);
815 return _cairo_fixed_from_double(point.x);
816 }
817
GetFixedY(const D2D1_POINT_2F & point)818 cairo_fixed_t GetFixedY(const D2D1_POINT_2F &point)
819 {
820 unsigned int control_word;
821 _controlfp_s(&control_word, _CW_DEFAULT, MCW_PC);
822 return _cairo_fixed_from_double(point.y);
823 }
824
BeginFigure(D2D1_POINT_2F startPoint,D2D1_FIGURE_BEGIN figureBegin)825 IFACEMETHODIMP_(void) BeginFigure(
826 D2D1_POINT_2F startPoint,
827 D2D1_FIGURE_BEGIN figureBegin)
828 {
829 mStartPoint = startPoint;
830 cairo_status_t status = _cairo_path_fixed_move_to(mCairoPath,
831 GetFixedX(startPoint),
832 GetFixedY(startPoint));
833 }
834
EndFigure(D2D1_FIGURE_END figureEnd)835 IFACEMETHODIMP_(void) EndFigure(
836 D2D1_FIGURE_END figureEnd)
837 {
838 if (figureEnd == D2D1_FIGURE_END_CLOSED) {
839 cairo_status_t status = _cairo_path_fixed_line_to(mCairoPath,
840 GetFixedX(mStartPoint),
841 GetFixedY(mStartPoint));
842 }
843 }
844
AddBeziers(const D2D1_BEZIER_SEGMENT * beziers,UINT beziersCount)845 IFACEMETHODIMP_(void) AddBeziers(
846 const D2D1_BEZIER_SEGMENT *beziers,
847 UINT beziersCount)
848 {
849 for (unsigned int i = 0; i < beziersCount; i++) {
850 cairo_status_t status = _cairo_path_fixed_curve_to(mCairoPath,
851 GetFixedX(beziers[i].point1),
852 GetFixedY(beziers[i].point1),
853 GetFixedX(beziers[i].point2),
854 GetFixedY(beziers[i].point2),
855 GetFixedX(beziers[i].point3),
856 GetFixedY(beziers[i].point3));
857 }
858 }
859
AddLines(const D2D1_POINT_2F * points,UINT pointsCount)860 IFACEMETHODIMP_(void) AddLines(
861 const D2D1_POINT_2F *points,
862 UINT pointsCount)
863 {
864 for (unsigned int i = 0; i < pointsCount; i++) {
865 cairo_status_t status = _cairo_path_fixed_line_to(mCairoPath,
866 GetFixedX(points[i]),
867 GetFixedY(points[i]));
868 }
869 }
870
871 private:
872 cairo_path_fixed_t *mCairoPath;
873 D2D1_POINT_2F mStartPoint;
874 };
875
876 cairo_int_status_t
_cairo_dwrite_scaled_font_init_glyph_path(cairo_dwrite_scaled_font_t * scaled_font,cairo_scaled_glyph_t * scaled_glyph)877 _cairo_dwrite_scaled_font_init_glyph_path(cairo_dwrite_scaled_font_t *scaled_font,
878 cairo_scaled_glyph_t *scaled_glyph)
879 {
880 cairo_path_fixed_t *path;
881 path = _cairo_path_fixed_create();
882 GeometryRecorder recorder(path);
883
884 DWRITE_GLYPH_OFFSET offset;
885 offset.advanceOffset = 0;
886 offset.ascenderOffset = 0;
887 UINT16 glyphId = (UINT16)_cairo_scaled_glyph_index(scaled_glyph);
888 FLOAT advance = 0.0;
889 cairo_dwrite_font_face_t *dwriteff = (cairo_dwrite_font_face_t*)scaled_font->base.font_face;
890 dwriteff->dwriteface->GetGlyphRunOutline((FLOAT)scaled_font->base.font_matrix.yy,
891 &glyphId,
892 &advance,
893 &offset,
894 1,
895 FALSE,
896 FALSE,
897 &recorder);
898 _cairo_path_fixed_close_path(path);
899
900 /* Now apply our transformation to the drawn path. */
901 _cairo_path_fixed_transform(path, &scaled_font->base.ctm);
902
903 _cairo_scaled_glyph_set_path (scaled_glyph,
904 &scaled_font->base,
905 path);
906 return CAIRO_INT_STATUS_SUCCESS;
907 }
908
909 /* Helper function also stolen from cairo-win32-font.c */
910
911 /* Compute an alpha-mask from a monochrome RGB24 image
912 */
913 static cairo_surface_t *
_compute_a8_mask(cairo_win32_surface_t * mask_surface)914 _compute_a8_mask (cairo_win32_surface_t *mask_surface)
915 {
916 cairo_image_surface_t *image24 = (cairo_image_surface_t *)mask_surface->image;
917 cairo_image_surface_t *image8;
918 int i, j;
919
920 if (image24->base.status)
921 return cairo_surface_reference (&image24->base);
922
923 image8 = (cairo_image_surface_t *)cairo_image_surface_create (CAIRO_FORMAT_A8,
924 image24->width, image24->height);
925 if (image8->base.status)
926 return &image8->base;
927
928 for (i = 0; i < image24->height; i++) {
929 uint32_t *p = (uint32_t *) (image24->data + i * image24->stride);
930 unsigned char *q = (unsigned char *) (image8->data + i * image8->stride);
931
932 for (j = 0; j < image24->width; j++) {
933 *q = 255 - ((*p & 0x0000ff00) >> 8);
934 p++;
935 q++;
936 }
937 }
938
939 return &image8->base;
940 }
941
942 cairo_int_status_t
_cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t * scaled_font,cairo_scaled_glyph_t * scaled_glyph)943 _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_font,
944 cairo_scaled_glyph_t *scaled_glyph)
945 {
946 cairo_int_status_t status;
947 cairo_glyph_t glyph;
948 cairo_win32_surface_t *surface;
949 cairo_t *cr;
950 cairo_surface_t *image;
951 int width, height;
952 double x1, y1, x2, y2;
953
954 x1 = _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
955 y1 = _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
956 x2 = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x);
957 y2 = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y);
958 width = (int)(x2 - x1);
959 height = (int)(y2 - y1);
960
961 glyph.index = _cairo_scaled_glyph_index (scaled_glyph);
962 glyph.x = -x1;
963 glyph.y = -y1;
964
965 DWRITE_GLYPH_RUN run;
966 FLOAT advance = 0;
967 UINT16 index = (UINT16)glyph.index;
968 DWRITE_GLYPH_OFFSET offset;
969 double x = glyph.x;
970 double y = glyph.y;
971 RECT area;
972 DWRITE_MATRIX matrix;
973
974 surface = (cairo_win32_surface_t *)
975 cairo_win32_surface_create_with_dib (CAIRO_FORMAT_RGB24, width, height);
976
977 cr = cairo_create (&surface->base);
978 cairo_set_source_rgb (cr, 1, 1, 1);
979 cairo_paint (cr);
980 status = (cairo_int_status_t)cairo_status (cr);
981 cairo_destroy(cr);
982 if (status)
983 goto FAIL;
984
985 /**
986 * We transform by the inverse transformation here. This will put our glyph
987 * locations in the space in which we draw. Which is later transformed by
988 * the transformation matrix that we use. This will transform the
989 * glyph positions back to where they were before when drawing, but the
990 * glyph shapes will be transformed by the transformation matrix.
991 */
992 cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y);
993 offset.advanceOffset = (FLOAT)x;
994 /** Y-axis is inverted */
995 offset.ascenderOffset = -(FLOAT)y;
996
997 area.top = 0;
998 area.bottom = height;
999 area.left = 0;
1000 area.right = width;
1001
1002 run.glyphCount = 1;
1003 run.glyphAdvances = &advance;
1004 run.fontFace = ((cairo_dwrite_font_face_t*)scaled_font->base.font_face)->dwriteface;
1005 run.fontEmSize = 1.0f;
1006 run.bidiLevel = 0;
1007 run.glyphIndices = &index;
1008 run.isSideways = FALSE;
1009 run.glyphOffsets = &offset;
1010
1011 matrix = _cairo_dwrite_matrix_from_matrix(&scaled_font->mat);
1012
1013 status = _dwrite_draw_glyphs_to_gdi_surface_gdi (surface, &matrix, &run,
1014 RGB(0,0,0), scaled_font, area);
1015 if (status)
1016 goto FAIL;
1017
1018 GdiFlush();
1019
1020 image = _compute_a8_mask (surface);
1021 status = (cairo_int_status_t)image->status;
1022 if (status)
1023 goto FAIL;
1024
1025 cairo_surface_set_device_offset (image, -x1, -y1);
1026 _cairo_scaled_glyph_set_surface (scaled_glyph,
1027 &scaled_font->base,
1028 (cairo_image_surface_t *) image);
1029
1030 FAIL:
1031 cairo_surface_destroy (&surface->base);
1032
1033 return status;
1034 }
1035
1036 cairo_int_status_t
_cairo_dwrite_load_truetype_table(void * scaled_font,unsigned long tag,long offset,unsigned char * buffer,unsigned long * length)1037 _cairo_dwrite_load_truetype_table(void *scaled_font,
1038 unsigned long tag,
1039 long offset,
1040 unsigned char *buffer,
1041 unsigned long *length)
1042 {
1043 cairo_dwrite_scaled_font_t *dwritesf = static_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
1044 cairo_dwrite_font_face_t *face = reinterpret_cast<cairo_dwrite_font_face_t*>(dwritesf->base.font_face);
1045
1046 const void *data;
1047 UINT32 size;
1048 void *tableContext;
1049 BOOL exists;
1050 face->dwriteface->TryGetFontTable(be32_to_cpu (tag),
1051 &data,
1052 &size,
1053 &tableContext,
1054 &exists);
1055
1056 if (!exists) {
1057 return CAIRO_INT_STATUS_UNSUPPORTED;
1058 }
1059
1060 if (buffer && *length && (UINT32)offset < size) {
1061 size = MIN(size - (UINT32)offset, *length);
1062 memcpy(buffer, (const char*)data + offset, size);
1063 }
1064 *length = size;
1065
1066 if (tableContext) {
1067 face->dwriteface->ReleaseFontTable(tableContext);
1068 }
1069 return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
1070 }
1071
1072 // WIN32 Helper Functions
1073 cairo_font_face_t*
cairo_dwrite_font_face_create_for_dwrite_fontface(void * dwrite_font,void * dwrite_font_face)1074 cairo_dwrite_font_face_create_for_dwrite_fontface(void* dwrite_font, void* dwrite_font_face)
1075 {
1076 IDWriteFont *dwritefont = static_cast<IDWriteFont*>(dwrite_font);
1077 IDWriteFontFace *dwriteface = static_cast<IDWriteFontFace*>(dwrite_font_face);
1078 cairo_dwrite_font_face_t *face = new cairo_dwrite_font_face_t;
1079 cairo_font_face_t *font_face;
1080
1081 dwriteface->AddRef();
1082
1083 face->dwriteface = dwriteface;
1084 face->font = NULL;
1085
1086 font_face = (cairo_font_face_t*)face;
1087
1088 _cairo_font_face_init (&((cairo_dwrite_font_face_t*)font_face)->base, &_cairo_dwrite_font_face_backend);
1089
1090 return font_face;
1091 }
1092
1093 void
cairo_dwrite_scaled_font_allow_manual_show_glyphs(cairo_scaled_font_t * dwrite_scaled_font,cairo_bool_t allowed)1094 cairo_dwrite_scaled_font_allow_manual_show_glyphs(cairo_scaled_font_t *dwrite_scaled_font, cairo_bool_t allowed)
1095 {
1096 cairo_dwrite_scaled_font_t *font = reinterpret_cast<cairo_dwrite_scaled_font_t*>(dwrite_scaled_font);
1097 font->manual_show_glyphs_allowed = allowed;
1098 }
1099
1100 void
cairo_dwrite_scaled_font_set_force_GDI_classic(cairo_scaled_font_t * dwrite_scaled_font,cairo_bool_t force)1101 cairo_dwrite_scaled_font_set_force_GDI_classic(cairo_scaled_font_t *dwrite_scaled_font, cairo_bool_t force)
1102 {
1103 cairo_dwrite_scaled_font_t *font = reinterpret_cast<cairo_dwrite_scaled_font_t*>(dwrite_scaled_font);
1104 if (force && font->rendering_mode == cairo_d2d_surface_t::TEXT_RENDERING_NORMAL) {
1105 font->rendering_mode = cairo_d2d_surface_t::TEXT_RENDERING_GDI_CLASSIC;
1106 } else if (!force && font->rendering_mode == cairo_d2d_surface_t::TEXT_RENDERING_GDI_CLASSIC) {
1107 font->rendering_mode = cairo_d2d_surface_t::TEXT_RENDERING_NORMAL;
1108 }
1109 }
1110
1111 cairo_bool_t
cairo_dwrite_scaled_font_get_force_GDI_classic(cairo_scaled_font_t * dwrite_scaled_font)1112 cairo_dwrite_scaled_font_get_force_GDI_classic(cairo_scaled_font_t *dwrite_scaled_font)
1113 {
1114 cairo_dwrite_scaled_font_t *font = reinterpret_cast<cairo_dwrite_scaled_font_t*>(dwrite_scaled_font);
1115 return font->rendering_mode == cairo_d2d_surface_t::TEXT_RENDERING_GDI_CLASSIC;
1116 }
1117
1118 void
cairo_dwrite_set_cleartype_params(FLOAT gamma,FLOAT contrast,FLOAT level,int geometry,int mode)1119 cairo_dwrite_set_cleartype_params(FLOAT gamma, FLOAT contrast, FLOAT level,
1120 int geometry, int mode)
1121 {
1122 DWriteFactory::SetRenderingParams(gamma, contrast, level, geometry, mode);
1123 }
1124
1125 int
cairo_dwrite_get_cleartype_rendering_mode()1126 cairo_dwrite_get_cleartype_rendering_mode()
1127 {
1128 return DWriteFactory::GetClearTypeRenderingMode();
1129 }
1130
1131 cairo_int_status_t
_dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t * surface,DWRITE_MATRIX * transform,DWRITE_GLYPH_RUN * run,COLORREF color,cairo_dwrite_scaled_font_t * scaled_font,const RECT & area)1132 _dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
1133 DWRITE_MATRIX *transform,
1134 DWRITE_GLYPH_RUN *run,
1135 COLORREF color,
1136 cairo_dwrite_scaled_font_t *scaled_font,
1137 const RECT &area)
1138 {
1139 IDWriteGdiInterop *gdiInterop;
1140 DWriteFactory::Instance()->GetGdiInterop(&gdiInterop);
1141 IDWriteBitmapRenderTarget *rt;
1142 HRESULT rv;
1143
1144 cairo_d2d_surface_t::TextRenderingState renderingState =
1145 scaled_font->rendering_mode;
1146
1147 rv = gdiInterop->CreateBitmapRenderTarget(surface->dc,
1148 area.right - area.left,
1149 area.bottom - area.top,
1150 &rt);
1151
1152 if (FAILED(rv)) {
1153 if (rv == E_OUTOFMEMORY) {
1154 return (cairo_int_status_t)CAIRO_STATUS_NO_MEMORY;
1155 } else {
1156 return CAIRO_INT_STATUS_UNSUPPORTED;
1157 }
1158 }
1159
1160 if ((renderingState == cairo_d2d_surface_t::TEXT_RENDERING_NORMAL ||
1161 renderingState == cairo_d2d_surface_t::TEXT_RENDERING_GDI_CLASSIC) &&
1162 !surface->base.permit_subpixel_antialiasing) {
1163 renderingState = cairo_d2d_surface_t::TEXT_RENDERING_NO_CLEARTYPE;
1164 IDWriteBitmapRenderTarget1* rt1;
1165 rv = rt->QueryInterface(&rt1);
1166
1167 if (SUCCEEDED(rv) && rt1) {
1168 rt1->SetTextAntialiasMode(DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE);
1169 rt1->Release();
1170 }
1171 }
1172
1173 IDWriteRenderingParams *params =
1174 DWriteFactory::RenderingParams(renderingState);
1175
1176 /**
1177 * We set the number of pixels per DIP to 1.0. This is because we always want
1178 * to draw in device pixels, and not device independent pixels. On high DPI
1179 * systems this value will be higher than 1.0 and automatically upscale
1180 * fonts, we don't want this since we do our own upscaling for various reasons.
1181 */
1182 rt->SetPixelsPerDip(1.0);
1183
1184 if (transform) {
1185 rt->SetCurrentTransform(transform);
1186 }
1187 BitBlt(rt->GetMemoryDC(),
1188 0, 0,
1189 area.right - area.left, area.bottom - area.top,
1190 surface->dc,
1191 area.left, area.top,
1192 SRCCOPY | NOMIRRORBITMAP);
1193 DWRITE_MEASURING_MODE measureMode;
1194 switch (renderingState) {
1195 case cairo_d2d_surface_t::TEXT_RENDERING_GDI_CLASSIC:
1196 case cairo_d2d_surface_t::TEXT_RENDERING_NO_CLEARTYPE:
1197 measureMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
1198 break;
1199 default:
1200 measureMode = DWRITE_MEASURING_MODE_NATURAL;
1201 break;
1202 }
1203 HRESULT hr = rt->DrawGlyphRun(0, 0, measureMode, run, params, color);
1204 BitBlt(surface->dc,
1205 area.left, area.top,
1206 area.right - area.left, area.bottom - area.top,
1207 rt->GetMemoryDC(),
1208 0, 0,
1209 SRCCOPY | NOMIRRORBITMAP);
1210 params->Release();
1211 rt->Release();
1212 gdiInterop->Release();
1213 return CAIRO_INT_STATUS_SUCCESS;
1214 }
1215
1216 cairo_int_status_t
_dwrite_draw_glyphs_to_gdi_surface_d2d(cairo_win32_surface_t * surface,DWRITE_MATRIX * transform,DWRITE_GLYPH_RUN * run,COLORREF color,const RECT & area)1217 _dwrite_draw_glyphs_to_gdi_surface_d2d(cairo_win32_surface_t *surface,
1218 DWRITE_MATRIX *transform,
1219 DWRITE_GLYPH_RUN *run,
1220 COLORREF color,
1221 const RECT &area)
1222 {
1223 HRESULT rv;
1224
1225 ID2D1DCRenderTarget *rt = D2DFactory::RenderTarget();
1226
1227 // XXX don't we need to set RenderingParams on this RenderTarget?
1228
1229 rv = rt->BindDC(surface->dc, &area);
1230
1231 printf("Rendering to surface: %p\n", surface->dc);
1232
1233 if (FAILED(rv)) {
1234 rt->Release();
1235 return CAIRO_INT_STATUS_UNSUPPORTED;
1236 }
1237
1238 // D2D uses 0x00RRGGBB not 0x00BBGGRR like COLORREF.
1239 color = (color & 0xFF) << 16 |
1240 (color & 0xFF00) |
1241 (color & 0xFF0000) >> 16;
1242 ID2D1SolidColorBrush *brush;
1243 rv = rt->CreateSolidColorBrush(D2D1::ColorF(color, 1.0), &brush);
1244
1245 if (FAILED(rv)) {
1246 rt->Release();
1247 return CAIRO_INT_STATUS_UNSUPPORTED;
1248 }
1249
1250 if (transform) {
1251 rt->SetTransform(D2D1::Matrix3x2F(transform->m11,
1252 transform->m12,
1253 transform->m21,
1254 transform->m22,
1255 transform->dx,
1256 transform->dy));
1257 }
1258 rt->BeginDraw();
1259 rt->DrawGlyphRun(D2D1::Point2F(0, 0), run, brush);
1260 rt->EndDraw();
1261 if (transform) {
1262 rt->SetTransform(D2D1::Matrix3x2F::Identity());
1263 }
1264 brush->Release();
1265 if (FAILED(rv)) {
1266 return CAIRO_INT_STATUS_UNSUPPORTED;
1267 }
1268
1269 return CAIRO_INT_STATUS_SUCCESS;
1270 }
1271
1272 /* Surface helper function */
1273 cairo_int_status_t
_cairo_dwrite_show_glyphs_on_surface(void * surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_glyph_t * glyphs,int num_glyphs,cairo_scaled_font_t * scaled_font,cairo_clip_t * clip)1274 _cairo_dwrite_show_glyphs_on_surface(void *surface,
1275 cairo_operator_t op,
1276 const cairo_pattern_t *source,
1277 cairo_glyph_t *glyphs,
1278 int num_glyphs,
1279 cairo_scaled_font_t *scaled_font,
1280 cairo_clip_t *clip)
1281 {
1282 // TODO: Check font & surface for types.
1283 cairo_dwrite_scaled_font_t *dwritesf = reinterpret_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
1284 cairo_dwrite_font_face_t *dwriteff = reinterpret_cast<cairo_dwrite_font_face_t*>(scaled_font->font_face);
1285 cairo_win32_surface_t *dst = reinterpret_cast<cairo_win32_surface_t*>(surface);
1286 cairo_int_status_t status;
1287 /* We can only handle dwrite fonts */
1288 if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_DWRITE)
1289 return CAIRO_INT_STATUS_UNSUPPORTED;
1290
1291 /* We can only handle opaque solid color sources */
1292 if (!_cairo_pattern_is_opaque_solid(source))
1293 return CAIRO_INT_STATUS_UNSUPPORTED;
1294
1295 /* We can only handle operator SOURCE or OVER with the destination
1296 * having no alpha */
1297 if (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER)
1298 return CAIRO_INT_STATUS_UNSUPPORTED;
1299
1300 /* If we have a fallback mask clip set on the dst, we have
1301 * to go through the fallback path */
1302 if (clip != NULL) {
1303 if ((dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) == 0) {
1304 cairo_region_t *clip_region;
1305 cairo_int_status_t status;
1306
1307 status = _cairo_clip_get_region (clip, &clip_region);
1308 assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
1309 if (status)
1310 return status;
1311
1312 _cairo_win32_surface_set_clip_region (dst, clip_region);
1313 }
1314 } else {
1315 _cairo_win32_surface_set_clip_region (surface, NULL);
1316 }
1317
1318 /* It is vital that dx values for dxy_buf are calculated from the delta of
1319 * _logical_ x coordinates (not user x coordinates) or else the sum of all
1320 * previous dx values may start to diverge from the current glyph's x
1321 * coordinate due to accumulated rounding error. As a result strings could
1322 * be painted shorter or longer than expected. */
1323
1324 AutoDWriteGlyphRun run;
1325 run.allocate(num_glyphs);
1326
1327 UINT16 *indices = const_cast<UINT16*>(run.glyphIndices);
1328 FLOAT *advances = const_cast<FLOAT*>(run.glyphAdvances);
1329 DWRITE_GLYPH_OFFSET *offsets = const_cast<DWRITE_GLYPH_OFFSET*>(run.glyphOffsets);
1330
1331 BOOL transform = FALSE;
1332 /* Needed to calculate bounding box for efficient blitting */
1333 INT32 smallestX = INT_MAX;
1334 INT32 largestX = 0;
1335 INT32 smallestY = INT_MAX;
1336 INT32 largestY = 0;
1337 for (int i = 0; i < num_glyphs; i++) {
1338 if (glyphs[i].x < smallestX) {
1339 smallestX = (INT32)glyphs[i].x;
1340 }
1341 if (glyphs[i].x > largestX) {
1342 largestX = (INT32)glyphs[i].x;
1343 }
1344 if (glyphs[i].y < smallestY) {
1345 smallestY = (INT32)glyphs[i].y;
1346 }
1347 if (glyphs[i].y > largestY) {
1348 largestY = (INT32)glyphs[i].y;
1349 }
1350 }
1351 /**
1352 * Here we try to get a rough estimate of the area that this glyph run will
1353 * cover on the surface. Since we use GDI interop to draw we will be copying
1354 * data around the size of the area of the surface that we map. We will want
1355 * to map an area as small as possible to prevent large surfaces to be
1356 * copied around. We take the X/Y-size of the font as margin on the left/top
1357 * twice the X/Y-size of the font as margin on the right/bottom.
1358 * This should always cover the entire area where the glyphs are.
1359 */
1360 RECT fontArea;
1361 fontArea.left = (INT32)(smallestX - scaled_font->font_matrix.xx);
1362 fontArea.right = (INT32)(largestX + scaled_font->font_matrix.xx * 2);
1363 fontArea.top = (INT32)(smallestY - scaled_font->font_matrix.yy);
1364 fontArea.bottom = (INT32)(largestY + scaled_font->font_matrix.yy * 2);
1365 if (fontArea.left < 0)
1366 fontArea.left = 0;
1367 if (fontArea.top < 0)
1368 fontArea.top = 0;
1369 if (fontArea.bottom > dst->extents.height) {
1370 fontArea.bottom = dst->extents.height;
1371 }
1372 if (fontArea.right > dst->extents.width) {
1373 fontArea.right = dst->extents.width;
1374 }
1375 if (fontArea.right <= fontArea.left ||
1376 fontArea.bottom <= fontArea.top) {
1377 return CAIRO_INT_STATUS_SUCCESS;
1378 }
1379 if (fontArea.right > dst->extents.width) {
1380 fontArea.right = dst->extents.width;
1381 }
1382 if (fontArea.bottom > dst->extents.height) {
1383 fontArea.bottom = dst->extents.height;
1384 }
1385
1386 run.bidiLevel = 0;
1387 run.fontFace = dwriteff->dwriteface;
1388 run.isSideways = FALSE;
1389 if (dwritesf->mat.xy == 0 && dwritesf->mat.yx == 0 &&
1390 dwritesf->mat.xx == scaled_font->font_matrix.xx &&
1391 dwritesf->mat.yy == scaled_font->font_matrix.yy) {
1392
1393 for (int i = 0; i < num_glyphs; i++) {
1394 indices[i] = (WORD) glyphs[i].index;
1395 // Since we will multiply by our ctm matrix later for rotation effects
1396 // and such, adjust positions by the inverse matrix now.
1397 offsets[i].ascenderOffset = (FLOAT)(fontArea.top - glyphs[i].y);
1398 offsets[i].advanceOffset = (FLOAT)(glyphs[i].x - fontArea.left);
1399 advances[i] = 0.0;
1400 }
1401 run.fontEmSize = (FLOAT)scaled_font->font_matrix.yy;
1402 } else {
1403 transform = TRUE;
1404 // See comment about EPSILON in _cairo_dwrite_glyph_run_from_glyphs
1405 const double EPSILON = 0.0001;
1406 for (int i = 0; i < num_glyphs; i++) {
1407 indices[i] = (WORD) glyphs[i].index;
1408 double x = glyphs[i].x - fontArea.left + EPSILON;
1409 double y = glyphs[i].y - fontArea.top;
1410 cairo_matrix_transform_point(&dwritesf->mat_inverse, &x, &y);
1411 /**
1412 * Since we will multiply by our ctm matrix later for rotation effects
1413 * and such, adjust positions by the inverse matrix now. The Y-axis
1414 * is inverted so the offset becomes negative.
1415 */
1416 offsets[i].ascenderOffset = -(FLOAT)y;
1417 offsets[i].advanceOffset = (FLOAT)x;
1418 advances[i] = 0.0;
1419 }
1420 run.fontEmSize = 1.0f;
1421 }
1422
1423 cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)source;
1424 COLORREF color = RGB(((int)solid_pattern->color.red_short) >> 8,
1425 ((int)solid_pattern->color.green_short) >> 8,
1426 ((int)solid_pattern->color.blue_short) >> 8);
1427
1428 DWRITE_MATRIX matrix = _cairo_dwrite_matrix_from_matrix(&dwritesf->mat);
1429
1430 DWRITE_MATRIX *mat;
1431 if (transform) {
1432 mat = &matrix;
1433 } else {
1434 mat = NULL;
1435 }
1436
1437 RECT area;
1438 area.left = dst->extents.x;
1439 area.top = dst->extents.y;
1440 area.right = area.left + dst->extents.width;
1441 area.bottom = area.top + dst->extents.height;
1442
1443 #ifdef CAIRO_TRY_D2D_TO_GDI
1444 status = _dwrite_draw_glyphs_to_gdi_surface_d2d(dst,
1445 mat,
1446 &run,
1447 color,
1448 fontArea);
1449
1450 if (status == (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED) {
1451 #endif
1452 status = _dwrite_draw_glyphs_to_gdi_surface_gdi(dst,
1453 mat,
1454 &run,
1455 color,
1456 dwritesf,
1457 fontArea);
1458
1459 #ifdef CAIRO_TRY_D2D_TO_GDI
1460 }
1461 #endif
1462
1463 return status;
1464 }
1465
1466 #define ENHANCED_CONTRAST_REGISTRY_KEY \
1467 HKEY_CURRENT_USER, "Software\\Microsoft\\Avalon.Graphics\\DISPLAY1\\EnhancedContrastLevel"
1468
1469 void
CreateRenderingParams()1470 DWriteFactory::CreateRenderingParams()
1471 {
1472 if (!Instance()) {
1473 return;
1474 }
1475
1476 Instance()->CreateRenderingParams(&mDefaultRenderingParams);
1477
1478 // For EnhancedContrast, we override the default if the user has not set it
1479 // in the registry (by using the ClearType Tuner).
1480 FLOAT contrast;
1481 if (mEnhancedContrast >= 0.0 && mEnhancedContrast <= 10.0) {
1482 contrast = mEnhancedContrast;
1483 } else {
1484 HKEY hKey;
1485 if (RegOpenKeyExA(ENHANCED_CONTRAST_REGISTRY_KEY,
1486 0, KEY_READ, &hKey) == ERROR_SUCCESS)
1487 {
1488 contrast = mDefaultRenderingParams->GetEnhancedContrast();
1489 RegCloseKey(hKey);
1490 } else {
1491 contrast = 1.0;
1492 }
1493 }
1494
1495 // For parameters that have not been explicitly set via the SetRenderingParams API,
1496 // we copy values from default params (or our overridden value for contrast)
1497 FLOAT gamma =
1498 mGamma >= 1.0 && mGamma <= 2.2 ?
1499 mGamma : mDefaultRenderingParams->GetGamma();
1500 FLOAT clearTypeLevel =
1501 mClearTypeLevel >= 0.0 && mClearTypeLevel <= 1.0 ?
1502 mClearTypeLevel : mDefaultRenderingParams->GetClearTypeLevel();
1503 DWRITE_PIXEL_GEOMETRY pixelGeometry =
1504 mPixelGeometry >= DWRITE_PIXEL_GEOMETRY_FLAT && mPixelGeometry <= DWRITE_PIXEL_GEOMETRY_BGR ?
1505 (DWRITE_PIXEL_GEOMETRY)mPixelGeometry : mDefaultRenderingParams->GetPixelGeometry();
1506 DWRITE_RENDERING_MODE renderingMode =
1507 mRenderingMode >= DWRITE_RENDERING_MODE_DEFAULT && mRenderingMode <= DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC ?
1508 (DWRITE_RENDERING_MODE)mRenderingMode : mDefaultRenderingParams->GetRenderingMode();
1509 Instance()->CreateCustomRenderingParams(gamma, contrast, clearTypeLevel,
1510 pixelGeometry, renderingMode,
1511 &mCustomClearTypeRenderingParams);
1512 Instance()->CreateCustomRenderingParams(gamma, contrast, clearTypeLevel,
1513 pixelGeometry, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC,
1514 &mForceGDIClassicRenderingParams);
1515 }
1516
1517 static cairo_bool_t
_name_tables_match(cairo_scaled_font_t * font1,cairo_scaled_font_t * font2)1518 _name_tables_match (cairo_scaled_font_t *font1,
1519 cairo_scaled_font_t *font2)
1520 {
1521 unsigned long size1;
1522 unsigned long size2;
1523 cairo_int_status_t status1;
1524 cairo_int_status_t status2;
1525 unsigned char *buffer1;
1526 unsigned char *buffer2;
1527 cairo_bool_t result = false;
1528
1529 if (!font1->backend || !font2->backend ||
1530 !font1->backend->load_truetype_table ||
1531 !font2->backend->load_truetype_table)
1532 return false;
1533
1534 status1 = font1->backend->load_truetype_table (font1,
1535 TT_TAG_name, 0, NULL, &size1);
1536 status2 = font2->backend->load_truetype_table (font2,
1537 TT_TAG_name, 0, NULL, &size2);
1538 if (status1 || status2)
1539 return false;
1540 if (size1 != size2)
1541 return false;
1542
1543 buffer1 = (unsigned char*)malloc (size1);
1544 buffer2 = (unsigned char*)malloc (size2);
1545
1546 if (buffer1 && buffer2) {
1547 status1 = font1->backend->load_truetype_table (font1,
1548 TT_TAG_name, 0, buffer1, &size1);
1549 status2 = font2->backend->load_truetype_table (font2,
1550 TT_TAG_name, 0, buffer2, &size2);
1551 if (!status1 && !status2) {
1552 result = memcmp (buffer1, buffer2, size1) == 0;
1553 }
1554 }
1555
1556 free (buffer1);
1557 free (buffer2);
1558 return result;
1559 }
1560
1561 // Helper for _cairo_win32_printing_surface_show_glyphs to create a win32 equivalent
1562 // of a dwrite scaled_font so that we can print using ExtTextOut instead of drawing
1563 // paths or blitting glyph bitmaps.
1564 cairo_int_status_t
_cairo_dwrite_scaled_font_create_win32_scaled_font(cairo_scaled_font_t * scaled_font,cairo_scaled_font_t ** new_font)1565 _cairo_dwrite_scaled_font_create_win32_scaled_font (cairo_scaled_font_t *scaled_font,
1566 cairo_scaled_font_t **new_font)
1567 {
1568 if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_DWRITE) {
1569 return CAIRO_INT_STATUS_UNSUPPORTED;
1570 }
1571
1572 cairo_font_face_t *face = cairo_scaled_font_get_font_face (scaled_font);
1573 cairo_dwrite_font_face_t *dwface = reinterpret_cast<cairo_dwrite_font_face_t*>(face);
1574
1575 RefPtr<IDWriteGdiInterop> gdiInterop;
1576 DWriteFactory::Instance()->GetGdiInterop(&gdiInterop);
1577 if (!gdiInterop) {
1578 return CAIRO_INT_STATUS_UNSUPPORTED;
1579 }
1580
1581 LOGFONTW logfont;
1582 if (FAILED(gdiInterop->ConvertFontFaceToLOGFONT (dwface->dwriteface, &logfont))) {
1583 return CAIRO_INT_STATUS_UNSUPPORTED;
1584 }
1585 // DW must have been using an outline font, so we want GDI to use the same,
1586 // even if there's also a bitmap face available
1587 logfont.lfOutPrecision = OUT_OUTLINE_PRECIS;
1588
1589 cairo_font_face_t *win32_face = cairo_win32_font_face_create_for_logfontw (&logfont);
1590 if (!win32_face) {
1591 return CAIRO_INT_STATUS_UNSUPPORTED;
1592 }
1593
1594 cairo_matrix_t font_matrix;
1595 cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix);
1596
1597 cairo_matrix_t ctm;
1598 cairo_scaled_font_get_ctm (scaled_font, &ctm);
1599
1600 cairo_font_options_t options;
1601 cairo_scaled_font_get_font_options (scaled_font, &options);
1602
1603 cairo_scaled_font_t *font = cairo_scaled_font_create (win32_face,
1604 &font_matrix,
1605 &ctm,
1606 &options);
1607 cairo_font_face_destroy (win32_face);
1608
1609 if (!font) {
1610 return CAIRO_INT_STATUS_UNSUPPORTED;
1611 }
1612
1613 if (!_name_tables_match (font, scaled_font)) {
1614 // If the font name tables aren't equal, then GDI may have failed to
1615 // find the right font and substituted a different font.
1616 cairo_scaled_font_destroy (font);
1617 return CAIRO_INT_STATUS_UNSUPPORTED;
1618 }
1619
1620 *new_font = font;
1621 return CAIRO_INT_STATUS_SUCCESS;
1622 }
1623