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