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