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