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