MagickCore  6.9.13-26
Convert, Edit, Or Compose Bitmap Images
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 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  *metrics,
948  *name,
949  *path,
950  *stretch,
951  *style;
952 
953  const TypeInfo
954  **type_info;
955 
956  ssize_t
957  i;
958 
959  size_t
960  number_fonts;
961 
962  if (file == (FILE *) NULL)
963  file=stdout;
964  number_fonts=0;
965  type_info=GetTypeInfoList("*",&number_fonts,exception);
966  if (type_info == (const TypeInfo **) NULL)
967  return(MagickFalse);
968  *weight='\0';
969  path=(const char *) NULL;
970  for (i=0; i < (ssize_t) number_fonts; i++)
971  {
972  if (type_info[i]->stealth != MagickFalse)
973  continue;
974  if (((path == (const char *) NULL) ||
975  (LocaleCompare(path,type_info[i]->path) != 0)) &&
976  (type_info[i]->path != (char *) NULL))
977  (void) FormatLocaleFile(file,"\nPath: %s\n",type_info[i]->path);
978  path=type_info[i]->path;
979  name="not defined";
980  if (type_info[i]->name != (char *) NULL)
981  name=type_info[i]->name;
982  family="not defined";
983  if (type_info[i]->family != (char *) NULL)
984  family=type_info[i]->family;
985  style=CommandOptionToMnemonic(MagickStyleOptions,type_info[i]->style);
986  stretch=CommandOptionToMnemonic(MagickStretchOptions,type_info[i]->stretch);
987  metrics="not defined";
988  if (type_info[i]->metrics != (char *) NULL)
989  metrics=type_info[i]->metrics;
990  glyphs="not defined";
991  if (type_info[i]->glyphs != (char *) NULL)
992  glyphs=type_info[i]->glyphs;
993  (void) FormatLocaleString(weight,MaxTextExtent,"%.20g",(double)
994  type_info[i]->weight);
995  (void) FormatLocaleFile(file," Font: %s\n",name);
996  (void) FormatLocaleFile(file," family: %s\n",family);
997  (void) FormatLocaleFile(file," style: %s\n",style);
998  (void) FormatLocaleFile(file," stretch: %s\n",stretch);
999  (void) FormatLocaleFile(file," weight: %s\n",weight);
1000  (void) FormatLocaleFile(file," metrics: %s\n",metrics);
1001  (void) FormatLocaleFile(file," glyphs: %s\n",glyphs);
1002  }
1003  (void) fflush(file);
1004  type_info=(const TypeInfo **) RelinquishMagickMemory((void *) type_info);
1005  return(MagickTrue);
1006 }
1007 ␌
1008 /*
1009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1010 % %
1011 % %
1012 % %
1013 + L o a d T y p e C a c h e %
1014 % %
1015 % %
1016 % %
1017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1018 %
1019 % LoadTypeCache() loads the type configurations which provides a mapping
1020 % between type attributes and a type name.
1021 %
1022 % The format of the LoadTypeCache method is:
1023 %
1024 % MagickBooleanType LoadTypeCache(SplayTreeInfo *cache,const char *xml,
1025 % const char *filename,const size_t depth,ExceptionInfo *exception)
1026 %
1027 % A description of each parameter follows:
1028 %
1029 % o xml: The type list in XML format.
1030 %
1031 % o filename: The type list filename.
1032 %
1033 % o depth: depth of <include /> statements.
1034 %
1035 % o exception: return any errors or warnings in this structure.
1036 %
1037 */
1038 static inline MagickBooleanType SetTypeNodePath(const char *filename,
1039  char *font_path,const char *token,char **target)
1040 {
1041  char
1042  *path;
1043 
1044  path=ConstantString(token);
1045 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1046  if (strchr(path,'@') != (char *) NULL)
1047  SubstituteString(&path,"@ghostscript_font_path@",font_path);
1048 #endif
1049  if (IsPathAccessible(path) == MagickFalse)
1050  {
1051  /*
1052  Relative path.
1053  */
1054  path=DestroyString(path);
1055  GetPathComponent(filename,HeadPath,font_path);
1056  (void) ConcatenateMagickString(font_path,DirectorySeparator,
1057  MaxTextExtent);
1058  (void) ConcatenateMagickString(font_path,token,MaxTextExtent);
1059  path=ConstantString(font_path);
1060 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1061  if (strchr(path,'@') != (char *) NULL)
1062  SubstituteString(&path,"@ghostscript_font_path@","");
1063 #endif
1064  if (IsPathAccessible(path) == MagickFalse)
1065  {
1066  path=DestroyString(path);
1067  return(MagickFalse);
1068  }
1069  }
1070 
1071  *target=path;
1072  return(MagickTrue);
1073 }
1074 
1075 static MagickBooleanType LoadTypeCache(SplayTreeInfo *cache,const char *xml,
1076  const char *filename,const size_t depth,ExceptionInfo *exception)
1077 {
1078  char
1079  font_path[MaxTextExtent],
1080  keyword[MaxTextExtent],
1081  *token;
1082 
1083  const char
1084  *q;
1085 
1086  MagickStatusType
1087  status;
1088 
1089  size_t
1090  extent;
1091 
1092  TypeInfo
1093  *type_info;
1094 
1095  /*
1096  Load the type map file.
1097  */
1098  if (IsEventLogging() != MagickFalse)
1099  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1100  "Loading type configure file \"%s\" ...",filename);
1101  if (xml == (const char *) NULL)
1102  return(MagickFalse);
1103  status=MagickTrue;
1104  type_info=(TypeInfo *) NULL;
1105  token=AcquireString(xml);
1106  extent=strlen(token)+MaxTextExtent;
1107 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1108  /*
1109  Determine the Ghostscript font path.
1110  */
1111  *font_path='\0';
1112  if (NTGhostscriptFonts(font_path,MaxTextExtent-2))
1113  (void) ConcatenateMagickString(font_path,DirectorySeparator,MaxTextExtent);
1114 #endif
1115  for (q=(char *) xml; *q != '\0'; )
1116  {
1117  /*
1118  Interpret XML.
1119  */
1120  (void) GetNextToken(q,&q,extent,token);
1121  if (*token == '\0')
1122  break;
1123  (void) CopyMagickString(keyword,token,MaxTextExtent);
1124  if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1125  {
1126  /*
1127  Doctype element.
1128  */
1129  while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1130  (void) GetNextToken(q,&q,extent,token);
1131  continue;
1132  }
1133  if (LocaleNCompare(keyword,"<!--",4) == 0)
1134  {
1135  /*
1136  Comment element.
1137  */
1138  while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1139  (void) GetNextToken(q,&q,extent,token);
1140  continue;
1141  }
1142  if (LocaleCompare(keyword,"<include") == 0)
1143  {
1144  /*
1145  Include element.
1146  */
1147  while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1148  {
1149  (void) CopyMagickString(keyword,token,MaxTextExtent);
1150  (void) GetNextToken(q,&q,extent,token);
1151  if (*token != '=')
1152  continue;
1153  (void) GetNextToken(q,&q,extent,token);
1154  if (LocaleCompare(keyword,"file") == 0)
1155  {
1156  if (depth > MagickMaxRecursionDepth)
1157  (void) ThrowMagickException(exception,GetMagickModule(),
1158  ConfigureError,"IncludeNodeNestedTooDeeply","`%s'",token);
1159  else
1160  {
1161  char
1162  path[MaxTextExtent],
1163  *xml;
1164 
1166  *sans_exception;
1167 
1168  *path='\0';
1169  GetPathComponent(filename,HeadPath,path);
1170  if (*path != '\0')
1171  (void) ConcatenateMagickString(path,DirectorySeparator,
1172  MaxTextExtent);
1173  if (*token == *DirectorySeparator)
1174  (void) CopyMagickString(path,token,MaxTextExtent);
1175  else
1176  (void) ConcatenateMagickString(path,token,MaxTextExtent);
1177  sans_exception=AcquireExceptionInfo();
1178  xml=FileToString(path,~0UL,sans_exception);
1179  sans_exception=DestroyExceptionInfo(sans_exception);
1180  if (xml != (char *) NULL)
1181  {
1182  status&=LoadTypeCache(cache,xml,path,depth+1,
1183  exception);
1184  xml=(char *) RelinquishMagickMemory(xml);
1185  }
1186  }
1187  }
1188  }
1189  continue;
1190  }
1191  if (LocaleCompare(keyword,"<type") == 0)
1192  {
1193  /*
1194  Type element.
1195  */
1196  type_info=(TypeInfo *) AcquireMagickMemory(sizeof(*type_info));
1197  if (type_info == (TypeInfo *) NULL)
1198  ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1199  (void) memset(type_info,0,sizeof(*type_info));
1200  type_info->path=ConstantString(filename);
1201  type_info->signature=MagickCoreSignature;
1202  continue;
1203  }
1204  if (type_info == (TypeInfo *) NULL)
1205  continue;
1206  if ((LocaleCompare(keyword,"/>") == 0) ||
1207  (LocaleCompare(keyword,"</policy>") == 0))
1208  {
1209  status=AddValueToSplayTree(cache,type_info->name,type_info);
1210  if (status == MagickFalse)
1211  (void) ThrowMagickException(exception,GetMagickModule(),
1212  ResourceLimitError,"MemoryAllocationFailed","`%s'",type_info->name);
1213  type_info=(TypeInfo *) NULL;
1214  continue;
1215  }
1216  (void) GetNextToken(q,(const char **) NULL,extent,token);
1217  if (*token != '=')
1218  continue;
1219  (void) GetNextToken(q,&q,extent,token);
1220  (void) GetNextToken(q,&q,extent,token);
1221  switch (*keyword)
1222  {
1223  case 'E':
1224  case 'e':
1225  {
1226  if (LocaleCompare((char *) keyword,"encoding") == 0)
1227  {
1228  type_info->encoding=ConstantString(token);
1229  break;
1230  }
1231  break;
1232  }
1233  case 'F':
1234  case 'f':
1235  {
1236  if (LocaleCompare((char *) keyword,"face") == 0)
1237  {
1238  type_info->face=StringToUnsignedLong(token);
1239  break;
1240  }
1241  if (LocaleCompare((char *) keyword,"family") == 0)
1242  {
1243  type_info->family=ConstantString(token);
1244  break;
1245  }
1246  if (LocaleCompare((char *) keyword,"format") == 0)
1247  {
1248  type_info->format=ConstantString(token);
1249  break;
1250  }
1251  if (LocaleCompare((char *) keyword,"foundry") == 0)
1252  {
1253  type_info->foundry=ConstantString(token);
1254  break;
1255  }
1256  if (LocaleCompare((char *) keyword,"fullname") == 0)
1257  {
1258  type_info->description=ConstantString(token);
1259  break;
1260  }
1261  break;
1262  }
1263  case 'G':
1264  case 'g':
1265  {
1266  if (LocaleCompare((char *) keyword,"glyphs") == 0)
1267  {
1268  if (SetTypeNodePath(filename,font_path,token,&type_info->glyphs) == MagickFalse)
1269  type_info=(TypeInfo *) DestroyTypeNode(type_info);
1270  break;
1271  }
1272  break;
1273  }
1274  case 'M':
1275  case 'm':
1276  {
1277  if (LocaleCompare((char *) keyword,"metrics") == 0)
1278  {
1279  if (SetTypeNodePath(filename,font_path,token,&type_info->metrics) == MagickFalse)
1280  type_info=(TypeInfo *) DestroyTypeNode(type_info);
1281  break;
1282  }
1283  break;
1284  }
1285  case 'N':
1286  case 'n':
1287  {
1288  if (LocaleCompare((char *) keyword,"name") == 0)
1289  {
1290  type_info->name=ConstantString(token);
1291  break;
1292  }
1293  break;
1294  }
1295  case 'S':
1296  case 's':
1297  {
1298  if (LocaleCompare((char *) keyword,"stealth") == 0)
1299  {
1300  type_info->stealth=IsMagickTrue(token);
1301  break;
1302  }
1303  if (LocaleCompare((char *) keyword,"stretch") == 0)
1304  {
1305  type_info->stretch=(StretchType) ParseCommandOption(
1306  MagickStretchOptions,MagickFalse,token);
1307  break;
1308  }
1309  if (LocaleCompare((char *) keyword,"style") == 0)
1310  {
1311  type_info->style=(StyleType) ParseCommandOption(MagickStyleOptions,
1312  MagickFalse,token);
1313  break;
1314  }
1315  break;
1316  }
1317  case 'W':
1318  case 'w':
1319  {
1320  if (LocaleCompare((char *) keyword,"weight") == 0)
1321  {
1322  ssize_t
1323  weight;
1324 
1325  weight=ParseCommandOption(MagickWeightOptions,MagickFalse,token);
1326  if (weight == -1)
1327  weight=StringToUnsignedLong(token);
1328  type_info->weight=(size_t) weight;
1329  break;
1330  }
1331  break;
1332  }
1333  default:
1334  break;
1335  }
1336  }
1337  token=(char *) RelinquishMagickMemory(token);
1338  return(status != 0 ? MagickTrue : MagickFalse);
1339 }
1340 ␌
1341 /*
1342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1343 % %
1344 % %
1345 % %
1346 + T y p e C o m p o n e n t G e n e s i s %
1347 % %
1348 % %
1349 % %
1350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1351 %
1352 % TypeComponentGenesis() instantiates the type component.
1353 %
1354 % The format of the TypeComponentGenesis method is:
1355 %
1356 % MagickBooleanType TypeComponentGenesis(void)
1357 %
1358 */
1359 MagickExport MagickBooleanType TypeComponentGenesis(void)
1360 {
1361  if (type_semaphore == (SemaphoreInfo *) NULL)
1362  type_semaphore=AllocateSemaphoreInfo();
1363  return(MagickTrue);
1364 }
1365 ␌
1366 /*
1367 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1368 % %
1369 % %
1370 % %
1371 + T y p e C o m p o n e n t T e r m i n u s %
1372 % %
1373 % %
1374 % %
1375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1376 %
1377 % TypeComponentTerminus() destroy type component.
1378 %
1379 % The format of the TypeComponentTerminus method is:
1380 %
1381 % void TypeComponentTerminus(void)
1382 %
1383 */
1384 MagickExport void TypeComponentTerminus(void)
1385 {
1386  if (type_semaphore == (SemaphoreInfo *) NULL)
1387  ActivateSemaphoreInfo(&type_semaphore);
1388  LockSemaphoreInfo(type_semaphore);
1389  if (type_cache != (SplayTreeInfo *) NULL)
1390  type_cache=DestroySplayTree(type_cache);
1391  UnlockSemaphoreInfo(type_semaphore);
1392  DestroySemaphoreInfo(&type_semaphore);
1393 }
Definition: type.h:51