Home | History | Annotate | Download | only in MagickCore
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                        TTTTT  Y   Y  PPPP   EEEEE                           %
      7 %                          T     Y Y   P   P  E                               %
      8 %                          T      Y    PPPP   EEE                             %
      9 %                          T      Y    P      E                               %
     10 %                          T      Y    P      EEEEE                           %
     11 %                                                                             %
     12 %                                                                             %
     13 %                       MagickCore Image Type Methods                         %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                                   Cristy                                    %
     17 %                                 May 2001                                    %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization      %
     21 %  dedicated to making software imaging solutions freely available.           %
     22 %                                                                             %
     23 %  You may not use this file except in compliance with the License.  You may  %
     24 %  obtain a copy of the License at                                            %
     25 %                                                                             %
     26 %    https://imagemagick.org/script/license.php                               %
     27 %                                                                             %
     28 %  Unless required by applicable law or agreed to in writing, software        %
     29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     31 %  See the License for the specific language governing permissions and        %
     32 %  limitations under the License.                                             %
     33 %                                                                             %
     34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     35 %
     36 %
     37 */
     38 
     39 /*
     41   Include declarations.
     42 */
     43 #include "MagickCore/studio.h"
     44 #include "MagickCore/blob.h"
     45 #include "MagickCore/client.h"
     46 #include "MagickCore/configure.h"
     47 #include "MagickCore/draw.h"
     48 #include "MagickCore/exception.h"
     49 #include "MagickCore/exception-private.h"
     50 #include "MagickCore/image-private.h"
     51 #include "MagickCore/linked-list.h"
     52 #include "MagickCore/log.h"
     53 #include "MagickCore/memory_.h"
     54 #include "MagickCore/memory-private.h"
     55 #include "MagickCore/nt-feature.h"
     56 #include "MagickCore/nt-base-private.h"
     57 #include "MagickCore/option.h"
     58 #include "MagickCore/semaphore.h"
     59 #include "MagickCore/splay-tree.h"
     60 #include "MagickCore/string_.h"
     61 #include "MagickCore/string-private.h"
     62 #include "MagickCore/type.h"
     63 #include "MagickCore/type-private.h"
     64 #include "MagickCore/token.h"
     65 #include "MagickCore/utility.h"
     66 #include "MagickCore/utility-private.h"
     67 #include "MagickCore/xml-tree.h"
     68 #if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
     69 # include "fontconfig/fontconfig.h"
     70 #if (FC_VERSION < 20209)
     71 #undef FC_WEIGHT_LIGHT
     72 #define FC_WIDTH                  "width"    /* Int */
     73 #define FC_WIDTH_ULTRACONDENSED    50
     74 #define FC_WIDTH_EXTRACONDENSED    63
     75 #define FC_WIDTH_CONDENSED         75
     76 #define FC_WIDTH_SEMICONDENSED     87
     77 #define FC_WIDTH_NORMAL            100
     78 #define FC_WIDTH_SEMIEXPANDED      113
     79 #define FC_WIDTH_EXPANDED          125
     80 #define FC_WIDTH_EXTRAEXPANDED     150
     81 #define FC_WIDTH_ULTRAEXPANDED     200
     82 
     83 #define FC_WEIGHT_THIN             0
     84 #define FC_WEIGHT_EXTRALIGHT       40
     85 #define FC_WEIGHT_ULTRALIGHT       FC_WEIGHT_EXTRALIGHT
     86 #define FC_WEIGHT_LIGHT            50
     87 #define FC_WEIGHT_BOOK             75
     88 #define FC_WEIGHT_REGULAR          80
     89 #define FC_WEIGHT_NORMAL           FC_WEIGHT_REGULAR
     90 #define FC_WEIGHT_MEDIUM           100
     91 #define FC_WEIGHT_DEMIBOLD         180
     92 #define FC_WEIGHT_SEMIBOLD         FC_WEIGHT_DEMIBOLD
     93 #define FC_WEIGHT_BOLD             200
     94 #define FC_WEIGHT_EXTRABOLD        205
     95 #define FC_WEIGHT_ULTRABOLD        FC_WEIGHT_EXTRABOLD
     96 #define FC_WEIGHT_BLACK            210
     97 #define FC_WEIGHT_HEAVY            FC_WEIGHT_BLACK
     98 #endif
     99 #endif
    100 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
    101 # include "MagickCore/nt-feature.h"
    102 #endif
    103 
    104 /*
    106   Define declarations.
    107 */
    108 #define MagickTypeFilename  "type.xml"
    109 
    110 /*
    112   Declare type map.
    113 */
    114 static const char
    115   *TypeMap = (const char *)
    116     "<?xml version=\"1.0\"?>"
    117     "<typemap>"
    118     "  <type stealth=\"True\" name=\"fixed\" family=\"helvetica\"/>"
    119     "  <type stealth=\"True\" name=\"helvetica\" family=\"helvetica\"/>"
    120     "</typemap>";
    121 
    122 /*
    124   Static declarations.
    125 */
    126 static SemaphoreInfo
    127   *type_semaphore = (SemaphoreInfo *) NULL;
    128 
    129 static SplayTreeInfo
    130   *type_cache = (SplayTreeInfo *) NULL;
    131 
    132 /*
    134   Forward declarations.
    135 */
    136 static MagickBooleanType
    137   IsTypeTreeInstantiated(ExceptionInfo *),
    138   LoadTypeCache(SplayTreeInfo *,const char *,const char *,const size_t,
    139     ExceptionInfo *);
    140 
    141 /*
    143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    144 %                                                                             %
    145 %                                                                             %
    146 %                                                                             %
    147 %  A c q u i r e T y p e S p l a y T r e e                                    %
    148 %                                                                             %
    149 %                                                                             %
    150 %                                                                             %
    151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    152 %
    153 %  AcquireTypeCache() caches one or more type configuration files which
    154 %  provides a mapping between type attributes and a type name.
    155 %
    156 %  The format of the AcquireTypeCache method is:
    157 %
    158 %      SplayTreeInfo *AcquireTypeCache(const char *filename,
    159 %        ExceptionInfo *exception)
    160 %
    161 %  A description of each parameter follows:
    162 %
    163 %    o filename: the font file name.
    164 %
    165 %    o exception: return any errors or warnings in this structure.
    166 %
    167 */
    168 
    169 static void *DestroyTypeNode(void *type_info)
    170 {
    171   register TypeInfo
    172     *p;
    173 
    174   p=(TypeInfo *) type_info;
    175   if (p->path != (char *) NULL)
    176     p->path=DestroyString(p->path);
    177   if (p->name != (char *) NULL)
    178     p->name=DestroyString(p->name);
    179   if (p->description != (char *) NULL)
    180     p->description=DestroyString(p->description);
    181   if (p->family != (char *) NULL)
    182     p->family=DestroyString(p->family);
    183   if (p->encoding != (char *) NULL)
    184     p->encoding=DestroyString(p->encoding);
    185   if (p->foundry != (char *) NULL)
    186     p->foundry=DestroyString(p->foundry);
    187   if (p->format != (char *) NULL)
    188     p->format=DestroyString(p->format);
    189   if (p->metrics != (char *) NULL)
    190     p->metrics=DestroyString(p->metrics);
    191   if (p->glyphs != (char *) NULL)
    192     p->glyphs=DestroyString(p->glyphs);
    193   return(RelinquishMagickMemory(p));
    194 }
    195 
    196 static SplayTreeInfo *AcquireTypeCache(const char *filename,
    197   ExceptionInfo *exception)
    198 {
    199   MagickStatusType
    200     status;
    201 
    202   SplayTreeInfo
    203     *cache;
    204 
    205   cache=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL,
    206     DestroyTypeNode);
    207   status=MagickTrue;
    208 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
    209   {
    210     char
    211       *font_path,
    212       path[MagickPathExtent];
    213 
    214     const StringInfo
    215       *option;
    216 
    217     LinkedListInfo
    218       *options;
    219 
    220     *path='\0';
    221     options=GetConfigureOptions(filename,exception);
    222     option=(const StringInfo *) GetNextValueInLinkedList(options);
    223     while (option != (const StringInfo *) NULL)
    224     {
    225       (void) CopyMagickString(path,GetStringInfoPath(option),MagickPathExtent);
    226       status&=LoadTypeCache(cache,(const char *)
    227         GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
    228       option=(const StringInfo *) GetNextValueInLinkedList(options);
    229     }
    230     options=DestroyConfigureOptions(options);
    231     font_path=GetEnvironmentValue("MAGICK_FONT_PATH");
    232     if (font_path != (char *) NULL)
    233       {
    234         char
    235           *xml;
    236 
    237         /*
    238           Search MAGICK_FONT_PATH.
    239         */
    240         (void) FormatLocaleString(path,MagickPathExtent,"%s%s%s",font_path,
    241           DirectorySeparator,filename);
    242         xml=FileToString(path,~0UL,exception);
    243         if (xml != (void *) NULL)
    244           {
    245             status&=LoadTypeCache(cache,xml,path,0,exception);
    246             xml=DestroyString(xml);
    247           }
    248         font_path=DestroyString(font_path);
    249       }
    250   }
    251 #endif
    252   if (GetNumberOfNodesInSplayTree(cache) == 0)
    253     status&=LoadTypeCache(cache,TypeMap,"built-in",0,exception);
    254   return(cache);
    255 }
    256 
    257 /*
    259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    260 %                                                                             %
    261 %                                                                             %
    262 %                                                                             %
    263 +   G e t T y p e I n f o                                                     %
    264 %                                                                             %
    265 %                                                                             %
    266 %                                                                             %
    267 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    268 %
    269 %  GetTypeInfo searches the type list for the specified name and if found
    270 %  returns attributes for that type.
    271 %
    272 %  The format of the GetTypeInfo method is:
    273 %
    274 %      const TypeInfo *GetTypeInfo(const char *name,ExceptionInfo *exception)
    275 %
    276 %  A description of each parameter follows:
    277 %
    278 %    o name: the type name.
    279 %
    280 %    o exception: return any errors or warnings in this structure.
    281 %
    282 */
    283 MagickExport const TypeInfo *GetTypeInfo(const char *name,
    284   ExceptionInfo *exception)
    285 {
    286   assert(exception != (ExceptionInfo *) NULL);
    287   if (IsTypeTreeInstantiated(exception) == MagickFalse)
    288     return((const TypeInfo *) NULL);
    289   if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
    290     return((const TypeInfo *) GetRootValueFromSplayTree(type_cache));
    291   return((const TypeInfo *) GetValueFromSplayTree(type_cache,name));
    292 }
    293 
    294 /*
    296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    297 %                                                                             %
    298 %                                                                             %
    299 %                                                                             %
    300 +   G e t T y p e I n f o B y F a m i l y                                     %
    301 %                                                                             %
    302 %                                                                             %
    303 %                                                                             %
    304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    305 %
    306 %  GetTypeInfoByFamily() searches the type list for the specified family and if
    307 %  found returns attributes for that type.
    308 %
    309 %  Type substitution and scoring algorithm contributed by Bob Friesenhahn.
    310 %
    311 %  The format of the GetTypeInfoByFamily method is:
    312 %
    313 %      const TypeInfo *GetTypeInfoByFamily(const char *family,
    314 %        const StyleType style,const StretchType stretch,
    315 %        const size_t weight,ExceptionInfo *exception)
    316 %
    317 %  A description of each parameter follows:
    318 %
    319 %    o family: the type family.
    320 %
    321 %    o style: the type style.
    322 %
    323 %    o stretch: the type stretch.
    324 %
    325 %    o weight: the type weight.
    326 %
    327 %    o exception: return any errors or warnings in this structure.
    328 %
    329 */
    330 
    331 MagickExport const TypeInfo *GetTypeInfoByFamily(const char *family,
    332   const StyleType style,const StretchType stretch,const size_t weight,
    333   ExceptionInfo *exception)
    334 {
    335   typedef struct _Fontmap
    336   {
    337     const char
    338       *name,
    339       *substitute;
    340   } Fontmap;
    341 
    342   const TypeInfo
    343     *type_info;
    344 
    345   register const TypeInfo
    346     *p;
    347 
    348   register ssize_t
    349     i;
    350 
    351   ssize_t
    352     range;
    353 
    354   static const Fontmap
    355     fontmap[] =
    356     {
    357       { "fixed", "courier" },
    358       { "modern","courier" },
    359       { "monotype corsiva", "courier" },
    360       { "news gothic", "helvetica" },
    361       { "system", "courier" },
    362       { "terminal", "courier" },
    363       { "wingdings", "symbol" },
    364       { NULL, NULL }
    365     };
    366 
    367   size_t
    368     font_weight,
    369     max_score,
    370     score;
    371 
    372   /*
    373     Check for an exact type match.
    374   */
    375   (void) GetTypeInfo("*",exception);
    376   if (type_cache == (SplayTreeInfo *) NULL)
    377     return((TypeInfo *) NULL);
    378   font_weight=(size_t) (weight == 0 ? 400 : weight);
    379   LockSemaphoreInfo(type_semaphore);
    380   ResetSplayTreeIterator(type_cache);
    381   type_info=(const TypeInfo *) NULL;
    382   p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
    383   while (p != (const TypeInfo *) NULL)
    384   {
    385     if (p->family == (char *) NULL)
    386       {
    387         p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
    388         continue;
    389       }
    390     if (family == (const char *) NULL)
    391       {
    392         if ((LocaleCompare(p->family,"arial") != 0) &&
    393             (LocaleCompare(p->family,"helvetica") != 0))
    394           {
    395             p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
    396             continue;
    397           }
    398       }
    399     else
    400       if (LocaleCompare(p->family,family) != 0)
    401         {
    402           p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
    403           continue;
    404         }
    405     if ((style != UndefinedStyle) && (style != AnyStyle) && (p->style != style))
    406       {
    407         p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
    408         continue;
    409       }
    410     if ((stretch != UndefinedStretch) && (stretch != AnyStretch) &&
    411         (p->stretch != stretch))
    412       {
    413         p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
    414         continue;
    415       }
    416     if (p->weight != font_weight)
    417       {
    418         p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
    419         continue;
    420       }
    421     type_info=p;
    422     break;
    423   }
    424   UnlockSemaphoreInfo(type_semaphore);
    425   if (type_info != (const TypeInfo *) NULL)
    426     return(type_info);
    427   /*
    428     Check for types in the same family.
    429   */
    430   max_score=0;
    431   LockSemaphoreInfo(type_semaphore);
    432   ResetSplayTreeIterator(type_cache);
    433   p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
    434   while (p != (const TypeInfo *) NULL)
    435   {
    436     if (p->family == (char *) NULL)
    437       {
    438         p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
    439         continue;
    440       }
    441     if (family == (const char *) NULL)
    442       {
    443         if ((LocaleCompare(p->family,"arial") != 0) &&
    444             (LocaleCompare(p->family,"helvetica") != 0))
    445           {
    446             p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
    447             continue;
    448           }
    449       }
    450     else
    451       if (LocaleCompare(p->family,family) != 0)
    452         {
    453           p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
    454           continue;
    455         }
    456     score=0;
    457     if ((style == UndefinedStyle) || (style == AnyStyle) || (p->style == style))
    458       score+=32;
    459     else
    460       if (((style == ItalicStyle) || (style == ObliqueStyle)) &&
    461           ((p->style == ItalicStyle) || (p->style == ObliqueStyle)))
    462         score+=25;
    463     score+=(16*(800-((ssize_t) MagickMax(MagickMin(font_weight,900),p->weight)-
    464       (ssize_t) MagickMin(MagickMin(font_weight,900),p->weight))))/800;
    465     if ((stretch == UndefinedStretch) || (stretch == AnyStretch))
    466       score+=8;
    467     else
    468       {
    469         range=(ssize_t) UltraExpandedStretch-(ssize_t) NormalStretch;
    470         score+=(8*(range-((ssize_t) MagickMax(stretch,p->stretch)-
    471           (ssize_t) MagickMin(stretch,p->stretch))))/range;
    472       }
    473     if (score > max_score)
    474       {
    475         max_score=score;
    476         type_info=p;
    477       }
    478     p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
    479   }
    480   UnlockSemaphoreInfo(type_semaphore);
    481   if (type_info != (const TypeInfo *) NULL)
    482     return(type_info);
    483   /*
    484     Check for table-based substitution match.
    485   */
    486   for (i=0; fontmap[i].name != (char *) NULL; i++)
    487   {
    488     if (family == (const char *) NULL)
    489       {
    490         if ((LocaleCompare(fontmap[i].name,"arial") != 0) &&
    491             (LocaleCompare(fontmap[i].name,"helvetica") != 0))
    492           continue;
    493       }
    494     else
    495       if (LocaleCompare(fontmap[i].name,family) != 0)
    496         continue;
    497     type_info=GetTypeInfoByFamily(fontmap[i].substitute,style,stretch,weight,
    498       exception);
    499     break;
    500   }
    501   if (type_info != (const TypeInfo *) NULL)
    502     {
    503       (void) ThrowMagickException(exception,GetMagickModule(),TypeError,
    504         "FontSubstitutionRequired","`%s'",type_info->family);
    505       return(type_info);
    506     }
    507   if (family != (const char *) NULL)
    508     type_info=GetTypeInfoByFamily((const char *) NULL,style,stretch,weight,
    509       exception);
    510   return(type_info);
    511 }
    512 
    513 /*
    515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    516 %                                                                             %
    517 %                                                                             %
    518 %                                                                             %
    519 %   G e t T y p e I n f o L i s t                                             %
    520 %                                                                             %
    521 %                                                                             %
    522 %                                                                             %
    523 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    524 %
    525 %  GetTypeInfoList() returns any fonts that match the specified pattern.
    526 %
    527 %  The format of the GetTypeInfoList function is:
    528 %
    529 %      const TypeInfo **GetTypeInfoList(const char *pattern,
    530 %        size_t *number_fonts,ExceptionInfo *exception)
    531 %
    532 %  A description of each parameter follows:
    533 %
    534 %    o pattern: Specifies a pointer to a text string containing a pattern.
    535 %
    536 %    o number_fonts:  This integer returns the number of types in the list.
    537 %
    538 %    o exception: return any errors or warnings in this structure.
    539 %
    540 */
    541 
    542 #if defined(__cplusplus) || defined(c_plusplus)
    543 extern "C" {
    544 #endif
    545 
    546 static int TypeInfoCompare(const void *x,const void *y)
    547 {
    548   const TypeInfo
    549     **p,
    550     **q;
    551 
    552   p=(const TypeInfo **) x,
    553   q=(const TypeInfo **) y;
    554   if (LocaleCompare((*p)->path,(*q)->path) == 0)
    555     return(LocaleCompare((*p)->name,(*q)->name));
    556   return(LocaleCompare((*p)->path,(*q)->path));
    557 }
    558 
    559 #if defined(__cplusplus) || defined(c_plusplus)
    560 }
    561 #endif
    562 
    563 MagickExport const TypeInfo **GetTypeInfoList(const char *pattern,
    564   size_t *number_fonts,ExceptionInfo *exception)
    565 {
    566   const TypeInfo
    567     **fonts;
    568 
    569   register const TypeInfo
    570     *p;
    571 
    572   register ssize_t
    573     i;
    574 
    575   /*
    576     Allocate type list.
    577   */
    578   assert(pattern != (char *) NULL);
    579   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
    580   assert(number_fonts != (size_t *) NULL);
    581   *number_fonts=0;
    582   p=GetTypeInfo("*",exception);
    583   if (p == (const TypeInfo *) NULL)
    584     return((const TypeInfo **) NULL);
    585   fonts=(const TypeInfo **) AcquireQuantumMemory((size_t)
    586     GetNumberOfNodesInSplayTree(type_cache)+1UL,sizeof(*fonts));
    587   if (fonts == (const TypeInfo **) NULL)
    588     return((const TypeInfo **) NULL);
    589   /*
    590     Generate type list.
    591   */
    592   LockSemaphoreInfo(type_semaphore);
    593   ResetSplayTreeIterator(type_cache);
    594   p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
    595   for (i=0; p != (const TypeInfo *) NULL; )
    596   {
    597     if ((p->stealth == MagickFalse) &&
    598         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
    599       fonts[i++]=p;
    600     p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
    601   }
    602   UnlockSemaphoreInfo(type_semaphore);
    603   qsort((void *) fonts,(size_t) i,sizeof(*fonts),TypeInfoCompare);
    604   fonts[i]=(TypeInfo *) NULL;
    605   *number_fonts=(size_t) i;
    606   return(fonts);
    607 }
    608 
    609 /*
    611 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    612 %                                                                             %
    613 %                                                                             %
    614 %                                                                             %
    615 %   G e t T y p e L i s t                                                     %
    616 %                                                                             %
    617 %                                                                             %
    618 %                                                                             %
    619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    620 %
    621 %  GetTypeList() returns any fonts that match the specified pattern.
    622 %
    623 %  The format of the GetTypeList function is:
    624 %
    625 %      char **GetTypeList(const char *pattern,size_t *number_fonts,
    626 %        ExceptionInfo *exception)
    627 %
    628 %  A description of each parameter follows:
    629 %
    630 %    o pattern: Specifies a pointer to a text string containing a pattern.
    631 %
    632 %    o number_fonts:  This integer returns the number of fonts in the list.
    633 %
    634 %    o exception: return any errors or warnings in this structure.
    635 %
    636 */
    637 
    638 #if defined(__cplusplus) || defined(c_plusplus)
    639 extern "C" {
    640 #endif
    641 
    642 static int TypeCompare(const void *x,const void *y)
    643 {
    644   register const char
    645     **p,
    646     **q;
    647 
    648   p=(const char **) x;
    649   q=(const char **) y;
    650   return(LocaleCompare(*p,*q));
    651 }
    652 
    653 #if defined(__cplusplus) || defined(c_plusplus)
    654 }
    655 #endif
    656 
    657 MagickExport char **GetTypeList(const char *pattern,size_t *number_fonts,
    658   ExceptionInfo *exception)
    659 {
    660   char
    661     **fonts;
    662 
    663   register const TypeInfo
    664     *p;
    665 
    666   register ssize_t
    667     i;
    668 
    669   /*
    670     Allocate type list.
    671   */
    672   assert(pattern != (char *) NULL);
    673   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
    674   assert(number_fonts != (size_t *) NULL);
    675   *number_fonts=0;
    676   p=GetTypeInfo("*",exception);
    677   if (p == (const TypeInfo *) NULL)
    678     return((char **) NULL);
    679   fonts=(char **) AcquireQuantumMemory((size_t)
    680     GetNumberOfNodesInSplayTree(type_cache)+1UL,sizeof(*fonts));
    681   if (fonts == (char **) NULL)
    682     return((char **) NULL);
    683   /*
    684     Generate type list.
    685   */
    686   LockSemaphoreInfo(type_semaphore);
    687   ResetSplayTreeIterator(type_cache);
    688   p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
    689   for (i=0; p != (const TypeInfo *) NULL; )
    690   {
    691     if ((p->stealth == MagickFalse) &&
    692         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
    693       fonts[i++]=ConstantString(p->name);
    694     p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
    695   }
    696   UnlockSemaphoreInfo(type_semaphore);
    697   qsort((void *) fonts,(size_t) i,sizeof(*fonts),TypeCompare);
    698   fonts[i]=(char *) NULL;
    699   *number_fonts=(size_t) i;
    700   return(fonts);
    701 }
    702 
    703 /*
    705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    706 %                                                                             %
    707 %                                                                             %
    708 %                                                                             %
    709 +   I s T y p e T r e e I n s t a n t i a t e d                               %
    710 %                                                                             %
    711 %                                                                             %
    712 %                                                                             %
    713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    714 %
    715 %  IsTypeTreeInstantiated() determines if the type tree is instantiated.  If
    716 %  not, it instantiates the tree and returns it.
    717 %
    718 %  The format of the IsTypeInstantiated method is:
    719 %
    720 %      MagickBooleanType IsTypeTreeInstantiated(ExceptionInfo *exception)
    721 %
    722 %  A description of each parameter follows.
    723 %
    724 %    o exception: return any errors or warnings in this structure.
    725 %
    726 */
    727 
    728 #if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
    729 MagickExport MagickBooleanType LoadFontConfigFonts(SplayTreeInfo *type_cache,
    730   ExceptionInfo *exception)
    731 {
    732 #if !defined(FC_FULLNAME)
    733 #define FC_FULLNAME "fullname"
    734 #endif
    735 
    736   char
    737     extension[MagickPathExtent],
    738     name[MagickPathExtent];
    739 
    740   FcBool
    741     result;
    742 
    743   FcChar8
    744     *family,
    745     *file,
    746     *fullname,
    747     *style;
    748 
    749   FcConfig
    750     *font_config;
    751 
    752   FcFontSet
    753     *font_set;
    754 
    755   FcObjectSet
    756     *object_set;
    757 
    758   FcPattern
    759     *pattern;
    760 
    761   FcResult
    762     status;
    763 
    764   int
    765     slant,
    766     width,
    767     weight;
    768 
    769   register ssize_t
    770     i;
    771 
    772   TypeInfo
    773     *type_info;
    774 
    775   /*
    776     Load system fonts.
    777   */
    778   (void) exception;
    779   result=FcInit();
    780   if (result == 0)
    781     return(MagickFalse);
    782   font_config=FcConfigGetCurrent();
    783   if (font_config == (FcConfig *) NULL)
    784     return(MagickFalse);
    785   FcConfigSetRescanInterval(font_config,0);
    786   font_set=(FcFontSet *) NULL;
    787   object_set=FcObjectSetBuild(FC_FULLNAME,FC_FAMILY,FC_STYLE,FC_SLANT,
    788     FC_WIDTH,FC_WEIGHT,FC_FILE,(char *) NULL);
    789   if (object_set != (FcObjectSet *) NULL)
    790     {
    791       pattern=FcPatternCreate();
    792       if (pattern != (FcPattern *) NULL)
    793         {
    794           font_set=FcFontList(font_config,pattern,object_set);
    795           FcPatternDestroy(pattern);
    796         }
    797       FcObjectSetDestroy(object_set);
    798     }
    799   if (font_set == (FcFontSet *) NULL)
    800     {
    801       FcConfigDestroy(font_config);
    802       return(MagickFalse);
    803     }
    804   for (i=0; i < (ssize_t) font_set->nfont; i++)
    805   {
    806     status=FcPatternGetString(font_set->fonts[i],FC_FAMILY,0,&family);
    807     if (status != FcResultMatch)
    808       continue;
    809     status=FcPatternGetString(font_set->fonts[i],FC_FILE,0,&file);
    810     if (status != FcResultMatch)
    811       continue;
    812     *extension='\0';
    813     GetPathComponent((const char *) file,ExtensionPath,extension);
    814     if ((*extension != '\0') && (LocaleCompare(extension,"gz") == 0))
    815       continue;
    816     type_info=(TypeInfo *) AcquireMagickMemory(sizeof(*type_info));
    817     if (type_info == (TypeInfo *) NULL)
    818       continue;
    819     (void) memset(type_info,0,sizeof(*type_info));
    820     type_info->path=ConstantString("System Fonts");
    821     type_info->signature=MagickCoreSignature;
    822     (void) CopyMagickString(name,"Unknown",MagickPathExtent);
    823     status=FcPatternGetString(font_set->fonts[i],FC_FULLNAME,0,&fullname);
    824     if ((status == FcResultMatch) && (fullname != (FcChar8 *) NULL))
    825       (void) CopyMagickString(name,(const char *) fullname,MagickPathExtent);
    826     else
    827       {
    828         if (family != (FcChar8 *) NULL)
    829           (void) CopyMagickString(name,(const char *) family,MagickPathExtent);
    830         status=FcPatternGetString(font_set->fonts[i],FC_STYLE,0,&style);
    831         if ((status == FcResultMatch) && (style != (FcChar8 *) NULL) &&
    832             (LocaleCompare((const char *) style,"Regular") != 0))
    833           {
    834             (void) ConcatenateMagickString(name," ",MagickPathExtent);
    835             (void) ConcatenateMagickString(name,(const char *) style,
    836               MagickPathExtent);
    837           }
    838       }
    839     type_info->name=ConstantString(name);
    840     (void) SubstituteString(&type_info->name," ","-");
    841     type_info->family=ConstantString((const char *) family);
    842     status=FcPatternGetInteger(font_set->fonts[i],FC_SLANT,0,&slant);
    843     type_info->style=NormalStyle;
    844     if (slant == FC_SLANT_ITALIC)
    845       type_info->style=ItalicStyle;
    846     if (slant == FC_SLANT_OBLIQUE)
    847       type_info->style=ObliqueStyle;
    848     status=FcPatternGetInteger(font_set->fonts[i],FC_WIDTH,0,&width);
    849     type_info->stretch=NormalStretch;
    850     if (width >= FC_WIDTH_ULTRACONDENSED)
    851       type_info->stretch=UltraCondensedStretch;
    852     if (width >= FC_WIDTH_EXTRACONDENSED)
    853       type_info->stretch=ExtraCondensedStretch;
    854     if (width >= FC_WIDTH_CONDENSED)
    855       type_info->stretch=CondensedStretch;
    856     if (width >= FC_WIDTH_SEMICONDENSED)
    857       type_info->stretch=SemiCondensedStretch;
    858     if (width >= FC_WIDTH_NORMAL)
    859       type_info->stretch=NormalStretch;
    860     if (width >= FC_WIDTH_SEMIEXPANDED)
    861       type_info->stretch=SemiExpandedStretch;
    862     if (width >= FC_WIDTH_EXPANDED)
    863       type_info->stretch=ExpandedStretch;
    864     if (width >= FC_WIDTH_EXTRAEXPANDED)
    865       type_info->stretch=ExtraExpandedStretch;
    866     if (width >= FC_WIDTH_ULTRAEXPANDED)
    867       type_info->stretch=UltraExpandedStretch;
    868     type_info->weight=400;
    869     status=FcPatternGetInteger(font_set->fonts[i],FC_WEIGHT,0,&weight);
    870     if (weight >= FC_WEIGHT_THIN)
    871       type_info->weight=100;
    872     if (weight >= FC_WEIGHT_EXTRALIGHT)
    873       type_info->weight=200;
    874     if (weight >= FC_WEIGHT_LIGHT)
    875       type_info->weight=300;
    876     if (weight >= FC_WEIGHT_NORMAL)
    877       type_info->weight=400;
    878     if (weight >= FC_WEIGHT_MEDIUM)
    879       type_info->weight=500;
    880     if (weight >= FC_WEIGHT_DEMIBOLD)
    881       type_info->weight=600;
    882     if (weight >= FC_WEIGHT_BOLD)
    883       type_info->weight=700;
    884     if (weight >= FC_WEIGHT_EXTRABOLD)
    885       type_info->weight=800;
    886     if (weight >= FC_WEIGHT_BLACK)
    887       type_info->weight=900;
    888     type_info->glyphs=ConstantString((const char *) file);
    889     (void) AddValueToSplayTree(type_cache,type_info->name,type_info);
    890   }
    891   FcFontSetDestroy(font_set);
    892   FcConfigDestroy(font_config);
    893   return(MagickTrue);
    894 }
    895 #endif
    896 
    897 static MagickBooleanType IsTypeTreeInstantiated(ExceptionInfo *exception)
    898 {
    899   if (type_cache == (SplayTreeInfo *) NULL)
    900     {
    901       if (type_semaphore == (SemaphoreInfo *) NULL)
    902         ActivateSemaphoreInfo(&type_semaphore);
    903       LockSemaphoreInfo(type_semaphore);
    904       if (type_cache == (SplayTreeInfo *) NULL)
    905         {
    906           SplayTreeInfo
    907             *splay_tree;
    908 
    909           splay_tree=AcquireTypeCache(MagickTypeFilename,exception);
    910 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
    911           (void) NTAcquireTypeCache(splay_tree,exception);
    912 #endif
    913 #if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
    914           (void) LoadFontConfigFonts(splay_tree,exception);
    915 #endif
    916           type_cache=splay_tree;
    917         }
    918       UnlockSemaphoreInfo(type_semaphore);
    919     }
    920   return(type_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
    921 }
    922 
    923 /*
    925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    926 %                                                                             %
    927 %                                                                             %
    928 %                                                                             %
    929 %  L i s t T y p e I n f o                                                    %
    930 %                                                                             %
    931 %                                                                             %
    932 %                                                                             %
    933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    934 %
    935 %  ListTypeInfo() lists the fonts to a file.
    936 %
    937 %  The format of the ListTypeInfo method is:
    938 %
    939 %      MagickBooleanType ListTypeInfo(FILE *file,ExceptionInfo *exception)
    940 %
    941 %  A description of each parameter follows.
    942 %
    943 %    o file:  An pointer to a FILE.
    944 %
    945 %    o exception: return any errors or warnings in this structure.
    946 %
    947 */
    948 MagickExport MagickBooleanType ListTypeInfo(FILE *file,ExceptionInfo *exception)
    949 {
    950   char
    951     weight[MagickPathExtent];
    952 
    953   const char
    954     *family,
    955     *glyphs,
    956     *name,
    957     *path,
    958     *stretch,
    959     *style;
    960 
    961   const TypeInfo
    962     **type_info;
    963 
    964   register ssize_t
    965     i;
    966 
    967   size_t
    968     number_fonts;
    969 
    970   if (file == (FILE *) NULL)
    971     file=stdout;
    972   number_fonts=0;
    973   type_info=GetTypeInfoList("*",&number_fonts,exception);
    974   if (type_info == (const TypeInfo **) NULL)
    975     return(MagickFalse);
    976   *weight='\0';
    977   path=(const char *) NULL;
    978   for (i=0; i < (ssize_t) number_fonts; i++)
    979   {
    980     if (type_info[i]->stealth != MagickFalse)
    981       continue;
    982     if (((path == (const char *) NULL) ||
    983          (LocaleCompare(path,type_info[i]->path) != 0)) &&
    984          (type_info[i]->path != (char *) NULL))
    985       (void) FormatLocaleFile(file,"\nPath: %s\n",type_info[i]->path);
    986     path=type_info[i]->path;
    987     name="unknown";
    988     if (type_info[i]->name != (char *) NULL)
    989       name=type_info[i]->name;
    990     family="unknown";
    991     if (type_info[i]->family != (char *) NULL)
    992       family=type_info[i]->family;
    993     style=CommandOptionToMnemonic(MagickStyleOptions,type_info[i]->style);
    994     stretch=CommandOptionToMnemonic(MagickStretchOptions,type_info[i]->stretch);
    995     glyphs="unknown";
    996     if (type_info[i]->glyphs != (char *) NULL)
    997       glyphs=type_info[i]->glyphs;
    998     (void) FormatLocaleString(weight,MagickPathExtent,"%.20g",(double)
    999       type_info[i]->weight);
   1000     (void) FormatLocaleFile(file,"  Font: %s\n",name);
   1001     (void) FormatLocaleFile(file,"    family: %s\n",family);
   1002     (void) FormatLocaleFile(file,"    style: %s\n",style);
   1003     (void) FormatLocaleFile(file,"    stretch: %s\n",stretch);
   1004     (void) FormatLocaleFile(file,"    weight: %s\n",weight);
   1005     (void) FormatLocaleFile(file,"    glyphs: %s\n",glyphs);
   1006   }
   1007   (void) fflush(file);
   1008   type_info=(const TypeInfo **) RelinquishMagickMemory((void *) type_info);
   1009   return(MagickTrue);
   1010 }
   1011 
   1012 /*
   1014 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1015 %                                                                             %
   1016 %                                                                             %
   1017 %                                                                             %
   1018 +   L o a d T y p e C a c h e                                                 %
   1019 %                                                                             %
   1020 %                                                                             %
   1021 %                                                                             %
   1022 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1023 %
   1024 %  LoadTypeCache() loads the type configurations which provides a mapping
   1025 %  between type attributes and a type name.
   1026 %
   1027 %  The format of the LoadTypeCache method is:
   1028 %
   1029 %      MagickBooleanType LoadTypeCache(SplayTreeInfo *cache,const char *xml,
   1030 %        const char *filename,const size_t depth,ExceptionInfo *exception)
   1031 %
   1032 %  A description of each parameter follows:
   1033 %
   1034 %    o xml:  The type list in XML format.
   1035 %
   1036 %    o filename:  The type list filename.
   1037 %
   1038 %    o depth: depth of <include /> statements.
   1039 %
   1040 %    o exception: return any errors or warnings in this structure.
   1041 %
   1042 */
   1043 
   1044 static inline MagickBooleanType SetTypeNodePath(const char *filename,
   1045   char *font_path,const char *token,char **target)
   1046 {
   1047   char
   1048    *path;
   1049 
   1050   path=ConstantString(token);
   1051 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
   1052   if (strchr(path,'@') != (char *) NULL)
   1053     SubstituteString(&path,"@ghostscript_font_path@",font_path);
   1054 #endif
   1055   if (IsPathAccessible(path) == MagickFalse)
   1056     {
   1057       /*
   1058         Relative path.
   1059       */
   1060       path=DestroyString(path);
   1061       GetPathComponent(filename,HeadPath,font_path);
   1062       (void) ConcatenateMagickString(font_path,DirectorySeparator,
   1063         MagickPathExtent);
   1064       (void) ConcatenateMagickString(font_path,token,MagickPathExtent);
   1065       path=ConstantString(font_path);
   1066 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
   1067       if (strchr(path,'@') != (char *) NULL)
   1068         SubstituteString(&path,"@ghostscript_font_path@","");
   1069 #endif
   1070       if (IsPathAccessible(path) == MagickFalse)
   1071         {
   1072           path=DestroyString(path);
   1073           return(MagickFalse);
   1074         }
   1075     }
   1076 
   1077   *target=path;
   1078   return(MagickTrue);
   1079 }
   1080 
   1081 static MagickBooleanType LoadTypeCache(SplayTreeInfo *cache,const char *xml,
   1082   const char *filename,const size_t depth,ExceptionInfo *exception)
   1083 {
   1084   char
   1085     font_path[MagickPathExtent],
   1086     keyword[MagickPathExtent],
   1087     *token;
   1088 
   1089   const char
   1090     *q;
   1091 
   1092   MagickStatusType
   1093     status;
   1094 
   1095   size_t
   1096     extent;
   1097 
   1098   TypeInfo
   1099     *type_info;
   1100 
   1101   /*
   1102     Load the type map file.
   1103   */
   1104   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
   1105     "Loading type configure file \"%s\" ...",filename);
   1106   if (xml == (const char *) NULL)
   1107     return(MagickFalse);
   1108   status=MagickTrue;
   1109   type_info=(TypeInfo *) NULL;
   1110   token=AcquireString(xml);
   1111   extent=strlen(token)+MagickPathExtent;
   1112 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
   1113   /*
   1114     Determine the Ghostscript font path.
   1115   */
   1116   *font_path='\0';
   1117   if (NTGhostscriptFonts(font_path,MagickPathExtent-2))
   1118     (void) ConcatenateMagickString(font_path,DirectorySeparator,MagickPathExtent);
   1119 #endif
   1120   for (q=(char *) xml; *q != '\0'; )
   1121   {
   1122     /*
   1123       Interpret XML.
   1124     */
   1125     GetNextToken(q,&q,extent,token);
   1126     if (*token == '\0')
   1127       break;
   1128     (void) CopyMagickString(keyword,token,MagickPathExtent);
   1129     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
   1130       {
   1131         /*
   1132           Doctype element.
   1133         */
   1134         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
   1135           GetNextToken(q,&q,extent,token);
   1136         continue;
   1137       }
   1138     if (LocaleNCompare(keyword,"<!--",4) == 0)
   1139       {
   1140         /*
   1141           Comment element.
   1142         */
   1143         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
   1144           GetNextToken(q,&q,extent,token);
   1145         continue;
   1146       }
   1147     if (LocaleCompare(keyword,"<include") == 0)
   1148       {
   1149         /*
   1150           Include element.
   1151         */
   1152         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
   1153         {
   1154           (void) CopyMagickString(keyword,token,MagickPathExtent);
   1155           GetNextToken(q,&q,extent,token);
   1156           if (*token != '=')
   1157             continue;
   1158           GetNextToken(q,&q,extent,token);
   1159           if (LocaleCompare(keyword,"file") == 0)
   1160             {
   1161               if (depth > MagickMaxRecursionDepth)
   1162                 (void) ThrowMagickException(exception,GetMagickModule(),
   1163                   ConfigureError,"IncludeNodeNestedTooDeeply","`%s'",token);
   1164               else
   1165                 {
   1166                   char
   1167                     path[MagickPathExtent],
   1168                     *file_xml;
   1169 
   1170                   ExceptionInfo
   1171                     *sans_exception;
   1172 
   1173                   *path='\0';
   1174                   GetPathComponent(filename,HeadPath,path);
   1175                   if (*path != '\0')
   1176                     (void) ConcatenateMagickString(path,DirectorySeparator,
   1177                       MagickPathExtent);
   1178                   if (*token == *DirectorySeparator)
   1179                     (void) CopyMagickString(path,token,MagickPathExtent);
   1180                   else
   1181                     (void) ConcatenateMagickString(path,token,MagickPathExtent);
   1182                   sans_exception=AcquireExceptionInfo();
   1183                   file_xml=FileToString(path,~0UL,sans_exception);
   1184                   sans_exception=DestroyExceptionInfo(sans_exception);
   1185                   if (file_xml != (char *) NULL)
   1186                     {
   1187                       status&=LoadTypeCache(cache,file_xml,path,depth+1,
   1188                         exception);
   1189                       file_xml=(char *) RelinquishMagickMemory(file_xml);
   1190                     }
   1191                 }
   1192             }
   1193         }
   1194         continue;
   1195       }
   1196     if (LocaleCompare(keyword,"<type") == 0)
   1197       {
   1198         /*
   1199           Type element.
   1200         */
   1201         type_info=(TypeInfo *) AcquireCriticalMemory(sizeof(*type_info));
   1202         (void) memset(type_info,0,sizeof(*type_info));
   1203         type_info->path=ConstantString(filename);
   1204         type_info->signature=MagickCoreSignature;
   1205         continue;
   1206       }
   1207     if (type_info == (TypeInfo *) NULL)
   1208       continue;
   1209     if ((LocaleCompare(keyword,"/>") == 0) ||
   1210         (LocaleCompare(keyword,"</policy>") == 0))
   1211       {
   1212         status=AddValueToSplayTree(cache,type_info->name,type_info);
   1213         if (status == MagickFalse)
   1214           (void) ThrowMagickException(exception,GetMagickModule(),
   1215             ResourceLimitError,"MemoryAllocationFailed","`%s'",type_info->name);
   1216         type_info=(TypeInfo *) NULL;
   1217         continue;
   1218       }
   1219     GetNextToken(q,(const char **) NULL,extent,token);
   1220     if (*token != '=')
   1221       continue;
   1222     GetNextToken(q,&q,extent,token);
   1223     GetNextToken(q,&q,extent,token);
   1224     switch (*keyword)
   1225     {
   1226       case 'E':
   1227       case 'e':
   1228       {
   1229         if (LocaleCompare((char *) keyword,"encoding") == 0)
   1230           {
   1231             type_info->encoding=ConstantString(token);
   1232             break;
   1233           }
   1234         break;
   1235       }
   1236       case 'F':
   1237       case 'f':
   1238       {
   1239         if (LocaleCompare((char *) keyword,"face") == 0)
   1240           {
   1241             type_info->face=StringToUnsignedLong(token);
   1242             break;
   1243           }
   1244         if (LocaleCompare((char *) keyword,"family") == 0)
   1245           {
   1246             type_info->family=ConstantString(token);
   1247             break;
   1248           }
   1249         if (LocaleCompare((char *) keyword,"format") == 0)
   1250           {
   1251             type_info->format=ConstantString(token);
   1252             break;
   1253           }
   1254         if (LocaleCompare((char *) keyword,"foundry") == 0)
   1255           {
   1256             type_info->foundry=ConstantString(token);
   1257             break;
   1258           }
   1259         if (LocaleCompare((char *) keyword,"fullname") == 0)
   1260           {
   1261             type_info->description=ConstantString(token);
   1262             break;
   1263           }
   1264         break;
   1265       }
   1266       case 'G':
   1267       case 'g':
   1268       {
   1269         if (LocaleCompare((char *) keyword,"glyphs") == 0)
   1270           {
   1271             if (SetTypeNodePath(filename,font_path,token,&type_info->glyphs) ==
   1272                 MagickFalse)
   1273               type_info=(TypeInfo *) DestroyTypeNode(type_info);
   1274             break;
   1275           }
   1276         break;
   1277       }
   1278       case 'M':
   1279       case 'm':
   1280       {
   1281         if (LocaleCompare((char *) keyword,"metrics") == 0)
   1282           {
   1283             if (SetTypeNodePath(filename,font_path,token,&type_info->metrics) ==
   1284                 MagickFalse)
   1285               type_info=(TypeInfo *) DestroyTypeNode(type_info);
   1286             break;
   1287           }
   1288         break;
   1289       }
   1290       case 'N':
   1291       case 'n':
   1292       {
   1293         if (LocaleCompare((char *) keyword,"name") == 0)
   1294           {
   1295             type_info->name=ConstantString(token);
   1296             break;
   1297           }
   1298         break;
   1299       }
   1300       case 'S':
   1301       case 's':
   1302       {
   1303         if (LocaleCompare((char *) keyword,"stealth") == 0)
   1304           {
   1305             type_info->stealth=IsStringTrue(token);
   1306             break;
   1307           }
   1308         if (LocaleCompare((char *) keyword,"stretch") == 0)
   1309           {
   1310             type_info->stretch=(StretchType) ParseCommandOption(
   1311               MagickStretchOptions,MagickFalse,token);
   1312             break;
   1313           }
   1314         if (LocaleCompare((char *) keyword,"style") == 0)
   1315           {
   1316             type_info->style=(StyleType) ParseCommandOption(MagickStyleOptions,
   1317               MagickFalse,token);
   1318             break;
   1319           }
   1320         break;
   1321       }
   1322       case 'W':
   1323       case 'w':
   1324       {
   1325         if (LocaleCompare((char *) keyword,"weight") == 0)
   1326           {
   1327             ssize_t
   1328               weight;
   1329 
   1330             weight=ParseCommandOption(MagickWeightOptions,MagickFalse,token);
   1331             if (weight == -1)
   1332               weight=(ssize_t) StringToUnsignedLong(token);
   1333             type_info->weight=(size_t) weight;
   1334             break;
   1335           }
   1336         break;
   1337       }
   1338       default:
   1339         break;
   1340     }
   1341   }
   1342   token=(char *) RelinquishMagickMemory(token);
   1343   return(status != 0 ? MagickTrue : MagickFalse);
   1344 }
   1345 
   1346 /*
   1348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1349 %                                                                             %
   1350 %                                                                             %
   1351 %                                                                             %
   1352 +   T y p e C o m p o n e n t G e n e s i s                                   %
   1353 %                                                                             %
   1354 %                                                                             %
   1355 %                                                                             %
   1356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1357 %
   1358 %  TypeComponentGenesis() instantiates the type component.
   1359 %
   1360 %  The format of the TypeComponentGenesis method is:
   1361 %
   1362 %      MagickBooleanType TypeComponentGenesis(void)
   1363 %
   1364 */
   1365 MagickPrivate MagickBooleanType TypeComponentGenesis(void)
   1366 {
   1367   if (type_semaphore == (SemaphoreInfo *) NULL)
   1368     type_semaphore=AcquireSemaphoreInfo();
   1369   return(MagickTrue);
   1370 }
   1371 
   1372 /*
   1374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1375 %                                                                             %
   1376 %                                                                             %
   1377 %                                                                             %
   1378 +   T y p e C o m p o n e n t T e r m i n u s                                 %
   1379 %                                                                             %
   1380 %                                                                             %
   1381 %                                                                             %
   1382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1383 %
   1384 %  TypeComponentTerminus() destroy type component.
   1385 %
   1386 %  The format of the TypeComponentTerminus method is:
   1387 %
   1388 %      void TypeComponentTerminus(void)
   1389 %
   1390 */
   1391 MagickPrivate void TypeComponentTerminus(void)
   1392 {
   1393   if (type_semaphore == (SemaphoreInfo *) NULL)
   1394     ActivateSemaphoreInfo(&type_semaphore);
   1395   LockSemaphoreInfo(type_semaphore);
   1396   if (type_cache != (SplayTreeInfo *) NULL)
   1397     type_cache=DestroySplayTree(type_cache);
   1398   UnlockSemaphoreInfo(type_semaphore);
   1399   RelinquishSemaphoreInfo(&type_semaphore);
   1400 }
   1401