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