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