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