1ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/***************************************************************************/ 2ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* */ 3ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* cf2font.c */ 4ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* */ 5ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* Adobe's code for font instances (body). */ 6ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* */ 7ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* Copyright 2007-2013 Adobe Systems Incorporated. */ 8ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* */ 9ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* This software, and all works of authorship, whether in source or */ 10ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* object code form as indicated by the copyright notice(s) included */ 11ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* herein (collectively, the "Work") is made available, and may only be */ 12ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* used, modified, and distributed under the FreeType Project License, */ 13ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* LICENSE.TXT. Additionally, subject to the terms and conditions of the */ 14ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* FreeType Project License, each contributor to the Work hereby grants */ 15ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* to any individual or legal entity exercising permissions granted by */ 16ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* the FreeType Project License and this section (hereafter, "You" or */ 17ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* "Your") a perpetual, worldwide, non-exclusive, no-charge, */ 18ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* royalty-free, irrevocable (except as stated in this section) patent */ 19ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* license to make, have made, use, offer to sell, sell, import, and */ 20ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* otherwise transfer the Work, where such license applies only to those */ 21ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* patent claims licensable by such contributor that are necessarily */ 22ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* infringed by their contribution(s) alone or by combination of their */ 23ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* contribution(s) with the Work to which such contribution(s) was */ 24ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* submitted. If You institute patent litigation against any entity */ 25ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* (including a cross-claim or counterclaim in a lawsuit) alleging that */ 26ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* the Work or a contribution incorporated within the Work constitutes */ 27ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* direct or contributory patent infringement, then any patent licenses */ 28ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* granted to You under this License for that Work shall terminate as of */ 29ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* the date such litigation is filed. */ 30ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* */ 31ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* By using, modifying, or distributing the Work you indicate that you */ 32ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* have read and understood the terms and conditions of the */ 33ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* FreeType Project License as well as those provided in this section, */ 34ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* and you accept them fully. */ 35ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* */ 36ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/***************************************************************************/ 37ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 38ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 39ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "cf2ft.h" 40ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 41ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "cf2glue.h" 42ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "cf2font.h" 43ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "cf2error.h" 44ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "cf2intrp.h" 45ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 46ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 47ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* Compute a stem darkening amount in character space. */ 48ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 49ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cf2_computeDarkening( CF2_Fixed emRatio, 50ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CF2_Fixed ppem, 51ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CF2_Fixed stemWidth, 52ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CF2_Fixed* darkenAmount, 53ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CF2_Fixed boldenAmount, 54ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Bool stemDarkened ) 55ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 56ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* Internal calculations are done in units per thousand for */ 57ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* convenience. */ 58ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CF2_Fixed stemWidthPer1000, scaledStem; 59ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 60ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 61ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *darkenAmount = 0; 62ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 63ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( boldenAmount == 0 && !stemDarkened ) 64ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 65ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 66ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* protect against range problems and divide by zero */ 67ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( emRatio < cf2_floatToFixed( .01 ) ) 68ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 69ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 70ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( stemDarkened ) 71ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 72ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* convert from true character space to 1000 unit character space; */ 73ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* add synthetic emboldening effect */ 74ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 75ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* we have to assure that the computation of `scaledStem' */ 76ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* and `stemWidthPer1000' don't overflow */ 77ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 78ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov stemWidthPer1000 = FT_MulFix( stemWidth + boldenAmount, emRatio ); 79ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 80ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( emRatio > CF2_FIXED_ONE && 81ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov stemWidthPer1000 <= ( stemWidth + boldenAmount ) ) 82ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 83ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov stemWidthPer1000 = 0; /* to pacify compiler */ 84ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov scaledStem = cf2_intToFixed( 2333 ); 85ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 86ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 87ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 88ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov scaledStem = FT_MulFix( stemWidthPer1000, ppem ); 89ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 90ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ppem > CF2_FIXED_ONE && 91ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov scaledStem <= stemWidthPer1000 ) 92ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov scaledStem = cf2_intToFixed( 2333 ); 93ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 94ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 95ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* 96ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * Total darkening amount is computed in 1000 unit character space 97ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * using the modified 5 part curve as Avalon rasterizer. 98ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * The darkening amount is smaller for thicker stems. 99ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * It becomes zero when the stem is thicker than 2.333 pixels. 100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * 101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * In Avalon rasterizer, 102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * 103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * darkenAmount = 0.5 pixels if scaledStem <= 0.5 pixels, 104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * darkenAmount = 0.333 pixels if 1 <= scaledStem <= 1.667 pixels, 105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * darkenAmount = 0 pixel if scaledStem >= 2.333 pixels, 106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * 107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * and piecewise linear in-between. 108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * 109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov */ 110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( scaledStem < cf2_intToFixed( 500 ) ) 111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *darkenAmount = FT_DivFix( cf2_intToFixed( 400 ), ppem ); 112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( scaledStem < cf2_intToFixed( 1000 ) ) 114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *darkenAmount = FT_DivFix( cf2_intToFixed( 525 ), ppem ) - 115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_MulFix( stemWidthPer1000, 116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cf2_floatToFixed( .25 ) ); 117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( scaledStem < cf2_intToFixed( 1667 ) ) 119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *darkenAmount = FT_DivFix( cf2_intToFixed( 275 ), ppem ); 120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( scaledStem < cf2_intToFixed( 2333 ) ) 122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *darkenAmount = FT_DivFix( cf2_intToFixed( 963 ), ppem ) - 123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_MulFix( stemWidthPer1000, 124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cf2_floatToFixed( .413 ) ); 125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* use half the amount on each side and convert back to true */ 127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* character space */ 128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *darkenAmount = FT_DivFix( *darkenAmount, 2 * emRatio ); 129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* add synthetic emboldening effect in character space */ 132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *darkenAmount += boldenAmount / 2; 133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* set up values for the current FontDict and matrix */ 137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* caller's transform is adjusted for subpixel positioning */ 139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cf2_font_setup( CF2_Font font, 141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const CF2_Matrix* transform ) 142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* pointer to parsed font object */ 144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CFF_Decoder* decoder = font->decoder; 145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Bool needExtraSetup; 147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* character space units */ 149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CF2_Fixed boldenX = font->syntheticEmboldeningAmountX; 150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CF2_Fixed boldenY = font->syntheticEmboldeningAmountY; 151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CF2_Fixed ppem; 153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* clear previous error */ 156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->error = FT_Err_Ok; 157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* if a CID fontDict has changed, we need to recompute some cached */ 159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* data */ 160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov needExtraSetup = 161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov (FT_Bool)( font->lastSubfont != cf2_getSubfont( decoder ) ); 162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* if ppem has changed, we need to recompute some cached data */ 164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* note: because of CID font matrix concatenation, ppem and transform */ 165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* do not necessarily track. */ 166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ppem = cf2_getPpemY( decoder ); 167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( font->ppem != ppem ) 168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->ppem = ppem; 170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov needExtraSetup = TRUE; 171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* copy hinted flag on each call */ 174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->hinted = (FT_Bool)( font->renderingFlags & CF2_FlagsHinted ); 175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* determine if transform has changed; */ 177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* include Fontmatrix but ignore translation */ 178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ft_memcmp( transform, 179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &font->currentTransform, 180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 4 * sizeof ( CF2_Fixed ) ) != 0 ) 181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* save `key' information for `cache of one' matrix data; */ 183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* save client transform, without the translation */ 184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->currentTransform = *transform; 185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->currentTransform.tx = 186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->currentTransform.ty = cf2_intToFixed( 0 ); 187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* TODO: FreeType transform is simple scalar; for now, use identity */ 189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* for outer */ 190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->innerTransform = *transform; 191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->outerTransform.a = 192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->outerTransform.d = cf2_intToFixed( 1 ); 193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->outerTransform.b = 194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->outerTransform.c = cf2_intToFixed( 0 ); 195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov needExtraSetup = TRUE; 197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* 200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * font->darkened is set to true if there is a stem darkening request or 201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * the font is synthetic emboldened. 202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * font->darkened controls whether to adjust blue zones, winding order, 203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * and hinting. 204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * 205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov */ 206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( font->stemDarkened != ( font->renderingFlags & CF2_FlagsDarkened ) ) 207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->stemDarkened = 209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov (FT_Bool)( font->renderingFlags & CF2_FlagsDarkened ); 210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* blue zones depend on darkened flag */ 212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov needExtraSetup = TRUE; 213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* recompute variables that are dependent on transform or FontDict or */ 216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* darken flag */ 217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( needExtraSetup ) 218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* StdVW is found in the private dictionary; */ 220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* recompute darkening amounts whenever private dictionary or */ 221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* transform change */ 222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* Note: a rendering flag turns darkening on or off, so we want to */ 223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* store the `on' amounts; */ 224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* darkening amount is computed in character space */ 225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* TODO: testing size-dependent darkening here; */ 226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* what to do for rotations? */ 227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CF2_Fixed emRatio; 229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CF2_Fixed stdHW; 230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CF2_Int unitsPerEm = font->unitsPerEm; 231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( unitsPerEm == 0 ) 234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov unitsPerEm = 1000; 235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ppem = FT_MAX( cf2_intToFixed( 4 ), 237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->ppem ); /* use minimum ppem of 4 */ 238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#if 0 240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* since vstem is measured in the x-direction, we use the `a' member */ 241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* of the fontMatrix */ 242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov emRatio = cf2_fixedFracMul( cf2_intToFixed( 1000 ), fontMatrix->a ); 243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif 244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* Freetype does not preserve the fontMatrix when parsing; use */ 246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* unitsPerEm instead. */ 247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* TODO: check precision of this */ 248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov emRatio = cf2_intToFixed( 1000 ) / unitsPerEm; 249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->stdVW = cf2_getStdVW( decoder ); 250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( font->stdVW <= 0 ) 252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->stdVW = FT_DivFix( cf2_intToFixed( 75 ), emRatio ); 253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( boldenX > 0 ) 255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* Ensure that boldenX is at least 1 pixel for synthetic bold font */ 257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* (similar to what Avalon does) */ 258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov boldenX = FT_MAX( boldenX, 259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_DivFix( cf2_intToFixed( unitsPerEm ), ppem ) ); 260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* Synthetic emboldening adds at least 1 pixel to darkenX, while */ 262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* stem darkening adds at most half pixel. Since the purpose of */ 263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* stem darkening (readability at small sizes) is met with */ 264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* synthetic emboldening, no need to add stem darkening for a */ 265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* synthetic bold font. */ 266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cf2_computeDarkening( emRatio, 267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ppem, 268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->stdVW, 269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &font->darkenX, 270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov boldenX, 271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FALSE ); 272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cf2_computeDarkening( emRatio, 275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ppem, 276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->stdVW, 277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &font->darkenX, 278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 0, 279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->stemDarkened ); 280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#if 0 282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* since hstem is measured in the y-direction, we use the `d' member */ 283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* of the fontMatrix */ 284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* TODO: use the same units per em as above; check this */ 285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov emRatio = cf2_fixedFracMul( cf2_intToFixed( 1000 ), fontMatrix->d ); 286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif 287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* set the default stem width, because it must be the same for all */ 289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* family members; */ 290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* choose a constant for StdHW that depends on font contrast */ 291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov stdHW = cf2_getStdHW( decoder ); 292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( stdHW > 0 && font->stdVW > 2 * stdHW ) 294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->stdHW = FT_DivFix( cf2_intToFixed( 75 ), emRatio ); 295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* low contrast font gets less hstem darkening */ 298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->stdHW = FT_DivFix( cf2_intToFixed( 110 ), emRatio ); 299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cf2_computeDarkening( emRatio, 302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ppem, 303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->stdHW, 304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &font->darkenY, 305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov boldenY, 306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->stemDarkened ); 307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( font->darkenX != 0 || font->darkenY != 0 ) 309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->darkened = TRUE; 310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->darkened = FALSE; 312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->reverseWinding = FALSE; /* initial expectation is CCW */ 314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* compute blue zones for this instance */ 316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cf2_blues_init( &font->blues, font ); 317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* equivalent to AdobeGetOutline */ 322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_LOCAL_DEF( FT_Error ) 323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cf2_getGlyphOutline( CF2_Font font, 324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CF2_Buffer charstring, 325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const CF2_Matrix* transform, 326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CF2_F16Dot16* glyphWidth ) 327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Error lastError = FT_Err_Ok; 329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Vector translation; 331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int refCount = 0; 332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#if 0 334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Vector advancePoint; 335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif 336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CF2_Fixed advWidth = 0; 338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Bool needWinding; 339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* Note: use both integer and fraction for outlines. This allows bbox */ 342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* to come out directly. */ 343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov translation.x = transform->tx; 345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov translation.y = transform->ty; 346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* set up values based on transform */ 348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cf2_font_setup( font, transform ); 349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( font->error ) 350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto exit; /* setup encountered an error */ 351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* reset darken direction */ 353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->reverseWinding = FALSE; 354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* winding order only affects darkening */ 356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov needWinding = font->darkened; 357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov while ( refCount++ < 1024) 359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* reset output buffer */ 361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cf2_outline_reset( &font->outline ); 362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* build the outline, passing the full translation */ 364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cf2_interpT2CharString( font, 365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov charstring, 366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov (CF2_OutlineCallbacks)&font->outline, 367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &translation, 368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FALSE, 369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 0, 370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 0, 371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &advWidth ); 372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( font->error ) 374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto exit; 375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( !needWinding ) 377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* check winding order */ 380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( font->outline.root.windingMomentum >= 0 ) /* CFF is CCW */ 381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* invert darkening and render again */ 384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* TODO: this should be a parameter to getOutline-computeOffset */ 385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov font->reverseWinding = TRUE; 386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov needWinding = FALSE; /* exit after next iteration */ 388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* finish storing client outline */ 391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cf2_outline_close( &font->outline ); 392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov exit: 394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* FreeType just wants the advance width; there is no translation */ 395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *glyphWidth = advWidth; 396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* free resources and collect errors from objects we've used */ 398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cf2_setError( &font->error, lastError ); 399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return font->error; 401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* END */ 405