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