1a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang/***************************************************************************/ 2a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang/* */ 3a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang/* cf2blues.c */ 4a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang/* */ 5a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang/* Adobe's code for handling Blue Zones (body). */ 6a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang/* */ 7a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang/* Copyright 2009-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#include FT_INTERNAL_DEBUG_H 41a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 42a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang#include "cf2blues.h" 43a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang#include "cf2hints.h" 44a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang#include "cf2font.h" 45a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 46a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 47a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /*************************************************************************/ 48a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* */ 49a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 50a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 51a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* messages during execution. */ 52a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* */ 53a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang#undef FT_COMPONENT 54a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang#define FT_COMPONENT trace_cf2blues 55a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 56a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 57a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* 58a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * For blue values, the FreeType parser produces an array of integers, 59a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * while the Adobe CFF engine produces an array of fixed. 60a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * Define a macro to convert FreeType to fixed. 61a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang */ 62a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang#define cf2_blueToFixed( x ) cf2_intToFixed( x ) 63a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 64a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 65a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FT_LOCAL_DEF( void ) 66a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_blues_init( CF2_Blues blues, 67a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Font font ) 68a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 69a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* pointer to parsed font object */ 70a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CFF_Decoder* decoder = font->decoder; 71a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 72a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Fixed zoneHeight; 73a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Fixed maxZoneHeight = 0; 74a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Fixed csUnitsPerPixel; 75a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 76a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang size_t numBlueValues; 77a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang size_t numOtherBlues; 78a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang size_t numFamilyBlues; 79a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang size_t numFamilyOtherBlues; 80a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 81a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FT_Pos* blueValues; 82a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FT_Pos* otherBlues; 83a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FT_Pos* familyBlues; 84a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FT_Pos* familyOtherBlues; 85a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 86a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang size_t i; 87a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Fixed emBoxBottom, emBoxTop; 88a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 89a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Int unitsPerEm = font->unitsPerEm; 90a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 91a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 92a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( unitsPerEm == 0 ) 93a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang unitsPerEm = 1000; 94a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 95a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FT_ZERO( blues ); 96a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->scale = font->innerTransform.d; 97a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 98a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_getBlueMetrics( decoder, 99a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang &blues->blueScale, 100a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang &blues->blueShift, 101a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang &blues->blueFuzz ); 102a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 103a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_getBlueValues( decoder, &numBlueValues, &blueValues ); 104a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_getOtherBlues( decoder, &numOtherBlues, &otherBlues ); 105a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_getFamilyBlues( decoder, &numFamilyBlues, &familyBlues ); 106a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_getFamilyOtherBlues( decoder, &numFamilyOtherBlues, &familyOtherBlues ); 107a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 108a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* 109a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * synthetic em box hint heuristic 110a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * 111a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * Apply this when ideographic dictionary (LanguageGroup 1) has no 112a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * real alignment zones. Adobe tools generate dummy zones at -250 and 113a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * 1100 for a 1000 unit em. Fonts with ICF-based alignment zones 114a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * should not enable the heuristic. When the heuristic is enabled, 115a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * the font's blue zones are ignored. 116a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * 117a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang */ 118a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 119a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* get em box from OS/2 typoAscender/Descender */ 120a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* TODO: FreeType does not parse these metrics. Skip them for now. */ 121a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang#if 0 122a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FCM_getHorizontalLineMetrics( &e, 123a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang font->font, 124a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang &ascender, 125a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang &descender, 126a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang &linegap ); 127a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( ascender - descender == unitsPerEm ) 128a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 129a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang emBoxBottom = cf2_intToFixed( descender ); 130a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang emBoxTop = cf2_intToFixed( ascender ); 131a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 132a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang else 133a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang#endif 134a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 135a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang emBoxBottom = CF2_ICF_Bottom; 136a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang emBoxTop = CF2_ICF_Top; 137a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 138a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 139a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( cf2_getLanguageGroup( decoder ) == 1 && 140a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang ( numBlueValues == 0 || 141a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang ( numBlueValues == 4 && 142a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_blueToFixed( blueValues[0] ) < emBoxBottom && 143a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_blueToFixed( blueValues[1] ) < emBoxBottom && 144a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_blueToFixed( blueValues[2] ) > emBoxTop && 145a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_blueToFixed( blueValues[3] ) > emBoxTop ) ) ) 146a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 147a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* 148a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * Construct hint edges suitable for synthetic ghost hints at top 149a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * and bottom of em box. +-CF2_MIN_COUNTER allows for unhinted 150a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * features above or below the last hinted edge. This also gives a 151a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * net 1 pixel boost to the height of ideographic glyphs. 152a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * 153a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * Note: Adjust synthetic hints outward by epsilon (0x.0001) to 154a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * avoid interference. E.g., some fonts have real hints at 155a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * 880 and -120. 156a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang */ 157a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 158a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->emBoxBottomEdge.csCoord = emBoxBottom - CF2_FIXED_EPSILON; 159a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->emBoxBottomEdge.dsCoord = cf2_fixedRound( 160a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FT_MulFix( 161a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->emBoxBottomEdge.csCoord, 162a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->scale ) ) - 163a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_MIN_COUNTER; 164a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->emBoxBottomEdge.scale = blues->scale; 165a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->emBoxBottomEdge.flags = CF2_GhostBottom | 166a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Locked | 167a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Synthetic; 168a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 169a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->emBoxTopEdge.csCoord = emBoxTop + CF2_FIXED_EPSILON + 170a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 2 * font->darkenY; 171a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->emBoxTopEdge.dsCoord = cf2_fixedRound( 172a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FT_MulFix( 173a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->emBoxTopEdge.csCoord, 174a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->scale ) ) + 175a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_MIN_COUNTER; 176a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->emBoxTopEdge.scale = blues->scale; 177a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->emBoxTopEdge.flags = CF2_GhostTop | 178a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Locked | 179a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Synthetic; 180a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 181a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->doEmBoxHints = TRUE; /* enable the heuristic */ 182a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 183a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang return; 184a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 185a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 186a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* copy `BlueValues' and `OtherBlues' to a combined array of top and */ 187a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* bottom zones */ 188a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang for ( i = 0; i < numBlueValues; i += 2 ) 189a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 190a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[blues->count].csBottomEdge = 191a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_blueToFixed( blueValues[i] ); 192a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[blues->count].csTopEdge = 193a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_blueToFixed( blueValues[i + 1] ); 194a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 195a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang zoneHeight = blues->zone[blues->count].csTopEdge - 196a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[blues->count].csBottomEdge; 197a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 198a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( zoneHeight < 0 ) 199a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 200a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" )); 201a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang continue; /* reject this zone */ 202a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 203a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 204a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( zoneHeight > maxZoneHeight ) 205a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 206a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* take maximum before darkening adjustment */ 207a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* so overshoot suppression point doesn't change */ 208a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang maxZoneHeight = zoneHeight; 209a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 210a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 211a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* adjust both edges of top zone upward by twice darkening amount */ 212a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( i != 0 ) 213a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 214a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[blues->count].csTopEdge += 2 * font->darkenY; 215a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[blues->count].csBottomEdge += 2 * font->darkenY; 216a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 217a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 218a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* first `BlueValue' is bottom zone; others are top */ 219a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( i == 0 ) 220a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 221a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[blues->count].bottomZone = 222a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang TRUE; 223a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[blues->count].csFlatEdge = 224a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[blues->count].csTopEdge; 225a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 226a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang else 227a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 228a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[blues->count].bottomZone = 229a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FALSE; 230a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[blues->count].csFlatEdge = 231a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[blues->count].csBottomEdge; 232a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 233a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 234a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->count += 1; 235a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 236a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 237a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang for ( i = 0; i < numOtherBlues; i += 2 ) 238a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 239a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[blues->count].csBottomEdge = 240a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_blueToFixed( otherBlues[i] ); 241a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[blues->count].csTopEdge = 242a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_blueToFixed( otherBlues[i + 1] ); 243a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 244a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang zoneHeight = blues->zone[blues->count].csTopEdge - 245a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[blues->count].csBottomEdge; 246a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 247a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( zoneHeight < 0 ) 248a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 249a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" )); 250a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang continue; /* reject this zone */ 251a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 252a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 253a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( zoneHeight > maxZoneHeight ) 254a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 255a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* take maximum before darkening adjustment */ 256a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* so overshoot suppression point doesn't change */ 257a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang maxZoneHeight = zoneHeight; 258a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 259a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 260a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* Note: bottom zones are not adjusted for darkening amount */ 261a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 262a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* all OtherBlues are bottom zone */ 263a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[blues->count].bottomZone = 264a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang TRUE; 265a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[blues->count].csFlatEdge = 266a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[blues->count].csTopEdge; 267a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 268a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->count += 1; 269a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 270a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 271a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* Adjust for FamilyBlues */ 272a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 273a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* Search for the nearest flat edge in `FamilyBlues' or */ 274a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* `FamilyOtherBlues'. According to the Black Book, any matching edge */ 275a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* must be within one device pixel */ 276a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 277a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang csUnitsPerPixel = FT_DivFix( cf2_intToFixed( 1 ), blues->scale ); 278a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 279a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* loop on all zones in this font */ 280a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang for ( i = 0; i < blues->count; i++ ) 281a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 282a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang size_t j; 283a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Fixed minDiff; 284a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Fixed flatFamilyEdge, diff; 285a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* value for this font */ 286a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Fixed flatEdge = blues->zone[i].csFlatEdge; 287a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 288a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 289a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( blues->zone[i].bottomZone ) 290a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 291a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* In a bottom zone, the top edge is the flat edge. */ 292a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* Search `FamilyOtherBlues' for bottom zones; look for closest */ 293a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* Family edge that is within the one pixel threshold. */ 294a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 295a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang minDiff = CF2_FIXED_MAX; 296a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 297a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang for ( j = 0; j < numFamilyOtherBlues; j += 2 ) 298a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 299a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* top edge */ 300a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang flatFamilyEdge = cf2_blueToFixed( familyOtherBlues[j + 1] ); 301a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 302a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang diff = cf2_fixedAbs( flatEdge - flatFamilyEdge ); 303a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 304a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( diff < minDiff && diff < csUnitsPerPixel ) 305a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 306a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[i].csFlatEdge = flatFamilyEdge; 307a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang minDiff = diff; 308a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 309a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( diff == 0 ) 310a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang break; 311a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 312a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 313a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 314a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* check the first member of FamilyBlues, which is a bottom zone */ 315a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( numFamilyBlues >= 2 ) 316a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 317a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* top edge */ 318a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang flatFamilyEdge = cf2_blueToFixed( familyBlues[1] ); 319a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 320a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang diff = cf2_fixedAbs( flatEdge - flatFamilyEdge ); 321a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 322a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( diff < minDiff && diff < csUnitsPerPixel ) 323a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[i].csFlatEdge = flatFamilyEdge; 324a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 325a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 326a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang else 327a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 328a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* In a top zone, the bottom edge is the flat edge. */ 329a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* Search `FamilyBlues' for top zones; skip first zone, which is a */ 330a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* bottom zone; look for closest Family edge that is within the */ 331a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* one pixel threshold */ 332a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 333a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang minDiff = CF2_FIXED_MAX; 334a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 335a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang for ( j = 2; j < numFamilyBlues; j += 2 ) 336a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 337a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* bottom edge */ 338a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang flatFamilyEdge = cf2_blueToFixed( familyBlues[j] ); 339a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 340a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* adjust edges of top zone upward by twice darkening amount */ 341a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang flatFamilyEdge += 2 * font->darkenY; /* bottom edge */ 342a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 343a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang diff = cf2_fixedAbs( flatEdge - flatFamilyEdge ); 344a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 345a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( diff < minDiff && diff < csUnitsPerPixel ) 346a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 347a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[i].csFlatEdge = flatFamilyEdge; 348a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang minDiff = diff; 349a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 350a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( diff == 0 ) 351a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang break; 352a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 353a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 354a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 355a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 356a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 357a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* TODO: enforce separation of zones, including BlueFuzz */ 358a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 359a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* Adjust BlueScale; similar to AdjustBlueScale() in coretype */ 360a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* `bcsetup.c'. */ 361a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 362a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( maxZoneHeight > 0 ) 363a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 364a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( blues->blueScale > FT_DivFix( cf2_intToFixed( 1 ), 365a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang maxZoneHeight ) ) 366a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 367a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* clamp at maximum scale */ 368a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->blueScale = FT_DivFix( cf2_intToFixed( 1 ), 369a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang maxZoneHeight ); 370a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 371a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 372a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* 373a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * TODO: Revisit the bug fix for 613448. The minimum scale 374a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * requirement catches a number of library fonts. For 375a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * example, with default BlueScale (.039625) and 0.4 minimum, 376a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * the test below catches any font with maxZoneHeight < 10.1. 377a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * There are library fonts ranging from 2 to 10 that get 378a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * caught, including e.g., Eurostile LT Std Medium with 379a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * maxZoneHeight of 6. 380a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * 381a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang */ 382a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang#if 0 383a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( blueScale < .4 / maxZoneHeight ) 384a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 385a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang tetraphilia_assert( 0 ); 386a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* clamp at minimum scale, per bug 0613448 fix */ 387a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blueScale = .4 / maxZoneHeight; 388a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 389a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang#endif 390a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 391a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 392a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 393a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* 394a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * Suppress overshoot and boost blue zones at small sizes. Boost 395a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * amount varies linearly from 0.5 pixel near 0 to 0 pixel at 396a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * blueScale cutoff. 397a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * Note: This boost amount is different from the coretype heuristic. 398a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * 399a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang */ 400a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 401a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( blues->scale < blues->blueScale ) 402a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 403a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->suppressOvershoot = TRUE; 404a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 405a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* Change rounding threshold for `dsFlatEdge'. */ 406a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* Note: constant changed from 0.5 to 0.6 to avoid a problem with */ 407a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* 10ppem Arial */ 408a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 409a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->boost = FT_MulFix( 410a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_floatToFixed( .6 ), 411a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang ( cf2_intToFixed( 1 ) - 412a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FT_DivFix( blues->scale, 413a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->blueScale ) ) ); 414a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( blues->boost > 0x7FFF ) 415a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 416a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* boost must remain less than 0.5, or baseline could go negative */ 417a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->boost = 0x7FFF; 418a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 419a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 420a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 421a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* boost and darkening have similar effects; don't do both */ 422a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( font->stemDarkened ) 423a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->boost = 0; 424a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 425a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* set device space alignment for each zone; */ 426a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* apply boost amount before rounding flat edge */ 427a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 428a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang for ( i = 0; i < blues->count; i++ ) 429a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 430a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( blues->zone[i].bottomZone ) 431a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[i].dsFlatEdge = cf2_fixedRound( 432a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FT_MulFix( 433a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[i].csFlatEdge, 434a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->scale ) - 435a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->boost ); 436a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang else 437a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[i].dsFlatEdge = cf2_fixedRound( 438a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FT_MulFix( 439a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[i].csFlatEdge, 440a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->scale ) + 441a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->boost ); 442a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 443a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 444a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 445a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 446a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* 447a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * Check whether `stemHint' is captured by one of the blue zones. 448a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * 449a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * Zero, one or both edges may be valid; only valid edges can be 450a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * captured. For compatibility with CoolType, search top and bottom 451a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * zones in the same pass (see `BlueLock'). If a hint is captured, 452a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * return true and position the edge(s) in one of 3 ways: 453a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * 454a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * 1) If `BlueScale' suppresses overshoot, position the captured edge 455a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * at the flat edge of the zone. 456a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * 2) If overshoot is not suppressed and `BlueShift' requires 457a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * overshoot, position the captured edge a minimum of 1 device pixel 458a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * from the flat edge. 459a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * 3) If overshoot is not suppressed or required, position the captured 460a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * edge at the nearest device pixel. 461a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang * 462a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang */ 463a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FT_LOCAL_DEF( FT_Bool ) 464a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_blues_capture( const CF2_Blues blues, 465a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Hint bottomHintEdge, 466a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Hint topHintEdge ) 467a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 468a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* TODO: validate? */ 469a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Fixed csFuzz = blues->blueFuzz; 470a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 471a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* new position of captured edge */ 472a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Fixed dsNew; 473a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 474a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* amount that hint is moved when positioned */ 475a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_Fixed dsMove = 0; 476a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 477a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FT_Bool captured = FALSE; 478a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang CF2_UInt i; 479a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 480a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 481a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* assert edge flags are consistent */ 482a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang FT_ASSERT( !cf2_hint_isTop( bottomHintEdge ) && 483a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang !cf2_hint_isBottom( topHintEdge ) ); 484a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 485a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* TODO: search once without blue fuzz for compatibility with coretype? */ 486a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang for ( i = 0; i < blues->count; i++ ) 487a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 488a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( blues->zone[i].bottomZone && 489a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_hint_isBottom( bottomHintEdge ) ) 490a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 491a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( ( blues->zone[i].csBottomEdge - csFuzz ) <= 492a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang bottomHintEdge->csCoord && 493a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang bottomHintEdge->csCoord <= 494a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang ( blues->zone[i].csTopEdge + csFuzz ) ) 495a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 496a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* bottom edge captured by bottom zone */ 497a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 498a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( blues->suppressOvershoot ) 499a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang dsNew = blues->zone[i].dsFlatEdge; 500a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 501a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang else if ( ( blues->zone[i].csTopEdge - bottomHintEdge->csCoord ) >= 502a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->blueShift ) 503a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 504a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* guarantee minimum of 1 pixel overshoot */ 505a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang dsNew = FT_MIN( 506a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_fixedRound( bottomHintEdge->dsCoord ), 507a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[i].dsFlatEdge - cf2_intToFixed( 1 ) ); 508a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 509a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 510a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang else 511a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 512a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* simply round captured edge */ 513a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang dsNew = cf2_fixedRound( bottomHintEdge->dsCoord ); 514a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 515a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 516a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang dsMove = dsNew - bottomHintEdge->dsCoord; 517a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang captured = TRUE; 518a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 519a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang break; 520a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 521a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 522a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 523a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( !blues->zone[i].bottomZone && cf2_hint_isTop( topHintEdge ) ) 524a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 525a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( ( blues->zone[i].csBottomEdge - csFuzz ) <= 526a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang topHintEdge->csCoord && 527a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang topHintEdge->csCoord <= 528a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang ( blues->zone[i].csTopEdge + csFuzz ) ) 529a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 530a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* top edge captured by top zone */ 531a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 532a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( blues->suppressOvershoot ) 533a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang dsNew = blues->zone[i].dsFlatEdge; 534a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 535a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang else if ( ( topHintEdge->csCoord - blues->zone[i].csBottomEdge ) >= 536a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->blueShift ) 537a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 538a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* guarantee minimum of 1 pixel overshoot */ 539a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang dsNew = FT_MAX( 540a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_fixedRound( topHintEdge->dsCoord ), 541a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang blues->zone[i].dsFlatEdge + cf2_intToFixed( 1 ) ); 542a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 543a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 544a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang else 545a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 546a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* simply round captured edge */ 547a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang dsNew = cf2_fixedRound( topHintEdge->dsCoord ); 548a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 549a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 550a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang dsMove = dsNew - topHintEdge->dsCoord; 551a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang captured = TRUE; 552a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 553a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang break; 554a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 555a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 556a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 557a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 558a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( captured ) 559a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 560a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang /* move both edges and flag them `locked' */ 561a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( cf2_hint_isValid( bottomHintEdge ) ) 562a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 563a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang bottomHintEdge->dsCoord += dsMove; 564a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_hint_lock( bottomHintEdge ); 565a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 566a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 567a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang if ( cf2_hint_isValid( topHintEdge ) ) 568a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang { 569a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang topHintEdge->dsCoord += dsMove; 570a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang cf2_hint_lock( topHintEdge ); 571a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 572a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 573a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 574a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang return captured; 575a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang } 576a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 577a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang 578a2b9955b49034a51dfbc8bf9f4e9d312149cecacXianzhu Wang/* END */ 579