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