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-2019 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 = (const char *)
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 register 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 !defined(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 */
322
GetTypeInfoByFamily(const char * family,const StyleType style,const StretchType stretch,const size_t weight,ExceptionInfo * exception)323 MagickExport 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,
331 *substitute;
332 } Fontmap;
333
334 const TypeInfo
335 *type_info;
336
337 register const TypeInfo
338 *p;
339
340 register ssize_t
341 i;
342
343 ssize_t
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 { NULL, NULL }
357 };
358
359 size_t
360 font_weight,
361 max_score,
362 score;
363
364 /*
365 Check for an exact type match.
366 */
367 (void) GetTypeInfo("*",exception);
368 if (type_cache == (SplayTreeInfo *) NULL)
369 return((TypeInfo *) NULL);
370 font_weight=(size_t) (weight == 0 ? 400 : weight);
371 LockSemaphoreInfo(type_semaphore);
372 ResetSplayTreeIterator(type_cache);
373 type_info=(const TypeInfo *) NULL;
374 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
375 while (p != (const TypeInfo *) NULL)
376 {
377 if (p->family == (char *) NULL)
378 {
379 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
380 continue;
381 }
382 if (family == (const char *) NULL)
383 {
384 if ((LocaleCompare(p->family,"arial") != 0) &&
385 (LocaleCompare(p->family,"helvetica") != 0))
386 {
387 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
388 continue;
389 }
390 }
391 else
392 if (LocaleCompare(p->family,family) != 0)
393 {
394 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
395 continue;
396 }
397 if ((style != UndefinedStyle) && (style != AnyStyle) && (p->style != style))
398 {
399 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
400 continue;
401 }
402 if ((stretch != UndefinedStretch) && (stretch != AnyStretch) &&
403 (p->stretch != stretch))
404 {
405 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
406 continue;
407 }
408 if (p->weight != font_weight)
409 {
410 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
411 continue;
412 }
413 type_info=p;
414 break;
415 }
416 UnlockSemaphoreInfo(type_semaphore);
417 if (type_info != (const TypeInfo *) NULL)
418 return(type_info);
419 /*
420 Check for types in the same family.
421 */
422 max_score=0;
423 LockSemaphoreInfo(type_semaphore);
424 ResetSplayTreeIterator(type_cache);
425 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
426 while (p != (const TypeInfo *) NULL)
427 {
428 if (p->family == (char *) NULL)
429 {
430 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
431 continue;
432 }
433 if (family == (const char *) NULL)
434 {
435 if ((LocaleCompare(p->family,"arial") != 0) &&
436 (LocaleCompare(p->family,"helvetica") != 0))
437 {
438 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
439 continue;
440 }
441 }
442 else
443 if (LocaleCompare(p->family,family) != 0)
444 {
445 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
446 continue;
447 }
448 score=0;
449 if ((style == UndefinedStyle) || (style == AnyStyle) || (p->style == style))
450 score+=32;
451 else
452 if (((style == ItalicStyle) || (style == ObliqueStyle)) &&
453 ((p->style == ItalicStyle) || (p->style == ObliqueStyle)))
454 score+=25;
455 score+=(16*(800-((ssize_t) MagickMax(MagickMin(font_weight,900),p->weight)-
456 (ssize_t) MagickMin(MagickMin(font_weight,900),p->weight))))/800;
457 if ((stretch == UndefinedStretch) || (stretch == AnyStretch))
458 score+=8;
459 else
460 {
461 range=(ssize_t) UltraExpandedStretch-(ssize_t) NormalStretch;
462 score+=(8*(range-((ssize_t) MagickMax(stretch,p->stretch)-
463 (ssize_t) MagickMin(stretch,p->stretch))))/range;
464 }
465 if (score > max_score)
466 {
467 max_score=score;
468 type_info=p;
469 }
470 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
471 }
472 UnlockSemaphoreInfo(type_semaphore);
473 if (type_info != (const TypeInfo *) NULL)
474 return(type_info);
475 /*
476 Check for table-based substitution match.
477 */
478 for (i=0; fontmap[i].name != (char *) NULL; i++)
479 {
480 if (family == (const char *) NULL)
481 {
482 if ((LocaleCompare(fontmap[i].name,"arial") != 0) &&
483 (LocaleCompare(fontmap[i].name,"helvetica") != 0))
484 continue;
485 }
486 else
487 if (LocaleCompare(fontmap[i].name,family) != 0)
488 continue;
489 type_info=GetTypeInfoByFamily(fontmap[i].substitute,style,stretch,weight,
490 exception);
491 break;
492 }
493 if (type_info != (const TypeInfo *) NULL)
494 {
495 (void) ThrowMagickException(exception,GetMagickModule(),TypeError,
496 "FontSubstitutionRequired","`%s'",type_info->family);
497 return(type_info);
498 }
499 if (family != (const char *) NULL)
500 type_info=GetTypeInfoByFamily((const char *) NULL,style,stretch,weight,
501 exception);
502 return(type_info);
503 }
504
505 /*
506 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
507 % %
508 % %
509 % %
510 % G e t T y p e I n f o L i s t %
511 % %
512 % %
513 % %
514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
515 %
516 % GetTypeInfoList() returns any fonts that match the specified pattern.
517 %
518 % The format of the GetTypeInfoList function is:
519 %
520 % const TypeInfo **GetTypeInfoList(const char *pattern,
521 % size_t *number_fonts,ExceptionInfo *exception)
522 %
523 % A description of each parameter follows:
524 %
525 % o pattern: Specifies a pointer to a text string containing a pattern.
526 %
527 % o number_fonts: This integer returns the number of types in the list.
528 %
529 % o exception: return any errors or warnings in this structure.
530 %
531 */
532
533 #if defined(__cplusplus) || defined(c_plusplus)
534 extern "C" {
535 #endif
536
TypeInfoCompare(const void * x,const void * y)537 static int TypeInfoCompare(const void *x,const void *y)
538 {
539 const TypeInfo
540 **p,
541 **q;
542
543 p=(const TypeInfo **) x,
544 q=(const TypeInfo **) y;
545 if (LocaleCompare((*p)->path,(*q)->path) == 0)
546 return(LocaleCompare((*p)->name,(*q)->name));
547 return(LocaleCompare((*p)->path,(*q)->path));
548 }
549
550 #if defined(__cplusplus) || defined(c_plusplus)
551 }
552 #endif
553
GetTypeInfoList(const char * pattern,size_t * number_fonts,ExceptionInfo * exception)554 MagickExport const TypeInfo **GetTypeInfoList(const char *pattern,
555 size_t *number_fonts,ExceptionInfo *exception)
556 {
557 const TypeInfo
558 **fonts;
559
560 register const TypeInfo
561 *p;
562
563 register ssize_t
564 i;
565
566 /*
567 Allocate type list.
568 */
569 assert(pattern != (char *) NULL);
570 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
571 assert(number_fonts != (size_t *) NULL);
572 *number_fonts=0;
573 p=GetTypeInfo("*",exception);
574 if (p == (const TypeInfo *) NULL)
575 return((const TypeInfo **) NULL);
576 fonts=(const TypeInfo **) AcquireQuantumMemory((size_t)
577 GetNumberOfNodesInSplayTree(type_cache)+1UL,sizeof(*fonts));
578 if (fonts == (const TypeInfo **) NULL)
579 return((const TypeInfo **) NULL);
580 /*
581 Generate type list.
582 */
583 LockSemaphoreInfo(type_semaphore);
584 ResetSplayTreeIterator(type_cache);
585 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
586 for (i=0; p != (const TypeInfo *) NULL; )
587 {
588 if ((p->stealth == MagickFalse) &&
589 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
590 fonts[i++]=p;
591 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
592 }
593 UnlockSemaphoreInfo(type_semaphore);
594 qsort((void *) fonts,(size_t) i,sizeof(*fonts),TypeInfoCompare);
595 fonts[i]=(TypeInfo *) NULL;
596 *number_fonts=(size_t) i;
597 return(fonts);
598 }
599
600 /*
601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
602 % %
603 % %
604 % %
605 % G e t T y p e L i s t %
606 % %
607 % %
608 % %
609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
610 %
611 % GetTypeList() returns any fonts that match the specified pattern.
612 %
613 % The format of the GetTypeList function is:
614 %
615 % char **GetTypeList(const char *pattern,size_t *number_fonts,
616 % ExceptionInfo *exception)
617 %
618 % A description of each parameter follows:
619 %
620 % o pattern: Specifies a pointer to a text string containing a pattern.
621 %
622 % o number_fonts: This integer returns the number of fonts in the list.
623 %
624 % o exception: return any errors or warnings in this structure.
625 %
626 */
627
628 #if defined(__cplusplus) || defined(c_plusplus)
629 extern "C" {
630 #endif
631
TypeCompare(const void * x,const void * y)632 static int TypeCompare(const void *x,const void *y)
633 {
634 register const char
635 **p,
636 **q;
637
638 p=(const char **) x;
639 q=(const char **) y;
640 return(LocaleCompare(*p,*q));
641 }
642
643 #if defined(__cplusplus) || defined(c_plusplus)
644 }
645 #endif
646
GetTypeList(const char * pattern,size_t * number_fonts,ExceptionInfo * exception)647 MagickExport char **GetTypeList(const char *pattern,size_t *number_fonts,
648 ExceptionInfo *exception)
649 {
650 char
651 **fonts;
652
653 register const TypeInfo
654 *p;
655
656 register ssize_t
657 i;
658
659 /*
660 Allocate type list.
661 */
662 assert(pattern != (char *) NULL);
663 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
664 assert(number_fonts != (size_t *) NULL);
665 *number_fonts=0;
666 p=GetTypeInfo("*",exception);
667 if (p == (const TypeInfo *) NULL)
668 return((char **) NULL);
669 fonts=(char **) AcquireQuantumMemory((size_t)
670 GetNumberOfNodesInSplayTree(type_cache)+1UL,sizeof(*fonts));
671 if (fonts == (char **) NULL)
672 return((char **) NULL);
673 /*
674 Generate type list.
675 */
676 LockSemaphoreInfo(type_semaphore);
677 ResetSplayTreeIterator(type_cache);
678 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
679 for (i=0; p != (const TypeInfo *) NULL; )
680 {
681 if ((p->stealth == MagickFalse) &&
682 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
683 fonts[i++]=ConstantString(p->name);
684 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
685 }
686 UnlockSemaphoreInfo(type_semaphore);
687 qsort((void *) fonts,(size_t) i,sizeof(*fonts),TypeCompare);
688 fonts[i]=(char *) NULL;
689 *number_fonts=(size_t) i;
690 return(fonts);
691 }
692
693 /*
694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
695 % %
696 % %
697 % %
698 + I s T y p e T r e e I n s t a n t i a t e d %
699 % %
700 % %
701 % %
702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
703 %
704 % IsTypeTreeInstantiated() determines if the type tree is instantiated. If
705 % not, it instantiates the tree and returns it.
706 %
707 % The format of the IsTypeInstantiated method is:
708 %
709 % MagickBooleanType IsTypeTreeInstantiated(ExceptionInfo *exception)
710 %
711 % A description of each parameter follows.
712 %
713 % o exception: return any errors or warnings in this structure.
714 %
715 */
716
717 #if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
LoadFontConfigFonts(SplayTreeInfo * type_cache,ExceptionInfo * exception)718 MagickExport MagickBooleanType LoadFontConfigFonts(SplayTreeInfo *type_cache,
719 ExceptionInfo *exception)
720 {
721 #if !defined(FC_FULLNAME)
722 #define FC_FULLNAME "fullname"
723 #endif
724
725 char
726 extension[MagickPathExtent],
727 name[MagickPathExtent];
728
729 FcBool
730 result;
731
732 FcChar8
733 *family,
734 *file,
735 *fullname,
736 *style;
737
738 FcConfig
739 *font_config;
740
741 FcFontSet
742 *font_set;
743
744 FcObjectSet
745 *object_set;
746
747 FcPattern
748 *pattern;
749
750 FcResult
751 status;
752
753 int
754 slant,
755 width,
756 weight;
757
758 register ssize_t
759 i;
760
761 TypeInfo
762 *type_info;
763
764 /*
765 Load system fonts.
766 */
767 (void) exception;
768 result=FcInit();
769 if (result == 0)
770 return(MagickFalse);
771 font_config=FcConfigGetCurrent();
772 if (font_config == (FcConfig *) NULL)
773 return(MagickFalse);
774 FcConfigSetRescanInterval(font_config,0);
775 font_set=(FcFontSet *) NULL;
776 object_set=FcObjectSetBuild(FC_FULLNAME,FC_FAMILY,FC_STYLE,FC_SLANT,
777 FC_WIDTH,FC_WEIGHT,FC_FILE,(char *) NULL);
778 if (object_set != (FcObjectSet *) NULL)
779 {
780 pattern=FcPatternCreate();
781 if (pattern != (FcPattern *) NULL)
782 {
783 font_set=FcFontList(font_config,pattern,object_set);
784 FcPatternDestroy(pattern);
785 }
786 FcObjectSetDestroy(object_set);
787 }
788 if (font_set == (FcFontSet *) NULL)
789 {
790 FcConfigDestroy(font_config);
791 return(MagickFalse);
792 }
793 for (i=0; i < (ssize_t) font_set->nfont; i++)
794 {
795 status=FcPatternGetString(font_set->fonts[i],FC_FAMILY,0,&family);
796 if (status != FcResultMatch)
797 continue;
798 status=FcPatternGetString(font_set->fonts[i],FC_FILE,0,&file);
799 if (status != FcResultMatch)
800 continue;
801 *extension='\0';
802 GetPathComponent((const char *) file,ExtensionPath,extension);
803 if ((*extension != '\0') && (LocaleCompare(extension,"gz") == 0))
804 continue;
805 type_info=(TypeInfo *) AcquireMagickMemory(sizeof(*type_info));
806 if (type_info == (TypeInfo *) NULL)
807 continue;
808 (void) memset(type_info,0,sizeof(*type_info));
809 type_info->path=ConstantString("System Fonts");
810 type_info->signature=MagickCoreSignature;
811 (void) CopyMagickString(name,"Unknown",MagickPathExtent);
812 status=FcPatternGetString(font_set->fonts[i],FC_FULLNAME,0,&fullname);
813 if ((status == FcResultMatch) && (fullname != (FcChar8 *) NULL))
814 (void) CopyMagickString(name,(const char *) fullname,MagickPathExtent);
815 else
816 {
817 if (family != (FcChar8 *) NULL)
818 (void) CopyMagickString(name,(const char *) family,MagickPathExtent);
819 status=FcPatternGetString(font_set->fonts[i],FC_STYLE,0,&style);
820 if ((status == FcResultMatch) && (style != (FcChar8 *) NULL) &&
821 (LocaleCompare((const char *) style,"Regular") != 0))
822 {
823 (void) ConcatenateMagickString(name," ",MagickPathExtent);
824 (void) ConcatenateMagickString(name,(const char *) style,
825 MagickPathExtent);
826 }
827 }
828 type_info->name=ConstantString(name);
829 (void) SubstituteString(&type_info->name," ","-");
830 type_info->family=ConstantString((const char *) family);
831 status=FcPatternGetInteger(font_set->fonts[i],FC_SLANT,0,&slant);
832 type_info->style=NormalStyle;
833 if (slant == FC_SLANT_ITALIC)
834 type_info->style=ItalicStyle;
835 if (slant == FC_SLANT_OBLIQUE)
836 type_info->style=ObliqueStyle;
837 status=FcPatternGetInteger(font_set->fonts[i],FC_WIDTH,0,&width);
838 type_info->stretch=NormalStretch;
839 if (width >= FC_WIDTH_ULTRACONDENSED)
840 type_info->stretch=UltraCondensedStretch;
841 if (width >= FC_WIDTH_EXTRACONDENSED)
842 type_info->stretch=ExtraCondensedStretch;
843 if (width >= FC_WIDTH_CONDENSED)
844 type_info->stretch=CondensedStretch;
845 if (width >= FC_WIDTH_SEMICONDENSED)
846 type_info->stretch=SemiCondensedStretch;
847 if (width >= FC_WIDTH_NORMAL)
848 type_info->stretch=NormalStretch;
849 if (width >= FC_WIDTH_SEMIEXPANDED)
850 type_info->stretch=SemiExpandedStretch;
851 if (width >= FC_WIDTH_EXPANDED)
852 type_info->stretch=ExpandedStretch;
853 if (width >= FC_WIDTH_EXTRAEXPANDED)
854 type_info->stretch=ExtraExpandedStretch;
855 if (width >= FC_WIDTH_ULTRAEXPANDED)
856 type_info->stretch=UltraExpandedStretch;
857 type_info->weight=400;
858 status=FcPatternGetInteger(font_set->fonts[i],FC_WEIGHT,0,&weight);
859 if (weight >= FC_WEIGHT_THIN)
860 type_info->weight=100;
861 if (weight >= FC_WEIGHT_EXTRALIGHT)
862 type_info->weight=200;
863 if (weight >= FC_WEIGHT_LIGHT)
864 type_info->weight=300;
865 if (weight >= FC_WEIGHT_NORMAL)
866 type_info->weight=400;
867 if (weight >= FC_WEIGHT_MEDIUM)
868 type_info->weight=500;
869 if (weight >= FC_WEIGHT_DEMIBOLD)
870 type_info->weight=600;
871 if (weight >= FC_WEIGHT_BOLD)
872 type_info->weight=700;
873 if (weight >= FC_WEIGHT_EXTRABOLD)
874 type_info->weight=800;
875 if (weight >= FC_WEIGHT_BLACK)
876 type_info->weight=900;
877 type_info->glyphs=ConstantString((const char *) file);
878 (void) AddValueToSplayTree(type_cache,type_info->name,type_info);
879 }
880 FcFontSetDestroy(font_set);
881 FcConfigDestroy(font_config);
882 return(MagickTrue);
883 }
884 #endif
885
IsTypeTreeInstantiated(ExceptionInfo * exception)886 static MagickBooleanType IsTypeTreeInstantiated(ExceptionInfo *exception)
887 {
888 if (type_cache == (SplayTreeInfo *) NULL)
889 {
890 if (type_semaphore == (SemaphoreInfo *) NULL)
891 ActivateSemaphoreInfo(&type_semaphore);
892 LockSemaphoreInfo(type_semaphore);
893 if (type_cache == (SplayTreeInfo *) NULL)
894 {
895 SplayTreeInfo
896 *splay_tree;
897
898 splay_tree=AcquireTypeCache(MagickTypeFilename,exception);
899 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
900 (void) NTAcquireTypeCache(splay_tree,exception);
901 #endif
902 #if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
903 (void) LoadFontConfigFonts(splay_tree,exception);
904 #endif
905 type_cache=splay_tree;
906 }
907 UnlockSemaphoreInfo(type_semaphore);
908 }
909 return(type_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
910 }
911
912 /*
913 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
914 % %
915 % %
916 % %
917 % L i s t T y p e I n f o %
918 % %
919 % %
920 % %
921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
922 %
923 % ListTypeInfo() lists the fonts to a file.
924 %
925 % The format of the ListTypeInfo method is:
926 %
927 % MagickBooleanType ListTypeInfo(FILE *file,ExceptionInfo *exception)
928 %
929 % A description of each parameter follows.
930 %
931 % o file: An pointer to a FILE.
932 %
933 % o exception: return any errors or warnings in this structure.
934 %
935 */
ListTypeInfo(FILE * file,ExceptionInfo * exception)936 MagickExport MagickBooleanType ListTypeInfo(FILE *file,ExceptionInfo *exception)
937 {
938 char
939 weight[MagickPathExtent];
940
941 const char
942 *family,
943 *glyphs,
944 *name,
945 *path,
946 *stretch,
947 *style;
948
949 const TypeInfo
950 **type_info;
951
952 register 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 *weight='\0';
965 path=(const char *) NULL;
966 for (i=0; i < (ssize_t) number_fonts; i++)
967 {
968 if (type_info[i]->stealth != MagickFalse)
969 continue;
970 if (((path == (const char *) NULL) ||
971 (LocaleCompare(path,type_info[i]->path) != 0)) &&
972 (type_info[i]->path != (char *) NULL))
973 (void) FormatLocaleFile(file,"\nPath: %s\n",type_info[i]->path);
974 path=type_info[i]->path;
975 name="unknown";
976 if (type_info[i]->name != (char *) NULL)
977 name=type_info[i]->name;
978 family="unknown";
979 if (type_info[i]->family != (char *) NULL)
980 family=type_info[i]->family;
981 style=CommandOptionToMnemonic(MagickStyleOptions,type_info[i]->style);
982 stretch=CommandOptionToMnemonic(MagickStretchOptions,type_info[i]->stretch);
983 glyphs="unknown";
984 if (type_info[i]->glyphs != (char *) NULL)
985 glyphs=type_info[i]->glyphs;
986 (void) FormatLocaleString(weight,MagickPathExtent,"%.20g",(double)
987 type_info[i]->weight);
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: %s\n",weight);
993 (void) FormatLocaleFile(file," glyphs: %s\n",glyphs);
994 }
995 (void) fflush(file);
996 type_info=(const TypeInfo **) RelinquishMagickMemory((void *) type_info);
997 return(MagickTrue);
998 }
999
1000 /*
1001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1002 % %
1003 % %
1004 % %
1005 + L o a d T y p e C a c h e %
1006 % %
1007 % %
1008 % %
1009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1010 %
1011 % LoadTypeCache() loads the type configurations which provides a mapping
1012 % between type attributes and a type name.
1013 %
1014 % The format of the LoadTypeCache method is:
1015 %
1016 % MagickBooleanType LoadTypeCache(SplayTreeInfo *cache,const char *xml,
1017 % const char *filename,const size_t depth,ExceptionInfo *exception)
1018 %
1019 % A description of each parameter follows:
1020 %
1021 % o xml: The type list in XML format.
1022 %
1023 % o filename: The type list filename.
1024 %
1025 % o depth: depth of <include /> statements.
1026 %
1027 % o exception: return any errors or warnings in this structure.
1028 %
1029 */
1030
SetTypeNodePath(const char * filename,char * font_path,const char * token,char ** target)1031 static inline MagickBooleanType SetTypeNodePath(const char *filename,
1032 char *font_path,const char *token,char **target)
1033 {
1034 char
1035 *path;
1036
1037 path=ConstantString(token);
1038 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1039 if (strchr(path,'@') != (char *) NULL)
1040 SubstituteString(&path,"@ghostscript_font_path@",font_path);
1041 #endif
1042 if (IsPathAccessible(path) == MagickFalse)
1043 {
1044 /*
1045 Relative path.
1046 */
1047 path=DestroyString(path);
1048 GetPathComponent(filename,HeadPath,font_path);
1049 (void) ConcatenateMagickString(font_path,DirectorySeparator,
1050 MagickPathExtent);
1051 (void) ConcatenateMagickString(font_path,token,MagickPathExtent);
1052 path=ConstantString(font_path);
1053 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1054 if (strchr(path,'@') != (char *) NULL)
1055 SubstituteString(&path,"@ghostscript_font_path@","");
1056 #endif
1057 if (IsPathAccessible(path) == MagickFalse)
1058 {
1059 path=DestroyString(path);
1060 return(MagickFalse);
1061 }
1062 }
1063
1064 *target=path;
1065 return(MagickTrue);
1066 }
1067
LoadTypeCache(SplayTreeInfo * cache,const char * xml,const char * filename,const size_t depth,ExceptionInfo * exception)1068 static MagickBooleanType LoadTypeCache(SplayTreeInfo *cache,const char *xml,
1069 const char *filename,const size_t depth,ExceptionInfo *exception)
1070 {
1071 char
1072 font_path[MagickPathExtent],
1073 keyword[MagickPathExtent],
1074 *token;
1075
1076 const char
1077 *q;
1078
1079 MagickStatusType
1080 status;
1081
1082 size_t
1083 extent;
1084
1085 TypeInfo
1086 *type_info;
1087
1088 /*
1089 Load the type map file.
1090 */
1091 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1092 "Loading type configure file \"%s\" ...",filename);
1093 if (xml == (const char *) NULL)
1094 return(MagickFalse);
1095 status=MagickTrue;
1096 type_info=(TypeInfo *) NULL;
1097 token=AcquireString(xml);
1098 extent=strlen(token)+MagickPathExtent;
1099 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1100 /*
1101 Determine the Ghostscript font path.
1102 */
1103 *font_path='\0';
1104 if (NTGhostscriptFonts(font_path,MagickPathExtent-2))
1105 (void) ConcatenateMagickString(font_path,DirectorySeparator,MagickPathExtent);
1106 #endif
1107 for (q=(char *) xml; *q != '\0'; )
1108 {
1109 /*
1110 Interpret XML.
1111 */
1112 GetNextToken(q,&q,extent,token);
1113 if (*token == '\0')
1114 break;
1115 (void) CopyMagickString(keyword,token,MagickPathExtent);
1116 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1117 {
1118 /*
1119 Doctype element.
1120 */
1121 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1122 GetNextToken(q,&q,extent,token);
1123 continue;
1124 }
1125 if (LocaleNCompare(keyword,"<!--",4) == 0)
1126 {
1127 /*
1128 Comment element.
1129 */
1130 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1131 GetNextToken(q,&q,extent,token);
1132 continue;
1133 }
1134 if (LocaleCompare(keyword,"<include") == 0)
1135 {
1136 /*
1137 Include element.
1138 */
1139 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1140 {
1141 (void) CopyMagickString(keyword,token,MagickPathExtent);
1142 GetNextToken(q,&q,extent,token);
1143 if (*token != '=')
1144 continue;
1145 GetNextToken(q,&q,extent,token);
1146 if (LocaleCompare(keyword,"file") == 0)
1147 {
1148 if (depth > MagickMaxRecursionDepth)
1149 (void) ThrowMagickException(exception,GetMagickModule(),
1150 ConfigureError,"IncludeNodeNestedTooDeeply","`%s'",token);
1151 else
1152 {
1153 char
1154 path[MagickPathExtent],
1155 *file_xml;
1156
1157 ExceptionInfo
1158 *sans_exception;
1159
1160 *path='\0';
1161 GetPathComponent(filename,HeadPath,path);
1162 if (*path != '\0')
1163 (void) ConcatenateMagickString(path,DirectorySeparator,
1164 MagickPathExtent);
1165 if (*token == *DirectorySeparator)
1166 (void) CopyMagickString(path,token,MagickPathExtent);
1167 else
1168 (void) ConcatenateMagickString(path,token,MagickPathExtent);
1169 sans_exception=AcquireExceptionInfo();
1170 file_xml=FileToString(path,~0UL,sans_exception);
1171 sans_exception=DestroyExceptionInfo(sans_exception);
1172 if (file_xml != (char *) NULL)
1173 {
1174 status&=LoadTypeCache(cache,file_xml,path,depth+1,
1175 exception);
1176 file_xml=(char *) RelinquishMagickMemory(file_xml);
1177 }
1178 }
1179 }
1180 }
1181 continue;
1182 }
1183 if (LocaleCompare(keyword,"<type") == 0)
1184 {
1185 /*
1186 Type element.
1187 */
1188 type_info=(TypeInfo *) AcquireCriticalMemory(sizeof(*type_info));
1189 (void) memset(type_info,0,sizeof(*type_info));
1190 type_info->path=ConstantString(filename);
1191 type_info->signature=MagickCoreSignature;
1192 continue;
1193 }
1194 if (type_info == (TypeInfo *) NULL)
1195 continue;
1196 if ((LocaleCompare(keyword,"/>") == 0) ||
1197 (LocaleCompare(keyword,"</policy>") == 0))
1198 {
1199 status=AddValueToSplayTree(cache,type_info->name,type_info);
1200 if (status == MagickFalse)
1201 (void) ThrowMagickException(exception,GetMagickModule(),
1202 ResourceLimitError,"MemoryAllocationFailed","`%s'",type_info->name);
1203 type_info=(TypeInfo *) NULL;
1204 continue;
1205 }
1206 GetNextToken(q,(const char **) NULL,extent,token);
1207 if (*token != '=')
1208 continue;
1209 GetNextToken(q,&q,extent,token);
1210 GetNextToken(q,&q,extent,token);
1211 switch (*keyword)
1212 {
1213 case 'E':
1214 case 'e':
1215 {
1216 if (LocaleCompare((char *) keyword,"encoding") == 0)
1217 {
1218 type_info->encoding=ConstantString(token);
1219 break;
1220 }
1221 break;
1222 }
1223 case 'F':
1224 case 'f':
1225 {
1226 if (LocaleCompare((char *) keyword,"face") == 0)
1227 {
1228 type_info->face=StringToUnsignedLong(token);
1229 break;
1230 }
1231 if (LocaleCompare((char *) keyword,"family") == 0)
1232 {
1233 type_info->family=ConstantString(token);
1234 break;
1235 }
1236 if (LocaleCompare((char *) keyword,"format") == 0)
1237 {
1238 type_info->format=ConstantString(token);
1239 break;
1240 }
1241 if (LocaleCompare((char *) keyword,"foundry") == 0)
1242 {
1243 type_info->foundry=ConstantString(token);
1244 break;
1245 }
1246 if (LocaleCompare((char *) keyword,"fullname") == 0)
1247 {
1248 type_info->description=ConstantString(token);
1249 break;
1250 }
1251 break;
1252 }
1253 case 'G':
1254 case 'g':
1255 {
1256 if (LocaleCompare((char *) keyword,"glyphs") == 0)
1257 {
1258 if (SetTypeNodePath(filename,font_path,token,&type_info->glyphs) ==
1259 MagickFalse)
1260 type_info=(TypeInfo *) DestroyTypeNode(type_info);
1261 break;
1262 }
1263 break;
1264 }
1265 case 'M':
1266 case 'm':
1267 {
1268 if (LocaleCompare((char *) keyword,"metrics") == 0)
1269 {
1270 if (SetTypeNodePath(filename,font_path,token,&type_info->metrics) ==
1271 MagickFalse)
1272 type_info=(TypeInfo *) DestroyTypeNode(type_info);
1273 break;
1274 }
1275 break;
1276 }
1277 case 'N':
1278 case 'n':
1279 {
1280 if (LocaleCompare((char *) keyword,"name") == 0)
1281 {
1282 type_info->name=ConstantString(token);
1283 break;
1284 }
1285 break;
1286 }
1287 case 'S':
1288 case 's':
1289 {
1290 if (LocaleCompare((char *) keyword,"stealth") == 0)
1291 {
1292 type_info->stealth=IsStringTrue(token);
1293 break;
1294 }
1295 if (LocaleCompare((char *) keyword,"stretch") == 0)
1296 {
1297 type_info->stretch=(StretchType) ParseCommandOption(
1298 MagickStretchOptions,MagickFalse,token);
1299 break;
1300 }
1301 if (LocaleCompare((char *) keyword,"style") == 0)
1302 {
1303 type_info->style=(StyleType) ParseCommandOption(MagickStyleOptions,
1304 MagickFalse,token);
1305 break;
1306 }
1307 break;
1308 }
1309 case 'W':
1310 case 'w':
1311 {
1312 if (LocaleCompare((char *) keyword,"weight") == 0)
1313 {
1314 ssize_t
1315 weight;
1316
1317 weight=ParseCommandOption(MagickWeightOptions,MagickFalse,token);
1318 if (weight == -1)
1319 weight=(ssize_t) StringToUnsignedLong(token);
1320 type_info->weight=(size_t) weight;
1321 break;
1322 }
1323 break;
1324 }
1325 default:
1326 break;
1327 }
1328 }
1329 token=(char *) RelinquishMagickMemory(token);
1330 return(status != 0 ? MagickTrue : MagickFalse);
1331 }
1332
1333 /*
1334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1335 % %
1336 % %
1337 % %
1338 + T y p e C o m p o n e n t G e n e s i s %
1339 % %
1340 % %
1341 % %
1342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1343 %
1344 % TypeComponentGenesis() instantiates the type component.
1345 %
1346 % The format of the TypeComponentGenesis method is:
1347 %
1348 % MagickBooleanType TypeComponentGenesis(void)
1349 %
1350 */
TypeComponentGenesis(void)1351 MagickPrivate MagickBooleanType TypeComponentGenesis(void)
1352 {
1353 if (type_semaphore == (SemaphoreInfo *) NULL)
1354 type_semaphore=AcquireSemaphoreInfo();
1355 return(MagickTrue);
1356 }
1357
1358 /*
1359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1360 % %
1361 % %
1362 % %
1363 + T y p e C o m p o n e n t T e r m i n u s %
1364 % %
1365 % %
1366 % %
1367 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1368 %
1369 % TypeComponentTerminus() destroy type component.
1370 %
1371 % The format of the TypeComponentTerminus method is:
1372 %
1373 % void TypeComponentTerminus(void)
1374 %
1375 */
TypeComponentTerminus(void)1376 MagickPrivate void TypeComponentTerminus(void)
1377 {
1378 if (type_semaphore == (SemaphoreInfo *) NULL)
1379 ActivateSemaphoreInfo(&type_semaphore);
1380 LockSemaphoreInfo(type_semaphore);
1381 if (type_cache != (SplayTreeInfo *) NULL)
1382 type_cache=DestroySplayTree(type_cache);
1383 UnlockSemaphoreInfo(type_semaphore);
1384 RelinquishSemaphoreInfo(&type_semaphore);
1385 }
1386