"Fossies" - the Fresh Open Source Software Archive

Member "libgdiplus-6.0.2/src/font.c" (31 Jul 2019, 35023 Bytes) of package /linux/misc/mono-sources/libgdiplus/libgdiplus-6.0.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "font.c": 5.6.1_vs_6.0.2.

    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
   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 *
   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
   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 *
   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
  107 gdip_delete_system_fonts (void)
  108 {
  109     GdipDeletePrivateFontCollection(&system_fonts);
  110 }
  111 
  112 // coverity[+alloc : arg-*0]
  113 GpStatus WINGDIPAPI
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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*
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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 static void
  740 gdip_get_fontfamily_details_from_freetype (GpFontFamily *family, FT_Face face)
  741 {
  742     if (FT_IS_SFNT (face)) {
  743         TT_HoriHeader *hhea = FT_Get_Sfnt_Table (face, ft_sfnt_hhea);
  744         TT_OS2 *os2 = FT_Get_Sfnt_Table (face, ft_sfnt_os2);
  745         
  746         if (os2 && (os2->fsSelection & fsSelectionUseTypoMetrics)) {
  747             /* Use the typographic Ascender, Descender, and LineGap values for everything. */
  748             family->linespacing = os2->sTypoAscender - os2->sTypoDescender + os2->sTypoLineGap;
  749             family->celldescent = -os2->sTypoDescender;
  750             family->cellascent = os2->sTypoAscender;
  751         } else {
  752             /* Calculate the LineSpacing for both the hhea table and the OS/2 table. */
  753             int hhea_linespacing = hhea->Ascender + abs (hhea->Descender) + hhea->Line_Gap;
  754             int os2_linespacing = os2 ? (os2->usWinAscent + os2->usWinDescent) : 0;
  755             
  756             /* The LineSpacing is the maximum of the two sumations. */
  757             family->linespacing = MAX (hhea_linespacing, os2_linespacing);
  758             
  759             /* If the OS/2 table exists, use usWinDescent as the
  760              * CellDescent. Otherwise use hhea's Descender value. */
  761             family->celldescent = os2 ? os2->usWinDescent : hhea->Descender;
  762             
  763             /* If the OS/2 table exists, use usWinAscent as the
  764              * CellAscent. Otherwise use hhea's Ascender value. */
  765             family->cellascent = os2 ? os2->usWinAscent : hhea->Ascender;
  766         }
  767     } else {
  768         /* Fall back to using whatever FreeType2 provides. */
  769         family->celldescent = -face->descender;
  770         family->cellascent = face->ascender;
  771         family->linespacing = face->height;
  772     }
  773     
  774     family->height = face->units_per_EM;
  775 }
  776 
  777 #ifdef USE_PANGO_RENDERING
  778 
  779 PangoFontDescription*
  780 gdip_get_pango_font_description (GpFont *font)
  781 {
  782     if (!font->pango) {
  783         font->pango = pango_font_description_new ();
  784         pango_font_description_set_family (font->pango, (char *)font->face);
  785         
  786         float sizeInPoints = gdip_unit_conversion (font->unit, UnitPoint, gdip_get_display_dpi(), gtMemoryBitmap, font->emSize);
  787         
  788         pango_font_description_set_size (font->pango, sizeInPoints * PANGO_SCALE);
  789 
  790         if (font->style & FontStyleBold)
  791             pango_font_description_set_weight (font->pango, PANGO_WEIGHT_BOLD);
  792 
  793         if (font->style & FontStyleItalic)
  794             pango_font_description_set_style (font->pango, PANGO_STYLE_ITALIC);
  795     }
  796     return font->pango;
  797 }
  798 
  799 static GpStatus
  800 gdip_get_fontfamily_details (GpFontFamily *family, FontStyle style)
  801 {
  802     GpFont *font;
  803     GpStatus status = GdipCreateFont (family, 8.0f, style, UnitPoint, &font);
  804     if (status != Ok)
  805         return status;
  806 
  807     PangoFontMap *map = family->collection->pango_font_map;
  808 #if PANGO_VERSION_CHECK(1,22,0)
  809     PangoContext *context = pango_font_map_create_context (PANGO_FONT_MAP (map));
  810 #else
  811     PangoContext *context = pango_cairo_font_map_create_context ((PangoCairoFontMap*)map);
  812 #endif
  813     PangoFont *pf = pango_font_map_load_font (map, context, gdip_get_pango_font_description (font));
  814 
  815     FT_Face face = pango_fc_font_lock_face ((PangoFcFont*)pf);
  816     if (face) {
  817         gdip_get_fontfamily_details_from_freetype (family, face);
  818         pango_fc_font_unlock_face ((PangoFcFont*)pf);
  819     } else {
  820         status = FontFamilyNotFound;
  821     }
  822 
  823     g_object_unref (pf);
  824     g_object_unref (context);
  825 
  826     GdipDeleteFont (font);
  827     return status;
  828 }
  829 
  830 #else
  831 
  832 cairo_font_face_t*
  833 gdip_get_cairo_font_face (GpFont *font)
  834 {
  835     if (!font->cairofnt) {
  836         FcPattern *pattern = FcPatternBuild (
  837             FcPatternDuplicate (font->family->pattern),
  838             FC_SLANT,  FcTypeInteger, ((font->style & FontStyleItalic) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN), 
  839             FC_WEIGHT, FcTypeInteger, ((font->style & FontStyleBold)   ? FC_WEIGHT_BOLD  : FC_WEIGHT_MEDIUM),
  840             NULL);
  841 
  842         font->cairofnt = cairo_ft_font_face_create_for_pattern (pattern);
  843         cairo_font_face_reference (font->cairofnt);
  844         FcPatternDestroy (pattern);
  845     }
  846     return font->cairofnt;
  847 }
  848 
  849 static GpStatus
  850 gdip_get_fontfamily_details (GpFontFamily *family, FontStyle style)
  851 {
  852     GpFont *font;
  853     GpStatus status = GdipCreateFont (family, 0.1f, style, UnitPoint, &font);
  854     if (status != Ok)
  855         return status;
  856 
  857     cairo_scaled_font_t* scaled_ft;
  858     FT_Face face = NULL;
  859     cairo_matrix_t matrix1, matrix2;
  860     cairo_font_options_t *options = cairo_font_options_create ();
  861     cairo_font_face_t* cairofnt = gdip_get_cairo_font_face (font);
  862 
  863     cairo_matrix_init (&matrix1, 1, 0, 0, 1, 0, 0);
  864     cairo_matrix_init (&matrix2, 1, 0, 0, 1, 0, 0);
  865     scaled_ft = cairo_scaled_font_create (cairofnt, &matrix1, &matrix2, options);
  866     /* a missing fonts.conf will resuls in a NULL *scaled_ft (#78237) */
  867     if (!scaled_ft) {
  868         static int flag = 0;
  869         if (flag == 0) {
  870             g_warning ("couldn't lock the font face. this may be due to a missing fonts.conf on the system.");
  871             flag = 1;
  872         }
  873         status = FontFamilyNotFound;
  874     }
  875 
  876     if (status == Ok)
  877         face = cairo_ft_scaled_font_lock_face (scaled_ft);
  878 
  879     cairo_font_options_destroy (options);
  880 
  881     if (face) {
  882         gdip_get_fontfamily_details_from_freetype (family, face);
  883 
  884         cairo_ft_scaled_font_unlock_face (scaled_ft);
  885         cairo_scaled_font_destroy (scaled_ft);
  886     } else {
  887         status = FontFamilyNotFound;
  888     }
  889 
  890     GdipDeleteFont (font);
  891     return status;
  892 }
  893 #endif
  894 
  895 GpStatus WINGDIPAPI
  896 GdipGetEmHeight (GDIPCONST GpFontFamily *family, INT style, UINT16 *EmHeight)
  897 {
  898     GpStatus status;
  899 
  900     if (!family || !EmHeight)
  901         return InvalidParameter;
  902 
  903     if (family->height == -1) {
  904         status = gdip_get_fontfamily_details ((GpFontFamily *) family, style);
  905         if (status != Ok)
  906             return status;
  907     }
  908 
  909     *EmHeight = family->height;
  910     return Ok;
  911 }
  912 
  913 GpStatus WINGDIPAPI
  914 GdipGetCellAscent (GDIPCONST GpFontFamily *family, INT style, UINT16 *CellAscent)
  915 {
  916     GpStatus status;
  917 
  918     if (!family || !CellAscent)
  919         return InvalidParameter;
  920 
  921     if (family->cellascent == -1) {
  922         status = gdip_get_fontfamily_details ((GpFontFamily *) family, style);
  923         if (status != Ok)
  924             return status;
  925     }
  926 
  927     *CellAscent = family->cellascent;
  928     return Ok;
  929 }
  930 
  931 GpStatus WINGDIPAPI
  932 GdipGetCellDescent (GDIPCONST GpFontFamily *family, INT style, UINT16 *CellDescent)
  933 {
  934     GpStatus status;
  935 
  936     if (!family || !CellDescent)
  937         return InvalidParameter;
  938 
  939     if (family->celldescent == -1) {
  940         status = gdip_get_fontfamily_details ((GpFontFamily *) family, style);
  941         if (status != Ok)
  942             return status;
  943     }
  944 
  945     *CellDescent = family->celldescent;
  946     return Ok;
  947 }
  948 
  949 GpStatus WINGDIPAPI
  950 GdipGetLineSpacing (GDIPCONST GpFontFamily *family, INT style, UINT16 *LineSpacing)
  951 {
  952     GpStatus status;
  953 
  954     if (!family || !LineSpacing)
  955         return InvalidParameter;
  956 
  957     if (family->linespacing == -1) {
  958         status = gdip_get_fontfamily_details ((GpFontFamily *) family, style);
  959         if (status != Ok)
  960             return status;
  961     }
  962 
  963     *LineSpacing = family->linespacing;
  964     return Ok;
  965 }
  966 
  967 GpStatus WINGDIPAPI
  968 GdipIsStyleAvailable (GDIPCONST GpFontFamily *family, INT style, BOOL *IsStyleAvailable)
  969 {
  970     if (!family || !IsStyleAvailable)
  971         return InvalidParameter;
  972 
  973     *IsStyleAvailable = TRUE;
  974     return Ok;    
  975 }
  976 
  977 /* Font functions */
  978 
  979 GpStatus
  980 gdip_create_font_without_validation (GDIPCONST GpFontFamily *family, REAL emSize, INT style, Unit unit, GpFont **font)
  981 {
  982     GpStatus status;
  983     FcChar8* str;
  984     FcResult r;
  985     GpFont *result;
  986     REAL sizeInPixels;
  987 
  988     r = FcPatternGetString (family->pattern, FC_FAMILY, 0, &str);
  989     status = gdip_status_from_fontconfig (r);
  990     if (status != Ok)
  991         return status;
  992     
  993     sizeInPixels = gdip_unit_conversion (unit, UnitPixel, gdip_get_display_dpi(), gtMemoryBitmap, emSize);
  994         
  995     result = gdip_font_new ();
  996     if (!result)
  997         return OutOfMemory;
  998 
  999     result->sizeInPixels = sizeInPixels;
 1000 
 1001     result->face = GdipAlloc (strlen ((char *) str) + 1);
 1002     if (!result->face) {
 1003         GdipDeleteFont (result);
 1004         return OutOfMemory;
 1005     }
 1006 
 1007     memcpy (result->face, str, strlen ((char *) str) + 1);
 1008 
 1009     result->style = style;
 1010     result->emSize = emSize;
 1011     result->unit = unit;
 1012     status = GdipCloneFontFamily ((GpFontFamily *) family, &result->family);
 1013     if (status != Ok) {
 1014         GdipDeleteFont (result);
 1015         return OutOfMemory;
 1016     }
 1017 
 1018     result->style = style;
 1019 #ifndef USE_PANGO_RENDERING
 1020     gdip_get_cairo_font_face (result);
 1021 #endif
 1022 
 1023     *font = result;
 1024     return Ok;
 1025 }
 1026 
 1027 // coverity[+alloc : arg-*4]
 1028 GpStatus
 1029 GdipCreateFont (GDIPCONST GpFontFamily *family, REAL emSize, INT style, Unit unit, GpFont **font)
 1030 {
 1031     if (!gdiplusInitialized)
 1032         return GdiplusNotInitialized;
 1033 
 1034     if (!family || !font || unit == UnitDisplay || unit < UnitWorld || unit > UnitCairoPoint || emSize <= 0)
 1035         return InvalidParameter;
 1036 
 1037     return gdip_create_font_without_validation (family, emSize, style, unit, font);
 1038 }
 1039 
 1040 GpStatus WINGDIPAPI
 1041 GdipCloneFont (GpFont* font, GpFont** cloneFont)
 1042 {
 1043     GpFont *result;
 1044     GpStatus status;
 1045 
 1046     if (!font || !cloneFont)
 1047         return InvalidParameter;
 1048         
 1049     result = gdip_font_new ();
 1050     if (!result)
 1051         return OutOfMemory;
 1052 
 1053     result->sizeInPixels = font->sizeInPixels;
 1054     result->style = font->style;
 1055     result->emSize = font->emSize;
 1056     result->unit = font->unit;
 1057 
 1058     result->face = (unsigned char *) g_strdup ((char *)font->face);
 1059     if (!result->face) {
 1060         GdipDeleteFont (result);
 1061         return OutOfMemory;
 1062     }
 1063 
 1064     status = GdipCloneFontFamily (font->family, &result->family);
 1065     if (status != Ok) {
 1066         GdipDeleteFont (result);
 1067         return OutOfMemory;
 1068     }
 1069 
 1070 #ifndef USE_PANGO_RENDERING
 1071     gdip_get_cairo_font_face (result);
 1072 #endif
 1073 
 1074     *cloneFont = result;
 1075     return Ok;
 1076 }
 1077 
 1078 GpStatus WINGDIPAPI
 1079 GdipDeleteFont (GpFont* font)
 1080 {
 1081     if (!font)
 1082         return InvalidParameter;
 1083 
 1084     if (font->family) {
 1085         GdipDeleteFontFamily (font->family);
 1086         font->family = NULL;
 1087     }
 1088 
 1089 #ifdef USE_PANGO_RENDERING
 1090     if (font->pango) {
 1091         pango_font_description_free (font->pango);
 1092         font->pango = NULL;
 1093     }
 1094 #else
 1095     if (font->cairofnt) {
 1096         cairo_font_face_destroy (font->cairofnt);
 1097         font->cairofnt = NULL;
 1098     }
 1099 #endif
 1100 
 1101     if (font->face) {
 1102         GdipFree (font->face);
 1103         font->face = NULL;
 1104     }
 1105 
 1106     GdipFree (font);
 1107     return Ok;         
 1108 }
 1109 
 1110 GpStatus WINGDIPAPI
 1111 GdipCreateFontFromDC (HDC hdc, GpFont **font)
 1112 {
 1113     if (!gdiplusInitialized)
 1114         return GdiplusNotInitialized;
 1115 
 1116     if (!hdc || !font)
 1117         return InvalidParameter;
 1118 
 1119     return NotImplemented;
 1120 }
 1121 
 1122 static GpStatus
 1123 gdip_logfont_from_font (GpFont *font, GpGraphics *graphics, void *lf, BOOL ucs2)
 1124 {
 1125     LOGFONTA        *logFont;
 1126 
 1127     if (!lf)
 1128         return InvalidParameter;
 1129 
 1130     logFont = (LOGFONTA *)lf;
 1131 
 1132     /* will be changed back to 1 inside System.Drawing */
 1133     logFont->lfCharSet = 0;
 1134 
 1135     if (!font || !graphics) {
 1136         int size = (ucs2) ? 2 * LF_FACESIZE : LF_FACESIZE;
 1137         memset (logFont->lfFaceName, 0, size);
 1138         return InvalidParameter;
 1139     }
 1140 
 1141     logFont->lfHeight = -(font->sizeInPixels);
 1142     logFont->lfWidth = 0;
 1143     logFont->lfEscapement = 0;  // FIXME
 1144     logFont->lfOrientation = logFont->lfEscapement;
 1145     if (font->style & FontStyleBold) {
 1146         logFont->lfWeight = 700;
 1147     } else {
 1148         logFont->lfWeight = 400;
 1149     }
 1150 
 1151     if (font->style & FontStyleItalic) {
 1152         logFont->lfItalic = 1;
 1153     } else {
 1154         logFont->lfItalic = 0;
 1155     }
 1156 
 1157     if (font->style & FontStyleUnderline) {
 1158         logFont->lfUnderline = 1;
 1159     } else {
 1160         logFont->lfUnderline = 0;
 1161     }
 1162 
 1163     if (font->style & FontStyleStrikeout) {
 1164         logFont->lfStrikeOut = 1;
 1165     } else {
 1166         logFont->lfStrikeOut = 0;
 1167     }
 1168 
 1169     logFont->lfOutPrecision = 0;
 1170     logFont->lfClipPrecision = 0;
 1171 
 1172     switch (graphics->text_mode) {
 1173         case TextRenderingHintSystemDefault: {
 1174             logFont->lfQuality = 0;
 1175             break;
 1176         }
 1177     
 1178         case TextRenderingHintSingleBitPerPixelGridFit:
 1179         case TextRenderingHintSingleBitPerPixel:
 1180         case TextRenderingHintAntiAliasGridFit:
 1181         case TextRenderingHintAntiAlias: {
 1182             logFont->lfQuality = 3; // ANTIALIASED_QUALITY;
 1183             break;
 1184         }
 1185     
 1186         case TextRenderingHintClearTypeGridFit: {
 1187             logFont->lfQuality = 5; // CLEARTYPE_QUALITY
 1188             break;
 1189         }
 1190     }
 1191 
 1192     logFont->lfPitchAndFamily = 0;
 1193     if (ucs2) {
 1194         utf8_to_ucs2 ((const gchar *) font->face, (gunichar2 *) logFont->lfFaceName, LF_FACESIZE);
 1195     } else {
 1196         int len = strlen ((char *) font->face);
 1197         memset (logFont->lfFaceName, 0, LF_FACESIZE);
 1198         memcpy (logFont->lfFaceName, font->face, len < LF_FACESIZE ? len : LF_FACESIZE - 1);
 1199     }
 1200     return Ok;
 1201 }
 1202 
 1203 // coverity[+alloc : arg-*1]
 1204 GpStatus WINGDIPAPI
 1205 GdipCreateFontFromHfontA (HFONT hfont, GpFont **font, void *lf)
 1206 {
 1207     GpStatus        status;
 1208     GpFont          *src_font;
 1209     GpFont          *result;
 1210 
 1211     if (!gdiplusInitialized)
 1212         return GdiplusNotInitialized;
 1213 
 1214     src_font = (GpFont *)hfont;
 1215 
 1216     result = gdip_font_new ();
 1217     if (!result)
 1218         return OutOfMemory;
 1219 
 1220     result->sizeInPixels = src_font->sizeInPixels;
 1221     result->style = src_font->style;
 1222     status = GdipCloneFontFamily (src_font->family, &result->family);
 1223     if (!status) {
 1224         GdipDeleteFont (result);
 1225         return OutOfMemory;
 1226     }
 1227 
 1228     result->style = src_font->style;
 1229     result->emSize = src_font->emSize;
 1230     result->unit = src_font->unit;
 1231 
 1232     result->face = GdipAlloc(strlen ((char *) src_font->face) + 1);
 1233     if (!result->face) {
 1234         GdipDeleteFont (result);
 1235         return OutOfMemory;
 1236     }
 1237 
 1238     memcpy(result->face, src_font->face, strlen((char *)src_font->face) + 1);
 1239 
 1240     *font = result;
 1241     return gdip_logfont_from_font (result, NULL, lf, FALSE);
 1242 }
 1243 
 1244 GpStatus WINGDIPAPI
 1245 GdipGetLogFontW (GpFont *font, GpGraphics *graphics, LOGFONTW *logfontW)
 1246 {
 1247     return gdip_logfont_from_font (font, graphics, logfontW, TRUE);
 1248 }
 1249 
 1250 GpStatus WINGDIPAPI
 1251 GdipGetLogFontA (GpFont *font, GpGraphics *graphics, LOGFONTA *logfontA)
 1252 {
 1253     return gdip_logfont_from_font (font, graphics, logfontA, FALSE);
 1254 }
 1255 
 1256 static GpStatus
 1257 gdip_create_font_from_logfont (HDC hdc, void *lf, GpFont **font, BOOL ucs2)
 1258 {
 1259     GpStatus status;
 1260 
 1261     if (!gdiplusInitialized)
 1262         return GdiplusNotInitialized;
 1263 
 1264     if (!hdc || !lf || !font)
 1265         return InvalidParameter;
 1266 
 1267     GpFont *result = gdip_font_new ();
 1268     if (!result)
 1269         return OutOfMemory;
 1270 
 1271     LOGFONTA *logfont = (LOGFONTA *)lf;
 1272 
 1273     if (logfont->lfHeight < 0) {
 1274         result->sizeInPixels = abs (logfont->lfHeight);
 1275     } else {
 1276         result->sizeInPixels = logfont->lfHeight;   // Fixme - convert units
 1277     }
 1278     result->style = 0;
 1279     /* Fixme - this is wrong, but I don't know of a quick way to get the emSize */
 1280     result->emSize = result->sizeInPixels;
 1281     result->unit = UnitWorld;
 1282 
 1283     if (logfont->lfItalic) {
 1284         result->style |= FontStyleItalic;
 1285     }
 1286     if (logfont->lfWeight > 400) {
 1287         result->style |= FontStyleBold;
 1288     }
 1289     if (logfont->lfUnderline) {
 1290         result->style |= FontStyleUnderline;
 1291     }
 1292     if (logfont->lfStrikeOut) {
 1293         result->style |= FontStyleStrikeout;
 1294     }
 1295 
 1296     if (ucs2) {
 1297         result->face = (BYTE*) utf16_to_utf8 ((WCHAR *) logfont->lfFaceName, -1);
 1298         if (!result->face){
 1299             GdipDeleteFont (result);
 1300             return OutOfMemory;
 1301         }
 1302     } else {
 1303         result->face = GdipAlloc (LF_FACESIZE);
 1304         if (!result->face){
 1305             GdipDeleteFont (result);
 1306             return OutOfMemory;
 1307         }
 1308         memcpy(result->face, logfont->lfFaceName, LF_FACESIZE);
 1309         result->face[LF_FACESIZE - 1] = '\0';
 1310     }
 1311 
 1312     status = create_fontfamily_from_name ((char *) result->face, &result->family);
 1313     if (status == OutOfMemory) {
 1314         GdipDeleteFont (result);
 1315         return status;
 1316     }
 1317 
 1318     *font = result;
 1319     return Ok;
 1320 }
 1321 
 1322 // coverity[+alloc : arg-*2]
 1323 GpStatus
 1324 GdipCreateFontFromLogfontA(HDC hdc, GDIPCONST LOGFONTA *logfont, GpFont **font)
 1325 {
 1326     return gdip_create_font_from_logfont (hdc, (void *)logfont, font, FALSE);
 1327 }
 1328 
 1329 // coverity[+alloc : arg-*2]
 1330 GpStatus
 1331 GdipCreateFontFromLogfontW(HDC hdc, GDIPCONST LOGFONTW *logfont, GpFont **font)
 1332 {
 1333     return gdip_create_font_from_logfont (hdc, (void *)logfont, font, TRUE);
 1334 }
 1335 
 1336 GpStatus WINGDIPAPI
 1337 GdipPrivateAddMemoryFont(GpFontCollection *fontCollection, GDIPCONST void *memory, INT length)
 1338 {
 1339     FcChar8 fontfile[256];
 1340 #ifdef WIN32
 1341     FILE    *f;
 1342 #else
 1343     int f;
 1344 #endif
 1345 
 1346     if (!fontCollection || !memory)
 1347         return InvalidParameter;
 1348     if (length <= 0)
 1349         return InvalidParameter;
 1350 
 1351 #ifdef WIN32
 1352     f = CreateTempFile (fontfile);
 1353     if (!f)
 1354         return FileNotFound;
 1355 
 1356     if (fwrite(memory, sizeof(BYTE), length, f) != length) {
 1357         fclose (f);
 1358         return FileNotFound;
 1359     }
 1360 
 1361     fclose (f);
 1362 #else
 1363     strcpy ((char *) fontfile, "/tmp/ffXXXXXX");
 1364     f = mkstemp ((char *) fontfile);
 1365     
 1366     if (f == -1)
 1367         return FileNotFound;
 1368 
 1369     if (write (f, memory, length) != length) {
 1370         close (f);
 1371         return FileNotFound;
 1372     }
 1373     close (f);
 1374 #endif
 1375 
 1376     FcConfigAppFontAddFile (fontCollection->config, fontfile);
 1377     /* FIXME - May we delete our temporary font file or does 
 1378        FcConfigAppFontAddFile just reference our file?  */
 1379     /* unlink(fontfile); */
 1380 
 1381     return Ok;
 1382 }
 1383 
 1384 GpStatus WINGDIPAPI
 1385 GdipGetFontHeight (GDIPCONST GpFont *font, GDIPCONST GpGraphics *graphics, REAL *height)
 1386 {
 1387     GpStatus status;
 1388     UINT16 emHeight, lineSpacing;
 1389     REAL emSize, h;
 1390 
 1391     if (!font || !height)
 1392         return InvalidParameter;
 1393 
 1394     status = GdipGetEmHeight (font->family, font->style, &emHeight);
 1395     if (status != Ok)
 1396         return status;
 1397 
 1398     status = GdipGetLineSpacing (font->family, font->style, &lineSpacing);
 1399     if (status != Ok)
 1400         return status;
 1401 
 1402     /* Operations in display dpi's */   
 1403     emSize = gdip_unit_conversion (font->unit, UnitPixel, gdip_get_display_dpi (), gtMemoryBitmap, font->emSize);
 1404 
 1405     h = lineSpacing * (emSize / emHeight);
 1406     if (!graphics)
 1407         *height = h;
 1408     else
 1409         *height = gdip_unit_conversion (UnitPixel, graphics->page_unit, gdip_get_display_dpi (), graphics->type, h);
 1410 
 1411     return Ok;
 1412 }
 1413 
 1414 GpStatus WINGDIPAPI
 1415 GdipGetFontHeightGivenDPI (GDIPCONST GpFont *font, REAL dpi, REAL *height)
 1416 {
 1417     GpStatus status;
 1418     UINT16 emHeight, lineSpacing;
 1419     REAL h;
 1420 
 1421     if (!font || !height)
 1422         return InvalidParameter;
 1423 
 1424     status = GdipGetEmHeight (font->family, font->style, &emHeight);
 1425     if (status != Ok)
 1426         return status;
 1427 
 1428     status = GdipGetLineSpacing (font->family, font->style, &lineSpacing);
 1429     if (status != Ok)
 1430         return status;
 1431 
 1432     h = lineSpacing * (font->emSize / emHeight);
 1433     *height = gdip_unit_conversion (font->unit, UnitInch, dpi, gtMemoryBitmap, h) * dpi;
 1434     return Ok;
 1435 }
 1436 
 1437 GpStatus WINGDIPAPI
 1438 GdipGetFontSize (GpFont *font, REAL *size)
 1439 {
 1440     if (!font ||!size)
 1441         return InvalidParameter;
 1442 
 1443     *size = font->emSize;
 1444     return Ok;
 1445 }
 1446 
 1447 GpStatus WINGDIPAPI
 1448 GdipGetFontStyle (GpFont *font, INT *style)
 1449 {
 1450     if (!font || !style)
 1451         return InvalidParameter;
 1452 
 1453     *style = font->style;
 1454     return Ok;
 1455 }
 1456 
 1457 GpStatus WINGDIPAPI
 1458 GdipGetFontUnit (GpFont *font, Unit *unit)
 1459 {
 1460     if (!font || !unit)
 1461         return InvalidParameter;
 1462 
 1463     *unit = font->unit;
 1464     return Ok;
 1465 }
 1466 
 1467 GpStatus WINGDIPAPI
 1468 GdipGetFamily (GpFont *font, GpFontFamily **family)
 1469 {
 1470     if (!font || !family)
 1471         return InvalidParameter;
 1472 
 1473     return GdipCloneFontFamily (font->family, family);
 1474 }