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