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