| OLD | NEW |
| 1 /***************************************************************************/ | 1 /***************************************************************************/ |
| 2 /* */ | 2 /* */ |
| 3 /* cf2hints.c */ | 3 /* cf2hints.c */ |
| 4 /* */ | 4 /* */ |
| 5 /* Adobe's code for handling CFF hints (body). */ | 5 /* Adobe's code for handling CFF hints (body). */ |
| 6 /* */ | 6 /* */ |
| 7 /* Copyright 2007-2013 Adobe Systems Incorporated. */ | 7 /* Copyright 2007-2014 Adobe Systems Incorporated. */ |
| 8 /* */ | 8 /* */ |
| 9 /* This software, and all works of authorship, whether in source or */ | 9 /* This software, and all works of authorship, whether in source or */ |
| 10 /* object code form as indicated by the copyright notice(s) included */ | 10 /* object code form as indicated by the copyright notice(s) included */ |
| 11 /* herein (collectively, the "Work") is made available, and may only be */ | 11 /* herein (collectively, the "Work") is made available, and may only be */ |
| 12 /* used, modified, and distributed under the FreeType Project License, */ | 12 /* used, modified, and distributed under the FreeType Project License, */ |
| 13 /* LICENSE.TXT. Additionally, subject to the terms and conditions of the */ | 13 /* LICENSE.TXT. Additionally, subject to the terms and conditions of the */ |
| 14 /* FreeType Project License, each contributor to the Work hereby grants */ | 14 /* FreeType Project License, each contributor to the Work hereby grants */ |
| 15 /* to any individual or legal entity exercising permissions granted by */ | 15 /* to any individual or legal entity exercising permissions granted by */ |
| 16 /* the FreeType Project License and this section (hereafter, "You" or */ | 16 /* the FreeType Project License and this section (hereafter, "You" or */ |
| 17 /* "Your") a perpetual, worldwide, non-exclusive, no-charge, */ | 17 /* "Your") a perpetual, worldwide, non-exclusive, no-charge, */ |
| (...skipping 12 matching lines...) Expand all Loading... |
| 30 /* */ | 30 /* */ |
| 31 /* By using, modifying, or distributing the Work you indicate that you */ | 31 /* By using, modifying, or distributing the Work you indicate that you */ |
| 32 /* have read and understood the terms and conditions of the */ | 32 /* have read and understood the terms and conditions of the */ |
| 33 /* FreeType Project License as well as those provided in this section, */ | 33 /* FreeType Project License as well as those provided in this section, */ |
| 34 /* and you accept them fully. */ | 34 /* and you accept them fully. */ |
| 35 /* */ | 35 /* */ |
| 36 /***************************************************************************/ | 36 /***************************************************************************/ |
| 37 | 37 |
| 38 | 38 |
| 39 #include "cf2ft.h" | 39 #include "cf2ft.h" |
| 40 #include "../../include/freetype/internal/ftdebug.h" | 40 #include FT_INTERNAL_DEBUG_H |
| 41 | 41 |
| 42 #include "cf2glue.h" | 42 #include "cf2glue.h" |
| 43 #include "cf2font.h" | 43 #include "cf2font.h" |
| 44 #include "cf2hints.h" | 44 #include "cf2hints.h" |
| 45 #include "cf2intrp.h" | 45 #include "cf2intrp.h" |
| 46 | 46 |
| 47 | 47 |
| 48 /*************************************************************************/ | 48 /*************************************************************************/ |
| 49 /* */ | 49 /* */ |
| 50 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ | 50 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 { | 297 { |
| 298 return hintmap->isValid; | 298 return hintmap->isValid; |
| 299 } | 299 } |
| 300 | 300 |
| 301 | 301 |
| 302 /* transform character space coordinate to device space using hint map */ | 302 /* transform character space coordinate to device space using hint map */ |
| 303 static CF2_Fixed | 303 static CF2_Fixed |
| 304 cf2_hintmap_map( CF2_HintMap hintmap, | 304 cf2_hintmap_map( CF2_HintMap hintmap, |
| 305 CF2_Fixed csCoord ) | 305 CF2_Fixed csCoord ) |
| 306 { | 306 { |
| 307 FT_ASSERT( hintmap->isValid ); /* must call Build before Map */ | |
| 308 FT_ASSERT( hintmap->lastIndex < CF2_MAX_HINT_EDGES ); | |
| 309 | |
| 310 if ( hintmap->count == 0 || ! hintmap->hinted ) | 307 if ( hintmap->count == 0 || ! hintmap->hinted ) |
| 311 { | 308 { |
| 312 /* there are no hints; use uniform scale and zero offset */ | 309 /* there are no hints; use uniform scale and zero offset */ |
| 313 return FT_MulFix( csCoord, hintmap->scale ); | 310 return FT_MulFix( csCoord, hintmap->scale ); |
| 314 } | 311 } |
| 315 else | 312 else |
| 316 { | 313 { |
| 317 /* start linear search from last hit */ | 314 /* start linear search from last hit */ |
| 318 CF2_UInt i = hintmap->lastIndex; | 315 CF2_UInt i = hintmap->lastIndex; |
| 319 | 316 |
| 317 FT_ASSERT( hintmap->lastIndex < CF2_MAX_HINT_EDGES ); |
| 320 | 318 |
| 321 /* search up */ | 319 /* search up */ |
| 322 while ( i < hintmap->count - 1 && | 320 while ( i < hintmap->count - 1 && |
| 323 csCoord >= hintmap->edge[i + 1].csCoord ) | 321 csCoord >= hintmap->edge[i + 1].csCoord ) |
| 324 i += 1; | 322 i += 1; |
| 325 | 323 |
| 326 /* search down */ | 324 /* search down */ |
| 327 while ( i > 0 && csCoord < hintmap->edge[i].csCoord ) | 325 while ( i > 0 && csCoord < hintmap->edge[i].csCoord ) |
| 328 i -= 1; | 326 i -= 1; |
| 329 | 327 |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 589 } | 587 } |
| 590 | 588 |
| 591 /* paired edges must be in proper order */ | 589 /* paired edges must be in proper order */ |
| 592 FT_ASSERT( !isPair || | 590 FT_ASSERT( !isPair || |
| 593 topHintEdge->csCoord >= bottomHintEdge->csCoord ); | 591 topHintEdge->csCoord >= bottomHintEdge->csCoord ); |
| 594 | 592 |
| 595 /* linear search to find index value of insertion point */ | 593 /* linear search to find index value of insertion point */ |
| 596 indexInsert = 0; | 594 indexInsert = 0; |
| 597 for ( ; indexInsert < hintmap->count; indexInsert++ ) | 595 for ( ; indexInsert < hintmap->count; indexInsert++ ) |
| 598 { | 596 { |
| 599 if ( hintmap->edge[indexInsert].csCoord > firstHintEdge->csCoord ) | 597 if ( hintmap->edge[indexInsert].csCoord >= firstHintEdge->csCoord ) |
| 600 break; | 598 break; |
| 601 } | 599 } |
| 602 | 600 |
| 603 /* | 601 /* |
| 604 * Discard any hints that overlap in character space. Most often, | 602 * Discard any hints that overlap in character space. Most often, this |
| 605 * this is while building the initial map, but in theory, it can also | 603 * is while building the initial map, where captured hints from all |
| 606 * occur because of darkening. | 604 * zones are combined. Define overlap to include hints that `touch' |
| 605 * (overlap zero). Hiragino Sans/Gothic fonts have numerous hints that |
| 606 * touch. Some fonts have non-ideographic glyphs that overlap our |
| 607 * synthetic hints. |
| 608 * |
| 609 * Overlap also occurs when darkening stem hints that are close. |
| 607 * | 610 * |
| 608 */ | 611 */ |
| 609 if ( indexInsert < hintmap->count ) | 612 if ( indexInsert < hintmap->count ) |
| 610 { | 613 { |
| 611 /* we are inserting before an existing edge: */ | 614 /* we are inserting before an existing edge: */ |
| 615 /* verify that an existing edge is not the same */ |
| 616 if ( hintmap->edge[indexInsert].csCoord == firstHintEdge->csCoord ) |
| 617 return; /* ignore overlapping stem hint */ |
| 618 |
| 612 /* verify that a new pair does not straddle the next edge */ | 619 /* verify that a new pair does not straddle the next edge */ |
| 613 if ( isPair && | 620 if ( isPair && |
| 614 hintmap->edge[indexInsert].csCoord < secondHintEdge->csCoord ) | 621 hintmap->edge[indexInsert].csCoord <= secondHintEdge->csCoord ) |
| 615 return; /* ignore overlapping stem hint */ | 622 return; /* ignore overlapping stem hint */ |
| 616 | 623 |
| 617 /* verify that we are not inserting between paired edges */ | 624 /* verify that we are not inserting between paired edges */ |
| 618 if ( cf2_hint_isPairTop( &hintmap->edge[indexInsert] ) ) | 625 if ( cf2_hint_isPairTop( &hintmap->edge[indexInsert] ) ) |
| 619 return; /* ignore overlapping stem hint */ | 626 return; /* ignore overlapping stem hint */ |
| 620 } | 627 } |
| 621 | 628 |
| 622 /* recompute device space locations using initial hint map */ | 629 /* recompute device space locations using initial hint map */ |
| 623 if ( cf2_hintmap_isValid( hintmap->initialHintMap ) && | 630 if ( cf2_hintmap_isValid( hintmap->initialHintMap ) && |
| 624 !cf2_hint_isLocked( firstHintEdge ) ) | 631 !cf2_hint_isLocked( firstHintEdge ) ) |
| (...skipping 13 matching lines...) Expand all Loading... |
| 638 | 645 |
| 639 | 646 |
| 640 firstHintEdge->dsCoord = midpoint - halfWidth; | 647 firstHintEdge->dsCoord = midpoint - halfWidth; |
| 641 secondHintEdge->dsCoord = midpoint + halfWidth; | 648 secondHintEdge->dsCoord = midpoint + halfWidth; |
| 642 } | 649 } |
| 643 else | 650 else |
| 644 firstHintEdge->dsCoord = cf2_hintmap_map( hintmap->initialHintMap, | 651 firstHintEdge->dsCoord = cf2_hintmap_map( hintmap->initialHintMap, |
| 645 firstHintEdge->csCoord ); | 652 firstHintEdge->csCoord ); |
| 646 } | 653 } |
| 647 | 654 |
| 648 /* discard any hints that overlap in device space; this can occur */ | 655 /* |
| 649 /* because locked hints have been moved to align with blue zones */ | 656 * Discard any hints that overlap in device space; this can occur |
| 657 * because locked hints have been moved to align with blue zones. |
| 658 * |
| 659 * TODO: Although we might correct this later during adjustment, we |
| 660 * don't currently have a way to delete a conflicting hint once it has |
| 661 * been inserted. See v2.030 MinionPro-Regular, 12 ppem darkened, |
| 662 * initial hint map for second path, glyph 945 (the perispomeni (tilde) |
| 663 * in U+1F6E, Greek omega with psili and perispomeni). Darkening is |
| 664 * 25. Pair 667,747 initially conflicts in design space with top edge |
| 665 * 660. This is because 667 maps to 7.87, and the top edge was |
| 666 * captured by a zone at 8.0. The pair is later successfully inserted |
| 667 * in a zone without the top edge. In this zone it is adjusted to 8.0, |
| 668 * and no longer conflicts with the top edge in design space. This |
| 669 * means it can be included in yet a later zone which does have the top |
| 670 * edge hint. This produces a small mismatch between the first and |
| 671 * last points of this path, even though the hint masks are the same. |
| 672 * The density map difference is tiny (1/256). |
| 673 * |
| 674 */ |
| 675 |
| 650 if ( indexInsert > 0 ) | 676 if ( indexInsert > 0 ) |
| 651 { | 677 { |
| 652 /* we are inserting after an existing edge */ | 678 /* we are inserting after an existing edge */ |
| 653 if ( firstHintEdge->dsCoord < hintmap->edge[indexInsert - 1].dsCoord ) | 679 if ( firstHintEdge->dsCoord < hintmap->edge[indexInsert - 1].dsCoord ) |
| 654 return; | 680 return; |
| 655 } | 681 } |
| 656 | 682 |
| 657 if ( indexInsert < hintmap->count ) | 683 if ( indexInsert < hintmap->count ) |
| 658 { | 684 { |
| 659 /* we are inserting before an existing edge */ | 685 /* we are inserting before an existing edge */ |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 718 */ | 744 */ |
| 719 FT_LOCAL_DEF( void ) | 745 FT_LOCAL_DEF( void ) |
| 720 cf2_hintmap_build( CF2_HintMap hintmap, | 746 cf2_hintmap_build( CF2_HintMap hintmap, |
| 721 CF2_ArrStack hStemHintArray, | 747 CF2_ArrStack hStemHintArray, |
| 722 CF2_ArrStack vStemHintArray, | 748 CF2_ArrStack vStemHintArray, |
| 723 CF2_HintMask hintMask, | 749 CF2_HintMask hintMask, |
| 724 CF2_Fixed hintOrigin, | 750 CF2_Fixed hintOrigin, |
| 725 FT_Bool initialMap ) | 751 FT_Bool initialMap ) |
| 726 { | 752 { |
| 727 FT_Byte* maskPtr; | 753 FT_Byte* maskPtr; |
| 728 FT_Byte* maskEndPtr; // add by Xiaochuan_Liu | |
| 729 | 754 |
| 730 CF2_Font font = hintmap->font; | 755 CF2_Font font = hintmap->font; |
| 731 CF2_HintMaskRec tempHintMask; | 756 CF2_HintMaskRec tempHintMask; |
| 732 | 757 |
| 733 size_t bitCount, i; | 758 size_t bitCount, i; |
| 734 FT_Byte maskByte; | 759 FT_Byte maskByte; |
| 735 | 760 |
| 736 | 761 |
| 737 /* check whether initial map is constructed */ | 762 /* check whether initial map is constructed */ |
| 738 if ( !initialMap && !cf2_hintmap_isValid( hintmap->initialHintMap ) ) | 763 if ( !initialMap && !cf2_hintmap_isValid( hintmap->initialHintMap ) ) |
| 739 { | 764 { |
| 740 /* make recursive call with initialHintMap and temporary mask; */ | 765 /* make recursive call with initialHintMap and temporary mask; */ |
| 741 /* temporary mask will get all bits set, below */ | 766 /* temporary mask will get all bits set, below */ |
| 742 cf2_hintmask_init( &tempHintMask, hintMask->error ); | 767 cf2_hintmask_init( &tempHintMask, hintMask->error ); |
| 743 cf2_hintmap_build( hintmap->initialHintMap, | 768 cf2_hintmap_build( hintmap->initialHintMap, |
| 744 hStemHintArray, | 769 hStemHintArray, |
| 745 vStemHintArray, | 770 vStemHintArray, |
| 746 &tempHintMask, | 771 &tempHintMask, |
| 747 hintOrigin, | 772 hintOrigin, |
| 748 TRUE ); | 773 TRUE ); |
| 749 } | 774 } |
| 750 | 775 |
| 751 if ( !cf2_hintmask_isValid( hintMask ) ) | 776 if ( !cf2_hintmask_isValid( hintMask ) ) |
| 752 { | 777 { |
| 753 /* without a hint mask, assume all hints are active */ | 778 /* without a hint mask, assume all hints are active */ |
| 754 cf2_hintmask_setAll( hintMask, | 779 cf2_hintmask_setAll( hintMask, |
| 755 cf2_arrstack_size( hStemHintArray ) + | 780 cf2_arrstack_size( hStemHintArray ) + |
| 756 cf2_arrstack_size( vStemHintArray ) ); | 781 cf2_arrstack_size( vStemHintArray ) ); |
| 782 if ( !cf2_hintmask_isValid( hintMask ) ) |
| 783 return; /* too many stem hints */ |
| 757 } | 784 } |
| 758 | 785 |
| 759 /* begin by clearing the map */ | 786 /* begin by clearing the map */ |
| 760 hintmap->count = 0; | 787 hintmap->count = 0; |
| 761 hintmap->lastIndex = 0; | 788 hintmap->lastIndex = 0; |
| 762 | 789 |
| 763 /* make a copy of the hint mask so we can modify it */ | 790 /* make a copy of the hint mask so we can modify it */ |
| 764 tempHintMask = *hintMask; | 791 tempHintMask = *hintMask; |
| 765 maskPtr = cf2_hintmask_getMaskPtr( &tempHintMask ); | 792 maskPtr = cf2_hintmask_getMaskPtr( &tempHintMask ); |
| 766 maskEndPtr = maskPtr + ( CF2_MAX_HINTS + 7 ) / 8; | |
| 767 | |
| 768 | 793 |
| 769 /* use the hStem hints only, which are first in the mask */ | 794 /* use the hStem hints only, which are first in the mask */ |
| 770 /* TODO: compare this to cffhintmaskGetBitCount */ | |
| 771 bitCount = cf2_arrstack_size( hStemHintArray ); | 795 bitCount = cf2_arrstack_size( hStemHintArray ); |
| 772 | 796 |
| 797 /* Defense-in-depth. Should never return here. */ |
| 798 if ( bitCount > hintMask->bitCount ) |
| 799 return; |
| 800 |
| 773 /* synthetic embox hints get highest priority */ | 801 /* synthetic embox hints get highest priority */ |
| 774 if ( font->blues.doEmBoxHints ) | 802 if ( font->blues.doEmBoxHints ) |
| 775 { | 803 { |
| 776 CF2_HintRec dummy; | 804 CF2_HintRec dummy; |
| 777 | 805 |
| 778 | 806 |
| 779 cf2_hint_initZero( &dummy ); /* invalid hint map element */ | 807 cf2_hint_initZero( &dummy ); /* invalid hint map element */ |
| 780 | 808 |
| 781 /* ghost bottom */ | 809 /* ghost bottom */ |
| 782 cf2_hintmap_insertHint( hintmap, | 810 cf2_hintmap_insertHint( hintmap, |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 823 cf2_hintmap_insertHint( hintmap, &bottomHintEdge, &topHintEdge ); | 851 cf2_hintmap_insertHint( hintmap, &bottomHintEdge, &topHintEdge ); |
| 824 | 852 |
| 825 *maskPtr &= ~maskByte; /* turn off the bit for this hint */ | 853 *maskPtr &= ~maskByte; /* turn off the bit for this hint */ |
| 826 } | 854 } |
| 827 } | 855 } |
| 828 | 856 |
| 829 if ( ( i & 7 ) == 7 ) | 857 if ( ( i & 7 ) == 7 ) |
| 830 { | 858 { |
| 831 /* move to next mask byte */ | 859 /* move to next mask byte */ |
| 832 maskPtr++; | 860 maskPtr++; |
| 833 if (maskPtr >= maskEndPtr) | |
| 834 { | |
| 835 break; | |
| 836 } | |
| 837 | |
| 838 maskByte = 0x80; | 861 maskByte = 0x80; |
| 839 } | 862 } |
| 840 else | 863 else |
| 841 maskByte >>= 1; | 864 maskByte >>= 1; |
| 842 } | 865 } |
| 843 | 866 |
| 844 /* initial hint map includes only captured hints plus maybe one at 0 */ | 867 /* initial hint map includes only captured hints plus maybe one at 0 */ |
| 845 | 868 |
| 846 /* | 869 /* |
| 847 * TODO: There is a problem here because we are trying to build a | 870 * TODO: There is a problem here because we are trying to build a |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 888 | 911 |
| 889 cf2_hint_initZero( &invalid ); | 912 cf2_hint_initZero( &invalid ); |
| 890 cf2_hintmap_insertHint( hintmap, &edge, &invalid ); | 913 cf2_hintmap_insertHint( hintmap, &edge, &invalid ); |
| 891 } | 914 } |
| 892 } | 915 } |
| 893 else | 916 else |
| 894 { | 917 { |
| 895 /* insert remaining hints */ | 918 /* insert remaining hints */ |
| 896 | 919 |
| 897 maskPtr = cf2_hintmask_getMaskPtr( &tempHintMask ); | 920 maskPtr = cf2_hintmask_getMaskPtr( &tempHintMask ); |
| 898 maskEndPtr = maskPtr + ( CF2_MAX_HINTS + 7 ) / 8; | |
| 899 | 921 |
| 900 for ( i = 0, maskByte = 0x80; i < bitCount; i++ ) | 922 for ( i = 0, maskByte = 0x80; i < bitCount; i++ ) |
| 901 { | 923 { |
| 902 if ( maskByte & *maskPtr ) | 924 if ( maskByte & *maskPtr ) |
| 903 { | 925 { |
| 904 CF2_HintRec bottomHintEdge, topHintEdge; | 926 CF2_HintRec bottomHintEdge, topHintEdge; |
| 905 | 927 |
| 906 | 928 |
| 907 cf2_hint_init( &bottomHintEdge, | 929 cf2_hint_init( &bottomHintEdge, |
| 908 hStemHintArray, | 930 hStemHintArray, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 919 hintmap->scale, | 941 hintmap->scale, |
| 920 FALSE /* top */ ); | 942 FALSE /* top */ ); |
| 921 | 943 |
| 922 cf2_hintmap_insertHint( hintmap, &bottomHintEdge, &topHintEdge ); | 944 cf2_hintmap_insertHint( hintmap, &bottomHintEdge, &topHintEdge ); |
| 923 } | 945 } |
| 924 | 946 |
| 925 if ( ( i & 7 ) == 7 ) | 947 if ( ( i & 7 ) == 7 ) |
| 926 { | 948 { |
| 927 /* move to next mask byte */ | 949 /* move to next mask byte */ |
| 928 maskPtr++; | 950 maskPtr++; |
| 929 if (maskPtr >= maskEndPtr) | |
| 930 { | |
| 931 break; | |
| 932 } | |
| 933 maskByte = 0x80; | 951 maskByte = 0x80; |
| 934 } | 952 } |
| 935 else | 953 else |
| 936 maskByte >>= 1; | 954 maskByte >>= 1; |
| 937 } | 955 } |
| 938 } | 956 } |
| 939 | 957 |
| 940 /* | 958 /* |
| 941 * Note: The following line is a convenient place to break when | 959 * Note: The following line is a convenient place to break when |
| 942 * debugging hinting. Examine `hintmap->edge' for the list of | 960 * debugging hinting. Examine `hintmap->edge' for the list of |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1041 glyphpath->yOffset = font->darkenY; | 1059 glyphpath->yOffset = font->darkenY; |
| 1042 glyphpath->miterLimit = 2 * FT_MAX( | 1060 glyphpath->miterLimit = 2 * FT_MAX( |
| 1043 cf2_fixedAbs( glyphpath->xOffset ), | 1061 cf2_fixedAbs( glyphpath->xOffset ), |
| 1044 cf2_fixedAbs( glyphpath->yOffset ) ); | 1062 cf2_fixedAbs( glyphpath->yOffset ) ); |
| 1045 | 1063 |
| 1046 /* .1 character space unit */ | 1064 /* .1 character space unit */ |
| 1047 glyphpath->snapThreshold = cf2_floatToFixed( 0.1f ); | 1065 glyphpath->snapThreshold = cf2_floatToFixed( 0.1f ); |
| 1048 | 1066 |
| 1049 glyphpath->moveIsPending = TRUE; | 1067 glyphpath->moveIsPending = TRUE; |
| 1050 glyphpath->pathIsOpen = FALSE; | 1068 glyphpath->pathIsOpen = FALSE; |
| 1069 glyphpath->pathIsClosing = FALSE; |
| 1051 glyphpath->elemIsQueued = FALSE; | 1070 glyphpath->elemIsQueued = FALSE; |
| 1052 } | 1071 } |
| 1053 | 1072 |
| 1054 | 1073 |
| 1055 FT_LOCAL_DEF( void ) | 1074 FT_LOCAL_DEF( void ) |
| 1056 cf2_glyphpath_finalize( CF2_GlyphPath glyphpath ) | 1075 cf2_glyphpath_finalize( CF2_GlyphPath glyphpath ) |
| 1057 { | 1076 { |
| 1058 cf2_arrstack_finalize( &glyphpath->hintMoves ); | 1077 cf2_arrstack_finalize( &glyphpath->hintMoves ); |
| 1059 } | 1078 } |
| 1060 | 1079 |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1181 glyphpath->miterLimit ) | 1200 glyphpath->miterLimit ) |
| 1182 return FALSE; | 1201 return FALSE; |
| 1183 | 1202 |
| 1184 return TRUE; | 1203 return TRUE; |
| 1185 } | 1204 } |
| 1186 | 1205 |
| 1187 | 1206 |
| 1188 /* | 1207 /* |
| 1189 * Push the cached element (glyphpath->prevElem*) to the outline | 1208 * Push the cached element (glyphpath->prevElem*) to the outline |
| 1190 * consumer. When a darkening offset is used, the end point of the | 1209 * consumer. When a darkening offset is used, the end point of the |
| 1191 * cached element may be adjusted to an intersection point or it may be | 1210 * cached element may be adjusted to an intersection point or we may |
| 1192 * connected by a line to the current element. This calculation must | 1211 * synthesize a connecting line to the current element. If we are |
| 1193 * use a HintMap that was valid at the time the element was saved. For | 1212 * closing a subpath, we may also generate a connecting line to the start |
| 1194 * the first point in a subpath, that is a saved HintMap. For most | 1213 * point. |
| 1195 * elements, it just means the caller has delayed building a HintMap | 1214 * |
| 1196 * from the current HintMask. | 1215 * This is where Character Space (CS) is converted to Device Space (DS) |
| 1216 * using a hint map. This calculation must use a HintMap that was valid |
| 1217 * at the time the element was saved. For the first point in a subpath, |
| 1218 * that is a saved HintMap. For most elements, it just means the caller |
| 1219 * has delayed building a HintMap from the current HintMask. |
| 1197 * | 1220 * |
| 1198 * Transform each point with outerTransform and call the outline | 1221 * Transform each point with outerTransform and call the outline |
| 1199 * callbacks. This is a general 3x3 transform: | 1222 * callbacks. This is a general 3x3 transform: |
| 1200 * | 1223 * |
| 1201 * x' = a*x + c*y + tx, y' = b*x + d*y + ty | 1224 * x' = a*x + c*y + tx, y' = b*x + d*y + ty |
| 1202 * | 1225 * |
| 1203 * but it uses 4 elements from CF2_Font and the translation part | 1226 * but it uses 4 elements from CF2_Font and the translation part |
| 1204 * from CF2_GlyphPath. | 1227 * from CF2_GlyphPath. |
| 1205 * | 1228 * |
| 1206 */ | 1229 */ |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1256 } | 1279 } |
| 1257 | 1280 |
| 1258 params.pt0 = glyphpath->currentDS; | 1281 params.pt0 = glyphpath->currentDS; |
| 1259 | 1282 |
| 1260 switch( glyphpath->prevElemOp ) | 1283 switch( glyphpath->prevElemOp ) |
| 1261 { | 1284 { |
| 1262 case CF2_PathOpLineTo: | 1285 case CF2_PathOpLineTo: |
| 1263 params.op = CF2_PathOpLineTo; | 1286 params.op = CF2_PathOpLineTo; |
| 1264 | 1287 |
| 1265 /* note: pt2 and pt3 are unused */ | 1288 /* note: pt2 and pt3 are unused */ |
| 1266 cf2_glyphpath_hintPoint( glyphpath, | |
| 1267 hintmap, | |
| 1268 ¶ms.pt1, | |
| 1269 glyphpath->prevElemP1.x, | |
| 1270 glyphpath->prevElemP1.y ); | |
| 1271 | 1289 |
| 1272 glyphpath->callbacks->lineTo( glyphpath->callbacks, ¶ms ); | 1290 if ( close ) |
| 1291 { |
| 1292 /* use first hint map if closing */ |
| 1293 cf2_glyphpath_hintPoint( glyphpath, |
| 1294 &glyphpath->firstHintMap, |
| 1295 ¶ms.pt1, |
| 1296 glyphpath->prevElemP1.x, |
| 1297 glyphpath->prevElemP1.y ); |
| 1298 } |
| 1299 else |
| 1300 { |
| 1301 cf2_glyphpath_hintPoint( glyphpath, |
| 1302 hintmap, |
| 1303 ¶ms.pt1, |
| 1304 glyphpath->prevElemP1.x, |
| 1305 glyphpath->prevElemP1.y ); |
| 1306 } |
| 1273 | 1307 |
| 1274 glyphpath->currentDS = params.pt1; | 1308 /* output only non-zero length lines */ |
| 1309 if ( params.pt0.x != params.pt1.x || params.pt0.y != params.pt1.y ) |
| 1310 { |
| 1311 glyphpath->callbacks->lineTo( glyphpath->callbacks, ¶ms ); |
| 1275 | 1312 |
| 1313 glyphpath->currentDS = params.pt1; |
| 1314 } |
| 1276 break; | 1315 break; |
| 1277 | 1316 |
| 1278 case CF2_PathOpCubeTo: | 1317 case CF2_PathOpCubeTo: |
| 1279 params.op = CF2_PathOpCubeTo; | 1318 params.op = CF2_PathOpCubeTo; |
| 1280 | 1319 |
| 1281 /* TODO: should we intersect the interior joins (p1-p2 and p2-p3)? */ | 1320 /* TODO: should we intersect the interior joins (p1-p2 and p2-p3)? */ |
| 1282 cf2_glyphpath_hintPoint( glyphpath, | 1321 cf2_glyphpath_hintPoint( glyphpath, |
| 1283 hintmap, | 1322 hintmap, |
| 1284 ¶ms.pt1, | 1323 ¶ms.pt1, |
| 1285 glyphpath->prevElemP1.x, | 1324 glyphpath->prevElemP1.x, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1302 break; | 1341 break; |
| 1303 } | 1342 } |
| 1304 | 1343 |
| 1305 if ( !useIntersection || close ) | 1344 if ( !useIntersection || close ) |
| 1306 { | 1345 { |
| 1307 /* insert connecting line between end of previous element and start */ | 1346 /* insert connecting line between end of previous element and start */ |
| 1308 /* of current one */ | 1347 /* of current one */ |
| 1309 /* note: at the end of a subpath, we might do both, so use `nextP0' */ | 1348 /* note: at the end of a subpath, we might do both, so use `nextP0' */ |
| 1310 /* before we change it, below */ | 1349 /* before we change it, below */ |
| 1311 | 1350 |
| 1312 cf2_glyphpath_hintPoint( glyphpath, | 1351 if ( close ) |
| 1313 hintmap, | 1352 { |
| 1314 ¶ms.pt1, | 1353 /* if we are closing the subpath, then nextP0 is in the first */ |
| 1315 nextP0->x, | 1354 /* hint zone */ |
| 1316 nextP0->y ); | 1355 cf2_glyphpath_hintPoint( glyphpath, |
| 1356 &glyphpath->firstHintMap, |
| 1357 ¶ms.pt1, |
| 1358 nextP0->x, |
| 1359 nextP0->y ); |
| 1360 } |
| 1361 else |
| 1362 { |
| 1363 cf2_glyphpath_hintPoint( glyphpath, |
| 1364 hintmap, |
| 1365 ¶ms.pt1, |
| 1366 nextP0->x, |
| 1367 nextP0->y ); |
| 1368 } |
| 1317 | 1369 |
| 1318 if ( params.pt1.x != glyphpath->currentDS.x || | 1370 if ( params.pt1.x != glyphpath->currentDS.x || |
| 1319 params.pt1.y != glyphpath->currentDS.y ) | 1371 params.pt1.y != glyphpath->currentDS.y ) |
| 1320 { | 1372 { |
| 1321 /* length is nonzero */ | 1373 /* length is nonzero */ |
| 1322 params.op = CF2_PathOpLineTo; | 1374 params.op = CF2_PathOpLineTo; |
| 1323 params.pt0 = glyphpath->currentDS; | 1375 params.pt0 = glyphpath->currentDS; |
| 1324 | 1376 |
| 1325 /* note: pt2 and pt3 are unused */ | 1377 /* note: pt2 and pt3 are unused */ |
| 1326 glyphpath->callbacks->lineTo( glyphpath->callbacks, ¶ms ); | 1378 glyphpath->callbacks->lineTo( glyphpath->callbacks, ¶ms ); |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1502 if ( -dx > -2 * dy ) | 1554 if ( -dx > -2 * dy ) |
| 1503 { | 1555 { |
| 1504 /* -x */ | 1556 /* -x */ |
| 1505 *x = 0; | 1557 *x = 0; |
| 1506 *y = 2 * glyphpath->yOffset; | 1558 *y = 2 * glyphpath->yOffset; |
| 1507 } | 1559 } |
| 1508 else if ( -dy > -2 * dx ) | 1560 else if ( -dy > -2 * dx ) |
| 1509 { | 1561 { |
| 1510 /* -y */ | 1562 /* -y */ |
| 1511 *x = -glyphpath->xOffset; | 1563 *x = -glyphpath->xOffset; |
| 1512 *y = glyphpath->xOffset; | 1564 *y = glyphpath->yOffset; |
| 1513 } | 1565 } |
| 1514 else | 1566 else |
| 1515 { | 1567 { |
| 1516 /* -x -y */ | 1568 /* -x -y */ |
| 1517 *x = FT_MulFix( cf2_floatToFixed( -0.7 ), | 1569 *x = FT_MulFix( cf2_floatToFixed( -0.7 ), |
| 1518 glyphpath->xOffset ); | 1570 glyphpath->xOffset ); |
| 1519 *y = FT_MulFix( cf2_floatToFixed( 1.0 + 0.7 ), | 1571 *y = FT_MulFix( cf2_floatToFixed( 1.0 + 0.7 ), |
| 1520 glyphpath->yOffset ); | 1572 glyphpath->yOffset ); |
| 1521 } | 1573 } |
| 1522 } | 1574 } |
| 1523 } | 1575 } |
| 1524 } | 1576 } |
| 1525 | 1577 |
| 1526 | 1578 |
| 1579 /* |
| 1580 * The functions cf2_glyphpath_{moveTo,lineTo,curveTo,closeOpenPath} are |
| 1581 * called by the interpreter with Character Space (CS) coordinates. Each |
| 1582 * path element is placed into a queue of length one to await the |
| 1583 * calculation of the following element. At that time, the darkening |
| 1584 * offset of the following element is known and joins can be computed, |
| 1585 * including possible modification of this element, before mapping to |
| 1586 * Device Space (DS) and passing it on to the outline consumer. |
| 1587 * |
| 1588 */ |
| 1527 FT_LOCAL_DEF( void ) | 1589 FT_LOCAL_DEF( void ) |
| 1528 cf2_glyphpath_moveTo( CF2_GlyphPath glyphpath, | 1590 cf2_glyphpath_moveTo( CF2_GlyphPath glyphpath, |
| 1529 CF2_Fixed x, | 1591 CF2_Fixed x, |
| 1530 CF2_Fixed y ) | 1592 CF2_Fixed y ) |
| 1531 { | 1593 { |
| 1532 cf2_glyphpath_closeOpenPath( glyphpath ); | 1594 cf2_glyphpath_closeOpenPath( glyphpath ); |
| 1533 | 1595 |
| 1534 /* save the parameters of the move for later, when we'll know how to */ | 1596 /* save the parameters of the move for later, when we'll know how to */ |
| 1535 /* offset it; */ | 1597 /* offset it; */ |
| 1536 /* also save last move point */ | 1598 /* also save last move point */ |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1554 } | 1616 } |
| 1555 | 1617 |
| 1556 | 1618 |
| 1557 FT_LOCAL_DEF( void ) | 1619 FT_LOCAL_DEF( void ) |
| 1558 cf2_glyphpath_lineTo( CF2_GlyphPath glyphpath, | 1620 cf2_glyphpath_lineTo( CF2_GlyphPath glyphpath, |
| 1559 CF2_Fixed x, | 1621 CF2_Fixed x, |
| 1560 CF2_Fixed y ) | 1622 CF2_Fixed y ) |
| 1561 { | 1623 { |
| 1562 CF2_Fixed xOffset, yOffset; | 1624 CF2_Fixed xOffset, yOffset; |
| 1563 FT_Vector P0, P1; | 1625 FT_Vector P0, P1; |
| 1626 FT_Bool newHintMap; |
| 1564 | 1627 |
| 1628 /* |
| 1629 * New hints will be applied after cf2_glyphpath_pushPrevElem has run. |
| 1630 * In case this is a synthesized closing line, any new hints should be |
| 1631 * delayed until this path is closed (`cf2_hintmask_isNew' will be |
| 1632 * called again before the next line or curve). |
| 1633 */ |
| 1565 | 1634 |
| 1566 /* can't compute offset of zero length line, so ignore them */ | 1635 /* true if new hint map not on close */ |
| 1567 if ( glyphpath->currentCS.x == x && glyphpath->currentCS.y == y ) | 1636 newHintMap = cf2_hintmask_isNew( glyphpath->hintMask ) && |
| 1637 !glyphpath->pathIsClosing; |
| 1638 |
| 1639 /* |
| 1640 * Zero-length lines may occur in the charstring. Because we cannot |
| 1641 * compute darkening offsets or intersections from zero-length lines, |
| 1642 * it is best to remove them and avoid artifacts. However, zero-length |
| 1643 * lines in CS at the start of a new hint map can generate non-zero |
| 1644 * lines in DS due to hint substitution. We detect a change in hint |
| 1645 * map here and pass those zero-length lines along. |
| 1646 */ |
| 1647 |
| 1648 /* |
| 1649 * Note: Find explicitly closed paths here with a conditional |
| 1650 * breakpoint using |
| 1651 * |
| 1652 * !gp->pathIsClosing && gp->start.x == x && gp->start.y == y |
| 1653 * |
| 1654 */ |
| 1655 |
| 1656 if ( glyphpath->currentCS.x == x && |
| 1657 glyphpath->currentCS.y == y && |
| 1658 !newHintMap ) |
| 1659 /* |
| 1660 * Ignore zero-length lines in CS where the hint map is the same |
| 1661 * because the line in DS will also be zero length. |
| 1662 * |
| 1663 * Ignore zero-length lines when we synthesize a closing line because |
| 1664 * the close will be handled in cf2_glyphPath_pushPrevElem. |
| 1665 */ |
| 1568 return; | 1666 return; |
| 1569 | 1667 |
| 1570 cf2_glyphpath_computeOffset( glyphpath, | 1668 cf2_glyphpath_computeOffset( glyphpath, |
| 1571 glyphpath->currentCS.x, | 1669 glyphpath->currentCS.x, |
| 1572 glyphpath->currentCS.y, | 1670 glyphpath->currentCS.y, |
| 1573 x, | 1671 x, |
| 1574 y, | 1672 y, |
| 1575 &xOffset, | 1673 &xOffset, |
| 1576 &yOffset ); | 1674 &yOffset ); |
| 1577 | 1675 |
| 1578 /* construct offset points */ | 1676 /* construct offset points */ |
| 1579 P0.x = glyphpath->currentCS.x + xOffset; | 1677 P0.x = glyphpath->currentCS.x + xOffset; |
| 1580 P0.y = glyphpath->currentCS.y + yOffset; | 1678 P0.y = glyphpath->currentCS.y + yOffset; |
| 1581 P1.x = x + xOffset; | 1679 P1.x = x + xOffset; |
| 1582 P1.y = y + yOffset; | 1680 P1.y = y + yOffset; |
| 1583 | 1681 |
| 1584 if ( glyphpath->moveIsPending ) | 1682 if ( glyphpath->moveIsPending ) |
| 1585 { | 1683 { |
| 1586 /* emit offset 1st point as MoveTo */ | 1684 /* emit offset 1st point as MoveTo */ |
| 1587 cf2_glyphpath_pushMove( glyphpath, P0 ); | 1685 cf2_glyphpath_pushMove( glyphpath, P0 ); |
| 1588 if (glyphpath->callbacks && glyphpath->callbacks->error && *glyphpath-
>callbacks->error) return; | |
| 1589 | 1686 |
| 1590 glyphpath->moveIsPending = FALSE; /* adjust state machine */ | 1687 glyphpath->moveIsPending = FALSE; /* adjust state machine */ |
| 1591 glyphpath->pathIsOpen = TRUE; | 1688 glyphpath->pathIsOpen = TRUE; |
| 1592 | 1689 |
| 1593 glyphpath->offsetStart1 = P1; /* record second point */ | 1690 glyphpath->offsetStart1 = P1; /* record second point */ |
| 1594 } | 1691 } |
| 1595 | 1692 |
| 1596 if ( glyphpath->elemIsQueued ) | 1693 if ( glyphpath->elemIsQueued ) |
| 1597 { | 1694 { |
| 1598 FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) ); | 1695 FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) || |
| 1696 glyphpath->hintMap.count == 0 ); |
| 1599 | 1697 |
| 1600 cf2_glyphpath_pushPrevElem( glyphpath, | 1698 cf2_glyphpath_pushPrevElem( glyphpath, |
| 1601 &glyphpath->hintMap, | 1699 &glyphpath->hintMap, |
| 1602 &P0, | 1700 &P0, |
| 1603 P1, | 1701 P1, |
| 1604 FALSE ); | 1702 FALSE ); |
| 1605 if (glyphpath->callbacks && glyphpath->callbacks->error && *glyphpath-
>callbacks->error) return; | |
| 1606 } | 1703 } |
| 1607 | 1704 |
| 1608 /* queue the current element with offset points */ | 1705 /* queue the current element with offset points */ |
| 1609 glyphpath->elemIsQueued = TRUE; | 1706 glyphpath->elemIsQueued = TRUE; |
| 1610 glyphpath->prevElemOp = CF2_PathOpLineTo; | 1707 glyphpath->prevElemOp = CF2_PathOpLineTo; |
| 1611 glyphpath->prevElemP0 = P0; | 1708 glyphpath->prevElemP0 = P0; |
| 1612 glyphpath->prevElemP1 = P1; | 1709 glyphpath->prevElemP1 = P1; |
| 1613 | 1710 |
| 1614 /* update current map */ | 1711 /* update current map */ |
| 1615 if ( cf2_hintmask_isNew( glyphpath->hintMask ) ) | 1712 if ( newHintMap ) |
| 1616 cf2_hintmap_build( &glyphpath->hintMap, | 1713 cf2_hintmap_build( &glyphpath->hintMap, |
| 1617 glyphpath->hStemHintArray, | 1714 glyphpath->hStemHintArray, |
| 1618 glyphpath->vStemHintArray, | 1715 glyphpath->vStemHintArray, |
| 1619 glyphpath->hintMask, | 1716 glyphpath->hintMask, |
| 1620 glyphpath->hintOriginY, | 1717 glyphpath->hintOriginY, |
| 1621 FALSE ); | 1718 FALSE ); |
| 1622 | 1719 |
| 1623 glyphpath->currentCS.x = x; /* pre-offset current point */ | 1720 glyphpath->currentCS.x = x; /* pre-offset current point */ |
| 1624 glyphpath->currentCS.y = y; | 1721 glyphpath->currentCS.y = y; |
| 1625 } | 1722 } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1666 /* note: preserve angle of final segment by using offset3 at both ends */ | 1763 /* note: preserve angle of final segment by using offset3 at both ends */ |
| 1667 P2.x = x2 + xOffset3; | 1764 P2.x = x2 + xOffset3; |
| 1668 P2.y = y2 + yOffset3; | 1765 P2.y = y2 + yOffset3; |
| 1669 P3.x = x3 + xOffset3; | 1766 P3.x = x3 + xOffset3; |
| 1670 P3.y = y3 + yOffset3; | 1767 P3.y = y3 + yOffset3; |
| 1671 | 1768 |
| 1672 if ( glyphpath->moveIsPending ) | 1769 if ( glyphpath->moveIsPending ) |
| 1673 { | 1770 { |
| 1674 /* emit offset 1st point as MoveTo */ | 1771 /* emit offset 1st point as MoveTo */ |
| 1675 cf2_glyphpath_pushMove( glyphpath, P0 ); | 1772 cf2_glyphpath_pushMove( glyphpath, P0 ); |
| 1676 if (glyphpath->callbacks && glyphpath->callbacks->error && *glyphpath-
>callbacks->error) return; | |
| 1677 | 1773 |
| 1678 glyphpath->moveIsPending = FALSE; | 1774 glyphpath->moveIsPending = FALSE; |
| 1679 glyphpath->pathIsOpen = TRUE; | 1775 glyphpath->pathIsOpen = TRUE; |
| 1680 | 1776 |
| 1681 glyphpath->offsetStart1 = P1; /* record second point */ | 1777 glyphpath->offsetStart1 = P1; /* record second point */ |
| 1682 } | 1778 } |
| 1683 | 1779 |
| 1684 if ( glyphpath->elemIsQueued ) | 1780 if ( glyphpath->elemIsQueued ) |
| 1685 { | 1781 { |
| 1686 FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) ); | 1782 FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) || |
| 1783 glyphpath->hintMap.count == 0 ); |
| 1687 | 1784 |
| 1688 cf2_glyphpath_pushPrevElem( glyphpath, | 1785 cf2_glyphpath_pushPrevElem( glyphpath, |
| 1689 &glyphpath->hintMap, | 1786 &glyphpath->hintMap, |
| 1690 &P0, | 1787 &P0, |
| 1691 P1, | 1788 P1, |
| 1692 FALSE ); | 1789 FALSE ); |
| 1693 if (glyphpath->callbacks && glyphpath->callbacks->error && *glyphpath-
>callbacks->error) return; | |
| 1694 } | 1790 } |
| 1695 | 1791 |
| 1696 /* queue the current element with offset points */ | 1792 /* queue the current element with offset points */ |
| 1697 glyphpath->elemIsQueued = TRUE; | 1793 glyphpath->elemIsQueued = TRUE; |
| 1698 glyphpath->prevElemOp = CF2_PathOpCubeTo; | 1794 glyphpath->prevElemOp = CF2_PathOpCubeTo; |
| 1699 glyphpath->prevElemP0 = P0; | 1795 glyphpath->prevElemP0 = P0; |
| 1700 glyphpath->prevElemP1 = P1; | 1796 glyphpath->prevElemP1 = P1; |
| 1701 glyphpath->prevElemP2 = P2; | 1797 glyphpath->prevElemP2 = P2; |
| 1702 glyphpath->prevElemP3 = P3; | 1798 glyphpath->prevElemP3 = P3; |
| 1703 | 1799 |
| 1704 /* update current map */ | 1800 /* update current map */ |
| 1705 if ( cf2_hintmask_isNew( glyphpath->hintMask ) ) | 1801 if ( cf2_hintmask_isNew( glyphpath->hintMask ) ) |
| 1706 cf2_hintmap_build( &glyphpath->hintMap, | 1802 cf2_hintmap_build( &glyphpath->hintMap, |
| 1707 glyphpath->hStemHintArray, | 1803 glyphpath->hStemHintArray, |
| 1708 glyphpath->vStemHintArray, | 1804 glyphpath->vStemHintArray, |
| 1709 glyphpath->hintMask, | 1805 glyphpath->hintMask, |
| 1710 glyphpath->hintOriginY, | 1806 glyphpath->hintOriginY, |
| 1711 FALSE ); | 1807 FALSE ); |
| 1712 | 1808 |
| 1713 glyphpath->currentCS.x = x3; /* pre-offset current point */ | 1809 glyphpath->currentCS.x = x3; /* pre-offset current point */ |
| 1714 glyphpath->currentCS.y = y3; | 1810 glyphpath->currentCS.y = y3; |
| 1715 } | 1811 } |
| 1716 | 1812 |
| 1717 | 1813 |
| 1718 FT_LOCAL_DEF( void ) | 1814 FT_LOCAL_DEF( void ) |
| 1719 cf2_glyphpath_closeOpenPath( CF2_GlyphPath glyphpath ) | 1815 cf2_glyphpath_closeOpenPath( CF2_GlyphPath glyphpath ) |
| 1720 { | 1816 { |
| 1721 if ( glyphpath->pathIsOpen ) | 1817 if ( glyphpath->pathIsOpen ) |
| 1722 { | 1818 { |
| 1723 FT_ASSERT( cf2_hintmap_isValid( &glyphpath->firstHintMap ) ); | 1819 /* |
| 1820 * A closing line in Character Space line is always generated below |
| 1821 * with `cf2_glyphPath_lineTo'. It may be ignored later if it turns |
| 1822 * out to be zero length in Device Space. |
| 1823 */ |
| 1824 glyphpath->pathIsClosing = TRUE; |
| 1724 | 1825 |
| 1725 /* since we need to apply an offset to the implicit lineto, we make */ | |
| 1726 /* it explicit here */ | |
| 1727 cf2_glyphpath_lineTo( glyphpath, | 1826 cf2_glyphpath_lineTo( glyphpath, |
| 1728 glyphpath->start.x, | 1827 glyphpath->start.x, |
| 1729 glyphpath->start.y ); | 1828 glyphpath->start.y ); |
| 1730 if (glyphpath->callbacks && glyphpath->callbacks->error && *glyphpath-
>callbacks->error) return; | |
| 1731 | 1829 |
| 1732 /* Draw previous element (the explicit LineTo we just created, */ | 1830 /* empty the final element from the queue and close the path */ |
| 1733 /* above) and connect it to the start point, but with the offset we */ | 1831 if ( glyphpath->elemIsQueued ) |
| 1734 /* saved from the first element. */ | 1832 cf2_glyphpath_pushPrevElem( glyphpath, |
| 1735 /* Use the saved HintMap, too. */ | 1833 &glyphpath->hintMap, |
| 1736 FT_ASSERT( glyphpath->elemIsQueued ); | 1834 &glyphpath->offsetStart0, |
| 1737 | 1835 glyphpath->offsetStart1, |
| 1738 cf2_glyphpath_pushPrevElem( glyphpath, | 1836 TRUE ); |
| 1739 &glyphpath->firstHintMap, | |
| 1740 &glyphpath->offsetStart0, | |
| 1741 glyphpath->offsetStart1, | |
| 1742 TRUE ); | |
| 1743 | 1837 |
| 1744 /* reset state machine */ | 1838 /* reset state machine */ |
| 1745 glyphpath->moveIsPending = TRUE; | 1839 glyphpath->moveIsPending = TRUE; |
| 1746 glyphpath->pathIsOpen = FALSE; | 1840 glyphpath->pathIsOpen = FALSE; |
| 1841 glyphpath->pathIsClosing = FALSE; |
| 1747 glyphpath->elemIsQueued = FALSE; | 1842 glyphpath->elemIsQueued = FALSE; |
| 1748 } | 1843 } |
| 1749 } | 1844 } |
| 1750 | 1845 |
| 1751 | 1846 |
| 1752 /* END */ | 1847 /* END */ |
| OLD | NEW |