• 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-2019 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    https://imagemagick.org/script/license.php                               %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 
39 /*
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 = (const char *)
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   register 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 !defined(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 */
322 
GetTypeInfoByFamily(const char * family,const StyleType style,const StretchType stretch,const size_t weight,ExceptionInfo * exception)323 MagickExport const TypeInfo *GetTypeInfoByFamily(const char *family,
324   const StyleType style,const StretchType stretch,const size_t weight,
325   ExceptionInfo *exception)
326 {
327   typedef struct _Fontmap
328   {
329     const char
330       *name,
331       *substitute;
332   } Fontmap;
333 
334   const TypeInfo
335     *type_info;
336 
337   register const TypeInfo
338     *p;
339 
340   register ssize_t
341     i;
342 
343   ssize_t
344     range;
345 
346   static const Fontmap
347     fontmap[] =
348     {
349       { "fixed", "courier" },
350       { "modern","courier" },
351       { "monotype corsiva", "courier" },
352       { "news gothic", "helvetica" },
353       { "system", "courier" },
354       { "terminal", "courier" },
355       { "wingdings", "symbol" },
356       { NULL, NULL }
357     };
358 
359   size_t
360     font_weight,
361     max_score,
362     score;
363 
364   /*
365     Check for an exact type match.
366   */
367   (void) GetTypeInfo("*",exception);
368   if (type_cache == (SplayTreeInfo *) NULL)
369     return((TypeInfo *) NULL);
370   font_weight=(size_t) (weight == 0 ? 400 : weight);
371   LockSemaphoreInfo(type_semaphore);
372   ResetSplayTreeIterator(type_cache);
373   type_info=(const TypeInfo *) NULL;
374   p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
375   while (p != (const TypeInfo *) NULL)
376   {
377     if (p->family == (char *) NULL)
378       {
379         p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
380         continue;
381       }
382     if (family == (const char *) NULL)
383       {
384         if ((LocaleCompare(p->family,"arial") != 0) &&
385             (LocaleCompare(p->family,"helvetica") != 0))
386           {
387             p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
388             continue;
389           }
390       }
391     else
392       if (LocaleCompare(p->family,family) != 0)
393         {
394           p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
395           continue;
396         }
397     if ((style != UndefinedStyle) && (style != AnyStyle) && (p->style != style))
398       {
399         p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
400         continue;
401       }
402     if ((stretch != UndefinedStretch) && (stretch != AnyStretch) &&
403         (p->stretch != stretch))
404       {
405         p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
406         continue;
407       }
408     if (p->weight != font_weight)
409       {
410         p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
411         continue;
412       }
413     type_info=p;
414     break;
415   }
416   UnlockSemaphoreInfo(type_semaphore);
417   if (type_info != (const TypeInfo *) NULL)
418     return(type_info);
419   /*
420     Check for types in the same family.
421   */
422   max_score=0;
423   LockSemaphoreInfo(type_semaphore);
424   ResetSplayTreeIterator(type_cache);
425   p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
426   while (p != (const TypeInfo *) NULL)
427   {
428     if (p->family == (char *) NULL)
429       {
430         p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
431         continue;
432       }
433     if (family == (const char *) NULL)
434       {
435         if ((LocaleCompare(p->family,"arial") != 0) &&
436             (LocaleCompare(p->family,"helvetica") != 0))
437           {
438             p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
439             continue;
440           }
441       }
442     else
443       if (LocaleCompare(p->family,family) != 0)
444         {
445           p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
446           continue;
447         }
448     score=0;
449     if ((style == UndefinedStyle) || (style == AnyStyle) || (p->style == style))
450       score+=32;
451     else
452       if (((style == ItalicStyle) || (style == ObliqueStyle)) &&
453           ((p->style == ItalicStyle) || (p->style == ObliqueStyle)))
454         score+=25;
455     score+=(16*(800-((ssize_t) MagickMax(MagickMin(font_weight,900),p->weight)-
456       (ssize_t) MagickMin(MagickMin(font_weight,900),p->weight))))/800;
457     if ((stretch == UndefinedStretch) || (stretch == AnyStretch))
458       score+=8;
459     else
460       {
461         range=(ssize_t) UltraExpandedStretch-(ssize_t) NormalStretch;
462         score+=(8*(range-((ssize_t) MagickMax(stretch,p->stretch)-
463           (ssize_t) MagickMin(stretch,p->stretch))))/range;
464       }
465     if (score > max_score)
466       {
467         max_score=score;
468         type_info=p;
469       }
470     p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
471   }
472   UnlockSemaphoreInfo(type_semaphore);
473   if (type_info != (const TypeInfo *) NULL)
474     return(type_info);
475   /*
476     Check for table-based substitution match.
477   */
478   for (i=0; fontmap[i].name != (char *) NULL; i++)
479   {
480     if (family == (const char *) NULL)
481       {
482         if ((LocaleCompare(fontmap[i].name,"arial") != 0) &&
483             (LocaleCompare(fontmap[i].name,"helvetica") != 0))
484           continue;
485       }
486     else
487       if (LocaleCompare(fontmap[i].name,family) != 0)
488         continue;
489     type_info=GetTypeInfoByFamily(fontmap[i].substitute,style,stretch,weight,
490       exception);
491     break;
492   }
493   if (type_info != (const TypeInfo *) NULL)
494     {
495       (void) ThrowMagickException(exception,GetMagickModule(),TypeError,
496         "FontSubstitutionRequired","`%s'",type_info->family);
497       return(type_info);
498     }
499   if (family != (const char *) NULL)
500     type_info=GetTypeInfoByFamily((const char *) NULL,style,stretch,weight,
501       exception);
502   return(type_info);
503 }
504 
505 /*
506 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
507 %                                                                             %
508 %                                                                             %
509 %                                                                             %
510 %   G e t T y p e I n f o L i s t                                             %
511 %                                                                             %
512 %                                                                             %
513 %                                                                             %
514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
515 %
516 %  GetTypeInfoList() returns any fonts that match the specified pattern.
517 %
518 %  The format of the GetTypeInfoList function is:
519 %
520 %      const TypeInfo **GetTypeInfoList(const char *pattern,
521 %        size_t *number_fonts,ExceptionInfo *exception)
522 %
523 %  A description of each parameter follows:
524 %
525 %    o pattern: Specifies a pointer to a text string containing a pattern.
526 %
527 %    o number_fonts:  This integer returns the number of types in the list.
528 %
529 %    o exception: return any errors or warnings in this structure.
530 %
531 */
532 
533 #if defined(__cplusplus) || defined(c_plusplus)
534 extern "C" {
535 #endif
536 
TypeInfoCompare(const void * x,const void * y)537 static int TypeInfoCompare(const void *x,const void *y)
538 {
539   const TypeInfo
540     **p,
541     **q;
542 
543   p=(const TypeInfo **) x,
544   q=(const TypeInfo **) y;
545   if (LocaleCompare((*p)->path,(*q)->path) == 0)
546     return(LocaleCompare((*p)->name,(*q)->name));
547   return(LocaleCompare((*p)->path,(*q)->path));
548 }
549 
550 #if defined(__cplusplus) || defined(c_plusplus)
551 }
552 #endif
553 
GetTypeInfoList(const char * pattern,size_t * number_fonts,ExceptionInfo * exception)554 MagickExport const TypeInfo **GetTypeInfoList(const char *pattern,
555   size_t *number_fonts,ExceptionInfo *exception)
556 {
557   const TypeInfo
558     **fonts;
559 
560   register const TypeInfo
561     *p;
562 
563   register ssize_t
564     i;
565 
566   /*
567     Allocate type list.
568   */
569   assert(pattern != (char *) NULL);
570   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
571   assert(number_fonts != (size_t *) NULL);
572   *number_fonts=0;
573   p=GetTypeInfo("*",exception);
574   if (p == (const TypeInfo *) NULL)
575     return((const TypeInfo **) NULL);
576   fonts=(const TypeInfo **) AcquireQuantumMemory((size_t)
577     GetNumberOfNodesInSplayTree(type_cache)+1UL,sizeof(*fonts));
578   if (fonts == (const TypeInfo **) NULL)
579     return((const TypeInfo **) NULL);
580   /*
581     Generate type list.
582   */
583   LockSemaphoreInfo(type_semaphore);
584   ResetSplayTreeIterator(type_cache);
585   p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
586   for (i=0; p != (const TypeInfo *) NULL; )
587   {
588     if ((p->stealth == MagickFalse) &&
589         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
590       fonts[i++]=p;
591     p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
592   }
593   UnlockSemaphoreInfo(type_semaphore);
594   qsort((void *) fonts,(size_t) i,sizeof(*fonts),TypeInfoCompare);
595   fonts[i]=(TypeInfo *) NULL;
596   *number_fonts=(size_t) i;
597   return(fonts);
598 }
599 
600 /*
601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
602 %                                                                             %
603 %                                                                             %
604 %                                                                             %
605 %   G e t T y p e L i s t                                                     %
606 %                                                                             %
607 %                                                                             %
608 %                                                                             %
609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
610 %
611 %  GetTypeList() returns any fonts that match the specified pattern.
612 %
613 %  The format of the GetTypeList function is:
614 %
615 %      char **GetTypeList(const char *pattern,size_t *number_fonts,
616 %        ExceptionInfo *exception)
617 %
618 %  A description of each parameter follows:
619 %
620 %    o pattern: Specifies a pointer to a text string containing a pattern.
621 %
622 %    o number_fonts:  This integer returns the number of fonts in the list.
623 %
624 %    o exception: return any errors or warnings in this structure.
625 %
626 */
627 
628 #if defined(__cplusplus) || defined(c_plusplus)
629 extern "C" {
630 #endif
631 
TypeCompare(const void * x,const void * y)632 static int TypeCompare(const void *x,const void *y)
633 {
634   register const char
635     **p,
636     **q;
637 
638   p=(const char **) x;
639   q=(const char **) y;
640   return(LocaleCompare(*p,*q));
641 }
642 
643 #if defined(__cplusplus) || defined(c_plusplus)
644 }
645 #endif
646 
GetTypeList(const char * pattern,size_t * number_fonts,ExceptionInfo * exception)647 MagickExport char **GetTypeList(const char *pattern,size_t *number_fonts,
648   ExceptionInfo *exception)
649 {
650   char
651     **fonts;
652 
653   register const TypeInfo
654     *p;
655 
656   register ssize_t
657     i;
658 
659   /*
660     Allocate type list.
661   */
662   assert(pattern != (char *) NULL);
663   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
664   assert(number_fonts != (size_t *) NULL);
665   *number_fonts=0;
666   p=GetTypeInfo("*",exception);
667   if (p == (const TypeInfo *) NULL)
668     return((char **) NULL);
669   fonts=(char **) AcquireQuantumMemory((size_t)
670     GetNumberOfNodesInSplayTree(type_cache)+1UL,sizeof(*fonts));
671   if (fonts == (char **) NULL)
672     return((char **) NULL);
673   /*
674     Generate type list.
675   */
676   LockSemaphoreInfo(type_semaphore);
677   ResetSplayTreeIterator(type_cache);
678   p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
679   for (i=0; p != (const TypeInfo *) NULL; )
680   {
681     if ((p->stealth == MagickFalse) &&
682         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
683       fonts[i++]=ConstantString(p->name);
684     p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
685   }
686   UnlockSemaphoreInfo(type_semaphore);
687   qsort((void *) fonts,(size_t) i,sizeof(*fonts),TypeCompare);
688   fonts[i]=(char *) NULL;
689   *number_fonts=(size_t) i;
690   return(fonts);
691 }
692 
693 /*
694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
695 %                                                                             %
696 %                                                                             %
697 %                                                                             %
698 +   I s T y p e T r e e I n s t a n t i a t e d                               %
699 %                                                                             %
700 %                                                                             %
701 %                                                                             %
702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
703 %
704 %  IsTypeTreeInstantiated() determines if the type tree is instantiated.  If
705 %  not, it instantiates the tree and returns it.
706 %
707 %  The format of the IsTypeInstantiated method is:
708 %
709 %      MagickBooleanType IsTypeTreeInstantiated(ExceptionInfo *exception)
710 %
711 %  A description of each parameter follows.
712 %
713 %    o exception: return any errors or warnings in this structure.
714 %
715 */
716 
717 #if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
LoadFontConfigFonts(SplayTreeInfo * type_cache,ExceptionInfo * exception)718 MagickExport MagickBooleanType LoadFontConfigFonts(SplayTreeInfo *type_cache,
719   ExceptionInfo *exception)
720 {
721 #if !defined(FC_FULLNAME)
722 #define FC_FULLNAME "fullname"
723 #endif
724 
725   char
726     extension[MagickPathExtent],
727     name[MagickPathExtent];
728 
729   FcBool
730     result;
731 
732   FcChar8
733     *family,
734     *file,
735     *fullname,
736     *style;
737 
738   FcConfig
739     *font_config;
740 
741   FcFontSet
742     *font_set;
743 
744   FcObjectSet
745     *object_set;
746 
747   FcPattern
748     *pattern;
749 
750   FcResult
751     status;
752 
753   int
754     slant,
755     width,
756     weight;
757 
758   register ssize_t
759     i;
760 
761   TypeInfo
762     *type_info;
763 
764   /*
765     Load system fonts.
766   */
767   (void) exception;
768   result=FcInit();
769   if (result == 0)
770     return(MagickFalse);
771   font_config=FcConfigGetCurrent();
772   if (font_config == (FcConfig *) NULL)
773     return(MagickFalse);
774   FcConfigSetRescanInterval(font_config,0);
775   font_set=(FcFontSet *) NULL;
776   object_set=FcObjectSetBuild(FC_FULLNAME,FC_FAMILY,FC_STYLE,FC_SLANT,
777     FC_WIDTH,FC_WEIGHT,FC_FILE,(char *) NULL);
778   if (object_set != (FcObjectSet *) NULL)
779     {
780       pattern=FcPatternCreate();
781       if (pattern != (FcPattern *) NULL)
782         {
783           font_set=FcFontList(font_config,pattern,object_set);
784           FcPatternDestroy(pattern);
785         }
786       FcObjectSetDestroy(object_set);
787     }
788   if (font_set == (FcFontSet *) NULL)
789     {
790       FcConfigDestroy(font_config);
791       return(MagickFalse);
792     }
793   for (i=0; i < (ssize_t) font_set->nfont; i++)
794   {
795     status=FcPatternGetString(font_set->fonts[i],FC_FAMILY,0,&family);
796     if (status != FcResultMatch)
797       continue;
798     status=FcPatternGetString(font_set->fonts[i],FC_FILE,0,&file);
799     if (status != FcResultMatch)
800       continue;
801     *extension='\0';
802     GetPathComponent((const char *) file,ExtensionPath,extension);
803     if ((*extension != '\0') && (LocaleCompare(extension,"gz") == 0))
804       continue;
805     type_info=(TypeInfo *) AcquireMagickMemory(sizeof(*type_info));
806     if (type_info == (TypeInfo *) NULL)
807       continue;
808     (void) memset(type_info,0,sizeof(*type_info));
809     type_info->path=ConstantString("System Fonts");
810     type_info->signature=MagickCoreSignature;
811     (void) CopyMagickString(name,"Unknown",MagickPathExtent);
812     status=FcPatternGetString(font_set->fonts[i],FC_FULLNAME,0,&fullname);
813     if ((status == FcResultMatch) && (fullname != (FcChar8 *) NULL))
814       (void) CopyMagickString(name,(const char *) fullname,MagickPathExtent);
815     else
816       {
817         if (family != (FcChar8 *) NULL)
818           (void) CopyMagickString(name,(const char *) family,MagickPathExtent);
819         status=FcPatternGetString(font_set->fonts[i],FC_STYLE,0,&style);
820         if ((status == FcResultMatch) && (style != (FcChar8 *) NULL) &&
821             (LocaleCompare((const char *) style,"Regular") != 0))
822           {
823             (void) ConcatenateMagickString(name," ",MagickPathExtent);
824             (void) ConcatenateMagickString(name,(const char *) style,
825               MagickPathExtent);
826           }
827       }
828     type_info->name=ConstantString(name);
829     (void) SubstituteString(&type_info->name," ","-");
830     type_info->family=ConstantString((const char *) family);
831     status=FcPatternGetInteger(font_set->fonts[i],FC_SLANT,0,&slant);
832     type_info->style=NormalStyle;
833     if (slant == FC_SLANT_ITALIC)
834       type_info->style=ItalicStyle;
835     if (slant == FC_SLANT_OBLIQUE)
836       type_info->style=ObliqueStyle;
837     status=FcPatternGetInteger(font_set->fonts[i],FC_WIDTH,0,&width);
838     type_info->stretch=NormalStretch;
839     if (width >= FC_WIDTH_ULTRACONDENSED)
840       type_info->stretch=UltraCondensedStretch;
841     if (width >= FC_WIDTH_EXTRACONDENSED)
842       type_info->stretch=ExtraCondensedStretch;
843     if (width >= FC_WIDTH_CONDENSED)
844       type_info->stretch=CondensedStretch;
845     if (width >= FC_WIDTH_SEMICONDENSED)
846       type_info->stretch=SemiCondensedStretch;
847     if (width >= FC_WIDTH_NORMAL)
848       type_info->stretch=NormalStretch;
849     if (width >= FC_WIDTH_SEMIEXPANDED)
850       type_info->stretch=SemiExpandedStretch;
851     if (width >= FC_WIDTH_EXPANDED)
852       type_info->stretch=ExpandedStretch;
853     if (width >= FC_WIDTH_EXTRAEXPANDED)
854       type_info->stretch=ExtraExpandedStretch;
855     if (width >= FC_WIDTH_ULTRAEXPANDED)
856       type_info->stretch=UltraExpandedStretch;
857     type_info->weight=400;
858     status=FcPatternGetInteger(font_set->fonts[i],FC_WEIGHT,0,&weight);
859     if (weight >= FC_WEIGHT_THIN)
860       type_info->weight=100;
861     if (weight >= FC_WEIGHT_EXTRALIGHT)
862       type_info->weight=200;
863     if (weight >= FC_WEIGHT_LIGHT)
864       type_info->weight=300;
865     if (weight >= FC_WEIGHT_NORMAL)
866       type_info->weight=400;
867     if (weight >= FC_WEIGHT_MEDIUM)
868       type_info->weight=500;
869     if (weight >= FC_WEIGHT_DEMIBOLD)
870       type_info->weight=600;
871     if (weight >= FC_WEIGHT_BOLD)
872       type_info->weight=700;
873     if (weight >= FC_WEIGHT_EXTRABOLD)
874       type_info->weight=800;
875     if (weight >= FC_WEIGHT_BLACK)
876       type_info->weight=900;
877     type_info->glyphs=ConstantString((const char *) file);
878     (void) AddValueToSplayTree(type_cache,type_info->name,type_info);
879   }
880   FcFontSetDestroy(font_set);
881   FcConfigDestroy(font_config);
882   return(MagickTrue);
883 }
884 #endif
885 
IsTypeTreeInstantiated(ExceptionInfo * exception)886 static MagickBooleanType IsTypeTreeInstantiated(ExceptionInfo *exception)
887 {
888   if (type_cache == (SplayTreeInfo *) NULL)
889     {
890       if (type_semaphore == (SemaphoreInfo *) NULL)
891         ActivateSemaphoreInfo(&type_semaphore);
892       LockSemaphoreInfo(type_semaphore);
893       if (type_cache == (SplayTreeInfo *) NULL)
894         {
895           SplayTreeInfo
896             *splay_tree;
897 
898           splay_tree=AcquireTypeCache(MagickTypeFilename,exception);
899 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
900           (void) NTAcquireTypeCache(splay_tree,exception);
901 #endif
902 #if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
903           (void) LoadFontConfigFonts(splay_tree,exception);
904 #endif
905           type_cache=splay_tree;
906         }
907       UnlockSemaphoreInfo(type_semaphore);
908     }
909   return(type_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
910 }
911 
912 /*
913 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
914 %                                                                             %
915 %                                                                             %
916 %                                                                             %
917 %  L i s t T y p e I n f o                                                    %
918 %                                                                             %
919 %                                                                             %
920 %                                                                             %
921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
922 %
923 %  ListTypeInfo() lists the fonts to a file.
924 %
925 %  The format of the ListTypeInfo method is:
926 %
927 %      MagickBooleanType ListTypeInfo(FILE *file,ExceptionInfo *exception)
928 %
929 %  A description of each parameter follows.
930 %
931 %    o file:  An pointer to a FILE.
932 %
933 %    o exception: return any errors or warnings in this structure.
934 %
935 */
ListTypeInfo(FILE * file,ExceptionInfo * exception)936 MagickExport MagickBooleanType ListTypeInfo(FILE *file,ExceptionInfo *exception)
937 {
938   char
939     weight[MagickPathExtent];
940 
941   const char
942     *family,
943     *glyphs,
944     *name,
945     *path,
946     *stretch,
947     *style;
948 
949   const TypeInfo
950     **type_info;
951 
952   register ssize_t
953     i;
954 
955   size_t
956     number_fonts;
957 
958   if (file == (FILE *) NULL)
959     file=stdout;
960   number_fonts=0;
961   type_info=GetTypeInfoList("*",&number_fonts,exception);
962   if (type_info == (const TypeInfo **) NULL)
963     return(MagickFalse);
964   *weight='\0';
965   path=(const char *) NULL;
966   for (i=0; i < (ssize_t) number_fonts; i++)
967   {
968     if (type_info[i]->stealth != MagickFalse)
969       continue;
970     if (((path == (const char *) NULL) ||
971          (LocaleCompare(path,type_info[i]->path) != 0)) &&
972          (type_info[i]->path != (char *) NULL))
973       (void) FormatLocaleFile(file,"\nPath: %s\n",type_info[i]->path);
974     path=type_info[i]->path;
975     name="unknown";
976     if (type_info[i]->name != (char *) NULL)
977       name=type_info[i]->name;
978     family="unknown";
979     if (type_info[i]->family != (char *) NULL)
980       family=type_info[i]->family;
981     style=CommandOptionToMnemonic(MagickStyleOptions,type_info[i]->style);
982     stretch=CommandOptionToMnemonic(MagickStretchOptions,type_info[i]->stretch);
983     glyphs="unknown";
984     if (type_info[i]->glyphs != (char *) NULL)
985       glyphs=type_info[i]->glyphs;
986     (void) FormatLocaleString(weight,MagickPathExtent,"%.20g",(double)
987       type_info[i]->weight);
988     (void) FormatLocaleFile(file,"  Font: %s\n",name);
989     (void) FormatLocaleFile(file,"    family: %s\n",family);
990     (void) FormatLocaleFile(file,"    style: %s\n",style);
991     (void) FormatLocaleFile(file,"    stretch: %s\n",stretch);
992     (void) FormatLocaleFile(file,"    weight: %s\n",weight);
993     (void) FormatLocaleFile(file,"    glyphs: %s\n",glyphs);
994   }
995   (void) fflush(file);
996   type_info=(const TypeInfo **) RelinquishMagickMemory((void *) type_info);
997   return(MagickTrue);
998 }
999 
1000 /*
1001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1002 %                                                                             %
1003 %                                                                             %
1004 %                                                                             %
1005 +   L o a d T y p e C a c h e                                                 %
1006 %                                                                             %
1007 %                                                                             %
1008 %                                                                             %
1009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1010 %
1011 %  LoadTypeCache() loads the type configurations which provides a mapping
1012 %  between type attributes and a type name.
1013 %
1014 %  The format of the LoadTypeCache method is:
1015 %
1016 %      MagickBooleanType LoadTypeCache(SplayTreeInfo *cache,const char *xml,
1017 %        const char *filename,const size_t depth,ExceptionInfo *exception)
1018 %
1019 %  A description of each parameter follows:
1020 %
1021 %    o xml:  The type list in XML format.
1022 %
1023 %    o filename:  The type list filename.
1024 %
1025 %    o depth: depth of <include /> statements.
1026 %
1027 %    o exception: return any errors or warnings in this structure.
1028 %
1029 */
1030 
SetTypeNodePath(const char * filename,char * font_path,const char * token,char ** target)1031 static inline MagickBooleanType SetTypeNodePath(const char *filename,
1032   char *font_path,const char *token,char **target)
1033 {
1034   char
1035    *path;
1036 
1037   path=ConstantString(token);
1038 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1039   if (strchr(path,'@') != (char *) NULL)
1040     SubstituteString(&path,"@ghostscript_font_path@",font_path);
1041 #endif
1042   if (IsPathAccessible(path) == MagickFalse)
1043     {
1044       /*
1045         Relative path.
1046       */
1047       path=DestroyString(path);
1048       GetPathComponent(filename,HeadPath,font_path);
1049       (void) ConcatenateMagickString(font_path,DirectorySeparator,
1050         MagickPathExtent);
1051       (void) ConcatenateMagickString(font_path,token,MagickPathExtent);
1052       path=ConstantString(font_path);
1053 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1054       if (strchr(path,'@') != (char *) NULL)
1055         SubstituteString(&path,"@ghostscript_font_path@","");
1056 #endif
1057       if (IsPathAccessible(path) == MagickFalse)
1058         {
1059           path=DestroyString(path);
1060           return(MagickFalse);
1061         }
1062     }
1063 
1064   *target=path;
1065   return(MagickTrue);
1066 }
1067 
LoadTypeCache(SplayTreeInfo * cache,const char * xml,const char * filename,const size_t depth,ExceptionInfo * exception)1068 static MagickBooleanType LoadTypeCache(SplayTreeInfo *cache,const char *xml,
1069   const char *filename,const size_t depth,ExceptionInfo *exception)
1070 {
1071   char
1072     font_path[MagickPathExtent],
1073     keyword[MagickPathExtent],
1074     *token;
1075 
1076   const char
1077     *q;
1078 
1079   MagickStatusType
1080     status;
1081 
1082   size_t
1083     extent;
1084 
1085   TypeInfo
1086     *type_info;
1087 
1088   /*
1089     Load the type map file.
1090   */
1091   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1092     "Loading type configure file \"%s\" ...",filename);
1093   if (xml == (const char *) NULL)
1094     return(MagickFalse);
1095   status=MagickTrue;
1096   type_info=(TypeInfo *) NULL;
1097   token=AcquireString(xml);
1098   extent=strlen(token)+MagickPathExtent;
1099 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1100   /*
1101     Determine the Ghostscript font path.
1102   */
1103   *font_path='\0';
1104   if (NTGhostscriptFonts(font_path,MagickPathExtent-2))
1105     (void) ConcatenateMagickString(font_path,DirectorySeparator,MagickPathExtent);
1106 #endif
1107   for (q=(char *) xml; *q != '\0'; )
1108   {
1109     /*
1110       Interpret XML.
1111     */
1112     GetNextToken(q,&q,extent,token);
1113     if (*token == '\0')
1114       break;
1115     (void) CopyMagickString(keyword,token,MagickPathExtent);
1116     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1117       {
1118         /*
1119           Doctype element.
1120         */
1121         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1122           GetNextToken(q,&q,extent,token);
1123         continue;
1124       }
1125     if (LocaleNCompare(keyword,"<!--",4) == 0)
1126       {
1127         /*
1128           Comment element.
1129         */
1130         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1131           GetNextToken(q,&q,extent,token);
1132         continue;
1133       }
1134     if (LocaleCompare(keyword,"<include") == 0)
1135       {
1136         /*
1137           Include element.
1138         */
1139         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1140         {
1141           (void) CopyMagickString(keyword,token,MagickPathExtent);
1142           GetNextToken(q,&q,extent,token);
1143           if (*token != '=')
1144             continue;
1145           GetNextToken(q,&q,extent,token);
1146           if (LocaleCompare(keyword,"file") == 0)
1147             {
1148               if (depth > MagickMaxRecursionDepth)
1149                 (void) ThrowMagickException(exception,GetMagickModule(),
1150                   ConfigureError,"IncludeNodeNestedTooDeeply","`%s'",token);
1151               else
1152                 {
1153                   char
1154                     path[MagickPathExtent],
1155                     *file_xml;
1156 
1157                   ExceptionInfo
1158                     *sans_exception;
1159 
1160                   *path='\0';
1161                   GetPathComponent(filename,HeadPath,path);
1162                   if (*path != '\0')
1163                     (void) ConcatenateMagickString(path,DirectorySeparator,
1164                       MagickPathExtent);
1165                   if (*token == *DirectorySeparator)
1166                     (void) CopyMagickString(path,token,MagickPathExtent);
1167                   else
1168                     (void) ConcatenateMagickString(path,token,MagickPathExtent);
1169                   sans_exception=AcquireExceptionInfo();
1170                   file_xml=FileToString(path,~0UL,sans_exception);
1171                   sans_exception=DestroyExceptionInfo(sans_exception);
1172                   if (file_xml != (char *) NULL)
1173                     {
1174                       status&=LoadTypeCache(cache,file_xml,path,depth+1,
1175                         exception);
1176                       file_xml=(char *) RelinquishMagickMemory(file_xml);
1177                     }
1178                 }
1179             }
1180         }
1181         continue;
1182       }
1183     if (LocaleCompare(keyword,"<type") == 0)
1184       {
1185         /*
1186           Type element.
1187         */
1188         type_info=(TypeInfo *) AcquireCriticalMemory(sizeof(*type_info));
1189         (void) memset(type_info,0,sizeof(*type_info));
1190         type_info->path=ConstantString(filename);
1191         type_info->signature=MagickCoreSignature;
1192         continue;
1193       }
1194     if (type_info == (TypeInfo *) NULL)
1195       continue;
1196     if ((LocaleCompare(keyword,"/>") == 0) ||
1197         (LocaleCompare(keyword,"</policy>") == 0))
1198       {
1199         status=AddValueToSplayTree(cache,type_info->name,type_info);
1200         if (status == MagickFalse)
1201           (void) ThrowMagickException(exception,GetMagickModule(),
1202             ResourceLimitError,"MemoryAllocationFailed","`%s'",type_info->name);
1203         type_info=(TypeInfo *) NULL;
1204         continue;
1205       }
1206     GetNextToken(q,(const char **) NULL,extent,token);
1207     if (*token != '=')
1208       continue;
1209     GetNextToken(q,&q,extent,token);
1210     GetNextToken(q,&q,extent,token);
1211     switch (*keyword)
1212     {
1213       case 'E':
1214       case 'e':
1215       {
1216         if (LocaleCompare((char *) keyword,"encoding") == 0)
1217           {
1218             type_info->encoding=ConstantString(token);
1219             break;
1220           }
1221         break;
1222       }
1223       case 'F':
1224       case 'f':
1225       {
1226         if (LocaleCompare((char *) keyword,"face") == 0)
1227           {
1228             type_info->face=StringToUnsignedLong(token);
1229             break;
1230           }
1231         if (LocaleCompare((char *) keyword,"family") == 0)
1232           {
1233             type_info->family=ConstantString(token);
1234             break;
1235           }
1236         if (LocaleCompare((char *) keyword,"format") == 0)
1237           {
1238             type_info->format=ConstantString(token);
1239             break;
1240           }
1241         if (LocaleCompare((char *) keyword,"foundry") == 0)
1242           {
1243             type_info->foundry=ConstantString(token);
1244             break;
1245           }
1246         if (LocaleCompare((char *) keyword,"fullname") == 0)
1247           {
1248             type_info->description=ConstantString(token);
1249             break;
1250           }
1251         break;
1252       }
1253       case 'G':
1254       case 'g':
1255       {
1256         if (LocaleCompare((char *) keyword,"glyphs") == 0)
1257           {
1258             if (SetTypeNodePath(filename,font_path,token,&type_info->glyphs) ==
1259                 MagickFalse)
1260               type_info=(TypeInfo *) DestroyTypeNode(type_info);
1261             break;
1262           }
1263         break;
1264       }
1265       case 'M':
1266       case 'm':
1267       {
1268         if (LocaleCompare((char *) keyword,"metrics") == 0)
1269           {
1270             if (SetTypeNodePath(filename,font_path,token,&type_info->metrics) ==
1271                 MagickFalse)
1272               type_info=(TypeInfo *) DestroyTypeNode(type_info);
1273             break;
1274           }
1275         break;
1276       }
1277       case 'N':
1278       case 'n':
1279       {
1280         if (LocaleCompare((char *) keyword,"name") == 0)
1281           {
1282             type_info->name=ConstantString(token);
1283             break;
1284           }
1285         break;
1286       }
1287       case 'S':
1288       case 's':
1289       {
1290         if (LocaleCompare((char *) keyword,"stealth") == 0)
1291           {
1292             type_info->stealth=IsStringTrue(token);
1293             break;
1294           }
1295         if (LocaleCompare((char *) keyword,"stretch") == 0)
1296           {
1297             type_info->stretch=(StretchType) ParseCommandOption(
1298               MagickStretchOptions,MagickFalse,token);
1299             break;
1300           }
1301         if (LocaleCompare((char *) keyword,"style") == 0)
1302           {
1303             type_info->style=(StyleType) ParseCommandOption(MagickStyleOptions,
1304               MagickFalse,token);
1305             break;
1306           }
1307         break;
1308       }
1309       case 'W':
1310       case 'w':
1311       {
1312         if (LocaleCompare((char *) keyword,"weight") == 0)
1313           {
1314             ssize_t
1315               weight;
1316 
1317             weight=ParseCommandOption(MagickWeightOptions,MagickFalse,token);
1318             if (weight == -1)
1319               weight=(ssize_t) StringToUnsignedLong(token);
1320             type_info->weight=(size_t) weight;
1321             break;
1322           }
1323         break;
1324       }
1325       default:
1326         break;
1327     }
1328   }
1329   token=(char *) RelinquishMagickMemory(token);
1330   return(status != 0 ? MagickTrue : MagickFalse);
1331 }
1332 
1333 /*
1334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1335 %                                                                             %
1336 %                                                                             %
1337 %                                                                             %
1338 +   T y p e C o m p o n e n t G e n e s i s                                   %
1339 %                                                                             %
1340 %                                                                             %
1341 %                                                                             %
1342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1343 %
1344 %  TypeComponentGenesis() instantiates the type component.
1345 %
1346 %  The format of the TypeComponentGenesis method is:
1347 %
1348 %      MagickBooleanType TypeComponentGenesis(void)
1349 %
1350 */
TypeComponentGenesis(void)1351 MagickPrivate MagickBooleanType TypeComponentGenesis(void)
1352 {
1353   if (type_semaphore == (SemaphoreInfo *) NULL)
1354     type_semaphore=AcquireSemaphoreInfo();
1355   return(MagickTrue);
1356 }
1357 
1358 /*
1359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1360 %                                                                             %
1361 %                                                                             %
1362 %                                                                             %
1363 +   T y p e C o m p o n e n t T e r m i n u s                                 %
1364 %                                                                             %
1365 %                                                                             %
1366 %                                                                             %
1367 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1368 %
1369 %  TypeComponentTerminus() destroy type component.
1370 %
1371 %  The format of the TypeComponentTerminus method is:
1372 %
1373 %      void TypeComponentTerminus(void)
1374 %
1375 */
TypeComponentTerminus(void)1376 MagickPrivate void TypeComponentTerminus(void)
1377 {
1378   if (type_semaphore == (SemaphoreInfo *) NULL)
1379     ActivateSemaphoreInfo(&type_semaphore);
1380   LockSemaphoreInfo(type_semaphore);
1381   if (type_cache != (SplayTreeInfo *) NULL)
1382     type_cache=DestroySplayTree(type_cache);
1383   UnlockSemaphoreInfo(type_semaphore);
1384   RelinquishSemaphoreInfo(&type_semaphore);
1385 }
1386