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