2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % TTTTT Y Y PPPP EEEEE %
13 % MagickCore Image Type Methods %
20 % Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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/hashmap.h"
50 #include "MagickCore/log.h"
51 #include "MagickCore/memory_.h"
52 #include "MagickCore/nt-feature.h"
53 #include "MagickCore/nt-base-private.h"
54 #include "MagickCore/option.h"
55 #include "MagickCore/semaphore.h"
56 #include "MagickCore/splay-tree.h"
57 #include "MagickCore/string_.h"
58 #include "MagickCore/string-private.h"
59 #include "MagickCore/type.h"
60 #include "MagickCore/type-private.h"
61 #include "MagickCore/token.h"
62 #include "MagickCore/utility.h"
63 #include "MagickCore/utility-private.h"
64 #include "MagickCore/xml-tree.h"
65 #if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
66 # include "fontconfig/fontconfig.h"
67 #if (FC_VERSION < 20209)
68 #undef FC_WEIGHT_LIGHT
69 #define FC_WIDTH "width" /* Int */
70 #define FC_WIDTH_ULTRACONDENSED 50
71 #define FC_WIDTH_EXTRACONDENSED 63
72 #define FC_WIDTH_CONDENSED 75
73 #define FC_WIDTH_SEMICONDENSED 87
74 #define FC_WIDTH_NORMAL 100
75 #define FC_WIDTH_SEMIEXPANDED 113
76 #define FC_WIDTH_EXPANDED 125
77 #define FC_WIDTH_EXTRAEXPANDED 150
78 #define FC_WIDTH_ULTRAEXPANDED 200
80 #define FC_WEIGHT_THIN 0
81 #define FC_WEIGHT_EXTRALIGHT 40
82 #define FC_WEIGHT_ULTRALIGHT FC_WEIGHT_EXTRALIGHT
83 #define FC_WEIGHT_LIGHT 50
84 #define FC_WEIGHT_BOOK 75
85 #define FC_WEIGHT_REGULAR 80
86 #define FC_WEIGHT_NORMAL FC_WEIGHT_REGULAR
87 #define FC_WEIGHT_MEDIUM 100
88 #define FC_WEIGHT_DEMIBOLD 180
89 #define FC_WEIGHT_SEMIBOLD FC_WEIGHT_DEMIBOLD
90 #define FC_WEIGHT_BOLD 200
91 #define FC_WEIGHT_EXTRABOLD 205
92 #define FC_WEIGHT_ULTRABOLD FC_WEIGHT_EXTRABOLD
93 #define FC_WEIGHT_BLACK 210
94 #define FC_WEIGHT_HEAVY FC_WEIGHT_BLACK
101 #define MagickTypeFilename "type.xml"
107 *TypeMap = (const char *)
108 "<?xml version=\"1.0\"?>"
110 " <type stealth=\"True\" name=\"fixed\" family=\"helvetica\"/>"
111 " <type stealth=\"True\" name=\"helvetica\" family=\"helvetica\"/>"
118 *type_semaphore = (SemaphoreInfo *) NULL;
121 *type_cache = (SplayTreeInfo *) NULL;
124 Forward declarations.
126 static MagickBooleanType
127 IsTypeTreeInstantiated(ExceptionInfo *),
128 LoadTypeCache(const char *,const char *,const size_t,ExceptionInfo *);
131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
135 % A c q u i r e T y p e S p l a y T r e e %
139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
141 % AcquireTypeCache() caches one or more type configuration files which
142 % provides a mapping between type attributes and a type name.
144 % The format of the AcquireTypeCache method is:
146 % SplayTreeInfo *AcquireTypeCache(const char *filename,
147 % ExceptionInfo *exception)
149 % A description of each parameter follows:
151 % o filename: the font file name.
153 % o exception: return any errors or warnings in this structure.
157 static void *DestroyTypeNode(void *type_info)
162 p=(TypeInfo *) type_info;
163 if (p->path != (char *) NULL)
164 p->path=DestroyString(p->path);
165 if (p->name != (char *) NULL)
166 p->name=DestroyString(p->name);
167 if (p->description != (char *) NULL)
168 p->description=DestroyString(p->description);
169 if (p->family != (char *) NULL)
170 p->family=DestroyString(p->family);
171 if (p->encoding != (char *) NULL)
172 p->encoding=DestroyString(p->encoding);
173 if (p->foundry != (char *) NULL)
174 p->foundry=DestroyString(p->foundry);
175 if (p->format != (char *) NULL)
176 p->format=DestroyString(p->format);
177 if (p->metrics != (char *) NULL)
178 p->metrics=DestroyString(p->metrics);
179 if (p->glyphs != (char *) NULL)
180 p->glyphs=DestroyString(p->glyphs);
181 return(RelinquishMagickMemory(p));
184 static SplayTreeInfo *AcquireTypeCache(const char *filename,
185 ExceptionInfo *exception)
187 #if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
188 return(LoadTypeCache(TypeMap,"built-in",0,exception));
206 type_cache=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL,
208 if (type_cache == (SplayTreeInfo *) NULL)
209 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
212 options=GetConfigureOptions(filename,exception);
213 option=(const StringInfo *) GetNextValueInLinkedList(options);
214 while (option != (const StringInfo *) NULL)
216 (void) CopyMagickString(path,GetStringInfoPath(option),MaxTextExtent);
217 status&=LoadTypeCache((const char *) GetStringInfoDatum(option),
218 GetStringInfoPath(option),0,exception);
219 option=(const StringInfo *) GetNextValueInLinkedList(options);
221 options=DestroyConfigureOptions(options);
222 font_path=GetEnvironmentValue("MAGICK_FONT_PATH");
223 if (font_path != (char *) NULL)
229 Search MAGICK_FONT_PATH.
231 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s",font_path,
232 DirectorySeparator,filename);
233 option=FileToString(path,~0UL,exception);
234 if (option != (void *) NULL)
236 status&=LoadTypeCache(option,path,0,exception);
237 option=DestroyString(option);
239 font_path=DestroyString(font_path);
241 if ((type_cache == (SplayTreeInfo *) NULL) ||
242 (GetNumberOfNodesInSplayTree(type_cache) == 0))
243 status&=LoadTypeCache(TypeMap,"built-in",0,exception);
249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
253 + G e t T y p e I n f o %
257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
259 % GetTypeInfo searches the type list for the specified name and if found
260 % returns attributes for that type.
262 % The format of the GetTypeInfo method is:
264 % const TypeInfo *GetTypeInfo(const char *name,ExceptionInfo *exception)
266 % A description of each parameter follows:
268 % o name: the type name.
270 % o exception: return any errors or warnings in this structure.
273 MagickExport const TypeInfo *GetTypeInfo(const char *name,
274 ExceptionInfo *exception)
279 assert(exception != (ExceptionInfo *) NULL);
280 if (IsTypeTreeInstantiated(exception) == MagickFalse)
281 return((const TypeInfo *) NULL);
282 LockSemaphoreInfo(type_semaphore);
283 if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
285 ResetSplayTreeIterator(type_cache);
286 type_info=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
287 UnlockSemaphoreInfo(type_semaphore);
290 type_info=(const TypeInfo *) GetValueFromSplayTree(type_cache,name);
291 UnlockSemaphoreInfo(type_semaphore);
296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
300 + G e t T y p e I n f o B y F a m i l y %
304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
306 % GetTypeInfoByFamily() searches the type list for the specified family and if
307 % found returns attributes for that type.
309 % Type substitution and scoring algorithm contributed by Bob Friesenhahn.
311 % The format of the GetTypeInfoByFamily method is:
313 % const TypeInfo *GetTypeInfoByFamily(const char *family,
314 % const StyleType style,const StretchType stretch,
315 % const size_t weight,ExceptionInfo *exception)
317 % A description of each parameter follows:
319 % o family: the type family.
321 % o style: the type style.
323 % o stretch: the type stretch.
325 % o weight: the type weight.
327 % o exception: return any errors or warnings in this structure.
331 static inline size_t MagickMax(const size_t x,const size_t y)
338 static inline size_t MagickMin(const size_t x,const size_t y)
345 MagickExport const TypeInfo *GetTypeInfoByFamily(const char *family,
346 const StyleType style,const StretchType stretch,const size_t weight,
347 ExceptionInfo *exception)
349 typedef struct _Fontmap
359 register const TypeInfo
371 { "fixed", "courier" },
372 { "modern","courier" },
373 { "monotype corsiva", "courier" },
374 { "news gothic", "helvetica" },
375 { "system", "courier" },
376 { "terminal", "courier" },
377 { "wingdings", "symbol" },
386 Check for an exact type match.
388 (void) GetTypeInfo("*",exception);
389 if (type_cache == (SplayTreeInfo *) NULL)
390 return((TypeInfo *) NULL);
391 LockSemaphoreInfo(type_semaphore);
392 ResetSplayTreeIterator(type_cache);
393 type_info=(const TypeInfo *) NULL;
394 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
395 while (p != (const TypeInfo *) NULL)
397 if (p->family == (char *) NULL)
399 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
402 if (family == (const char *) NULL)
404 if ((LocaleCompare(p->family,"arial") != 0) &&
405 (LocaleCompare(p->family,"helvetica") != 0))
407 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
412 if (LocaleCompare(p->family,family) != 0)
414 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
417 if ((style != UndefinedStyle) && (style != AnyStyle) && (p->style != style))
419 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
422 if ((stretch != UndefinedStretch) && (stretch != AnyStretch) &&
423 (p->stretch != stretch))
425 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
428 if ((weight != 0) && (p->weight != weight))
430 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
436 UnlockSemaphoreInfo(type_semaphore);
437 if (type_info != (const TypeInfo *) NULL)
440 Check for types in the same family.
443 LockSemaphoreInfo(type_semaphore);
444 ResetSplayTreeIterator(type_cache);
445 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
446 while (p != (const TypeInfo *) NULL)
448 if (p->family == (char *) NULL)
450 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
453 if (family == (const char *) NULL)
455 if ((LocaleCompare(p->family,"arial") != 0) &&
456 (LocaleCompare(p->family,"helvetica") != 0))
458 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
463 if (LocaleCompare(p->family,family) != 0)
465 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
469 if ((style == UndefinedStyle) || (style == AnyStyle) || (p->style == style))
472 if (((style == ItalicStyle) || (style == ObliqueStyle)) &&
473 ((p->style == ItalicStyle) || (p->style == ObliqueStyle)))
478 score+=(16*(800-((ssize_t) MagickMax(MagickMin(weight,900),p->weight)-
479 (ssize_t) MagickMin(MagickMin(weight,900),p->weight))))/800;
480 if ((stretch == UndefinedStretch) || (stretch == AnyStretch))
484 range=(ssize_t) UltraExpandedStretch-(ssize_t) NormalStretch;
485 score+=(8*(range-((ssize_t) MagickMax(stretch,p->stretch)-
486 (ssize_t) MagickMin(stretch,p->stretch))))/range;
488 if (score > max_score)
493 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
495 UnlockSemaphoreInfo(type_semaphore);
496 if (type_info != (const TypeInfo *) NULL)
499 Check for table-based substitution match.
501 for (i=0; fontmap[i].name != (char *) NULL; i++)
503 if (family == (const char *) NULL)
505 if ((LocaleCompare(fontmap[i].name,"arial") != 0) &&
506 (LocaleCompare(fontmap[i].name,"helvetica") != 0))
510 if (LocaleCompare(fontmap[i].name,family) != 0)
512 type_info=GetTypeInfoByFamily(fontmap[i].substitute,style,stretch,weight,
516 if (type_info != (const TypeInfo *) NULL)
518 (void) ThrowMagickException(exception,GetMagickModule(),TypeError,
519 "FontSubstitutionRequired","`%s'",type_info->family);
522 if (family != (const char *) NULL)
523 type_info=GetTypeInfoByFamily((const char *) NULL,style,stretch,weight,
529 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
533 % G e t T y p e I n f o L i s t %
537 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
539 % GetTypeInfoList() returns any fonts that match the specified pattern.
541 % The format of the GetTypeInfoList function is:
543 % const TypeInfo **GetTypeInfoList(const char *pattern,
544 % size_t *number_fonts,ExceptionInfo *exception)
546 % A description of each parameter follows:
548 % o pattern: Specifies a pointer to a text string containing a pattern.
550 % o number_fonts: This integer returns the number of types in the list.
552 % o exception: return any errors or warnings in this structure.
556 #if defined(__cplusplus) || defined(c_plusplus)
560 static int TypeInfoCompare(const void *x,const void *y)
566 p=(const TypeInfo **) x,
567 q=(const TypeInfo **) y;
568 if (LocaleCompare((*p)->path,(*q)->path) == 0)
569 return(LocaleCompare((*p)->name,(*q)->name));
570 return(LocaleCompare((*p)->path,(*q)->path));
573 #if defined(__cplusplus) || defined(c_plusplus)
577 MagickExport const TypeInfo **GetTypeInfoList(const char *pattern,
578 size_t *number_fonts,ExceptionInfo *exception)
583 register const TypeInfo
592 assert(pattern != (char *) NULL);
593 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
594 assert(number_fonts != (size_t *) NULL);
596 p=GetTypeInfo("*",exception);
597 if (p == (const TypeInfo *) NULL)
598 return((const TypeInfo **) NULL);
599 fonts=(const TypeInfo **) AcquireQuantumMemory((size_t)
600 GetNumberOfNodesInSplayTree(type_cache)+1UL,sizeof(*fonts));
601 if (fonts == (const TypeInfo **) NULL)
602 return((const TypeInfo **) NULL);
606 LockSemaphoreInfo(type_semaphore);
607 ResetSplayTreeIterator(type_cache);
608 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
609 for (i=0; p != (const TypeInfo *) NULL; )
611 if ((p->stealth == MagickFalse) &&
612 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
614 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
616 UnlockSemaphoreInfo(type_semaphore);
617 qsort((void *) fonts,(size_t) i,sizeof(*fonts),TypeInfoCompare);
618 fonts[i]=(TypeInfo *) NULL;
619 *number_fonts=(size_t) i;
624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
628 % G e t T y p e L i s t %
632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
634 % GetTypeList() returns any fonts that match the specified pattern.
636 % The format of the GetTypeList function is:
638 % char **GetTypeList(const char *pattern,size_t *number_fonts,
639 % ExceptionInfo *exception)
641 % A description of each parameter follows:
643 % o pattern: Specifies a pointer to a text string containing a pattern.
645 % o number_fonts: This integer returns the number of fonts in the list.
647 % o exception: return any errors or warnings in this structure.
651 #if defined(__cplusplus) || defined(c_plusplus)
655 static int TypeCompare(const void *x,const void *y)
663 return(LocaleCompare(*p,*q));
666 #if defined(__cplusplus) || defined(c_plusplus)
670 MagickExport char **GetTypeList(const char *pattern,size_t *number_fonts,
671 ExceptionInfo *exception)
676 register const TypeInfo
685 assert(pattern != (char *) NULL);
686 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
687 assert(number_fonts != (size_t *) NULL);
689 p=GetTypeInfo("*",exception);
690 if (p == (const TypeInfo *) NULL)
691 return((char **) NULL);
692 fonts=(char **) AcquireQuantumMemory((size_t)
693 GetNumberOfNodesInSplayTree(type_cache)+1UL,sizeof(*fonts));
694 if (fonts == (char **) NULL)
695 return((char **) NULL);
699 LockSemaphoreInfo(type_semaphore);
700 ResetSplayTreeIterator(type_cache);
701 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
702 for (i=0; p != (const TypeInfo *) NULL; )
704 if ((p->stealth == MagickFalse) &&
705 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
706 fonts[i++]=ConstantString(p->name);
707 p=(const TypeInfo *) GetNextValueInSplayTree(type_cache);
709 UnlockSemaphoreInfo(type_semaphore);
710 qsort((void *) fonts,(size_t) i,sizeof(*fonts),TypeCompare);
711 fonts[i]=(char *) NULL;
712 *number_fonts=(size_t) i;
717 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
721 + I s T y p e T r e e I n s t a n t i a t e d %
725 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
727 % IsTypeTreeInstantiated() etermines if the type tree is instantiated. If
728 % not, it instantiates the tree and returns it.
730 % The format of the IsTypeInstantiated method is:
732 % MagickBooleanType IsTypeTreeInstantiated(ExceptionInfo *exception)
734 % A description of each parameter follows.
736 % o exception: return any errors or warnings in this structure.
740 #if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
741 MagickExport MagickBooleanType LoadFontConfigFonts(SplayTreeInfo *type_cache,
742 ExceptionInfo *exception)
744 #if !defined(FC_FULLNAME)
745 #define FC_FULLNAME "fullname"
749 extension[MaxTextExtent],
788 font_config=FcInitLoadConfigAndFonts();
789 if (font_config == (FcConfig *) NULL)
791 font_set=(FcFontSet *) NULL;
792 object_set=FcObjectSetBuild(FC_FULLNAME,FC_FAMILY,FC_STYLE,FC_SLANT,
793 FC_WIDTH,FC_WEIGHT,FC_FILE,(char *) NULL);
794 if (object_set != (FcObjectSet *) NULL)
796 pattern=FcPatternCreate();
797 if (pattern != (FcPattern *) NULL)
799 font_set=FcFontList(0,pattern,object_set);
800 FcPatternDestroy(pattern);
802 FcObjectSetDestroy(object_set);
804 if (font_set == (FcFontSet *) NULL)
806 FcConfigDestroy(font_config);
809 for (i=0; i < (ssize_t) font_set->nfont; i++)
811 status=FcPatternGetString(font_set->fonts[i],FC_FAMILY,0,&family);
812 if (status != FcResultMatch)
814 status=FcPatternGetString(font_set->fonts[i],FC_FILE,0,&file);
815 if (status != FcResultMatch)
818 GetPathComponent((const char *) file,ExtensionPath,extension);
819 if ((*extension != '\0') && (LocaleCompare(extension,"gz") == 0))
821 type_info=(TypeInfo *) AcquireMagickMemory(sizeof(*type_info));
822 if (type_info == (TypeInfo *) NULL)
824 (void) ResetMagickMemory(type_info,0,sizeof(*type_info));
825 type_info->path=ConstantString("System Fonts");
826 type_info->signature=MagickSignature;
827 (void) CopyMagickString(name,"Unknown",MaxTextExtent);
828 status=FcPatternGetString(font_set->fonts[i],FC_FULLNAME,0,&fullname);
829 if ((status == FcResultMatch) && (fullname != (FcChar8 *) NULL))
830 (void) CopyMagickString(name,(const char *) fullname,MaxTextExtent);
833 if (family != (FcChar8 *) NULL)
834 (void) CopyMagickString(name,(const char *) family,MaxTextExtent);
835 status=FcPatternGetString(font_set->fonts[i],FC_STYLE,0,&style);
836 if ((status == FcResultMatch) && (style != (FcChar8 *) NULL) &&
837 (LocaleCompare((const char *) style,"Regular") != 0))
839 (void) ConcatenateMagickString(name," ",MaxTextExtent);
840 (void) ConcatenateMagickString(name,(const char *) style,
844 type_info->name=ConstantString(name);
845 (void) SubstituteString(&type_info->name," ","-");
846 type_info->family=ConstantString((const char *) family);
847 status=FcPatternGetInteger(font_set->fonts[i],FC_SLANT,0,&slant);
848 type_info->style=NormalStyle;
849 if (slant == FC_SLANT_ITALIC)
850 type_info->style=ItalicStyle;
851 if (slant == FC_SLANT_OBLIQUE)
852 type_info->style=ObliqueStyle;
853 status=FcPatternGetInteger(font_set->fonts[i],FC_WIDTH,0,&width);
854 type_info->stretch=NormalStretch;
855 if (width >= FC_WIDTH_ULTRACONDENSED)
856 type_info->stretch=UltraCondensedStretch;
857 if (width >= FC_WIDTH_EXTRACONDENSED)
858 type_info->stretch=ExtraCondensedStretch;
859 if (width >= FC_WIDTH_CONDENSED)
860 type_info->stretch=CondensedStretch;
861 if (width >= FC_WIDTH_SEMICONDENSED)
862 type_info->stretch=SemiCondensedStretch;
863 if (width >= FC_WIDTH_NORMAL)
864 type_info->stretch=NormalStretch;
865 if (width >= FC_WIDTH_SEMIEXPANDED)
866 type_info->stretch=SemiExpandedStretch;
867 if (width >= FC_WIDTH_EXPANDED)
868 type_info->stretch=ExpandedStretch;
869 if (width >= FC_WIDTH_EXTRAEXPANDED)
870 type_info->stretch=ExtraExpandedStretch;
871 if (width >= FC_WIDTH_ULTRAEXPANDED)
872 type_info->stretch=UltraExpandedStretch;
873 type_info->weight=400;
874 status=FcPatternGetInteger(font_set->fonts[i],FC_WEIGHT,0,&weight);
875 if (weight >= FC_WEIGHT_THIN)
876 type_info->weight=100;
877 if (weight >= FC_WEIGHT_EXTRALIGHT)
878 type_info->weight=200;
879 if (weight >= FC_WEIGHT_LIGHT)
880 type_info->weight=300;
881 if (weight >= FC_WEIGHT_NORMAL)
882 type_info->weight=400;
883 if (weight >= FC_WEIGHT_MEDIUM)
884 type_info->weight=500;
885 if (weight >= FC_WEIGHT_DEMIBOLD)
886 type_info->weight=600;
887 if (weight >= FC_WEIGHT_BOLD)
888 type_info->weight=700;
889 if (weight >= FC_WEIGHT_EXTRABOLD)
890 type_info->weight=800;
891 if (weight >= FC_WEIGHT_BLACK)
892 type_info->weight=900;
893 type_info->glyphs=ConstantString((const char *) file);
894 (void) AddValueToSplayTree(type_cache,type_info->name,type_info);
896 FcFontSetDestroy(font_set);
897 FcConfigDestroy(font_config);
902 static MagickBooleanType IsTypeTreeInstantiated(ExceptionInfo *exception)
904 if (type_cache == (SplayTreeInfo *) NULL)
906 if (type_semaphore == (SemaphoreInfo *) NULL)
907 ActivateSemaphoreInfo(&type_semaphore);
908 LockSemaphoreInfo(type_semaphore);
909 if (type_cache == (SplayTreeInfo *) NULL)
911 type_cache=AcquireTypeCache(MagickTypeFilename,exception);
912 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
913 (void) NTAcquireTypeCache(type_cache,exception);
915 #if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
916 (void) LoadFontConfigFonts(type_cache,exception);
919 UnlockSemaphoreInfo(type_semaphore);
921 return(type_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
929 % L i s t T y p e I n f o %
933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
935 % ListTypeInfo() lists the fonts to a file.
937 % The format of the ListTypeInfo method is:
939 % MagickBooleanType ListTypeInfo(FILE *file,ExceptionInfo *exception)
941 % A description of each parameter follows.
943 % o file: An pointer to a FILE.
945 % o exception: return any errors or warnings in this structure.
948 MagickExport MagickBooleanType ListTypeInfo(FILE *file,ExceptionInfo *exception)
951 weight[MaxTextExtent];
970 if (file == (FILE *) NULL)
973 type_info=GetTypeInfoList("*",&number_fonts,exception);
974 if (type_info == (const TypeInfo **) NULL)
977 path=(const char *) NULL;
978 for (i=0; i < (ssize_t) number_fonts; i++)
980 if (type_info[i]->stealth != MagickFalse)
982 if (((path == (const char *) NULL) ||
983 (LocaleCompare(path,type_info[i]->path) != 0)) &&
984 (type_info[i]->path != (char *) NULL))
985 (void) FormatLocaleFile(file,"\nPath: %s\n",type_info[i]->path);
986 path=type_info[i]->path;
988 if (type_info[i]->name != (char *) NULL)
989 name=type_info[i]->name;
991 if (type_info[i]->family != (char *) NULL)
992 family=type_info[i]->family;
993 style=CommandOptionToMnemonic(MagickStyleOptions,type_info[i]->style);
994 stretch=CommandOptionToMnemonic(MagickStretchOptions,type_info[i]->stretch);
996 if (type_info[i]->glyphs != (char *) NULL)
997 glyphs=type_info[i]->glyphs;
998 (void) FormatLocaleString(weight,MaxTextExtent,"%.20g",(double)
999 type_info[i]->weight);
1000 (void) FormatLocaleFile(file," Font: %s\n",name);
1001 (void) FormatLocaleFile(file," family: %s\n",family);
1002 (void) FormatLocaleFile(file," style: %s\n",style);
1003 (void) FormatLocaleFile(file," stretch: %s\n",stretch);
1004 (void) FormatLocaleFile(file," weight: %s\n",weight);
1005 (void) FormatLocaleFile(file," glyphs: %s\n",glyphs);
1007 (void) fflush(file);
1008 type_info=(const TypeInfo **) RelinquishMagickMemory((void *) type_info);
1013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1017 + L o a d T y p e L i s t %
1021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1023 % LoadTypeCache() loads the type configurations which provides a mapping
1024 % between type attributes and a type name.
1026 % The format of the LoadTypeCache method is:
1028 % MagickBooleanType LoadTypeCache(const char *xml,const char *filename,
1029 % const size_t depth,ExceptionInfo *exception)
1031 % A description of each parameter follows:
1033 % o xml: The type list in XML format.
1035 % o filename: The type list filename.
1037 % o depth: depth of <include /> statements.
1039 % o exception: return any errors or warnings in this structure.
1043 static inline MagickBooleanType SetTypeNodePath(const char *filename,
1044 char *font_path,const char *token,char **target)
1049 path=ConstantString(token);
1050 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1051 if (strchr(path,'@') != (char *) NULL)
1052 SubstituteString(&path,"@ghostscript_font_path@",font_path);
1054 if (IsPathAccessible(path) == MagickFalse)
1059 path=DestroyString(path);
1060 GetPathComponent(filename,HeadPath,font_path);
1061 (void) ConcatenateMagickString(font_path,DirectorySeparator,
1063 (void) ConcatenateMagickString(font_path,token,MaxTextExtent);
1064 path=ConstantString(font_path);
1065 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1066 if (strchr(path,'@') != (char *) NULL)
1067 SubstituteString(&path,"@ghostscript_font_path@","");
1069 if (IsPathAccessible(path) == MagickFalse)
1071 path=DestroyString(path);
1072 return(MagickFalse);
1080 static MagickBooleanType LoadTypeCache(const char *xml,const char *filename,
1081 const size_t depth,ExceptionInfo *exception)
1084 font_path[MaxTextExtent],
1085 keyword[MaxTextExtent],
1098 Load the type map file.
1100 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1101 "Loading type configure file \"%s\" ...",filename);
1102 if (xml == (const char *) NULL)
1103 return(MagickFalse);
1104 if (type_cache == (SplayTreeInfo *) NULL)
1106 type_cache=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL,
1108 if (type_cache == (SplayTreeInfo *) NULL)
1110 ThrowFileException(exception,ResourceLimitError,
1111 "MemoryAllocationFailed",filename);
1112 return(MagickFalse);
1116 type_info=(TypeInfo *) NULL;
1117 token=AcquireString(xml);
1118 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1120 Determine the Ghostscript font path.
1123 if (NTGhostscriptFonts(font_path,MaxTextExtent-2))
1124 (void) ConcatenateMagickString(font_path,DirectorySeparator,MaxTextExtent);
1126 for (q=(char *) xml; *q != '\0'; )
1131 GetMagickToken(q,&q,token);
1134 (void) CopyMagickString(keyword,token,MaxTextExtent);
1135 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1140 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1141 GetMagickToken(q,&q,token);
1144 if (LocaleNCompare(keyword,"<!--",4) == 0)
1149 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1150 GetMagickToken(q,&q,token);
1153 if (LocaleCompare(keyword,"<include") == 0)
1158 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1160 (void) CopyMagickString(keyword,token,MaxTextExtent);
1161 GetMagickToken(q,&q,token);
1164 GetMagickToken(q,&q,token);
1165 if (LocaleCompare(keyword,"file") == 0)
1168 (void) ThrowMagickException(exception,GetMagickModule(),
1169 ConfigureError,"IncludeNodeNestedTooDeeply","`%s'",token);
1173 path[MaxTextExtent],
1180 GetPathComponent(filename,HeadPath,path);
1182 (void) ConcatenateMagickString(path,DirectorySeparator,
1184 if (*token == *DirectorySeparator)
1185 (void) CopyMagickString(path,token,MaxTextExtent);
1187 (void) ConcatenateMagickString(path,token,MaxTextExtent);
1188 sans_exception=AcquireExceptionInfo();
1189 xml=FileToString(path,~0UL,sans_exception);
1190 sans_exception=DestroyExceptionInfo(sans_exception);
1191 if (xml != (char *) NULL)
1193 status=LoadTypeCache(xml,path,depth+1,exception);
1194 xml=(char *) RelinquishMagickMemory(xml);
1201 if (LocaleCompare(keyword,"<type") == 0)
1206 type_info=(TypeInfo *) AcquireMagickMemory(sizeof(*type_info));
1207 if (type_info == (TypeInfo *) NULL)
1208 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1209 (void) ResetMagickMemory(type_info,0,sizeof(*type_info));
1210 type_info->path=ConstantString(filename);
1211 type_info->signature=MagickSignature;
1214 if (type_info == (TypeInfo *) NULL)
1216 if (LocaleCompare(keyword,"/>") == 0)
1218 status=AddValueToSplayTree(type_cache,type_info->name,type_info);
1219 if (status == MagickFalse)
1220 (void) ThrowMagickException(exception,GetMagickModule(),
1221 ResourceLimitError,"MemoryAllocationFailed","`%s'",type_info->name);
1222 type_info=(TypeInfo *) NULL;
1225 GetMagickToken(q,(const char **) NULL,token);
1228 GetMagickToken(q,&q,token);
1229 GetMagickToken(q,&q,token);
1235 if (LocaleCompare((char *) keyword,"encoding") == 0)
1237 type_info->encoding=ConstantString(token);
1245 if (LocaleCompare((char *) keyword,"face") == 0)
1247 type_info->face=StringToUnsignedLong(token);
1250 if (LocaleCompare((char *) keyword,"family") == 0)
1252 type_info->family=ConstantString(token);
1255 if (LocaleCompare((char *) keyword,"format") == 0)
1257 type_info->format=ConstantString(token);
1260 if (LocaleCompare((char *) keyword,"foundry") == 0)
1262 type_info->foundry=ConstantString(token);
1265 if (LocaleCompare((char *) keyword,"fullname") == 0)
1267 type_info->description=ConstantString(token);
1275 if (LocaleCompare((char *) keyword,"glyphs") == 0)
1277 if (SetTypeNodePath(filename,font_path,token,&type_info->glyphs) ==
1279 type_info=(TypeInfo *) DestroyTypeNode(type_info);
1287 if (LocaleCompare((char *) keyword,"metrics") == 0)
1289 if (SetTypeNodePath(filename,font_path,token,&type_info->metrics) ==
1291 type_info=(TypeInfo *) DestroyTypeNode(type_info);
1299 if (LocaleCompare((char *) keyword,"name") == 0)
1301 type_info->name=ConstantString(token);
1309 if (LocaleCompare((char *) keyword,"stealth") == 0)
1311 type_info->stealth=IsStringTrue(token);
1314 if (LocaleCompare((char *) keyword,"stretch") == 0)
1316 type_info->stretch=(StretchType) ParseCommandOption(
1317 MagickStretchOptions,MagickFalse,token);
1320 if (LocaleCompare((char *) keyword,"style") == 0)
1322 type_info->style=(StyleType) ParseCommandOption(MagickStyleOptions,
1331 if (LocaleCompare((char *) keyword,"weight") == 0)
1333 type_info->weight=StringToUnsignedLong(token);
1334 if (LocaleCompare(token,"bold") == 0)
1335 type_info->weight=700;
1336 if (LocaleCompare(token,"normal") == 0)
1337 type_info->weight=400;
1346 token=(char *) RelinquishMagickMemory(token);
1351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1355 + T y p e C o m p o n e n t G e n e s i s %
1359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1361 % TypeComponentGenesis() instantiates the type component.
1363 % The format of the TypeComponentGenesis method is:
1365 % MagickBooleanType TypeComponentGenesis(void)
1368 MagickPrivate MagickBooleanType TypeComponentGenesis(void)
1370 type_semaphore=AcquireSemaphoreInfo();
1375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1379 + T y p e C o m p o n e n t T e r m i n u s %
1383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1385 % TypeComponentTerminus() destroy type component.
1387 % The format of the TypeComponentTerminus method is:
1389 % void TypeComponentTerminus(void)
1392 MagickPrivate void TypeComponentTerminus(void)
1394 if (type_semaphore == (SemaphoreInfo *) NULL)
1395 ActivateSemaphoreInfo(&type_semaphore);
1396 LockSemaphoreInfo(type_semaphore);
1397 if (type_cache != (SplayTreeInfo *) NULL)
1398 type_cache=DestroySplayTree(type_cache);
1399 UnlockSemaphoreInfo(type_semaphore);
1400 RelinquishSemaphoreInfo(&type_semaphore);