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