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