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