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