1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % TTTTT Y Y PPPP EEEEE %
7 % T Y Y P P E %
8 % T Y PPPP EEE %
9 % T Y P E %
10 % T Y P EEEEE %
11 % %
12 % %
13 % MagickCore Image Type Methods %
14 % %
15 % Software Design %
16 % Cristy %
17 % May 2001 %
18 % %
19 % %
20 % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38
39 /*
40 Include declarations.
41 */
42 #include "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 */
111 static 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 */
122 static SemaphoreInfo
123 *type_semaphore = (SemaphoreInfo *) NULL;
124
125 static SplayTreeInfo
126 *type_cache = (SplayTreeInfo *) NULL;
127
128 /*
129 Forward declarations.
130 */
131 static 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
DestroyTypeNode(void * type_info)163 static void *DestroyTypeNode(void *type_info)
164 {
165 TypeInfo
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
AcquireTypeCache(const char * filename,ExceptionInfo * exception)190 static SplayTreeInfo *AcquireTypeCache(const char *filename,
191 ExceptionInfo *exception)
192 {
193 MagickStatusType
194 status;
195
196 SplayTreeInfo
197 *cache;
198
199 cache=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL,
200 DestroyTypeNode);
201 status=MagickTrue;
202 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
203 {
204 char
205 *font_path,
206 path[MagickPathExtent];
207
208 const StringInfo
209 *option;
210
211 LinkedListInfo
212 *options;
213
214 *path='\0';
215 options=GetConfigureOptions(filename,exception);
216 option=(const StringInfo *) GetNextValueInLinkedList(options);
217 while (option != (const StringInfo *) NULL)
218 {
219 (void) CopyMagickString(path,GetStringInfoPath(option),MagickPathExtent);
220 status&=LoadTypeCache(cache,(const char *)
221 GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
222 option=(const StringInfo *) GetNextValueInLinkedList(options);
223 }
224 options=DestroyConfigureOptions(options);
225 font_path=GetEnvironmentValue("MAGICK_FONT_PATH");
226 if (font_path != (char *) NULL)
227 {
228 char
229 *xml;
230
231 /*
232 Search MAGICK_FONT_PATH.
233 */
234 (void) FormatLocaleString(path,MagickPathExtent,"%s%s%s",font_path,
235 DirectorySeparator,filename);
236 xml=FileToString(path,~0UL,exception);
237 if (xml != (void *) NULL)
238 {
239 status&=LoadTypeCache(cache,xml,path,0,exception);
240 xml=DestroyString(xml);
241 }
242 font_path=DestroyString(font_path);
243 }
244 }
245 #endif
246 if (GetNumberOfNodesInSplayTree(cache) == 0)
247 status&=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 */
GetTypeInfo(const char * name,ExceptionInfo * exception)276 MagickExport 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 */
GetTypeInfoByFamily(const char * family,const StyleType style,const StretchType stretch,const size_t weight,ExceptionInfo * exception)322 MagickExport 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 *type_info;
335
336 const TypeInfo
337 *p;
338
339 ssize_t
340 i;
341
342 ssize_t
343 range;
344
345 static const Fontmap
346 fontmap[] =
347 {
348 { "fixed", "courier" },
349 { "modern","courier" },
350 { "monotype corsiva", "courier" },
351 { "news gothic", "helvetica" },
352 { "system", "courier" },
353 { "terminal", "courier" },
354 { "wingdings", "symbol" }
355 };
356
357 size_t
358 font_weight,
359 max_score,
360 score;
361
362 /*
363 Check for an exact type match.
364 */
365 (void) GetTypeInfo("*",exception);
366 if (type_cache == (SplayTreeInfo *) NULL)
367 return((TypeInfo *) NULL);
368 font_weight=(size_t) (weight == 0 ? 400 : weight);
369 LockSemaphoreInfo(type_semaphore);
370 ResetSplayTreeIterator(type_cache);
371 type_info=(const TypeInfo *) NULL;
372 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
373 while (p != (const TypeInfo *) NULL)
374 {
375 if (p->family == (char *) NULL)
376 {
377 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
378 continue;
379 }
380 if (family == (const char *) NULL)
381 {
382 if ((LocaleCompare(p->family,"arial") != 0) &&
383 (LocaleCompare(p->family,"helvetica") != 0))
384 {
385 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
386 continue;
387 }
388 }
389 else
390 if (LocaleCompare(p->family,family) != 0)
391 {
392 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
393 continue;
394 }
395 if ((style != UndefinedStyle) && (style != AnyStyle) && (p->style != style))
396 {
397 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
398 continue;
399 }
400 if ((stretch != UndefinedStretch) && (stretch != AnyStretch) &&
401 (p->stretch != stretch))
402 {
403 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
404 continue;
405 }
406 if (p->weight != font_weight)
407 {
408 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
409 continue;
410 }
411 type_info=p;
412 break;
413 }
414 UnlockSemaphoreInfo(type_semaphore);
415 if (type_info != (const TypeInfo *) NULL)
416 return(type_info);
417 /*
418 Check for types in the same family.
419 */
420 max_score=0;
421 LockSemaphoreInfo(type_semaphore);
422 ResetSplayTreeIterator(type_cache);
423 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
424 while (p != (const TypeInfo *) NULL)
425 {
426 if (p->family == (char *) NULL)
427 {
428 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
429 continue;
430 }
431 if (family == (const char *) NULL)
432 {
433 if ((LocaleCompare(p->family,"arial") != 0) &&
434 (LocaleCompare(p->family,"helvetica") != 0))
435 {
436 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
437 continue;
438 }
439 }
440 else
441 if (LocaleCompare(p->family,family) != 0)
442 {
443 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
444 continue;
445 }
446 score=0;
447 if ((style == UndefinedStyle) || (style == AnyStyle) || (p->style == style))
448 score+=32;
449 else
450 if (((style == ItalicStyle) || (style == ObliqueStyle)) &&
451 ((p->style == ItalicStyle) || (p->style == ObliqueStyle)))
452 score+=25;
453 score+=(16*(800-((ssize_t) MagickMax(MagickMin(font_weight,900),p->weight)-
454 (ssize_t) MagickMin(MagickMin(font_weight,900),p->weight))))/800;
455 if ((stretch == UndefinedStretch) || (stretch == AnyStretch))
456 score+=8;
457 else
458 {
459 range=(ssize_t) UltraExpandedStretch-(ssize_t) NormalStretch;
460 score+=(8*(range-((ssize_t) MagickMax(stretch,p->stretch)-
461 (ssize_t) MagickMin(stretch,p->stretch))))/range;
462 }
463 if (score > max_score)
464 {
465 max_score=score;
466 type_info=p;
467 }
468 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
469 }
470 UnlockSemaphoreInfo(type_semaphore);
471 if (type_info != (const TypeInfo *) NULL)
472 return(type_info);
473 /*
474 Check for table-based substitution match.
475 */
476 for (i=0; i < (ssize_t) (sizeof(fontmap)/sizeof(fontmap[0])); i++)
477 {
478 if (family == (const char *) NULL)
479 {
480 if ((LocaleCompare(fontmap[i].name,"arial") != 0) &&
481 (LocaleCompare(fontmap[i].name,"helvetica") != 0))
482 continue;
483 }
484 else
485 if (LocaleCompare(fontmap[i].name,family) != 0)
486 continue;
487 type_info=GetTypeInfoByFamily(fontmap[i].substitute,style,stretch,weight,
488 exception);
489 break;
490 }
491 if (type_info != (const TypeInfo *) NULL)
492 {
493 (void) ThrowMagickException(exception,GetMagickModule(),TypeWarning,
494 "FontSubstitutionRequired","`%s'",type_info->family);
495 return(type_info);
496 }
497 if (family != (const char *) NULL)
498 type_info=GetTypeInfoByFamily((const char *) NULL,style,stretch,weight,
499 exception);
500 return(type_info);
501 }
502
503 /*
504 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
505 % %
506 % %
507 % %
508 % G e t T y p e I n f o L i s t %
509 % %
510 % %
511 % %
512 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
513 %
514 % GetTypeInfoList() returns any fonts that match the specified pattern.
515 %
516 % The format of the GetTypeInfoList function is:
517 %
518 % const TypeInfo **GetTypeInfoList(const char *pattern,
519 % size_t *number_fonts,ExceptionInfo *exception)
520 %
521 % A description of each parameter follows:
522 %
523 % o pattern: Specifies a pointer to a text string containing a pattern.
524 %
525 % o number_fonts: This integer returns the number of types in the list.
526 %
527 % o exception: return any errors or warnings in this structure.
528 %
529 */
530
531 #if defined(__cplusplus) || defined(c_plusplus)
532 extern "C" {
533 #endif
534
TypeInfoCompare(const void * x,const void * y)535 static int TypeInfoCompare(const void *x,const void *y)
536 {
537 const TypeInfo
538 **p,
539 **q;
540
541 p=(const TypeInfo **) x,
542 q=(const TypeInfo **) y;
543 if (LocaleCompare((*p)->path,(*q)->path) == 0)
544 return(LocaleCompare((*p)->name,(*q)->name));
545 return(LocaleCompare((*p)->path,(*q)->path));
546 }
547
548 #if defined(__cplusplus) || defined(c_plusplus)
549 }
550 #endif
551
GetTypeInfoList(const char * pattern,size_t * number_fonts,ExceptionInfo * exception)552 MagickExport const TypeInfo **GetTypeInfoList(const char *pattern,
553 size_t *number_fonts,ExceptionInfo *exception)
554 {
555 const TypeInfo
556 **fonts;
557
558 const TypeInfo
559 *p;
560
561 ssize_t
562 i;
563
564 /*
565 Allocate type list.
566 */
567 assert(pattern != (char *) NULL);
568 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
569 assert(number_fonts != (size_t *) NULL);
570 *number_fonts=0;
571 p=GetTypeInfo("*",exception);
572 if (p == (const TypeInfo *) NULL)
573 return((const TypeInfo **) NULL);
574 fonts=(const TypeInfo **) AcquireQuantumMemory((size_t)
575 GetNumberOfNodesInSplayTree(type_cache)+1UL,sizeof(*fonts));
576 if (fonts == (const TypeInfo **) NULL)
577 return((const TypeInfo **) NULL);
578 /*
579 Generate type list.
580 */
581 LockSemaphoreInfo(type_semaphore);
582 ResetSplayTreeIterator(type_cache);
583 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
584 for (i=0; p != (const TypeInfo *) NULL; )
585 {
586 if ((p->stealth == MagickFalse) &&
587 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
588 fonts[i++]=p;
589 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
590 }
591 UnlockSemaphoreInfo(type_semaphore);
592 qsort((void *) fonts,(size_t) i,sizeof(*fonts),TypeInfoCompare);
593 fonts[i]=(TypeInfo *) NULL;
594 *number_fonts=(size_t) i;
595 return(fonts);
596 }
597
598 /*
599 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
600 % %
601 % %
602 % %
603 % G e t T y p e L i s t %
604 % %
605 % %
606 % %
607 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
608 %
609 % GetTypeList() returns any fonts that match the specified pattern.
610 %
611 % The format of the GetTypeList function is:
612 %
613 % char **GetTypeList(const char *pattern,size_t *number_fonts,
614 % ExceptionInfo *exception)
615 %
616 % A description of each parameter follows:
617 %
618 % o pattern: Specifies a pointer to a text string containing a pattern.
619 %
620 % o number_fonts: This integer returns the number of fonts in the list.
621 %
622 % o exception: return any errors or warnings in this structure.
623 %
624 */
625
626 #if defined(__cplusplus) || defined(c_plusplus)
627 extern "C" {
628 #endif
629
TypeCompare(const void * x,const void * y)630 static int TypeCompare(const void *x,const void *y)
631 {
632 const char
633 **p,
634 **q;
635
636 p=(const char **) x;
637 q=(const char **) y;
638 return(LocaleCompare(*p,*q));
639 }
640
641 #if defined(__cplusplus) || defined(c_plusplus)
642 }
643 #endif
644
GetTypeList(const char * pattern,size_t * number_fonts,ExceptionInfo * exception)645 MagickExport char **GetTypeList(const char *pattern,size_t *number_fonts,
646 ExceptionInfo *exception)
647 {
648 char
649 **fonts;
650
651 const TypeInfo
652 *p;
653
654 ssize_t
655 i;
656
657 /*
658 Allocate type list.
659 */
660 assert(pattern != (char *) NULL);
661 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
662 assert(number_fonts != (size_t *) NULL);
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)
LoadFontConfigFonts(SplayTreeInfo * type_cache,ExceptionInfo * exception)716 MagickExport 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 slant,
753 width,
754 weight;
755
756 ssize_t
757 i;
758
759 TypeInfo
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,(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_SLANT,0,&slant);
830 type_info->style=NormalStyle;
831 if (slant == FC_SLANT_ITALIC)
832 type_info->style=ItalicStyle;
833 if (slant == FC_SLANT_OBLIQUE)
834 type_info->style=ObliqueStyle;
835 status=FcPatternGetInteger(font_set->fonts[i],FC_WIDTH,0,&width);
836 type_info->stretch=NormalStretch;
837 if (width >= FC_WIDTH_ULTRACONDENSED)
838 type_info->stretch=UltraCondensedStretch;
839 if (width >= FC_WIDTH_EXTRACONDENSED)
840 type_info->stretch=ExtraCondensedStretch;
841 if (width >= FC_WIDTH_CONDENSED)
842 type_info->stretch=CondensedStretch;
843 if (width >= FC_WIDTH_SEMICONDENSED)
844 type_info->stretch=SemiCondensedStretch;
845 if (width >= FC_WIDTH_NORMAL)
846 type_info->stretch=NormalStretch;
847 if (width >= FC_WIDTH_SEMIEXPANDED)
848 type_info->stretch=SemiExpandedStretch;
849 if (width >= FC_WIDTH_EXPANDED)
850 type_info->stretch=ExpandedStretch;
851 if (width >= FC_WIDTH_EXTRAEXPANDED)
852 type_info->stretch=ExtraExpandedStretch;
853 if (width >= FC_WIDTH_ULTRAEXPANDED)
854 type_info->stretch=UltraExpandedStretch;
855 type_info->weight=400;
856 status=FcPatternGetInteger(font_set->fonts[i],FC_WEIGHT,0,&weight);
857 if (weight >= FC_WEIGHT_THIN)
858 type_info->weight=100;
859 if (weight >= FC_WEIGHT_EXTRALIGHT)
860 type_info->weight=200;
861 if (weight >= FC_WEIGHT_LIGHT)
862 type_info->weight=300;
863 if (weight >= FC_WEIGHT_NORMAL)
864 type_info->weight=400;
865 if (weight >= FC_WEIGHT_MEDIUM)
866 type_info->weight=500;
867 if (weight >= FC_WEIGHT_DEMIBOLD)
868 type_info->weight=600;
869 if (weight >= FC_WEIGHT_BOLD)
870 type_info->weight=700;
871 if (weight >= FC_WEIGHT_EXTRABOLD)
872 type_info->weight=800;
873 if (weight >= FC_WEIGHT_BLACK)
874 type_info->weight=900;
875 type_info->glyphs=ConstantString((const char *) file);
876 (void) AddValueToSplayTree(type_cache,type_info->name,type_info);
877 }
878 FcFontSetDestroy(font_set);
879 FcConfigDestroy(font_config);
880 return(MagickTrue);
881 }
882 #endif
883
IsTypeTreeInstantiated(ExceptionInfo * exception)884 static MagickBooleanType IsTypeTreeInstantiated(ExceptionInfo *exception)
885 {
886 if (type_cache == (SplayTreeInfo *) NULL)
887 {
888 if (type_semaphore == (SemaphoreInfo *) NULL)
889 ActivateSemaphoreInfo(&type_semaphore);
890 LockSemaphoreInfo(type_semaphore);
891 if (type_cache == (SplayTreeInfo *) NULL)
892 {
893 SplayTreeInfo
894 *splay_tree;
895
896 splay_tree=AcquireTypeCache(MagickTypeFilename,exception);
897 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
898 (void) NTAcquireTypeCache(splay_tree,exception);
899 #endif
900 #if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
901 (void) LoadFontConfigFonts(splay_tree,exception);
902 #endif
903 type_cache=splay_tree;
904 }
905 UnlockSemaphoreInfo(type_semaphore);
906 }
907 return(type_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
908 }
909
910 /*
911 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
912 % %
913 % %
914 % %
915 % L i s t T y p e I n f o %
916 % %
917 % %
918 % %
919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
920 %
921 % ListTypeInfo() lists the fonts to a file.
922 %
923 % The format of the ListTypeInfo method is:
924 %
925 % MagickBooleanType ListTypeInfo(FILE *file,ExceptionInfo *exception)
926 %
927 % A description of each parameter follows.
928 %
929 % o file: An pointer to a FILE.
930 %
931 % o exception: return any errors or warnings in this structure.
932 %
933 */
ListTypeInfo(FILE * file,ExceptionInfo * exception)934 MagickExport MagickBooleanType ListTypeInfo(FILE *file,ExceptionInfo *exception)
935 {
936 char
937 weight[MagickPathExtent];
938
939 const char
940 *family,
941 *glyphs,
942 *name,
943 *path,
944 *stretch,
945 *style;
946
947 const TypeInfo
948 **type_info;
949
950 ssize_t
951 i;
952
953 size_t
954 number_fonts;
955
956 if (file == (FILE *) NULL)
957 file=stdout;
958 number_fonts=0;
959 type_info=GetTypeInfoList("*",&number_fonts,exception);
960 if (type_info == (const TypeInfo **) NULL)
961 return(MagickFalse);
962 *weight='\0';
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="unknown";
974 if (type_info[i]->name != (char *) NULL)
975 name=type_info[i]->name;
976 family="unknown";
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 glyphs="unknown";
982 if (type_info[i]->glyphs != (char *) NULL)
983 glyphs=type_info[i]->glyphs;
984 (void) FormatLocaleString(weight,MagickPathExtent,"%.20g",(double)
985 type_info[i]->weight);
986 (void) FormatLocaleFile(file," Font: %s\n",name);
987 (void) FormatLocaleFile(file," family: %s\n",family);
988 (void) FormatLocaleFile(file," style: %s\n",style);
989 (void) FormatLocaleFile(file," stretch: %s\n",stretch);
990 (void) FormatLocaleFile(file," weight: %s\n",weight);
991 (void) FormatLocaleFile(file," glyphs: %s\n",glyphs);
992 }
993 (void) fflush(file);
994 type_info=(const TypeInfo **) RelinquishMagickMemory((void *) type_info);
995 return(MagickTrue);
996 }
997
998 /*
999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1000 % %
1001 % %
1002 % %
1003 + L o a d T y p e C a c h e %
1004 % %
1005 % %
1006 % %
1007 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1008 %
1009 % LoadTypeCache() loads the type configurations which provides a mapping
1010 % between type attributes and a type name.
1011 %
1012 % The format of the LoadTypeCache method is:
1013 %
1014 % MagickBooleanType LoadTypeCache(SplayTreeInfo *cache,const char *xml,
1015 % const char *filename,const size_t depth,ExceptionInfo *exception)
1016 %
1017 % A description of each parameter follows:
1018 %
1019 % o xml: The type list in XML format.
1020 %
1021 % o filename: The type list filename.
1022 %
1023 % o depth: depth of <include /> statements.
1024 %
1025 % o exception: return any errors or warnings in this structure.
1026 %
1027 */
1028
SetTypeNodePath(const char * filename,char * font_path,const char * token,char ** target)1029 static inline MagickBooleanType SetTypeNodePath(const char *filename,
1030 char *font_path,const char *token,char **target)
1031 {
1032 char
1033 *path;
1034
1035 path=ConstantString(token);
1036 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1037 if (strchr(path,'@') != (char *) NULL)
1038 SubstituteString(&path,"@ghostscript_font_path@",font_path);
1039 #endif
1040 if (IsPathAccessible(path) == MagickFalse)
1041 {
1042 /*
1043 Relative path.
1044 */
1045 path=DestroyString(path);
1046 GetPathComponent(filename,HeadPath,font_path);
1047 (void) ConcatenateMagickString(font_path,DirectorySeparator,
1048 MagickPathExtent);
1049 (void) ConcatenateMagickString(font_path,token,MagickPathExtent);
1050 path=ConstantString(font_path);
1051 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1052 if (strchr(path,'@') != (char *) NULL)
1053 SubstituteString(&path,"@ghostscript_font_path@","");
1054 #endif
1055 if (IsPathAccessible(path) == MagickFalse)
1056 {
1057 path=DestroyString(path);
1058 return(MagickFalse);
1059 }
1060 }
1061
1062 *target=path;
1063 return(MagickTrue);
1064 }
1065
LoadTypeCache(SplayTreeInfo * cache,const char * xml,const char * filename,const size_t depth,ExceptionInfo * exception)1066 static MagickBooleanType LoadTypeCache(SplayTreeInfo *cache,const char *xml,
1067 const char *filename,const size_t depth,ExceptionInfo *exception)
1068 {
1069 char
1070 font_path[MagickPathExtent],
1071 keyword[MagickPathExtent],
1072 *token;
1073
1074 const char
1075 *q;
1076
1077 MagickStatusType
1078 status;
1079
1080 size_t
1081 extent;
1082
1083 TypeInfo
1084 *type_info;
1085
1086 /*
1087 Load the type map file.
1088 */
1089 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1090 "Loading type configure file \"%s\" ...",filename);
1091 if (xml == (const char *) NULL)
1092 return(MagickFalse);
1093 status=MagickTrue;
1094 type_info=(TypeInfo *) NULL;
1095 token=AcquireString(xml);
1096 extent=strlen(token)+MagickPathExtent;
1097 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1098 /*
1099 Determine the Ghostscript font path.
1100 */
1101 *font_path='\0';
1102 if (NTGhostscriptFonts(font_path,MagickPathExtent-2))
1103 (void) ConcatenateMagickString(font_path,DirectorySeparator,MagickPathExtent);
1104 #endif
1105 for (q=(char *) xml; *q != '\0'; )
1106 {
1107 /*
1108 Interpret XML.
1109 */
1110 (void) GetNextToken(q,&q,extent,token);
1111 if (*token == '\0')
1112 break;
1113 (void) CopyMagickString(keyword,token,MagickPathExtent);
1114 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1115 {
1116 /*
1117 Doctype element.
1118 */
1119 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1120 (void) GetNextToken(q,&q,extent,token);
1121 continue;
1122 }
1123 if (LocaleNCompare(keyword,"<!--",4) == 0)
1124 {
1125 /*
1126 Comment element.
1127 */
1128 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1129 (void) GetNextToken(q,&q,extent,token);
1130 continue;
1131 }
1132 if (LocaleCompare(keyword,"<include") == 0)
1133 {
1134 /*
1135 Include element.
1136 */
1137 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1138 {
1139 (void) CopyMagickString(keyword,token,MagickPathExtent);
1140 (void) GetNextToken(q,&q,extent,token);
1141 if (*token != '=')
1142 continue;
1143 (void) GetNextToken(q,&q,extent,token);
1144 if (LocaleCompare(keyword,"file") == 0)
1145 {
1146 if (depth > MagickMaxRecursionDepth)
1147 (void) ThrowMagickException(exception,GetMagickModule(),
1148 ConfigureError,"IncludeNodeNestedTooDeeply","`%s'",token);
1149 else
1150 {
1151 char
1152 path[MagickPathExtent],
1153 *file_xml;
1154
1155 ExceptionInfo
1156 *sans_exception;
1157
1158 *path='\0';
1159 GetPathComponent(filename,HeadPath,path);
1160 if (*path != '\0')
1161 (void) ConcatenateMagickString(path,DirectorySeparator,
1162 MagickPathExtent);
1163 if (*token == *DirectorySeparator)
1164 (void) CopyMagickString(path,token,MagickPathExtent);
1165 else
1166 (void) ConcatenateMagickString(path,token,MagickPathExtent);
1167 sans_exception=AcquireExceptionInfo();
1168 file_xml=FileToString(path,~0UL,sans_exception);
1169 sans_exception=DestroyExceptionInfo(sans_exception);
1170 if (file_xml != (char *) NULL)
1171 {
1172 status&=LoadTypeCache(cache,file_xml,path,depth+1,
1173 exception);
1174 file_xml=(char *) RelinquishMagickMemory(file_xml);
1175 }
1176 }
1177 }
1178 }
1179 continue;
1180 }
1181 if (LocaleCompare(keyword,"<type") == 0)
1182 {
1183 /*
1184 Type element.
1185 */
1186 type_info=(TypeInfo *) AcquireCriticalMemory(sizeof(*type_info));
1187 (void) memset(type_info,0,sizeof(*type_info));
1188 type_info->path=ConstantString(filename);
1189 type_info->signature=MagickCoreSignature;
1190 continue;
1191 }
1192 if (type_info == (TypeInfo *) NULL)
1193 continue;
1194 if ((LocaleCompare(keyword,"/>") == 0) ||
1195 (LocaleCompare(keyword,"</policy>") == 0))
1196 {
1197 status=AddValueToSplayTree(cache,type_info->name,type_info);
1198 if (status == MagickFalse)
1199 (void) ThrowMagickException(exception,GetMagickModule(),
1200 ResourceLimitError,"MemoryAllocationFailed","`%s'",type_info->name);
1201 type_info=(TypeInfo *) NULL;
1202 continue;
1203 }
1204 (void) GetNextToken(q,(const char **) NULL,extent,token);
1205 if (*token != '=')
1206 continue;
1207 (void) GetNextToken(q,&q,extent,token);
1208 (void) GetNextToken(q,&q,extent,token);
1209 switch (*keyword)
1210 {
1211 case 'E':
1212 case 'e':
1213 {
1214 if (LocaleCompare((char *) keyword,"encoding") == 0)
1215 {
1216 type_info->encoding=ConstantString(token);
1217 break;
1218 }
1219 break;
1220 }
1221 case 'F':
1222 case 'f':
1223 {
1224 if (LocaleCompare((char *) keyword,"face") == 0)
1225 {
1226 type_info->face=StringToUnsignedLong(token);
1227 break;
1228 }
1229 if (LocaleCompare((char *) keyword,"family") == 0)
1230 {
1231 type_info->family=ConstantString(token);
1232 break;
1233 }
1234 if (LocaleCompare((char *) keyword,"format") == 0)
1235 {
1236 type_info->format=ConstantString(token);
1237 break;
1238 }
1239 if (LocaleCompare((char *) keyword,"foundry") == 0)
1240 {
1241 type_info->foundry=ConstantString(token);
1242 break;
1243 }
1244 if (LocaleCompare((char *) keyword,"fullname") == 0)
1245 {
1246 type_info->description=ConstantString(token);
1247 break;
1248 }
1249 break;
1250 }
1251 case 'G':
1252 case 'g':
1253 {
1254 if (LocaleCompare((char *) keyword,"glyphs") == 0)
1255 {
1256 if (SetTypeNodePath(filename,font_path,token,&type_info->glyphs) ==
1257 MagickFalse)
1258 type_info=(TypeInfo *) DestroyTypeNode(type_info);
1259 break;
1260 }
1261 break;
1262 }
1263 case 'M':
1264 case 'm':
1265 {
1266 if (LocaleCompare((char *) keyword,"metrics") == 0)
1267 {
1268 if (SetTypeNodePath(filename,font_path,token,&type_info->metrics) ==
1269 MagickFalse)
1270 type_info=(TypeInfo *) DestroyTypeNode(type_info);
1271 break;
1272 }
1273 break;
1274 }
1275 case 'N':
1276 case 'n':
1277 {
1278 if (LocaleCompare((char *) keyword,"name") == 0)
1279 {
1280 type_info->name=ConstantString(token);
1281 break;
1282 }
1283 break;
1284 }
1285 case 'S':
1286 case 's':
1287 {
1288 if (LocaleCompare((char *) keyword,"stealth") == 0)
1289 {
1290 type_info->stealth=IsStringTrue(token);
1291 break;
1292 }
1293 if (LocaleCompare((char *) keyword,"stretch") == 0)
1294 {
1295 type_info->stretch=(StretchType) ParseCommandOption(
1296 MagickStretchOptions,MagickFalse,token);
1297 break;
1298 }
1299 if (LocaleCompare((char *) keyword,"style") == 0)
1300 {
1301 type_info->style=(StyleType) ParseCommandOption(MagickStyleOptions,
1302 MagickFalse,token);
1303 break;
1304 }
1305 break;
1306 }
1307 case 'W':
1308 case 'w':
1309 {
1310 if (LocaleCompare((char *) keyword,"weight") == 0)
1311 {
1312 ssize_t
1313 weight;
1314
1315 weight=ParseCommandOption(MagickWeightOptions,MagickFalse,token);
1316 if (weight == -1)
1317 weight=(ssize_t) StringToUnsignedLong(token);
1318 type_info->weight=(size_t) weight;
1319 break;
1320 }
1321 break;
1322 }
1323 default:
1324 break;
1325 }
1326 }
1327 token=(char *) RelinquishMagickMemory(token);
1328 return(status != 0 ? MagickTrue : MagickFalse);
1329 }
1330
1331 /*
1332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1333 % %
1334 % %
1335 % %
1336 + T y p e C o m p o n e n t G e n e s i s %
1337 % %
1338 % %
1339 % %
1340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1341 %
1342 % TypeComponentGenesis() instantiates the type component.
1343 %
1344 % The format of the TypeComponentGenesis method is:
1345 %
1346 % MagickBooleanType TypeComponentGenesis(void)
1347 %
1348 */
TypeComponentGenesis(void)1349 MagickPrivate MagickBooleanType TypeComponentGenesis(void)
1350 {
1351 if (type_semaphore == (SemaphoreInfo *) NULL)
1352 type_semaphore=AcquireSemaphoreInfo();
1353 return(MagickTrue);
1354 }
1355
1356 /*
1357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1358 % %
1359 % %
1360 % %
1361 + T y p e C o m p o n e n t T e r m i n u s %
1362 % %
1363 % %
1364 % %
1365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1366 %
1367 % TypeComponentTerminus() destroy type component.
1368 %
1369 % The format of the TypeComponentTerminus method is:
1370 %
1371 % void TypeComponentTerminus(void)
1372 %
1373 */
TypeComponentTerminus(void)1374 MagickPrivate void TypeComponentTerminus(void)
1375 {
1376 if (type_semaphore == (SemaphoreInfo *) NULL)
1377 ActivateSemaphoreInfo(&type_semaphore);
1378 LockSemaphoreInfo(type_semaphore);
1379 if (type_cache != (SplayTreeInfo *) NULL)
1380 type_cache=DestroySplayTree(type_cache);
1381 UnlockSemaphoreInfo(type_semaphore);
1382 RelinquishSemaphoreInfo(&type_semaphore);
1383 }
1384