1 /*
2 * Copyright (c) 2004 Ximian
3 * Copyright (c) 2004-2007 Novell, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
6 * and associated documentation files (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
9 * subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in all copies or substantial
12 * portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
15 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
18 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 *
20 * Authors:
21 * Jordi Mas i Hernandez <jordi@ximian.com>, 2004-2006
22 * Peter Dennis Bartok <pbartok@novell.com>
23 * Sebastien Pouliot <sebastien@ximian.com>
24 * Jeffrey Stedfast <fejj@novell.com>
25 */
26
27 #ifdef WIN32
28 #include "win32-private.h"
29 #endif
30
31 #include <cairo-features.h>
32 #include "gdiplus-private.h"
33 #include "font-private.h"
34 #include "fontcollection-private.h"
35 #include "fontfamily-private.h"
36 #include "general-private.h"
37 #include "graphics-private.h"
38
39 /* Generic fonts families */
40 #if GLIB_CHECK_VERSION(2,32,0)
41 static GMutex generic;
42 #else
43 static GStaticMutex generic = G_STATIC_MUTEX_INIT;
44 #endif
45 static GpFontFamily *familySerif = NULL;
46 static GpFontFamily *familySansSerif = NULL;
47 static GpFontFamily *familyMonospace = NULL;
48 static int ref_familySerif = 0;
49 static int ref_familySansSerif = 0;
50 static int ref_familyMonospace = 0;
51
52
53 /* Family and collections font functions */
54 static void
gdip_fontfamily_init(GpFontFamily * fontFamily)55 gdip_fontfamily_init (GpFontFamily *fontFamily)
56 {
57 fontFamily->collection = NULL;
58 fontFamily->height = -1;
59 fontFamily->linespacing = -1;
60 fontFamily->celldescent = -1;
61 fontFamily->cellascent = -1;
62 fontFamily->pattern = NULL;
63 fontFamily->allocated = FALSE;
64 }
65
66 static GpFontFamily *
gdip_fontfamily_new()67 gdip_fontfamily_new ()
68 {
69 GpFontFamily *result = (GpFontFamily *) GdipAlloc (sizeof (GpFontFamily));
70
71 if (result)
72 gdip_fontfamily_init (result);
73
74 return result;
75 }
76
77 static void
gdip_font_init(GpFont * font)78 gdip_font_init (GpFont *font)
79 {
80 font->sizeInPixels = 0;
81 font->style = FontStyleRegular;
82 font->face = NULL;
83 font->family = NULL;
84 font->emSize = 0;
85 font->unit = UnitPixel;
86 #ifdef USE_PANGO_RENDERING
87 font->pango = NULL;
88 #else
89 font->cairofnt = NULL;
90 #endif
91 }
92
93 static GpFont *
gdip_font_new()94 gdip_font_new ()
95 {
96 GpFont *result = (GpFont *) GdipAlloc (sizeof (GpFont));
97
98 if (result)
99 gdip_font_init (result);
100
101 return result;
102 }
103
104 static GpFontCollection *system_fonts = NULL;
105
106 void
gdip_delete_system_fonts(void)107 gdip_delete_system_fonts (void)
108 {
109 GdipDeletePrivateFontCollection(&system_fonts);
110 }
111
112 // coverity[+alloc : arg-*0]
113 GpStatus WINGDIPAPI
GdipNewInstalledFontCollection(GpFontCollection ** fontCollection)114 GdipNewInstalledFontCollection (GpFontCollection **fontCollection)
115 {
116 if (!fontCollection)
117 return InvalidParameter;
118
119 /*
120 * Ensure we leak this data only a single time, because:
121 * (a) there is no API to free it;
122 * (b) other libgdiplus structures depends on that allocated data;
123 */
124 if (!system_fonts) {
125 FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, FC_FOUNDRY, NULL);
126 FcPattern *pat = FcPatternCreate ();
127 FcValue val;
128 FcFontSet *col;
129
130 /* Only Scalable fonts for now */
131 val.type = FcTypeBool;
132 val.u.b = FcTrue;
133 FcPatternAdd (pat, FC_SCALABLE, val, TRUE);
134 FcObjectSetAdd (os, FC_SCALABLE);
135
136 col = FcFontList (0, pat, os);
137 FcPatternDestroy (pat);
138 FcObjectSetDestroy (os);
139
140 system_fonts = (GpFontCollection *) GdipAlloc (sizeof (GpFontCollection));
141 if (!system_fonts)
142 return OutOfMemory;
143
144 system_fonts->fontset = col;
145 system_fonts->config = NULL;
146
147 #if USE_PANGO_RENDERING
148 system_fonts->pango_font_map = pango_cairo_font_map_new_for_font_type (CAIRO_FONT_TYPE_FT);
149 #endif
150 }
151
152 *fontCollection = system_fonts;
153 return Ok;
154 }
155
156 // coverity[+alloc : arg-*0]
157 GpStatus WINGDIPAPI
GdipNewPrivateFontCollection(GpFontCollection ** fontCollection)158 GdipNewPrivateFontCollection (GpFontCollection **fontCollection)
159 {
160 GpFontCollection *result;
161
162 if (!gdiplusInitialized)
163 return GdiplusNotInitialized;
164
165 if (!fontCollection)
166 return InvalidParameter;
167
168 result = (GpFontCollection *) GdipAlloc (sizeof (GpFontCollection));
169 if (!result)
170 return OutOfMemory;
171
172 result->fontset = NULL;
173 result->config = FcConfigCreate ();
174
175 #if USE_PANGO_RENDERING
176 result->pango_font_map = pango_cairo_font_map_new_for_font_type (CAIRO_FONT_TYPE_FT);
177 pango_fc_font_map_set_config ((PangoFcFontMap *)result->pango_font_map, result->config);
178 #endif
179
180 *fontCollection = result;
181 return Ok;
182 }
183
184 // coverity[+free : arg-0]
185 GpStatus
GdipDeletePrivateFontCollection(GpFontCollection ** fontCollection)186 GdipDeletePrivateFontCollection (GpFontCollection **fontCollection)
187 {
188 if (!gdiplusInitialized)
189 return GdiplusNotInitialized;
190
191 if (!fontCollection)
192 return InvalidParameter;
193
194 if (*fontCollection) {
195 #if USE_PANGO_RENDERING
196 if ((*fontCollection)->pango_font_map != NULL) {
197 g_object_unref ((*fontCollection)->pango_font_map);
198 (*fontCollection)->pango_font_map = NULL;
199 }
200 #endif
201 if ((*fontCollection)->fontset != NULL) {
202 FcFontSetDestroy ((*fontCollection)->fontset);
203 (*fontCollection)->fontset = NULL;
204 }
205 if ((*fontCollection)->config != NULL) {
206 FcConfigDestroy ((*fontCollection)->config);
207 (*fontCollection)->config = NULL;
208 }
209 GdipFree (*fontCollection);
210 }
211
212 *fontCollection = NULL;
213 return Ok;
214 }
215
216 GpStatus WINGDIPAPI
GdipPrivateAddFontFile(GpFontCollection * fontCollection,GDIPCONST WCHAR * filename)217 GdipPrivateAddFontFile (GpFontCollection *fontCollection, GDIPCONST WCHAR *filename)
218 {
219 BYTE *file;
220 FILE *fileHandle;
221
222 if (!fontCollection || !filename)
223 return InvalidParameter;
224
225 file = (BYTE*) utf16_to_utf8 ((const gunichar2 *)filename, -1);
226 if (!file)
227 return OutOfMemory;
228
229 fileHandle = fopen ((char *)file, "r");
230 if (!fileHandle) {
231 GdipFree (file);
232 return FileNotFound;
233 }
234
235 fclose (fileHandle);
236 FcConfigAppFontAddFile (fontCollection->config, file);
237
238 GdipFree (file);
239 return Ok;
240 }
241
242 GpStatus WINGDIPAPI
GdipCloneFontFamily(GpFontFamily * fontFamily,GpFontFamily ** clonedFontFamily)243 GdipCloneFontFamily (GpFontFamily *fontFamily, GpFontFamily **clonedFontFamily)
244 {
245 GpFontFamily *result;
246
247 if (!fontFamily || !clonedFontFamily)
248 return InvalidParameter;
249
250 result = gdip_fontfamily_new ();
251 if (!result)
252 return OutOfMemory;
253
254 result->collection = fontFamily->collection;
255 result->height = fontFamily->height;
256 result->linespacing = fontFamily->linespacing;
257 result->celldescent = fontFamily->celldescent;
258 result->cellascent = fontFamily->cellascent;
259
260 if (fontFamily->pattern) {
261 result->pattern = FcPatternDuplicate (fontFamily->pattern);
262 result->allocated = TRUE;
263 }
264
265 *clonedFontFamily = result;
266 return Ok;
267 }
268
269 GpStatus WINGDIPAPI
GdipDeleteFontFamily(GpFontFamily * fontFamily)270 GdipDeleteFontFamily (GpFontFamily *fontFamily)
271 {
272 BOOL delete = TRUE;
273
274 if (!fontFamily)
275 return InvalidParameter;
276
277 #if GLIB_CHECK_VERSION(2,32,0)
278 g_mutex_lock (&generic);
279 #else
280 g_static_mutex_lock (&generic);
281 #endif
282
283 if (fontFamily == familySerif) {
284 ref_familySerif--;
285 if (ref_familySerif)
286 delete = FALSE;
287 else
288 familySerif = NULL;
289 }
290
291 if (fontFamily == familySansSerif) {
292 ref_familySansSerif--;
293 if (ref_familySansSerif)
294 delete = FALSE;
295 else
296 familySansSerif = NULL;
297 }
298
299 if (fontFamily == familyMonospace) {
300 ref_familyMonospace--;
301 if (ref_familyMonospace)
302 delete = FALSE;
303 else
304 familyMonospace = NULL;
305 }
306
307 #if GLIB_CHECK_VERSION(2,32,0)
308 g_mutex_unlock (&generic);
309 #else
310 g_static_mutex_unlock (&generic);
311 #endif
312
313 if (delete) {
314 if (fontFamily->allocated) {
315 FcPatternDestroy (fontFamily->pattern);
316 fontFamily->pattern = NULL;
317 }
318 GdipFree (fontFamily);
319 }
320
321 return Ok;
322 }
323
324 static void
gdip_createPrivateFontSet(GpFontCollection * font_collection)325 gdip_createPrivateFontSet (GpFontCollection *font_collection)
326 {
327 FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, FC_FOUNDRY, FC_FILE, NULL);
328 FcPattern *pat = FcPatternCreate ();
329 FcFontSet *col = FcFontList (font_collection->config, pat, os);
330
331 if (font_collection->fontset)
332 FcFontSetDestroy (font_collection->fontset);
333
334 FcPatternDestroy (pat);
335 FcObjectSetDestroy (os);
336
337 font_collection->fontset = col;
338 }
339
340 GpStatus WINGDIPAPI
GdipGetFontCollectionFamilyCount(GpFontCollection * fontCollection,INT * numFound)341 GdipGetFontCollectionFamilyCount (GpFontCollection *fontCollection, INT *numFound)
342 {
343 if (!fontCollection || !numFound)
344 return InvalidParameter;
345
346 if (fontCollection->config)
347 gdip_createPrivateFontSet (fontCollection);
348
349 if (fontCollection->fontset)
350 *numFound = fontCollection->fontset->nfont;
351 else
352 *numFound = 0;
353
354 return Ok;
355 }
356
357 GpStatus WINGDIPAPI
GdipGetFontCollectionFamilyList(GpFontCollection * fontCollection,INT numSought,GpFontFamily * gpfamilies[],INT * numFound)358 GdipGetFontCollectionFamilyList (GpFontCollection *fontCollection, INT numSought, GpFontFamily *gpfamilies[], INT *numFound)
359 {
360 int i;
361
362 if (!fontCollection || !gpfamilies || !numFound)
363 return InvalidParameter;
364
365 if (fontCollection->config)
366 gdip_createPrivateFontSet (fontCollection);
367
368 for (i = 0; i < numSought && i < fontCollection->fontset->nfont; i++) {
369 gpfamilies[i] = gdip_fontfamily_new ();
370 if (!gpfamilies[i]) {
371 while (--i >= 0) {
372 GdipFree (gpfamilies[i]);
373 gpfamilies[i] = NULL;
374 }
375 return OutOfMemory;
376 }
377
378 gpfamilies[i]->collection = fontCollection;
379 gpfamilies[i]->pattern = fontCollection->fontset->fonts[i];
380 gpfamilies[i]->allocated = FALSE;
381 }
382
383 *numFound = i;
384 return Ok;
385 }
386
387 static GpStatus
gdip_status_from_fontconfig(FcResult result)388 gdip_status_from_fontconfig (FcResult result)
389 {
390 switch (result) {
391 case FcResultMatch:
392 return Ok;
393 case FcResultNoMatch:
394 case FcResultTypeMismatch:
395 case FcResultNoId:
396 return FontFamilyNotFound;
397 default:
398 return GenericError;
399 }
400 }
401
402 /* note: MUST be executed inside a lock because FcConfig isn't thread-safe */
403 static FcPattern*
create_pattern_from_name(char * name)404 create_pattern_from_name (char* name)
405 {
406 FcValue val;
407 /* FcResult must be initialized because it's changed only in error conditions */
408 FcResult rlt = FcResultMatch;
409 FcPattern *full_pattern = NULL;
410 FcPattern *name_pattern = FcPatternCreate ();
411
412 if (!name_pattern)
413 return NULL;
414
415 /* find the family we want */
416 val.type = FcTypeString;
417 val.u.s = (BYTE*)name;
418 if (!FcPatternAdd (name_pattern, FC_FAMILY, val, TRUE)) {
419 FcPatternDestroy (name_pattern);
420 return NULL;
421 }
422
423 if (!FcConfigSubstitute (0, name_pattern, FcMatchPattern)) {
424 FcPatternDestroy (name_pattern);
425 return NULL;
426 }
427
428 FcDefaultSubstitute (name_pattern);
429
430 full_pattern = FcFontMatch (0, name_pattern, &rlt);
431 if (gdip_status_from_fontconfig (rlt) == Ok) {
432 if (full_pattern == NULL) {
433 full_pattern = name_pattern;
434 } else {
435 FcPatternDestroy (name_pattern);
436 }
437 } else {
438 FcPatternDestroy (name_pattern);
439 if (full_pattern) {
440 FcPatternDestroy (full_pattern);
441 full_pattern = NULL;
442 }
443 }
444
445 return full_pattern;
446 }
447
448 #if GLIB_CHECK_VERSION(2,32,0)
449 static GMutex patterns_mutex;
450 #else
451 static GStaticMutex patterns_mutex = G_STATIC_MUTEX_INIT;
452 #endif
453 static GHashTable *patterns_hashtable = NULL;
454
455 static GpStatus
create_fontfamily_from_name(char * name,GpFontFamily ** fontFamily)456 create_fontfamily_from_name (char* name, GpFontFamily **fontFamily)
457 {
458 GpStatus status;
459 GpFontFamily *ff = NULL;
460 FcPattern *pat = NULL;
461 GpFontCollection *font_collection;
462
463 status = GdipNewInstalledFontCollection (&font_collection);
464 if (status != Ok) {
465 return status;
466 }
467 status = FontFamilyNotFound;
468
469 #if GLIB_CHECK_VERSION(2,32,0)
470 g_mutex_lock (&patterns_mutex);
471 #else
472 g_static_mutex_lock (&patterns_mutex);
473 #endif
474
475 if (patterns_hashtable) {
476 pat = (FcPattern*) g_hash_table_lookup (patterns_hashtable, name);
477 } else {
478 patterns_hashtable = g_hash_table_new (g_str_hash, g_str_equal);
479 }
480
481 if (!pat) {
482 pat = create_pattern_from_name (name);
483 if (pat) {
484 /* create the pattern and store it for further usage */
485 g_hash_table_insert (patterns_hashtable, g_strdup (name), pat);
486 }
487 }
488
489 if (pat) {
490 ff = gdip_fontfamily_new ();
491 if (ff) {
492 ff->pattern = pat;
493 ff->allocated = FALSE;
494 ff->collection = font_collection;
495 status = Ok;
496 } else
497 status = OutOfMemory;
498 }
499
500 *fontFamily = ff;
501 #if GLIB_CHECK_VERSION(2,32,0)
502 g_mutex_unlock (&patterns_mutex);
503 #else
504 g_static_mutex_unlock (&patterns_mutex);
505 #endif
506 return status;
507 }
508
509 static BOOL
free_cached_pattern(gpointer key,gpointer value,gpointer user)510 free_cached_pattern (gpointer key, gpointer value, gpointer user)
511 {
512 g_free (key);
513 FcPatternDestroy ((FcPattern*) value);
514 return TRUE;
515 }
516
517 void
gdip_font_clear_pattern_cache(void)518 gdip_font_clear_pattern_cache (void)
519 {
520 #if GLIB_CHECK_VERSION(2,32,0)
521 g_mutex_lock (&patterns_mutex);
522 #else
523 g_static_mutex_lock (&patterns_mutex);
524 #endif
525 if (patterns_hashtable) {
526 g_hash_table_foreach_remove (patterns_hashtable, free_cached_pattern, NULL);
527 g_hash_table_destroy (patterns_hashtable);
528 }
529 #if GLIB_CHECK_VERSION(2,32,0)
530 g_mutex_unlock (&patterns_mutex);
531 #else
532 g_static_mutex_unlock (&patterns_mutex);
533 #endif
534 }
535
536 static GpStatus
create_fontfamily_from_collection(char * name,GpFontCollection * font_collection,GpFontFamily ** fontFamily)537 create_fontfamily_from_collection (char* name, GpFontCollection *font_collection, GpFontFamily **fontFamily)
538 {
539 /* note: fontset can be NULL when we supply an empty private collection */
540 if (font_collection->fontset) {
541 int i;
542 FcChar8 *str;
543 FcPattern **gpfam = font_collection->fontset->fonts;
544
545 for (i=0; i < font_collection->fontset->nfont; gpfam++, i++) {
546 FcResult rlt = FcPatternGetString (*gpfam, FC_FAMILY, 0, &str);
547 GpStatus status = gdip_status_from_fontconfig (rlt);
548 if (status != Ok)
549 return status;
550
551 if (strcmp ((char *)name, (const char *)str) == 0) {
552 GpFontFamily *result = gdip_fontfamily_new ();
553 if (!result)
554 return OutOfMemory;
555
556 result->pattern = *gpfam;
557 result->allocated = FALSE;
558 result->collection = font_collection;
559
560 *fontFamily = result;
561 return Ok;
562 }
563 }
564 }
565 return FontFamilyNotFound;
566 }
567
568 // coverity[+alloc : arg-*2]
569 GpStatus WINGDIPAPI
GdipCreateFontFamilyFromName(GDIPCONST WCHAR * name,GpFontCollection * font_collection,GpFontFamily ** fontFamily)570 GdipCreateFontFamilyFromName (GDIPCONST WCHAR *name, GpFontCollection *font_collection, GpFontFamily **fontFamily)
571 {
572 GpStatus status;
573 char *string;
574
575 if (!gdiplusInitialized)
576 return GdiplusNotInitialized;
577
578 if (!name || !fontFamily)
579 return InvalidParameter;
580
581 string = (char*)utf16_to_utf8 ((const gunichar2 *)name, -1);
582 if (!string)
583 return OutOfMemory;
584
585 if (font_collection) {
586 if (font_collection->config)
587 gdip_createPrivateFontSet (font_collection);
588
589 status = create_fontfamily_from_collection (string, font_collection, fontFamily);
590 } else {
591 status = create_fontfamily_from_name (string, fontFamily);
592 }
593
594 GdipFree (string);
595 return status;
596 }
597
598 GpStatus WINGDIPAPI
GdipGetFamilyName(GDIPCONST GpFontFamily * family,WCHAR name[LF_FACESIZE],LANGID language)599 GdipGetFamilyName (GDIPCONST GpFontFamily *family, WCHAR name[LF_FACESIZE], LANGID language)
600 {
601 GpStatus status;
602 FcChar8 *fc_str;
603 FcResult r;
604
605 if (!family)
606 return InvalidParameter;
607
608 if (!name)
609 return Ok;
610
611 r = FcPatternGetString (family->pattern, FC_FAMILY, 0, &fc_str);
612 status = gdip_status_from_fontconfig (r);
613 if (status != Ok)
614 return status;
615
616 utf8_to_ucs2((const gchar *)fc_str, (gunichar2 *)name, LF_FACESIZE);
617 return Ok;
618 }
619
620 // coverity[+alloc : arg-*0]
621 GpStatus WINGDIPAPI
GdipGetGenericFontFamilySansSerif(GpFontFamily ** nativeFamily)622 GdipGetGenericFontFamilySansSerif (GpFontFamily **nativeFamily)
623 {
624 const WCHAR MSSansSerif[] = {'M','S',' ','S','a','n','s',' ', 'S','e','r','i','f', 0};
625 GpStatus status = Ok;
626
627 if (!nativeFamily)
628 return InvalidParameter;
629
630 #if GLIB_CHECK_VERSION(2,32,0)
631 g_mutex_lock (&generic);
632 #else
633 g_static_mutex_lock (&generic);
634 #endif
635
636 if (ref_familySansSerif == 0)
637 status = GdipCreateFontFamilyFromName (MSSansSerif, NULL, &familySansSerif);
638
639 if (status == Ok)
640 ref_familySansSerif++;
641 else
642 familySansSerif = NULL;
643
644 #if GLIB_CHECK_VERSION(2,32,0)
645 g_mutex_unlock (&generic);
646 #else
647 g_static_mutex_unlock (&generic);
648 #endif
649
650 *nativeFamily = familySansSerif;
651 return status;
652 }
653
654 // coverity[+alloc : arg-*0]
655 GpStatus WINGDIPAPI
GdipGetGenericFontFamilySerif(GpFontFamily ** nativeFamily)656 GdipGetGenericFontFamilySerif (GpFontFamily **nativeFamily)
657 {
658 const WCHAR Serif[] = {'S','e','r','i','f', 0};
659 GpStatus status = Ok;
660
661 if (!nativeFamily)
662 return InvalidParameter;
663
664 #if GLIB_CHECK_VERSION(2,32,0)
665 g_mutex_lock (&generic);
666 #else
667 g_static_mutex_lock (&generic);
668 #endif
669
670 if (ref_familySerif == 0)
671 status = GdipCreateFontFamilyFromName (Serif, NULL, &familySerif);
672
673 if (status == Ok)
674 ref_familySerif++;
675 else
676 familySerif = NULL;
677
678 #if GLIB_CHECK_VERSION(2,32,0)
679 g_mutex_unlock (&generic);
680 #else
681 g_static_mutex_unlock (&generic);
682 #endif
683
684 *nativeFamily = familySerif;
685 return status;
686 }
687
688 // coverity[+alloc : arg-*0]
689 GpStatus WINGDIPAPI
GdipGetGenericFontFamilyMonospace(GpFontFamily ** nativeFamily)690 GdipGetGenericFontFamilyMonospace (GpFontFamily **nativeFamily)
691 {
692 const WCHAR Monospace[] = {'C','o','u','r','i', 'e', 'r', ' ', 'N', 'e', 'w', 0};
693 GpStatus status = Ok;
694
695 if (!nativeFamily)
696 return InvalidParameter;
697
698 #if GLIB_CHECK_VERSION(2,32,0)
699 g_mutex_lock (&generic);
700 #else
701 g_static_mutex_lock (&generic);
702 #endif
703
704 if (ref_familyMonospace == 0)
705 status = GdipCreateFontFamilyFromName (Monospace, NULL, &familyMonospace);
706
707 if (status == Ok)
708 ref_familyMonospace++;
709 else
710 familyMonospace = NULL;
711
712 #if GLIB_CHECK_VERSION(2,32,0)
713 g_mutex_unlock (&generic);
714 #else
715 g_static_mutex_unlock (&generic);
716 #endif
717
718 *nativeFamily = familyMonospace;
719 return status;
720 }
721
722 /* OpenType's OS/2 fsSelection Table:
723 *
724 * http://www.microsoft.com/typography/otspec/os2.htm#fss
725 */
726 enum fsSelection {
727 fsSelectionItalic = (1 << 0),
728 fsSelectionUnderscore = (1 << 1),
729 fsSelectionNegative = (1 << 2),
730 fsSelectionOutlined = (1 << 3),
731 fsSelectionStrikeout = (1 << 4),
732 fsSelectionBold = (1 << 5),
733 fsSelectionRegular = (1 << 6),
734 fsSelectionUseTypoMetrics = (1 << 7),
735 fsSelectionWWS = (1 << 8),
736 fsSelectionOblique = (1 << 9),
737 };
738
739 #if defined(PANGO_VERSION_CHECK)
740 #if PANGO_VERSION_CHECK(1,44,0)
741 #define PANGO_DEPRECATED_FREETYPE_DEPENDENCY
742 #endif
743 #endif
744
745 #if !defined(USE_PANGO_RENDERING) || !defined (PANGO_DEPRECATED_FREETYPE_DEPENDENCY)
746 static void
gdip_get_fontfamily_details_from_freetype(GpFontFamily * family,FT_Face face)747 gdip_get_fontfamily_details_from_freetype (GpFontFamily *family, FT_Face face)
748 {
749 if (FT_IS_SFNT (face)) {
750 TT_HoriHeader *hhea = FT_Get_Sfnt_Table (face, ft_sfnt_hhea);
751 TT_OS2 *os2 = FT_Get_Sfnt_Table (face, ft_sfnt_os2);
752
753 if (os2 && (os2->fsSelection & fsSelectionUseTypoMetrics)) {
754 /* Use the typographic Ascender, Descender, and LineGap values for everything. */
755 family->linespacing = os2->sTypoAscender - os2->sTypoDescender + os2->sTypoLineGap;
756 family->celldescent = -os2->sTypoDescender;
757 family->cellascent = os2->sTypoAscender;
758 } else {
759 /* Calculate the LineSpacing for both the hhea table and the OS/2 table. */
760 int hhea_linespacing = hhea->Ascender + abs (hhea->Descender) + hhea->Line_Gap;
761 int os2_linespacing = os2 ? (os2->usWinAscent + os2->usWinDescent) : 0;
762
763 /* The LineSpacing is the maximum of the two sumations. */
764 family->linespacing = MAX (hhea_linespacing, os2_linespacing);
765
766 /* If the OS/2 table exists, use usWinDescent as the
767 * CellDescent. Otherwise use hhea's Descender value. */
768 family->celldescent = os2 ? os2->usWinDescent : hhea->Descender;
769
770 /* If the OS/2 table exists, use usWinAscent as the
771 * CellAscent. Otherwise use hhea's Ascender value. */
772 family->cellascent = os2 ? os2->usWinAscent : hhea->Ascender;
773 }
774 } else {
775 /* Fall back to using whatever FreeType2 provides. */
776 family->celldescent = -face->descender;
777 family->cellascent = face->ascender;
778 family->linespacing = face->height;
779 }
780
781 family->height = face->units_per_EM;
782 }
783 #endif
784
785 #ifdef USE_PANGO_RENDERING
786
787 PangoFontDescription*
gdip_get_pango_font_description(GpFont * font)788 gdip_get_pango_font_description (GpFont *font)
789 {
790 if (!font->pango) {
791 font->pango = pango_font_description_new ();
792 pango_font_description_set_family (font->pango, (char *)font->face);
793
794 float sizeInPoints = gdip_unit_conversion (font->unit, UnitPoint, gdip_get_display_dpi(), gtMemoryBitmap, font->emSize);
795
796 pango_font_description_set_size (font->pango, sizeInPoints * PANGO_SCALE);
797
798 if (font->style & FontStyleBold)
799 pango_font_description_set_weight (font->pango, PANGO_WEIGHT_BOLD);
800
801 if (font->style & FontStyleItalic)
802 pango_font_description_set_style (font->pango, PANGO_STYLE_ITALIC);
803 }
804 return font->pango;
805 }
806
807 #ifdef PANGO_DEPRECATED_FREETYPE_DEPENDENCY
808 static void
gdip_get_fontfamily_details_from_harfbuzz(GpFontFamily * family,hb_font_t * font)809 gdip_get_fontfamily_details_from_harfbuzz (GpFontFamily *family, hb_font_t *font)
810 {
811 hb_font_extents_t font_extents;
812 hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
813
814 family->celldescent = -font_extents.descender;
815 family->cellascent = font_extents.ascender;
816 family->linespacing = family->cellascent + family->celldescent + font_extents.line_gap;
817
818 family->height = hb_face_get_upem (hb_font_get_face (font));
819 }
820 #endif
821
822 static GpStatus
gdip_get_fontfamily_details(GpFontFamily * family,FontStyle style)823 gdip_get_fontfamily_details (GpFontFamily *family, FontStyle style)
824 {
825 GpFont *font;
826 GpStatus status = GdipCreateFont (family, 8.0f, style, UnitPoint, &font);
827 if (status != Ok)
828 return status;
829
830 status = FontFamilyNotFound;
831 PangoFontMap *map = family->collection->pango_font_map;
832 #if PANGO_VERSION_CHECK(1,22,0)
833 PangoContext *context = pango_font_map_create_context (PANGO_FONT_MAP (map));
834 #else
835 PangoContext *context = pango_cairo_font_map_create_context ((PangoCairoFontMap*)map);
836 #endif
837 PangoFont *pf = pango_font_map_load_font (map, context, gdip_get_pango_font_description (font));
838
839 if (pf) {
840 #ifdef PANGO_DEPRECATED_FREETYPE_DEPENDENCY
841 hb_font_t *hb_font = pango_font_get_hb_font (pf);
842
843 if (hb_font) {
844 gdip_get_fontfamily_details_from_harfbuzz (family, hb_font);
845 status = Ok;
846 }
847 #else
848 FT_Face face = pango_fc_font_lock_face ((PangoFcFont*)pf);
849 if (face) {
850 gdip_get_fontfamily_details_from_freetype (family, face);
851 pango_fc_font_unlock_face ((PangoFcFont*)pf);
852 status = Ok;
853 }
854 #endif
855 g_object_unref (pf);
856 }
857
858 g_object_unref (context);
859
860 GdipDeleteFont (font);
861 return status;
862 }
863
864 #else
865
866 cairo_font_face_t*
gdip_get_cairo_font_face(GpFont * font)867 gdip_get_cairo_font_face (GpFont *font)
868 {
869 if (!font->cairofnt) {
870 FcPattern *pattern = FcPatternBuild (
871 FcPatternDuplicate (font->family->pattern),
872 FC_SLANT, FcTypeInteger, ((font->style & FontStyleItalic) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN),
873 FC_WEIGHT, FcTypeInteger, ((font->style & FontStyleBold) ? FC_WEIGHT_BOLD : FC_WEIGHT_MEDIUM),
874 NULL);
875
876 font->cairofnt = cairo_ft_font_face_create_for_pattern (pattern);
877 cairo_font_face_reference (font->cairofnt);
878 FcPatternDestroy (pattern);
879 }
880 return font->cairofnt;
881 }
882
883 static GpStatus
gdip_get_fontfamily_details(GpFontFamily * family,FontStyle style)884 gdip_get_fontfamily_details (GpFontFamily *family, FontStyle style)
885 {
886 GpFont *font;
887 GpStatus status = GdipCreateFont (family, 0.1f, style, UnitPoint, &font);
888 if (status != Ok)
889 return status;
890
891 cairo_scaled_font_t* scaled_ft;
892 FT_Face face = NULL;
893 cairo_matrix_t matrix1, matrix2;
894 cairo_font_options_t *options = cairo_font_options_create ();
895 cairo_font_face_t* cairofnt = gdip_get_cairo_font_face (font);
896
897 cairo_matrix_init (&matrix1, 1, 0, 0, 1, 0, 0);
898 cairo_matrix_init (&matrix2, 1, 0, 0, 1, 0, 0);
899 scaled_ft = cairo_scaled_font_create (cairofnt, &matrix1, &matrix2, options);
900 /* a missing fonts.conf will resuls in a NULL *scaled_ft (#78237) */
901 if (!scaled_ft) {
902 static int flag = 0;
903 if (flag == 0) {
904 g_warning ("couldn't lock the font face. this may be due to a missing fonts.conf on the system.");
905 flag = 1;
906 }
907 status = FontFamilyNotFound;
908 }
909
910 if (status == Ok)
911 face = cairo_ft_scaled_font_lock_face (scaled_ft);
912
913 cairo_font_options_destroy (options);
914
915 if (face) {
916 gdip_get_fontfamily_details_from_freetype (family, face);
917
918 cairo_ft_scaled_font_unlock_face (scaled_ft);
919 cairo_scaled_font_destroy (scaled_ft);
920 } else {
921 status = FontFamilyNotFound;
922 }
923
924 GdipDeleteFont (font);
925 return status;
926 }
927 #endif
928
929 GpStatus WINGDIPAPI
GdipGetEmHeight(GDIPCONST GpFontFamily * family,INT style,UINT16 * EmHeight)930 GdipGetEmHeight (GDIPCONST GpFontFamily *family, INT style, UINT16 *EmHeight)
931 {
932 GpStatus status;
933
934 if (!family || !EmHeight)
935 return InvalidParameter;
936
937 if (family->height == -1) {
938 status = gdip_get_fontfamily_details ((GpFontFamily *) family, style);
939 if (status != Ok)
940 return status;
941 }
942
943 *EmHeight = family->height;
944 return Ok;
945 }
946
947 GpStatus WINGDIPAPI
GdipGetCellAscent(GDIPCONST GpFontFamily * family,INT style,UINT16 * CellAscent)948 GdipGetCellAscent (GDIPCONST GpFontFamily *family, INT style, UINT16 *CellAscent)
949 {
950 GpStatus status;
951
952 if (!family || !CellAscent)
953 return InvalidParameter;
954
955 if (family->cellascent == -1) {
956 status = gdip_get_fontfamily_details ((GpFontFamily *) family, style);
957 if (status != Ok)
958 return status;
959 }
960
961 *CellAscent = family->cellascent;
962 return Ok;
963 }
964
965 GpStatus WINGDIPAPI
GdipGetCellDescent(GDIPCONST GpFontFamily * family,INT style,UINT16 * CellDescent)966 GdipGetCellDescent (GDIPCONST GpFontFamily *family, INT style, UINT16 *CellDescent)
967 {
968 GpStatus status;
969
970 if (!family || !CellDescent)
971 return InvalidParameter;
972
973 if (family->celldescent == -1) {
974 status = gdip_get_fontfamily_details ((GpFontFamily *) family, style);
975 if (status != Ok)
976 return status;
977 }
978
979 *CellDescent = family->celldescent;
980 return Ok;
981 }
982
983 GpStatus WINGDIPAPI
GdipGetLineSpacing(GDIPCONST GpFontFamily * family,INT style,UINT16 * LineSpacing)984 GdipGetLineSpacing (GDIPCONST GpFontFamily *family, INT style, UINT16 *LineSpacing)
985 {
986 GpStatus status;
987
988 if (!family || !LineSpacing)
989 return InvalidParameter;
990
991 if (family->linespacing == -1) {
992 status = gdip_get_fontfamily_details ((GpFontFamily *) family, style);
993 if (status != Ok)
994 return status;
995 }
996
997 *LineSpacing = family->linespacing;
998 return Ok;
999 }
1000
1001 GpStatus WINGDIPAPI
GdipIsStyleAvailable(GDIPCONST GpFontFamily * family,INT style,BOOL * IsStyleAvailable)1002 GdipIsStyleAvailable (GDIPCONST GpFontFamily *family, INT style, BOOL *IsStyleAvailable)
1003 {
1004 if (!family || !IsStyleAvailable)
1005 return InvalidParameter;
1006
1007 *IsStyleAvailable = TRUE;
1008 return Ok;
1009 }
1010
1011 /* Font functions */
1012
1013 GpStatus
gdip_create_font_without_validation(GDIPCONST GpFontFamily * family,REAL emSize,INT style,Unit unit,GpFont ** font)1014 gdip_create_font_without_validation (GDIPCONST GpFontFamily *family, REAL emSize, INT style, Unit unit, GpFont **font)
1015 {
1016 GpStatus status;
1017 FcChar8* str;
1018 FcResult r;
1019 GpFont *result;
1020 REAL sizeInPixels;
1021
1022 r = FcPatternGetString (family->pattern, FC_FAMILY, 0, &str);
1023 status = gdip_status_from_fontconfig (r);
1024 if (status != Ok)
1025 return status;
1026
1027 sizeInPixels = gdip_unit_conversion (unit, UnitPixel, gdip_get_display_dpi(), gtMemoryBitmap, emSize);
1028
1029 result = gdip_font_new ();
1030 if (!result)
1031 return OutOfMemory;
1032
1033 result->sizeInPixels = sizeInPixels;
1034
1035 result->face = GdipAlloc (strlen ((char *) str) + 1);
1036 if (!result->face) {
1037 GdipDeleteFont (result);
1038 return OutOfMemory;
1039 }
1040
1041 memcpy (result->face, str, strlen ((char *) str) + 1);
1042
1043 result->style = style;
1044 result->emSize = emSize;
1045 result->unit = unit;
1046 status = GdipCloneFontFamily ((GpFontFamily *) family, &result->family);
1047 if (status != Ok) {
1048 GdipDeleteFont (result);
1049 return OutOfMemory;
1050 }
1051
1052 result->style = style;
1053 #ifndef USE_PANGO_RENDERING
1054 gdip_get_cairo_font_face (result);
1055 #endif
1056
1057 *font = result;
1058 return Ok;
1059 }
1060
1061 // coverity[+alloc : arg-*4]
1062 GpStatus
GdipCreateFont(GDIPCONST GpFontFamily * family,REAL emSize,INT style,Unit unit,GpFont ** font)1063 GdipCreateFont (GDIPCONST GpFontFamily *family, REAL emSize, INT style, Unit unit, GpFont **font)
1064 {
1065 if (!gdiplusInitialized)
1066 return GdiplusNotInitialized;
1067
1068 if (!family || !font || unit == UnitDisplay || unit < UnitWorld || unit > UnitCairoPoint || emSize <= 0)
1069 return InvalidParameter;
1070
1071 return gdip_create_font_without_validation (family, emSize, style, unit, font);
1072 }
1073
1074 GpStatus WINGDIPAPI
GdipCloneFont(GpFont * font,GpFont ** cloneFont)1075 GdipCloneFont (GpFont* font, GpFont** cloneFont)
1076 {
1077 GpFont *result;
1078 GpStatus status;
1079
1080 if (!font || !cloneFont)
1081 return InvalidParameter;
1082
1083 result = gdip_font_new ();
1084 if (!result)
1085 return OutOfMemory;
1086
1087 result->sizeInPixels = font->sizeInPixels;
1088 result->style = font->style;
1089 result->emSize = font->emSize;
1090 result->unit = font->unit;
1091
1092 result->face = (unsigned char *) g_strdup ((char *)font->face);
1093 if (!result->face) {
1094 GdipDeleteFont (result);
1095 return OutOfMemory;
1096 }
1097
1098 status = GdipCloneFontFamily (font->family, &result->family);
1099 if (status != Ok) {
1100 GdipDeleteFont (result);
1101 return OutOfMemory;
1102 }
1103
1104 #ifndef USE_PANGO_RENDERING
1105 gdip_get_cairo_font_face (result);
1106 #endif
1107
1108 *cloneFont = result;
1109 return Ok;
1110 }
1111
1112 GpStatus WINGDIPAPI
GdipDeleteFont(GpFont * font)1113 GdipDeleteFont (GpFont* font)
1114 {
1115 if (!font)
1116 return InvalidParameter;
1117
1118 if (font->family) {
1119 GdipDeleteFontFamily (font->family);
1120 font->family = NULL;
1121 }
1122
1123 #ifdef USE_PANGO_RENDERING
1124 if (font->pango) {
1125 pango_font_description_free (font->pango);
1126 font->pango = NULL;
1127 }
1128 #else
1129 if (font->cairofnt) {
1130 cairo_font_face_destroy (font->cairofnt);
1131 font->cairofnt = NULL;
1132 }
1133 #endif
1134
1135 if (font->face) {
1136 GdipFree (font->face);
1137 font->face = NULL;
1138 }
1139
1140 GdipFree (font);
1141 return Ok;
1142 }
1143
1144 GpStatus WINGDIPAPI
GdipCreateFontFromDC(HDC hdc,GpFont ** font)1145 GdipCreateFontFromDC (HDC hdc, GpFont **font)
1146 {
1147 if (!gdiplusInitialized)
1148 return GdiplusNotInitialized;
1149
1150 if (!hdc || !font)
1151 return InvalidParameter;
1152
1153 return NotImplemented;
1154 }
1155
1156 static GpStatus
gdip_logfont_from_font(GpFont * font,GpGraphics * graphics,void * lf,BOOL ucs2)1157 gdip_logfont_from_font (GpFont *font, GpGraphics *graphics, void *lf, BOOL ucs2)
1158 {
1159 LOGFONTA *logFont;
1160
1161 if (!lf)
1162 return InvalidParameter;
1163
1164 logFont = (LOGFONTA *)lf;
1165
1166 /* will be changed back to 1 inside System.Drawing */
1167 logFont->lfCharSet = 0;
1168
1169 if (!font || !graphics) {
1170 int size = (ucs2) ? 2 * LF_FACESIZE : LF_FACESIZE;
1171 memset (logFont->lfFaceName, 0, size);
1172 return InvalidParameter;
1173 }
1174
1175 logFont->lfHeight = -(font->sizeInPixels);
1176 logFont->lfWidth = 0;
1177 logFont->lfEscapement = 0; // FIXME
1178 logFont->lfOrientation = logFont->lfEscapement;
1179 if (font->style & FontStyleBold) {
1180 logFont->lfWeight = 700;
1181 } else {
1182 logFont->lfWeight = 400;
1183 }
1184
1185 if (font->style & FontStyleItalic) {
1186 logFont->lfItalic = 1;
1187 } else {
1188 logFont->lfItalic = 0;
1189 }
1190
1191 if (font->style & FontStyleUnderline) {
1192 logFont->lfUnderline = 1;
1193 } else {
1194 logFont->lfUnderline = 0;
1195 }
1196
1197 if (font->style & FontStyleStrikeout) {
1198 logFont->lfStrikeOut = 1;
1199 } else {
1200 logFont->lfStrikeOut = 0;
1201 }
1202
1203 logFont->lfOutPrecision = 0;
1204 logFont->lfClipPrecision = 0;
1205
1206 switch (graphics->text_mode) {
1207 case TextRenderingHintSystemDefault: {
1208 logFont->lfQuality = 0;
1209 break;
1210 }
1211
1212 case TextRenderingHintSingleBitPerPixelGridFit:
1213 case TextRenderingHintSingleBitPerPixel:
1214 case TextRenderingHintAntiAliasGridFit:
1215 case TextRenderingHintAntiAlias: {
1216 logFont->lfQuality = 3; // ANTIALIASED_QUALITY;
1217 break;
1218 }
1219
1220 case TextRenderingHintClearTypeGridFit: {
1221 logFont->lfQuality = 5; // CLEARTYPE_QUALITY
1222 break;
1223 }
1224 }
1225
1226 logFont->lfPitchAndFamily = 0;
1227 if (ucs2) {
1228 utf8_to_ucs2 ((const gchar *) font->face, (gunichar2 *) logFont->lfFaceName, LF_FACESIZE);
1229 } else {
1230 int len = strlen ((char *) font->face);
1231 memset (logFont->lfFaceName, 0, LF_FACESIZE);
1232 memcpy (logFont->lfFaceName, font->face, len < LF_FACESIZE ? len : LF_FACESIZE - 1);
1233 }
1234 return Ok;
1235 }
1236
1237 // coverity[+alloc : arg-*1]
1238 GpStatus WINGDIPAPI
GdipCreateFontFromHfontA(HFONT hfont,GpFont ** font,void * lf)1239 GdipCreateFontFromHfontA (HFONT hfont, GpFont **font, void *lf)
1240 {
1241 GpStatus status;
1242 GpFont *src_font;
1243 GpFont *result;
1244
1245 if (!gdiplusInitialized)
1246 return GdiplusNotInitialized;
1247
1248 src_font = (GpFont *)hfont;
1249
1250 result = gdip_font_new ();
1251 if (!result)
1252 return OutOfMemory;
1253
1254 result->sizeInPixels = src_font->sizeInPixels;
1255 result->style = src_font->style;
1256 status = GdipCloneFontFamily (src_font->family, &result->family);
1257 if (!status) {
1258 GdipDeleteFont (result);
1259 return OutOfMemory;
1260 }
1261
1262 result->style = src_font->style;
1263 result->emSize = src_font->emSize;
1264 result->unit = src_font->unit;
1265
1266 result->face = GdipAlloc(strlen ((char *) src_font->face) + 1);
1267 if (!result->face) {
1268 GdipDeleteFont (result);
1269 return OutOfMemory;
1270 }
1271
1272 memcpy(result->face, src_font->face, strlen((char *)src_font->face) + 1);
1273
1274 *font = result;
1275 return gdip_logfont_from_font (result, NULL, lf, FALSE);
1276 }
1277
1278 GpStatus WINGDIPAPI
GdipGetLogFontW(GpFont * font,GpGraphics * graphics,LOGFONTW * logfontW)1279 GdipGetLogFontW (GpFont *font, GpGraphics *graphics, LOGFONTW *logfontW)
1280 {
1281 return gdip_logfont_from_font (font, graphics, logfontW, TRUE);
1282 }
1283
1284 GpStatus WINGDIPAPI
GdipGetLogFontA(GpFont * font,GpGraphics * graphics,LOGFONTA * logfontA)1285 GdipGetLogFontA (GpFont *font, GpGraphics *graphics, LOGFONTA *logfontA)
1286 {
1287 return gdip_logfont_from_font (font, graphics, logfontA, FALSE);
1288 }
1289
1290 static GpStatus
gdip_create_font_from_logfont(HDC hdc,void * lf,GpFont ** font,BOOL ucs2)1291 gdip_create_font_from_logfont (HDC hdc, void *lf, GpFont **font, BOOL ucs2)
1292 {
1293 GpStatus status;
1294
1295 if (!gdiplusInitialized)
1296 return GdiplusNotInitialized;
1297
1298 if (!hdc || !lf || !font)
1299 return InvalidParameter;
1300
1301 GpFont *result = gdip_font_new ();
1302 if (!result)
1303 return OutOfMemory;
1304
1305 LOGFONTA *logfont = (LOGFONTA *)lf;
1306
1307 if (logfont->lfHeight < 0) {
1308 result->sizeInPixels = abs (logfont->lfHeight);
1309 } else {
1310 result->sizeInPixels = logfont->lfHeight; // Fixme - convert units
1311 }
1312 result->style = 0;
1313 /* Fixme - this is wrong, but I don't know of a quick way to get the emSize */
1314 result->emSize = result->sizeInPixels;
1315 result->unit = UnitWorld;
1316
1317 if (logfont->lfItalic) {
1318 result->style |= FontStyleItalic;
1319 }
1320 if (logfont->lfWeight > 400) {
1321 result->style |= FontStyleBold;
1322 }
1323 if (logfont->lfUnderline) {
1324 result->style |= FontStyleUnderline;
1325 }
1326 if (logfont->lfStrikeOut) {
1327 result->style |= FontStyleStrikeout;
1328 }
1329
1330 if (ucs2) {
1331 result->face = (BYTE*) utf16_to_utf8 ((WCHAR *) logfont->lfFaceName, -1);
1332 if (!result->face){
1333 GdipDeleteFont (result);
1334 return OutOfMemory;
1335 }
1336 } else {
1337 result->face = GdipAlloc (LF_FACESIZE);
1338 if (!result->face){
1339 GdipDeleteFont (result);
1340 return OutOfMemory;
1341 }
1342 memcpy(result->face, logfont->lfFaceName, LF_FACESIZE);
1343 result->face[LF_FACESIZE - 1] = '\0';
1344 }
1345
1346 status = create_fontfamily_from_name ((char *) result->face, &result->family);
1347 if (status == OutOfMemory) {
1348 GdipDeleteFont (result);
1349 return status;
1350 }
1351
1352 *font = result;
1353 return Ok;
1354 }
1355
1356 // coverity[+alloc : arg-*2]
1357 GpStatus
GdipCreateFontFromLogfontA(HDC hdc,GDIPCONST LOGFONTA * logfont,GpFont ** font)1358 GdipCreateFontFromLogfontA(HDC hdc, GDIPCONST LOGFONTA *logfont, GpFont **font)
1359 {
1360 return gdip_create_font_from_logfont (hdc, (void *)logfont, font, FALSE);
1361 }
1362
1363 // coverity[+alloc : arg-*2]
1364 GpStatus
GdipCreateFontFromLogfontW(HDC hdc,GDIPCONST LOGFONTW * logfont,GpFont ** font)1365 GdipCreateFontFromLogfontW(HDC hdc, GDIPCONST LOGFONTW *logfont, GpFont **font)
1366 {
1367 return gdip_create_font_from_logfont (hdc, (void *)logfont, font, TRUE);
1368 }
1369
1370 GpStatus WINGDIPAPI
GdipPrivateAddMemoryFont(GpFontCollection * fontCollection,GDIPCONST void * memory,INT length)1371 GdipPrivateAddMemoryFont(GpFontCollection *fontCollection, GDIPCONST void *memory, INT length)
1372 {
1373 FcChar8 fontfile[256];
1374 #ifdef WIN32
1375 FILE *f;
1376 #else
1377 int f;
1378 #endif
1379
1380 if (!fontCollection || !memory)
1381 return InvalidParameter;
1382 if (length <= 0)
1383 return InvalidParameter;
1384
1385 #ifdef WIN32
1386 f = CreateTempFile (fontfile);
1387 if (!f)
1388 return FileNotFound;
1389
1390 if (fwrite(memory, sizeof(BYTE), length, f) != length) {
1391 fclose (f);
1392 return FileNotFound;
1393 }
1394
1395 fclose (f);
1396 #else
1397 strcpy ((char *) fontfile, "/tmp/ffXXXXXX");
1398 f = mkstemp ((char *) fontfile);
1399
1400 if (f == -1)
1401 return FileNotFound;
1402
1403 if (write (f, memory, length) != length) {
1404 close (f);
1405 return FileNotFound;
1406 }
1407 close (f);
1408 #endif
1409
1410 FcConfigAppFontAddFile (fontCollection->config, fontfile);
1411 /* FIXME - May we delete our temporary font file or does
1412 FcConfigAppFontAddFile just reference our file? */
1413 /* unlink(fontfile); */
1414
1415 return Ok;
1416 }
1417
1418 GpStatus WINGDIPAPI
GdipGetFontHeight(GDIPCONST GpFont * font,GDIPCONST GpGraphics * graphics,REAL * height)1419 GdipGetFontHeight (GDIPCONST GpFont *font, GDIPCONST GpGraphics *graphics, REAL *height)
1420 {
1421 GpStatus status;
1422 UINT16 emHeight, lineSpacing;
1423 REAL emSize, h;
1424
1425 if (!font || !height)
1426 return InvalidParameter;
1427
1428 status = GdipGetEmHeight (font->family, font->style, &emHeight);
1429 if (status != Ok)
1430 return status;
1431
1432 status = GdipGetLineSpacing (font->family, font->style, &lineSpacing);
1433 if (status != Ok)
1434 return status;
1435
1436 /* Operations in display dpi's */
1437 emSize = gdip_unit_conversion (font->unit, UnitPixel, gdip_get_display_dpi (), gtMemoryBitmap, font->emSize);
1438
1439 h = lineSpacing * (emSize / emHeight);
1440 if (!graphics)
1441 *height = h;
1442 else
1443 *height = gdip_unit_conversion (UnitPixel, graphics->page_unit, gdip_get_display_dpi (), graphics->type, h);
1444
1445 return Ok;
1446 }
1447
1448 GpStatus WINGDIPAPI
GdipGetFontHeightGivenDPI(GDIPCONST GpFont * font,REAL dpi,REAL * height)1449 GdipGetFontHeightGivenDPI (GDIPCONST GpFont *font, REAL dpi, REAL *height)
1450 {
1451 GpStatus status;
1452 UINT16 emHeight, lineSpacing;
1453 REAL h;
1454
1455 if (!font || !height)
1456 return InvalidParameter;
1457
1458 status = GdipGetEmHeight (font->family, font->style, &emHeight);
1459 if (status != Ok)
1460 return status;
1461
1462 status = GdipGetLineSpacing (font->family, font->style, &lineSpacing);
1463 if (status != Ok)
1464 return status;
1465
1466 h = lineSpacing * (font->emSize / emHeight);
1467 *height = gdip_unit_conversion (font->unit, UnitInch, dpi, gtMemoryBitmap, h) * dpi;
1468 return Ok;
1469 }
1470
1471 GpStatus WINGDIPAPI
GdipGetFontSize(GpFont * font,REAL * size)1472 GdipGetFontSize (GpFont *font, REAL *size)
1473 {
1474 if (!font ||!size)
1475 return InvalidParameter;
1476
1477 *size = font->emSize;
1478 return Ok;
1479 }
1480
1481 GpStatus WINGDIPAPI
GdipGetFontStyle(GpFont * font,INT * style)1482 GdipGetFontStyle (GpFont *font, INT *style)
1483 {
1484 if (!font || !style)
1485 return InvalidParameter;
1486
1487 *style = font->style;
1488 return Ok;
1489 }
1490
1491 GpStatus WINGDIPAPI
GdipGetFontUnit(GpFont * font,Unit * unit)1492 GdipGetFontUnit (GpFont *font, Unit *unit)
1493 {
1494 if (!font || !unit)
1495 return InvalidParameter;
1496
1497 *unit = font->unit;
1498 return Ok;
1499 }
1500
1501 GpStatus WINGDIPAPI
GdipGetFamily(GpFont * font,GpFontFamily ** family)1502 GdipGetFamily (GpFont *font, GpFontFamily **family)
1503 {
1504 if (!font || !family)
1505 return InvalidParameter;
1506
1507 return GdipCloneFontFamily (font->family, family);
1508 }
1509