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