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 "magick/studio.h"
43 #include "magick/blob.h"
44 #include "magick/client.h"
45 #include "magick/configure.h"
46 #include "magick/draw.h"
47 #include "magick/exception.h"
48 #include "magick/exception-private.h"
49 #include "magick/hashmap.h"
50 #include "magick/image-private.h"
51 #include "magick/log.h"
52 #include "magick/memory_.h"
53 #include "magick/nt-base-private.h"
54 #include "magick/nt-feature.h"
55 #include "magick/option.h"
56 #include "magick/semaphore.h"
57 #include "magick/splay-tree.h"
58 #include "magick/string_.h"
59 #include "magick/string-private.h"
60 #include "magick/type.h"
61 #include "magick/token.h"
62 #include "magick/utility.h"
63 #include "magick/xml-tree.h"
64 #if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
65 # include "fontconfig/fontconfig.h"
66 #if (FC_VERSION < 20209)
67 #undef FC_WEIGHT_LIGHT
68 #define FC_WIDTH "width" /* Int */
69 #define FC_WIDTH_ULTRACONDENSED 50
70 #define FC_WIDTH_EXTRACONDENSED 63
71 #define FC_WIDTH_CONDENSED 75
72 #define FC_WIDTH_SEMICONDENSED 87
73 #define FC_WIDTH_NORMAL 100
74 #define FC_WIDTH_SEMIEXPANDED 113
75 #define FC_WIDTH_EXPANDED 125
76 #define FC_WIDTH_EXTRAEXPANDED 150
77 #define FC_WIDTH_ULTRAEXPANDED 200
78
79 #define FC_WEIGHT_THIN 0
80 #define FC_WEIGHT_EXTRALIGHT 40
81 #define FC_WEIGHT_ULTRALIGHT FC_WEIGHT_EXTRALIGHT
82 #define FC_WEIGHT_LIGHT 50
83 #define FC_WEIGHT_BOOK 75
84 #define FC_WEIGHT_REGULAR 80
85 #define FC_WEIGHT_NORMAL FC_WEIGHT_REGULAR
86 #define FC_WEIGHT_MEDIUM 100
87 #define FC_WEIGHT_DEMIBOLD 180
88 #define FC_WEIGHT_SEMIBOLD FC_WEIGHT_DEMIBOLD
89 #define FC_WEIGHT_BOLD 200
90 #define FC_WEIGHT_EXTRABOLD 205
91 #define FC_WEIGHT_ULTRABOLD FC_WEIGHT_EXTRABOLD
92 #define FC_WEIGHT_BLACK 210
93 #define FC_WEIGHT_HEAVY FC_WEIGHT_BLACK
94 #endif
95 #endif
96 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
97 # include "magick/nt-feature.h"
98 #endif
99
100 /*
101 Define declarations.
102 */
103 #define MagickTypeFilename "type.xml"
104
105 /*
106 Declare type map.
107 */
108 static const char
109 TypeMap[] =
110 "<?xml version=\"1.0\"?>"
111 "<typemap>"
112 " <type stealth=\"True\" name=\"fixed\" family=\"helvetica\"/>"
113 " <type stealth=\"True\" name=\"helvetica\" family=\"helvetica\"/>"
114 "</typemap>";
115
116 /*
117 Static declarations.
118 */
119 static SemaphoreInfo
120 *type_semaphore = (SemaphoreInfo *) NULL;
121
122 static SplayTreeInfo
123 *type_cache = (SplayTreeInfo *) NULL;
124
125 /*
126 Forward declarations.
127 */
128 static MagickBooleanType
129 IsTypeTreeInstantiated(ExceptionInfo *),
130 LoadTypeCache(SplayTreeInfo *,const char *,const char *,const size_t,
131 ExceptionInfo *);
132
133 /*
134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
135 % %
136 % %
137 % %
138 % A c q u i r e T y p e S p l a y T r e e %
139 % %
140 % %
141 % %
142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143 %
144 % AcquireTypeCache() caches one or more type configuration files which
145 % provides a mapping between type attributes and a type name.
146 %
147 % The format of the AcquireTypeCache method is:
148 %
149 % SplayTreeInfo *AcquireTypeCache(const char *filename,
150 % ExceptionInfo *exception)
151 %
152 % A description of each parameter follows:
153 %
154 % o filename: the font file name.
155 %
156 % o exception: return any errors or warnings in this structure.
157 %
158 */
159
DestroyTypeNode(void * type_info)160 static void *DestroyTypeNode(void *type_info)
161 {
162 TypeInfo
163 *p;
164
165 p=(TypeInfo *) type_info;
166 if (p->path != (char *) NULL)
167 p->path=DestroyString(p->path);
168 if (p->name != (char *) NULL)
169 p->name=DestroyString(p->name);
170 if (p->description != (char *) NULL)
171 p->description=DestroyString(p->description);
172 if (p->family != (char *) NULL)
173 p->family=DestroyString(p->family);
174 if (p->encoding != (char *) NULL)
175 p->encoding=DestroyString(p->encoding);
176 if (p->foundry != (char *) NULL)
177 p->foundry=DestroyString(p->foundry);
178 if (p->format != (char *) NULL)
179 p->format=DestroyString(p->format);
180 if (p->metrics != (char *) NULL)
181 p->metrics=DestroyString(p->metrics);
182 if (p->glyphs != (char *) NULL)
183 p->glyphs=DestroyString(p->glyphs);
184 return(RelinquishMagickMemory(p));
185 }
186
AcquireTypeCache(const char * filename,ExceptionInfo * exception)187 static SplayTreeInfo *AcquireTypeCache(const char *filename,
188 ExceptionInfo *exception)
189 {
190 MagickStatusType
191 status;
192
193 SplayTreeInfo
194 *cache;
195
196 cache=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL,
197 DestroyTypeNode);
198 if (cache == (SplayTreeInfo *) NULL)
199 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
200 status=MagickTrue;
201 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
202 {
203 char
204 *font_path,
205 path[MaxTextExtent];
206
207 const StringInfo
208 *option;
209
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),MaxTextExtent);
219 status&=LoadTypeCache(cache,(const char *) GetStringInfoDatum(option),
220 GetStringInfoPath(option),0,exception);
221 option=(const StringInfo *) GetNextValueInLinkedList(options);
222 }
223 options=DestroyConfigureOptions(options);
224 font_path=GetEnvironmentValue("MAGICK_FONT_PATH");
225 if (font_path != (char *) NULL)
226 {
227 char
228 *option;
229
230 /*
231 Search MAGICK_FONT_PATH.
232 */
233 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s",font_path,
234 DirectorySeparator,filename);
235 option=FileToString(path,~0UL,exception);
236 if (option != (void *) NULL)
237 {
238 status&=LoadTypeCache(cache,option,path,0,exception);
239 option=DestroyString(option);
240 }
241 font_path=DestroyString(font_path);
242 }
243 }
244 #endif
245 if (GetNumberOfNodesInSplayTree(cache) == 0)
246 status&=LoadTypeCache(cache,TypeMap,"built-in",0,exception);
247 return(cache);
248 }
249
250 /*
251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252 % %
253 % %
254 % %
255 + G e t T y p e I n f o %
256 % %
257 % %
258 % %
259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
260 %
261 % GetTypeInfo searches the type list for the specified name and if found
262 % returns attributes for that type.
263 %
264 % The format of the GetTypeInfo method is:
265 %
266 % const TypeInfo *GetTypeInfo(const char *name,ExceptionInfo *exception)
267 %
268 % A description of each parameter follows:
269 %
270 % o name: the type name.
271 %
272 % o exception: return any errors or warnings in this structure.
273 %
274 */
GetTypeInfo(const char * name,ExceptionInfo * exception)275 MagickExport const TypeInfo *GetTypeInfo(const char *name,
276 ExceptionInfo *exception)
277 {
278 assert(exception != (ExceptionInfo *) NULL);
279 if (IsTypeTreeInstantiated(exception) == MagickFalse)
280 return((const TypeInfo *) NULL);
281 if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
282 return((const TypeInfo *) GetRootValueFromSplayTree(type_cache));
283 return((const TypeInfo *) GetValueFromSplayTree(type_cache,name));
284 }
285
286 /*
287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288 % %
289 % %
290 % %
291 + G e t T y p e I n f o B y F a m i l y %
292 % %
293 % %
294 % %
295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296 %
297 % GetTypeInfoByFamily() searches the type list for the specified family and if
298 % found returns attributes for that type.
299 %
300 % Type substitution and scoring algorithm contributed by Bob Friesenhahn.
301 %
302 % The format of the GetTypeInfoByFamily method is:
303 %
304 % const TypeInfo *GetTypeInfoByFamily(const char *family,
305 % const StyleType style,const StretchType stretch,
306 % const size_t weight,ExceptionInfo *exception)
307 %
308 % A description of each parameter follows:
309 %
310 % o family: the type family.
311 %
312 % o style: the type style.
313 %
314 % o stretch: the type stretch.
315 %
316 % o weight: the type weight.
317 %
318 % o exception: return any errors or warnings in this structure.
319 %
320 */
GetTypeInfoByFamily(const char * family,const StyleType style,const StretchType stretch,const size_t weight,ExceptionInfo * exception)321 MagickExport const TypeInfo *GetTypeInfoByFamily(const char *family,
322 const StyleType style,const StretchType stretch,const size_t weight,
323 ExceptionInfo *exception)
324 {
325 typedef struct _Fontmap
326 {
327 const char
328 name[17],
329 substitute[10];
330 } Fontmap;
331
332 const TypeInfo
333 *type_info;
334
335 const TypeInfo
336 *p;
337
338 ssize_t
339 i;
340
341 ssize_t
342 range;
343
344 static const Fontmap
345 fontmap[] =
346 {
347 { "fixed", "courier" },
348 { "modern","courier" },
349 { "monotype corsiva", "courier" },
350 { "news gothic", "helvetica" },
351 { "system", "courier" },
352 { "terminal", "courier" },
353 { "wingdings", "symbol" }
354 };
355
356 size_t
357 font_weight,
358 max_score,
359 score;
360
361 /*
362 Check for an exact type match.
363 */
364 (void) GetTypeInfo("*",exception);
365 if (type_cache == (SplayTreeInfo *) NULL)
366 return((TypeInfo *) NULL);
367 font_weight=weight == 0 ? 400 : weight;
368 LockSemaphoreInfo(type_semaphore);
369 ResetSplayTreeIterator(type_cache);
370 type_info=(const TypeInfo *) NULL;
371 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
372 while (p != (const TypeInfo *) NULL)
373 {
374 if (p->family == (char *) NULL)
375 {
376 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
377 continue;
378 }
379 if (family == (const char *) NULL)
380 {
381 if ((LocaleCompare(p->family,"arial") != 0) &&
382 (LocaleCompare(p->family,"helvetica") != 0))
383 {
384 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
385 continue;
386 }
387 }
388 else
389 if (LocaleCompare(p->family,family) != 0)
390 {
391 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
392 continue;
393 }
394 if ((style != UndefinedStyle) && (style != AnyStyle) && (p->style != style))
395 {
396 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
397 continue;
398 }
399 if ((stretch != UndefinedStretch) && (stretch != AnyStretch) &&
400 (p->stretch != stretch))
401 {
402 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
403 continue;
404 }
405 if (p->weight != font_weight)
406 {
407 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
408 continue;
409 }
410 type_info=p;
411 break;
412 }
413 UnlockSemaphoreInfo(type_semaphore);
414 if (type_info != (const TypeInfo *) NULL)
415 return(type_info);
416 /*
417 Check for types in the same family.
418 */
419 max_score=0;
420 LockSemaphoreInfo(type_semaphore);
421 ResetSplayTreeIterator(type_cache);
422 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
423 while (p != (const TypeInfo *) NULL)
424 {
425 if (p->family == (char *) NULL)
426 {
427 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
428 continue;
429 }
430 if (family == (const char *) NULL)
431 {
432 if ((LocaleCompare(p->family,"arial") != 0) &&
433 (LocaleCompare(p->family,"helvetica") != 0))
434 {
435 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
436 continue;
437 }
438 }
439 else
440 if (LocaleCompare(p->family,family) != 0)
441 {
442 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
443 continue;
444 }
445 score=0;
446 if ((style == UndefinedStyle) || (style == AnyStyle) || (p->style == style))
447 score+=32;
448 else
449 if (((style == ItalicStyle) || (style == ObliqueStyle)) &&
450 ((p->style == ItalicStyle) || (p->style == ObliqueStyle)))
451 score+=25;
452 score+=(16*(800-((ssize_t) MagickMax(MagickMin(font_weight,900),p->weight)-
453 (ssize_t) MagickMin(MagickMin(font_weight,900),p->weight))))/800;
454 if ((stretch == UndefinedStretch) || (stretch == AnyStretch))
455 score+=8;
456 else
457 {
458 range=(ssize_t) UltraExpandedStretch-(ssize_t) NormalStretch;
459 score+=(8*(range-((ssize_t) MagickMax(stretch,p->stretch)-
460 (ssize_t) MagickMin(stretch,p->stretch))))/range;
461 }
462 if (score > max_score)
463 {
464 max_score=score;
465 type_info=p;
466 }
467 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
468 }
469 UnlockSemaphoreInfo(type_semaphore);
470 if (type_info != (const TypeInfo *) NULL)
471 return(type_info);
472 /*
473 Check for table-based substitution match.
474 */
475 for (i=0; i < (ssize_t) (sizeof(fontmap)/sizeof(fontmap[0])); i++)
476 {
477 if (family == (const char *) NULL)
478 {
479 if ((LocaleCompare(fontmap[i].name,"arial") != 0) &&
480 (LocaleCompare(fontmap[i].name,"helvetica") != 0))
481 continue;
482 }
483 else
484 if (LocaleCompare(fontmap[i].name,family) != 0)
485 continue;
486 type_info=GetTypeInfoByFamily(fontmap[i].substitute,style,stretch,weight,
487 exception);
488 break;
489 }
490 if (type_info != (const TypeInfo *) NULL)
491 {
492 (void) ThrowMagickException(exception,GetMagickModule(),TypeWarning,
493 "FontSubstitutionRequired","`%s'",type_info->family);
494 return(type_info);
495 }
496 if (family != (const char *) NULL)
497 type_info=GetTypeInfoByFamily((const char *) NULL,style,stretch,weight,
498 exception);
499 return(type_info);
500 }
501
502 /*
503 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
504 % %
505 % %
506 % %
507 % G e t T y p e I n f o L i s t %
508 % %
509 % %
510 % %
511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
512 %
513 % GetTypeInfoList() returns any fonts that match the specified pattern.
514 %
515 % The format of the GetTypeInfoList function is:
516 %
517 % const TypeInfo **GetTypeInfoList(const char *pattern,
518 % size_t *number_fonts,ExceptionInfo *exception)
519 %
520 % A description of each parameter follows:
521 %
522 % o pattern: Specifies a pointer to a text string containing a pattern.
523 %
524 % o number_fonts: This integer returns the number of types in the list.
525 %
526 % o exception: return any errors or warnings in this structure.
527 %
528 */
529
530 #if defined(__cplusplus) || defined(c_plusplus)
531 extern "C" {
532 #endif
533
TypeInfoCompare(const void * x,const void * y)534 static int TypeInfoCompare(const void *x,const void *y)
535 {
536 const TypeInfo
537 **p,
538 **q;
539
540 p=(const TypeInfo **) x,
541 q=(const TypeInfo **) y;
542 if (LocaleCompare((*p)->path,(*q)->path) == 0)
543 return(LocaleCompare((*p)->name,(*q)->name));
544 return(LocaleCompare((*p)->path,(*q)->path));
545 }
546
547 #if defined(__cplusplus) || defined(c_plusplus)
548 }
549 #endif
550
GetTypeInfoList(const char * pattern,size_t * number_fonts,ExceptionInfo * exception)551 MagickExport const TypeInfo **GetTypeInfoList(const char *pattern,
552 size_t *number_fonts,ExceptionInfo *exception)
553 {
554 const TypeInfo
555 **fonts;
556
557 const TypeInfo
558 *p;
559
560 ssize_t
561 i;
562
563 /*
564 Allocate type list.
565 */
566 assert(pattern != (char *) NULL);
567 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
568 assert(number_fonts != (size_t *) NULL);
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)
626 extern "C" {
627 #endif
628
TypeCompare(const void * x,const void * y)629 static 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
GetTypeList(const char * pattern,size_t * number_fonts,ExceptionInfo * exception)644 MagickExport 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 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
661 assert(number_fonts != (size_t *) NULL);
662 *number_fonts=0;
663 p=GetTypeInfo("*",exception);
664 if (p == (const TypeInfo *) NULL)
665 return((char **) NULL);
666 fonts=(char **) AcquireQuantumMemory((size_t)
667 GetNumberOfNodesInSplayTree(type_cache)+1UL,sizeof(*fonts));
668 if (fonts == (char **) NULL)
669 return((char **) NULL);
670 /*
671 Generate type list.
672 */
673 LockSemaphoreInfo(type_semaphore);
674 ResetSplayTreeIterator(type_cache);
675 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
676 for (i=0; p != (const TypeInfo *) NULL; )
677 {
678 if ((p->stealth == MagickFalse) &&
679 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
680 fonts[i++]=ConstantString(p->name);
681 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
682 }
683 UnlockSemaphoreInfo(type_semaphore);
684 qsort((void *) fonts,(size_t) i,sizeof(*fonts),TypeCompare);
685 fonts[i]=(char *) NULL;
686 *number_fonts=(size_t) i;
687 return(fonts);
688 }
689
690 /*
691 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
692 % %
693 % %
694 % %
695 + I s T y p e T r e e I n s t a n t i a t e d %
696 % %
697 % %
698 % %
699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
700 %
701 % IsTypeTreeInstantiated() determines if the type tree is instantiated. If
702 % not, it instantiates the tree and returns it.
703 %
704 % The format of the IsTypeInstantiated method is:
705 %
706 % MagickBooleanType IsTypeTreeInstantiated(ExceptionInfo *exception)
707 %
708 % A description of each parameter follows.
709 %
710 % o exception: return any errors or warnings in this structure.
711 %
712 */
713
714 #if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
LoadFontConfigFonts(SplayTreeInfo * type_cache,ExceptionInfo * exception)715 MagickExport MagickBooleanType LoadFontConfigFonts(SplayTreeInfo *type_cache,
716 ExceptionInfo *exception)
717 {
718 #if !defined(FC_FULLNAME)
719 #define FC_FULLNAME "fullname"
720 #endif
721
722 char
723 extension[MaxTextExtent],
724 name[MaxTextExtent];
725
726 FcBool
727 result;
728
729 FcChar8
730 *family,
731 *file,
732 *fullname,
733 *style;
734
735 FcConfig
736 *font_config;
737
738 FcFontSet
739 *font_set;
740
741 FcObjectSet
742 *object_set;
743
744 FcPattern
745 *pattern;
746
747 FcResult
748 status;
749
750 int
751 slant,
752 width,
753 weight;
754
755 ssize_t
756 i;
757
758 TypeInfo
759 *type_info;
760
761 /*
762 Load system fonts.
763 */
764 (void) exception;
765 result=FcInit();
766 if (result == 0)
767 return(MagickFalse);
768 font_config=FcConfigGetCurrent();
769 if (font_config == (FcConfig *) NULL)
770 return(MagickFalse);
771 FcConfigSetRescanInterval(font_config,0);
772 font_set=(FcFontSet *) NULL;
773 object_set=FcObjectSetBuild(FC_FULLNAME,FC_FAMILY,FC_STYLE,FC_SLANT,
774 FC_WIDTH,FC_WEIGHT,FC_FILE,(char *) NULL);
775 if (object_set != (FcObjectSet *) NULL)
776 {
777 pattern=FcPatternCreate();
778 if (pattern != (FcPattern *) NULL)
779 {
780 font_set=FcFontList(font_config,pattern,object_set);
781 FcPatternDestroy(pattern);
782 }
783 FcObjectSetDestroy(object_set);
784 }
785 if (font_set == (FcFontSet *) NULL)
786 {
787 FcConfigDestroy(font_config);
788 return(MagickFalse);
789 }
790 for (i=0; i < (ssize_t) font_set->nfont; i++)
791 {
792 status=FcPatternGetString(font_set->fonts[i],FC_FAMILY,0,&family);
793 if (status != FcResultMatch)
794 continue;
795 status=FcPatternGetString(font_set->fonts[i],FC_FILE,0,&file);
796 if (status != FcResultMatch)
797 continue;
798 *extension='\0';
799 GetPathComponent((const char *) file,ExtensionPath,extension);
800 if ((*extension != '\0') && (LocaleCompare(extension,"gz") == 0))
801 continue;
802 type_info=(TypeInfo *) AcquireMagickMemory(sizeof(*type_info));
803 if (type_info == (TypeInfo *) NULL)
804 continue;
805 (void) memset(type_info,0,sizeof(*type_info));
806 type_info->path=ConstantString("System Fonts");
807 type_info->signature=MagickCoreSignature;
808 (void) CopyMagickString(name,"Unknown",MaxTextExtent);
809 status=FcPatternGetString(font_set->fonts[i],FC_FULLNAME,0,&fullname);
810 if ((status == FcResultMatch) && (fullname != (FcChar8 *) NULL))
811 (void) CopyMagickString(name,(const char *) fullname,MaxTextExtent);
812 else
813 {
814 if (family != (FcChar8 *) NULL)
815 (void) CopyMagickString(name,(const char *) family,MaxTextExtent);
816 status=FcPatternGetString(font_set->fonts[i],FC_STYLE,0,&style);
817 if ((status == FcResultMatch) && (style != (FcChar8 *) NULL) &&
818 (LocaleCompare((const char *) style,"Regular") != 0))
819 {
820 (void) ConcatenateMagickString(name," ",MaxTextExtent);
821 (void) ConcatenateMagickString(name,(const char *) style,
822 MaxTextExtent);
823 }
824 }
825 type_info->name=ConstantString(name);
826 (void) SubstituteString(&type_info->name," ","-");
827 type_info->family=ConstantString((const char *) family);
828 status=FcPatternGetInteger(font_set->fonts[i],FC_SLANT,0,&slant);
829 type_info->style=NormalStyle;
830 if (slant == FC_SLANT_ITALIC)
831 type_info->style=ItalicStyle;
832 if (slant == FC_SLANT_OBLIQUE)
833 type_info->style=ObliqueStyle;
834 status=FcPatternGetInteger(font_set->fonts[i],FC_WIDTH,0,&width);
835 type_info->stretch=NormalStretch;
836 if (width >= FC_WIDTH_ULTRACONDENSED)
837 type_info->stretch=UltraCondensedStretch;
838 if (width >= FC_WIDTH_EXTRACONDENSED)
839 type_info->stretch=ExtraCondensedStretch;
840 if (width >= FC_WIDTH_CONDENSED)
841 type_info->stretch=CondensedStretch;
842 if (width >= FC_WIDTH_SEMICONDENSED)
843 type_info->stretch=SemiCondensedStretch;
844 if (width >= FC_WIDTH_NORMAL)
845 type_info->stretch=NormalStretch;
846 if (width >= FC_WIDTH_SEMIEXPANDED)
847 type_info->stretch=SemiExpandedStretch;
848 if (width >= FC_WIDTH_EXPANDED)
849 type_info->stretch=ExpandedStretch;
850 if (width >= FC_WIDTH_EXTRAEXPANDED)
851 type_info->stretch=ExtraExpandedStretch;
852 if (width >= FC_WIDTH_ULTRAEXPANDED)
853 type_info->stretch=UltraExpandedStretch;
854 type_info->weight=400;
855 status=FcPatternGetInteger(font_set->fonts[i],FC_WEIGHT,0,&weight);
856 if (weight >= FC_WEIGHT_THIN)
857 type_info->weight=100;
858 if (weight >= FC_WEIGHT_EXTRALIGHT)
859 type_info->weight=200;
860 if (weight >= FC_WEIGHT_LIGHT)
861 type_info->weight=300;
862 if (weight >= FC_WEIGHT_NORMAL)
863 type_info->weight=400;
864 if (weight >= FC_WEIGHT_MEDIUM)
865 type_info->weight=500;
866 if (weight >= FC_WEIGHT_DEMIBOLD)
867 type_info->weight=600;
868 if (weight >= FC_WEIGHT_BOLD)
869 type_info->weight=700;
870 if (weight >= FC_WEIGHT_EXTRABOLD)
871 type_info->weight=800;
872 if (weight >= FC_WEIGHT_BLACK)
873 type_info->weight=900;
874 type_info->glyphs=ConstantString((const char *) file);
875 (void) AddValueToSplayTree(type_cache,type_info->name,type_info);
876 }
877 FcFontSetDestroy(font_set);
878 FcConfigDestroy(font_config);
879 return(MagickTrue);
880 }
881 #endif
882
IsTypeTreeInstantiated(ExceptionInfo * exception)883 static MagickBooleanType IsTypeTreeInstantiated(ExceptionInfo *exception)
884 {
885 if (type_cache == (SplayTreeInfo *) NULL)
886 {
887 if (type_semaphore == (SemaphoreInfo *) NULL)
888 ActivateSemaphoreInfo(&type_semaphore);
889 LockSemaphoreInfo(type_semaphore);
890 if (type_cache == (SplayTreeInfo *) NULL)
891 {
892 SplayTreeInfo
893 *splay_tree;
894
895 splay_tree=AcquireTypeCache(MagickTypeFilename,exception);
896 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
897 (void) NTAcquireTypeCache(splay_tree,exception);
898 #endif
899 #if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
900 (void) LoadFontConfigFonts(splay_tree,exception);
901 #endif
902 type_cache=splay_tree;
903 }
904 UnlockSemaphoreInfo(type_semaphore);
905 }
906 return(type_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
907 }
908
909 /*
910 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
911 % %
912 % %
913 % %
914 % L i s t T y p e I n f o %
915 % %
916 % %
917 % %
918 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
919 %
920 % ListTypeInfo() lists the fonts to a file.
921 %
922 % The format of the ListTypeInfo method is:
923 %
924 % MagickBooleanType ListTypeInfo(FILE *file,ExceptionInfo *exception)
925 %
926 % A description of each parameter follows.
927 %
928 % o file: An pointer to a FILE.
929 %
930 % o exception: return any errors or warnings in this structure.
931 %
932 */
ListTypeInfo(FILE * file,ExceptionInfo * exception)933 MagickExport MagickBooleanType ListTypeInfo(FILE *file,ExceptionInfo *exception)
934 {
935 char
936 weight[MaxTextExtent];
937
938 const char
939 *family,
940 *glyphs,
941 *name,
942 *path,
943 *stretch,
944 *style;
945
946 const TypeInfo
947 **type_info;
948
949 ssize_t
950 i;
951
952 size_t
953 number_fonts;
954
955 if (file == (FILE *) NULL)
956 file=stdout;
957 number_fonts=0;
958 type_info=GetTypeInfoList("*",&number_fonts,exception);
959 if (type_info == (const TypeInfo **) NULL)
960 return(MagickFalse);
961 *weight='\0';
962 path=(const char *) NULL;
963 for (i=0; i < (ssize_t) number_fonts; i++)
964 {
965 if (type_info[i]->stealth != MagickFalse)
966 continue;
967 if (((path == (const char *) NULL) ||
968 (LocaleCompare(path,type_info[i]->path) != 0)) &&
969 (type_info[i]->path != (char *) NULL))
970 (void) FormatLocaleFile(file,"\nPath: %s\n",type_info[i]->path);
971 path=type_info[i]->path;
972 name="unknown";
973 if (type_info[i]->name != (char *) NULL)
974 name=type_info[i]->name;
975 family="unknown";
976 if (type_info[i]->family != (char *) NULL)
977 family=type_info[i]->family;
978 style=CommandOptionToMnemonic(MagickStyleOptions,type_info[i]->style);
979 stretch=CommandOptionToMnemonic(MagickStretchOptions,type_info[i]->stretch);
980 glyphs="unknown";
981 if (type_info[i]->glyphs != (char *) NULL)
982 glyphs=type_info[i]->glyphs;
983 (void) FormatLocaleString(weight,MaxTextExtent,"%.20g",(double)
984 type_info[i]->weight);
985 (void) FormatLocaleFile(file," Font: %s\n",name);
986 (void) FormatLocaleFile(file," family: %s\n",family);
987 (void) FormatLocaleFile(file," style: %s\n",style);
988 (void) FormatLocaleFile(file," stretch: %s\n",stretch);
989 (void) FormatLocaleFile(file," weight: %s\n",weight);
990 (void) FormatLocaleFile(file," glyphs: %s\n",glyphs);
991 }
992 (void) fflush(file);
993 type_info=(const TypeInfo **) RelinquishMagickMemory((void *) type_info);
994 return(MagickTrue);
995 }
996
997 /*
998 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
999 % %
1000 % %
1001 % %
1002 + L o a d T y p e C a c h e %
1003 % %
1004 % %
1005 % %
1006 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1007 %
1008 % LoadTypeCache() loads the type configurations which provides a mapping
1009 % between type attributes and a type name.
1010 %
1011 % The format of the LoadTypeCache method is:
1012 %
1013 % MagickBooleanType LoadTypeCache(SplayTreeInfo *cache,const char *xml,
1014 % const char *filename,const size_t depth,ExceptionInfo *exception)
1015 %
1016 % A description of each parameter follows:
1017 %
1018 % o xml: The type list in XML format.
1019 %
1020 % o filename: The type list filename.
1021 %
1022 % o depth: depth of <include /> statements.
1023 %
1024 % o exception: return any errors or warnings in this structure.
1025 %
1026 */
SetTypeNodePath(const char * filename,char * font_path,const char * token,char ** target)1027 static inline MagickBooleanType SetTypeNodePath(const char *filename,
1028 char *font_path,const char *token,char **target)
1029 {
1030 char
1031 *path;
1032
1033 path=ConstantString(token);
1034 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1035 if (strchr(path,'@') != (char *) NULL)
1036 SubstituteString(&path,"@ghostscript_font_path@",font_path);
1037 #endif
1038 if (IsPathAccessible(path) == MagickFalse)
1039 {
1040 /*
1041 Relative path.
1042 */
1043 path=DestroyString(path);
1044 GetPathComponent(filename,HeadPath,font_path);
1045 (void) ConcatenateMagickString(font_path,DirectorySeparator,
1046 MaxTextExtent);
1047 (void) ConcatenateMagickString(font_path,token,MaxTextExtent);
1048 path=ConstantString(font_path);
1049 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1050 if (strchr(path,'@') != (char *) NULL)
1051 SubstituteString(&path,"@ghostscript_font_path@","");
1052 #endif
1053 if (IsPathAccessible(path) == MagickFalse)
1054 {
1055 path=DestroyString(path);
1056 return(MagickFalse);
1057 }
1058 }
1059
1060 *target=path;
1061 return(MagickTrue);
1062 }
1063
LoadTypeCache(SplayTreeInfo * cache,const char * xml,const char * filename,const size_t depth,ExceptionInfo * exception)1064 static MagickBooleanType LoadTypeCache(SplayTreeInfo *cache,const char *xml,
1065 const char *filename,const size_t depth,ExceptionInfo *exception)
1066 {
1067 char
1068 font_path[MaxTextExtent],
1069 keyword[MaxTextExtent],
1070 *token;
1071
1072 const char
1073 *q;
1074
1075 MagickStatusType
1076 status;
1077
1078 size_t
1079 extent;
1080
1081 TypeInfo
1082 *type_info;
1083
1084 /*
1085 Load the type map file.
1086 */
1087 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1088 "Loading type configure file \"%s\" ...",filename);
1089 if (xml == (const char *) NULL)
1090 return(MagickFalse);
1091 status=MagickTrue;
1092 type_info=(TypeInfo *) NULL;
1093 token=AcquireString(xml);
1094 extent=strlen(token)+MaxTextExtent;
1095 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1096 /*
1097 Determine the Ghostscript font path.
1098 */
1099 *font_path='\0';
1100 if (NTGhostscriptFonts(font_path,MaxTextExtent-2))
1101 (void) ConcatenateMagickString(font_path,DirectorySeparator,MaxTextExtent);
1102 #endif
1103 for (q=(char *) xml; *q != '\0'; )
1104 {
1105 /*
1106 Interpret XML.
1107 */
1108 (void) GetNextToken(q,&q,extent,token);
1109 if (*token == '\0')
1110 break;
1111 (void) CopyMagickString(keyword,token,MaxTextExtent);
1112 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1113 {
1114 /*
1115 Doctype element.
1116 */
1117 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1118 (void) GetNextToken(q,&q,extent,token);
1119 continue;
1120 }
1121 if (LocaleNCompare(keyword,"<!--",4) == 0)
1122 {
1123 /*
1124 Comment element.
1125 */
1126 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1127 (void) GetNextToken(q,&q,extent,token);
1128 continue;
1129 }
1130 if (LocaleCompare(keyword,"<include") == 0)
1131 {
1132 /*
1133 Include element.
1134 */
1135 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1136 {
1137 (void) CopyMagickString(keyword,token,MaxTextExtent);
1138 (void) GetNextToken(q,&q,extent,token);
1139 if (*token != '=')
1140 continue;
1141 (void) GetNextToken(q,&q,extent,token);
1142 if (LocaleCompare(keyword,"file") == 0)
1143 {
1144 if (depth > MagickMaxRecursionDepth)
1145 (void) ThrowMagickException(exception,GetMagickModule(),
1146 ConfigureError,"IncludeNodeNestedTooDeeply","`%s'",token);
1147 else
1148 {
1149 char
1150 path[MaxTextExtent],
1151 *xml;
1152
1153 ExceptionInfo
1154 *sans_exception;
1155
1156 *path='\0';
1157 GetPathComponent(filename,HeadPath,path);
1158 if (*path != '\0')
1159 (void) ConcatenateMagickString(path,DirectorySeparator,
1160 MaxTextExtent);
1161 if (*token == *DirectorySeparator)
1162 (void) CopyMagickString(path,token,MaxTextExtent);
1163 else
1164 (void) ConcatenateMagickString(path,token,MaxTextExtent);
1165 sans_exception=AcquireExceptionInfo();
1166 xml=FileToString(path,~0UL,sans_exception);
1167 sans_exception=DestroyExceptionInfo(sans_exception);
1168 if (xml != (char *) NULL)
1169 {
1170 status&=LoadTypeCache(cache,xml,path,depth+1,
1171 exception);
1172 xml=(char *) RelinquishMagickMemory(xml);
1173 }
1174 }
1175 }
1176 }
1177 continue;
1178 }
1179 if (LocaleCompare(keyword,"<type") == 0)
1180 {
1181 /*
1182 Type element.
1183 */
1184 type_info=(TypeInfo *) AcquireMagickMemory(sizeof(*type_info));
1185 if (type_info == (TypeInfo *) NULL)
1186 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
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=IsMagickTrue(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=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 MagickExport MagickBooleanType TypeComponentGenesis(void)
1350 {
1351 if (type_semaphore == (SemaphoreInfo *) NULL)
1352 type_semaphore=AllocateSemaphoreInfo();
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 MagickExport 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 DestroySemaphoreInfo(&type_semaphore);
1383 }
1384