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