1ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/***************************************************************************/ 2ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* */ 3ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* pshalgo.c */ 4ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* */ 5ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* PostScript hinting algorithm (body). */ 6ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* */ 7ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* Copyright 2001-2010, 2012, 2013 by */ 8ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* David Turner, Robert Wilhelm, and Werner Lemberg. */ 9ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* */ 10ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* This file is part of the FreeType project, and may only be used */ 11ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* modified and distributed under the terms of the FreeType project */ 12ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 13ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* this file you indicate that you have read the license and */ 14ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* understand and accept it fully. */ 15ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* */ 16ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/***************************************************************************/ 17ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 18ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 19ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "../../include/ft2build.h" 20ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "../../include/freetype/internal/ftobjs.h" 21ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "../../include/freetype/internal/ftdebug.h" 22ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "../../include/freetype/internal/ftcalc.h" 23ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "pshalgo.h" 24ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 25ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "pshnterr.h" 26ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 27ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 28ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#undef FT_COMPONENT 29ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define FT_COMPONENT trace_pshalgo2 30ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 31ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 32ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef DEBUG_HINTER 33ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint_Table ps_debug_hint_table = 0; 34ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_HintFunc ps_debug_hint_func = 0; 35ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Glyph ps_debug_glyph = 0; 36ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif 37ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 38ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 39ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define COMPUTE_INFLEXS /* compute inflection points to optimize `S' */ 40ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* and similar glyphs */ 41ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define STRONGER /* slightly increase the contrast of smooth */ 42ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* hinting */ 43ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 44ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 45ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 46ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 47ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /***** *****/ 48ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /***** BASIC HINTS RECORDINGS *****/ 49ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /***** *****/ 50ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 51ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 52ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 53ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* return true if two stem hints overlap */ 54ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static FT_Int 55ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_overlap( PSH_Hint hint1, 56ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint hint2 ) 57ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 58ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return hint1->org_pos + hint1->org_len >= hint2->org_pos && 59ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint2->org_pos + hint2->org_len >= hint1->org_pos; 60ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 61ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 62ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 63ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* destroy hints table */ 64ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 65ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_done( PSH_Hint_Table table, 66ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Memory memory ) 67ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 68ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_FREE( table->zones ); 69ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov table->num_zones = 0; 70ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov table->zone = 0; 71ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 72ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_FREE( table->sort ); 73ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_FREE( table->hints ); 74ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov table->num_hints = 0; 75ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov table->max_hints = 0; 76ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov table->sort_global = 0; 77ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 78ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 79ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 80ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* deactivate all hints in a table */ 81ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 82ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_deactivate( PSH_Hint_Table table ) 83ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 84ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt count = table->max_hints; 85ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint hint = table->hints; 86ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 87ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 88ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( ; count > 0; count--, hint++ ) 89ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 90ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_deactivate( hint ); 91ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->order = -1; 92ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 93ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 94ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 95ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 96ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* internal function to record a new hint */ 97ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 98ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_record( PSH_Hint_Table table, 99ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt idx ) 100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint hint = table->hints + idx; 102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( idx >= table->max_hints ) 105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_TRACE0(( "psh_hint_table_record: invalid hint index %d\n", idx )); 107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* ignore active hints */ 111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( psh_hint_is_active( hint ) ) 112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_activate( hint ); 115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* now scan the current active hint set to check */ 117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* whether `hint' overlaps with another hint */ 118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint* sorted = table->sort_global; 120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt count = table->num_hints; 121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint hint2; 122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->parent = 0; 125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( ; count > 0; count--, sorted++ ) 126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint2 = sorted[0]; 128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( psh_hint_overlap( hint, hint2 ) ) 130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->parent = hint2; 132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( table->num_hints < table->max_hints ) 138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov table->sort_global[table->num_hints++] = hint; 139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_TRACE0(( "psh_hint_table_record: too many sorted hints! BUG!\n" )); 141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_record_mask( PSH_Hint_Table table, 146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PS_Mask hint_mask ) 147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int mask = 0, val = 0; 149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Byte* cursor = hint_mask->bytes; 150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt idx, limit; 151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov limit = hint_mask->num_bits; 154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( idx = 0; idx < limit; idx++ ) 156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( mask == 0 ) 158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov val = *cursor++; 160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mask = 0x80; 161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( val & mask ) 164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_record( table, idx ); 165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mask >>= 1; 167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* create hints table */ 172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static FT_Error 173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_init( PSH_Hint_Table table, 174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PS_Hint_Table hints, 175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PS_Mask_Table hint_masks, 176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PS_Mask_Table counter_masks, 177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Memory memory ) 178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt count; 180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Error error; 181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UNUSED( counter_masks ); 183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov count = hints->num_hints; 186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* allocate our tables */ 188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( FT_NEW_ARRAY( table->sort, 2 * count ) || 189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_NEW_ARRAY( table->hints, count ) || 190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_NEW_ARRAY( table->zones, 2 * count + 1 ) ) 191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Exit; 192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov table->max_hints = count; 194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov table->sort_global = table->sort + count; 195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov table->num_hints = 0; 196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov table->num_zones = 0; 197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov table->zone = 0; 198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* initialize the `table->hints' array */ 200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint write = table->hints; 202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PS_Hint read = hints->hints; 203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( ; count > 0; count--, write++, read++ ) 206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov write->org_pos = read->pos; 208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov write->org_len = read->len; 209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov write->flags = read->flags; 210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* we now need to determine the initial `parent' stems; first */ 214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* activate the hints that are given by the initial hint masks */ 215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( hint_masks ) 216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PS_Mask mask = hint_masks->masks; 218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov count = hint_masks->num_masks; 221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov table->hint_masks = hint_masks; 222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( ; count > 0; count--, mask++ ) 224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_record_mask( table, mask ); 225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* finally, do a linear parse in case some hints were left alone */ 228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( table->num_hints != table->max_hints ) 229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt idx; 231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_TRACE0(( "psh_hint_table_init: missing/incorrect hint masks\n" )); 234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov count = table->max_hints; 236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( idx = 0; idx < count; idx++ ) 237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_record( table, idx ); 238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Exit: 241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return error; 242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_activate_mask( PSH_Hint_Table table, 247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PS_Mask hint_mask ) 248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int mask = 0, val = 0; 250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Byte* cursor = hint_mask->bytes; 251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt idx, limit, count; 252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov limit = hint_mask->num_bits; 255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov count = 0; 256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_deactivate( table ); 258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( idx = 0; idx < limit; idx++ ) 260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( mask == 0 ) 262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov val = *cursor++; 264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mask = 0x80; 265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( val & mask ) 268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint hint = &table->hints[idx]; 270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( !psh_hint_is_active( hint ) ) 273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt count2; 275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#if 0 277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint* sort = table->sort; 278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint hint2; 279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( count2 = count; count2 > 0; count2--, sort++ ) 282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint2 = sort[0]; 284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( psh_hint_overlap( hint, hint2 ) ) 285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_TRACE0(( "psh_hint_table_activate_mask:" 286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov " found overlapping hints\n" )) 287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#else 289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov count2 = 0; 290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif 291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( count2 == 0 ) 293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_activate( hint ); 295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( count < table->max_hints ) 296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov table->sort[count++] = hint; 297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_TRACE0(( "psh_hint_tableactivate_mask:" 299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov " too many active hints\n" )); 300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mask >>= 1; 305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov table->num_hints = count; 307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* now, sort the hints; they are guaranteed to not overlap */ 309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* so we can compare their "org_pos" field directly */ 310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int i1, i2; 312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint hint1, hint2; 313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint* sort = table->sort; 314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* a simple bubble sort will do, since in 99% of cases, the hints */ 317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* will be already sorted -- and the sort will be linear */ 318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( i1 = 1; i1 < (FT_Int)count; i1++ ) 319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint1 = sort[i1]; 321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( i2 = i1 - 1; i2 >= 0; i2-- ) 322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint2 = sort[i2]; 324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( hint2->org_pos < hint1->org_pos ) 326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov sort[i2 + 1] = hint2; 329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov sort[i2] = hint1; 330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /***** *****/ 339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /***** HINTS GRID-FITTING AND OPTIMIZATION *****/ 340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /***** *****/ 341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#if 1 345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static FT_Pos 346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_dimension_quantize_len( PSH_Dimension dim, 347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos len, 348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Bool do_snapping ) 349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( len <= 64 ) 351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov len = 64; 352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos delta = len - dim->stdw.widths[0].cur; 355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( delta < 0 ) 358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov delta = -delta; 359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( delta < 40 ) 361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov len = dim->stdw.widths[0].cur; 363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( len < 48 ) 364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov len = 48; 365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( len < 3 * 64 ) 368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov delta = ( len & 63 ); 370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov len &= -64; 371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( delta < 10 ) 373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov len += delta; 374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( delta < 32 ) 376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov len += 10; 377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( delta < 54 ) 379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov len += 54; 380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov len += delta; 383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov len = FT_PIX_ROUND( len ); 386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( do_snapping ) 389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov len = FT_PIX_ROUND( len ); 390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return len; 392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* 0 */ 394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef DEBUG_HINTER 397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ps_simple_scale( PSH_Hint_Table table, 400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed scale, 401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed delta, 402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int dimension ) 403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt count; 405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( count = 0; count < table->max_hints; count++ ) 408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint hint = table->hints + count; 410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta; 413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_len = FT_MulFix( hint->org_len, scale ); 414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ps_debug_hint_func ) 416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ps_debug_hint_func( hint, dimension ); 417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* DEBUG_HINTER */ 421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static FT_Fixed 424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_snap_stem_side_delta( FT_Fixed pos, 425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed len ) 426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed delta1 = FT_PIX_ROUND( pos ) - pos; 428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed delta2 = FT_PIX_ROUND( pos + len ) - pos - len; 429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( FT_ABS( delta1 ) <= FT_ABS( delta2 ) ) 432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return delta1; 433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return delta2; 435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_align( PSH_Hint hint, 440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Globals globals, 441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int dimension, 442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Glyph glyph ) 443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Dimension dim = &globals->dimension[dimension]; 445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed scale = dim->scale_mult; 446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed delta = dim->scale_delta; 447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( !psh_hint_is_fitted( hint ) ) 450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta; 452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos len = FT_MulFix( hint->org_len, scale ); 453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int do_snapping; 455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos fit_len; 456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_AlignmentRec align; 457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* ignore stem alignments when requested through the hint flags */ 460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ( dimension == 0 && !glyph->do_horz_hints ) || 461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ( dimension == 1 && !glyph->do_vert_hints ) ) 462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_pos = pos; 464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_len = len; 465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_set_fitted( hint ); 467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* perform stem snapping when requested - this is necessary 471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * for monochrome and LCD hinting modes only 472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov */ 473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov do_snapping = ( dimension == 0 && glyph->do_horz_snapping ) || 474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ( dimension == 1 && glyph->do_vert_snapping ); 475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_len = fit_len = len; 477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* check blue zones for horizontal stems */ 479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov align.align = PSH_BLUE_ALIGN_NONE; 480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov align.align_bot = align.align_top = 0; 481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( dimension == 1 ) 483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_blues_snap_stem( &globals->blues, 484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->org_pos + hint->org_len, 485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->org_pos, 486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &align ); 487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov switch ( align.align ) 489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov case PSH_BLUE_ALIGN_TOP: 491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* the top of the stem is aligned against a blue zone */ 492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_pos = align.align_top - fit_len; 493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov case PSH_BLUE_ALIGN_BOT: 496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* the bottom of the stem is aligned against a blue zone */ 497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_pos = align.align_bot; 498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT: 501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* both edges of the stem are aligned against blue zones */ 502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_pos = align.align_bot; 503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_len = align.align_top - align.align_bot; 504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov default: 507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint parent = hint->parent; 509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( parent ) 512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos par_org_center, par_cur_center; 514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos cur_org_center, cur_delta; 515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* ensure that parent is already fitted */ 518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( !psh_hint_is_fitted( parent ) ) 519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_align( parent, globals, dimension, glyph ); 520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* keep original relation between hints, this is, use the */ 522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* scaled distance between the centers of the hints to */ 523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* compute the new position */ 524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov par_org_center = parent->org_pos + ( parent->org_len >> 1 ); 525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov par_cur_center = parent->cur_pos + ( parent->cur_len >> 1 ); 526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cur_org_center = hint->org_pos + ( hint->org_len >> 1 ); 527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cur_delta = FT_MulFix( cur_org_center - par_org_center, scale ); 529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pos = par_cur_center + cur_delta - ( len >> 1 ); 530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_pos = pos; 533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_len = fit_len; 534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* Stem adjustment tries to snap stem widths to standard 536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * ones. This is important to prevent unpleasant rounding 537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * artefacts. 538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov */ 539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( glyph->do_stem_adjust ) 540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( len <= 64 ) 542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* the stem is less than one pixel; we will center it 544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * around the nearest pixel center 545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov */ 546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( len >= 32 ) 547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* This is a special case where we also widen the stem 549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * and align it to the pixel grid. 550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * 551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * stem_center = pos + (len/2) 552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * nearest_pixel_center = FT_ROUND(stem_center-32)+32 553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * new_pos = nearest_pixel_center-32 554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * = FT_ROUND(stem_center-32) 555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * = FT_FLOOR(stem_center-32+32) 556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * = FT_FLOOR(stem_center) 557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * new_len = 64 558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov */ 559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pos = FT_PIX_FLOOR( pos + ( len >> 1 ) ); 560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov len = 64; 561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( len > 0 ) 563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* This is a very small stem; we simply align it to the 565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * pixel grid, trying to find the minimum displacement. 566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * 567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * left = pos 568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * right = pos + len 569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * left_nearest_edge = ROUND(pos) 570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * right_nearest_edge = ROUND(right) 571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * 572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * if ( ABS(left_nearest_edge - left) <= 573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * ABS(right_nearest_edge - right) ) 574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * new_pos = left 575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * else 576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * new_pos = right 577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov */ 578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos left_nearest = FT_PIX_ROUND( pos ); 579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos right_nearest = FT_PIX_ROUND( pos + len ); 580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos left_disp = left_nearest - pos; 581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos right_disp = right_nearest - ( pos + len ); 582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( left_disp < 0 ) 585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov left_disp = -left_disp; 586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( right_disp < 0 ) 587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov right_disp = -right_disp; 588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( left_disp <= right_disp ) 589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pos = left_nearest; 590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pos = right_nearest; 592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 595ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* this is a ghost stem; we simply round it */ 596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pos = FT_PIX_ROUND( pos ); 597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov len = psh_dimension_quantize_len( dim, len, 0 ); 602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 605ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* now that we have a good hinted stem width, try to position */ 606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* the stem along a pixel grid integer coordinate */ 607ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_pos = pos + psh_hint_snap_stem_side_delta( pos, len ); 608ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_len = len; 609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 610ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( do_snapping ) 613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pos = hint->cur_pos; 615ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov len = hint->cur_len; 616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( len < 64 ) 618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov len = 64; 619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov len = FT_PIX_ROUND( len ); 621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov switch ( align.align ) 623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov case PSH_BLUE_ALIGN_TOP: 625ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_pos = align.align_top - len; 626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_len = len; 627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov case PSH_BLUE_ALIGN_BOT: 630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_len = len; 631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov case PSH_BLUE_ALIGN_BOT | PSH_BLUE_ALIGN_TOP: 634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* don't touch */ 635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov default: 639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_len = len; 640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( len & 64 ) 641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pos = FT_PIX_FLOOR( pos + ( len >> 1 ) ) + 32; 642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pos = FT_PIX_ROUND( pos + ( len >> 1 ) ); 644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 645ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_pos = pos - ( len >> 1 ); 646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_len = len; 647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 648ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_set_fitted( hint ); 651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef DEBUG_HINTER 653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ps_debug_hint_func ) 654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ps_debug_hint_func( hint, dimension ); 655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif 656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#if 0 /* not used for now, experimental */ 661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* 663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * A variant to perform "light" hinting (i.e. FT_RENDER_MODE_LIGHT) 664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * of stems 665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov */ 666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_align_light( PSH_Hint hint, 668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Globals globals, 669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int dimension, 670ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Glyph glyph ) 671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Dimension dim = &globals->dimension[dimension]; 673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed scale = dim->scale_mult; 674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed delta = dim->scale_delta; 675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 676ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( !psh_hint_is_fitted( hint ) ) 678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta; 680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos len = FT_MulFix( hint->org_len, scale ); 681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos fit_len; 683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_AlignmentRec align; 685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* ignore stem alignments when requested through the hint flags */ 688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ( dimension == 0 && !glyph->do_horz_hints ) || 689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ( dimension == 1 && !glyph->do_vert_hints ) ) 690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_pos = pos; 692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_len = len; 693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_set_fitted( hint ); 695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 697ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 698ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov fit_len = len; 699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_len = fit_len; 701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* check blue zones for horizontal stems */ 703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov align.align = PSH_BLUE_ALIGN_NONE; 704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov align.align_bot = align.align_top = 0; 705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( dimension == 1 ) 707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_blues_snap_stem( &globals->blues, 708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->org_pos + hint->org_len, 709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->org_pos, 710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &align ); 711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov switch ( align.align ) 713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov case PSH_BLUE_ALIGN_TOP: 715ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* the top of the stem is aligned against a blue zone */ 716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_pos = align.align_top - fit_len; 717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov case PSH_BLUE_ALIGN_BOT: 720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* the bottom of the stem is aligned against a blue zone */ 721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_pos = align.align_bot; 722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 723ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT: 725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* both edges of the stem are aligned against blue zones */ 726ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_pos = align.align_bot; 727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_len = align.align_top - align.align_bot; 728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 730ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov default: 731ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint parent = hint->parent; 733ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( parent ) 736ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos par_org_center, par_cur_center; 738ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos cur_org_center, cur_delta; 739ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* ensure that parent is already fitted */ 742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( !psh_hint_is_fitted( parent ) ) 743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_align_light( parent, globals, dimension, glyph ); 744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov par_org_center = parent->org_pos + ( parent->org_len / 2 ); 746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov par_cur_center = parent->cur_pos + ( parent->cur_len / 2 ); 747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cur_org_center = hint->org_pos + ( hint->org_len / 2 ); 748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cur_delta = FT_MulFix( cur_org_center - par_org_center, scale ); 750ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pos = par_cur_center + cur_delta - ( len >> 1 ); 751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* Stems less than one pixel wide are easy -- we want to 754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * make them as dark as possible, so they must fall within 755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * one pixel. If the stem is split between two pixels 756ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * then snap the edge that is nearer to the pixel boundary 757ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * to the pixel boundary. 758ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov */ 759ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( len <= 64 ) 760ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 761ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ( pos + len + 63 ) / 64 != pos / 64 + 1 ) 762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pos += psh_hint_snap_stem_side_delta ( pos, len ); 763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* Position stems other to minimize the amount of mid-grays. 766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * There are, in general, two positions that do this, 767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * illustrated as A) and B) below. 768ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * 769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * + + + + 770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * 771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * A) |--------------------------------| 772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * B) |--------------------------------| 773ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * C) |--------------------------------| 774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * 775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * Position A) (split the excess stem equally) should be better 776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * for stems of width N + f where f < 0.5. 777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * 778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * Position B) (split the deficiency equally) should be better 779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * for stems of width N + f where f > 0.5. 780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * 781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * It turns out though that minimizing the total number of lit 782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * pixels is also important, so position C), with one edge 783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * aligned with a pixel boundary is actually preferable 784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * to A). There are also more possibile positions for C) than 785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * for A) or B), so it involves less distortion of the overall 786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * character shape. 787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov */ 788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else /* len > 64 */ 789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed frac_len = len & 63; 791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed center = pos + ( len >> 1 ); 792ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed delta_a, delta_b; 793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 794ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 795ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ( len / 64 ) & 1 ) 796ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 797ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov delta_a = FT_PIX_FLOOR( center ) + 32 - center; 798ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov delta_b = FT_PIX_ROUND( center ) - center; 799ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 800ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 801ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 802ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov delta_a = FT_PIX_ROUND( center ) - center; 803ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov delta_b = FT_PIX_FLOOR( center ) + 32 - center; 804ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 805ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 806ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* We choose between B) and C) above based on the amount 807ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * of fractinal stem width; for small amounts, choose 808ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * C) always, for large amounts, B) always, and inbetween, 809ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * pick whichever one involves less stem movement. 810ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov */ 811ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( frac_len < 32 ) 812ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 813ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pos += psh_hint_snap_stem_side_delta ( pos, len ); 814ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 815ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( frac_len < 48 ) 816ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 817ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed side_delta = psh_hint_snap_stem_side_delta ( pos, 818ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov len ); 819ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 820ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( FT_ABS( side_delta ) < FT_ABS( delta_b ) ) 821ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pos += side_delta; 822ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 823ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pos += delta_b; 824ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 825ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 826ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 827ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pos += delta_b; 828ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 829ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 830ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 831ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->cur_pos = pos; 832ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 833ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } /* switch */ 834ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 835ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_set_fitted( hint ); 836ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 837ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef DEBUG_HINTER 838ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ps_debug_hint_func ) 839ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ps_debug_hint_func( hint, dimension ); 840ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif 841ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 842ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 843ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 844ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* 0 */ 845ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 846ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 847ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 848ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_align_hints( PSH_Hint_Table table, 849ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Globals globals, 850ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int dimension, 851ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Glyph glyph ) 852ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 853ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint hint; 854ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt count; 855ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 856ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef DEBUG_HINTER 857ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 858ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Dimension dim = &globals->dimension[dimension]; 859ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed scale = dim->scale_mult; 860ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed delta = dim->scale_delta; 861ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 862ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 863ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ps_debug_no_vert_hints && dimension == 0 ) 864ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 865ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ps_simple_scale( table, scale, delta, dimension ); 866ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 867ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 868ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 869ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ps_debug_no_horz_hints && dimension == 1 ) 870ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 871ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ps_simple_scale( table, scale, delta, dimension ); 872ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 873ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 874ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 875ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* DEBUG_HINTER*/ 876ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 877ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint = table->hints; 878ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov count = table->max_hints; 879ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 880ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( ; count > 0; count--, hint++ ) 881ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_align( hint, globals, dimension, glyph ); 882ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 883ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 884ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 885ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 886ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 887ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /***** *****/ 888ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /***** POINTS INTERPOLATION ROUTINES *****/ 889ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /***** *****/ 890ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 891ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 892ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 893ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define PSH_ZONE_MIN -3200000L 894ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define PSH_ZONE_MAX +3200000L 895ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 896ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define xxDEBUG_ZONES 897ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 898ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 899ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef DEBUG_ZONES 900ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 901ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "../../include/freetype/config/ftstdlib.h" 902ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 903ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 904ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_print_zone( PSH_Zone zone ) 905ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 906ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n", 907ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov zone->scale / 65536.0, 908ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov zone->delta / 64.0, 909ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov zone->min, 910ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov zone->max ); 911ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 912ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 913ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#else 914ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 915ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define psh_print_zone( x ) do { } while ( 0 ) 916ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 917ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* DEBUG_ZONES */ 918ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 919ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 920ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 921ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 922ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /***** *****/ 923ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /***** HINTER GLYPH MANAGEMENT *****/ 924ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /***** *****/ 925ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 926ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 927ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 928ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#if 1 929ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 930ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define psh_corner_is_flat ft_corner_is_flat 931ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define psh_corner_orientation ft_corner_orientation 932ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 933ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#else 934ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 935ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_LOCAL_DEF( FT_Int ) 936ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_corner_is_flat( FT_Pos x_in, 937ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos y_in, 938ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos x_out, 939ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos y_out ) 940ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 941ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos ax = x_in; 942ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos ay = y_in; 943ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 944ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos d_in, d_out, d_corner; 945ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 946ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 947ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ax < 0 ) 948ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ax = -ax; 949ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ay < 0 ) 950ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ay = -ay; 951ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov d_in = ax + ay; 952ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 953ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ax = x_out; 954ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ax < 0 ) 955ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ax = -ax; 956ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ay = y_out; 957ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ay < 0 ) 958ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ay = -ay; 959ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov d_out = ax + ay; 960ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 961ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ax = x_out + x_in; 962ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ax < 0 ) 963ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ax = -ax; 964ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ay = y_out + y_in; 965ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ay < 0 ) 966ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ay = -ay; 967ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov d_corner = ax + ay; 968ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 969ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return ( d_in + d_out - d_corner ) < ( d_corner >> 4 ); 970ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 971ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 972ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static FT_Int 973ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_corner_orientation( FT_Pos in_x, 974ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos in_y, 975ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos out_x, 976ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos out_y ) 977ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 978ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int result; 979ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 980ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 981ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* deal with the trivial cases quickly */ 982ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( in_y == 0 ) 983ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 984ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( in_x >= 0 ) 985ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov result = out_y; 986ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 987ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov result = -out_y; 988ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 989ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( in_x == 0 ) 990ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 991ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( in_y >= 0 ) 992ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov result = -out_x; 993ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 994ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov result = out_x; 995ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 996ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( out_y == 0 ) 997ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 998ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( out_x >= 0 ) 999ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov result = in_y; 1000ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1001ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov result = -in_y; 1002ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1003ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( out_x == 0 ) 1004ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1005ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( out_y >= 0 ) 1006ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov result = -in_x; 1007ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1008ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov result = in_x; 1009ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1010ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else /* general case */ 1011ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1012ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov long long delta = (long long)in_x * out_y - (long long)in_y * out_x; 1013ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1014ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( delta == 0 ) 1015ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov result = 0; 1016ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1017ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov result = 1 - 2 * ( delta < 0 ); 1018ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1019ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1020ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return result; 1021ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1022ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1023ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* !1 */ 1024ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1025ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1026ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef COMPUTE_INFLEXS 1027ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1028ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* compute all inflex points in a given glyph */ 1029ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 1030ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_compute_inflections( PSH_Glyph glyph ) 1031ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1032ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt n; 1033ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1034ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1035ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( n = 0; n < glyph->num_contours; n++ ) 1036ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1037ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point first, start, end, before, after; 1038ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos in_x, in_y, out_x, out_y; 1039ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int orient_prev, orient_cur; 1040ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int finished = 0; 1041ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1042ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1043ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* we need at least 4 points to create an inflection point */ 1044ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( glyph->contours[n].count < 4 ) 1045ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov continue; 1046ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1047ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* compute first segment in contour */ 1048ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov first = glyph->contours[n].start; 1049ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1050ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov start = end = first; 1051ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov do 1052ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1053ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov end = end->next; 1054ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( end == first ) 1055ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Skip; 1056ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1057ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov in_x = end->org_u - start->org_u; 1058ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov in_y = end->org_v - start->org_v; 1059ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1060ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } while ( in_x == 0 && in_y == 0 ); 1061ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1062ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* extend the segment start whenever possible */ 1063ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov before = start; 1064ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov do 1065ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1066ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov do 1067ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1068ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov start = before; 1069ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov before = before->prev; 1070ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( before == first ) 1071ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Skip; 1072ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1073ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov out_x = start->org_u - before->org_u; 1074ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov out_y = start->org_v - before->org_v; 1075ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1076ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } while ( out_x == 0 && out_y == 0 ); 1077ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1078ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov orient_prev = psh_corner_orientation( in_x, in_y, out_x, out_y ); 1079ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1080ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } while ( orient_prev == 0 ); 1081ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1082ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov first = start; 1083ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov in_x = out_x; 1084ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov in_y = out_y; 1085ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1086ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* now, process all segments in the contour */ 1087ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov do 1088ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1089ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* first, extend current segment's end whenever possible */ 1090ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov after = end; 1091ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov do 1092ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1093ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov do 1094ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1095ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov end = after; 1096ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov after = after->next; 1097ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( after == first ) 1098ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov finished = 1; 1099ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov out_x = after->org_u - end->org_u; 1101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov out_y = after->org_v - end->org_v; 1102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } while ( out_x == 0 && out_y == 0 ); 1104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov orient_cur = psh_corner_orientation( in_x, in_y, out_x, out_y ); 1106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } while ( orient_cur == 0 ); 1108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ( orient_cur ^ orient_prev ) < 0 ) 1110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov do 1112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_point_set_inflex( start ); 1114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov start = start->next; 1115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov while ( start != end ); 1117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_point_set_inflex( start ); 1119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov start = end; 1122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov end = after; 1123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov orient_prev = orient_cur; 1124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov in_x = out_x; 1125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov in_y = out_y; 1126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } while ( !finished ); 1128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Skip: 1130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ; 1131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* COMPUTE_INFLEXS */ 1135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 1138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_done( PSH_Glyph glyph ) 1139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Memory memory = glyph->memory; 1141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_done( &glyph->hint_tables[1], memory ); 1144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_done( &glyph->hint_tables[0], memory ); 1145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_FREE( glyph->points ); 1147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_FREE( glyph->contours ); 1148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov glyph->num_points = 0; 1150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov glyph->num_contours = 0; 1151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov glyph->memory = 0; 1153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static int 1157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_compute_dir( FT_Pos dx, 1158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos dy ) 1159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos ax, ay; 1161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int result = PSH_DIR_NONE; 1162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ax = FT_ABS( dx ); 1165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ay = FT_ABS( dy ); 1166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ay * 12 < ax ) 1168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* |dy| <<< |dx| means a near-horizontal segment */ 1170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov result = ( dx >= 0 ) ? PSH_DIR_RIGHT : PSH_DIR_LEFT; 1171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( ax * 12 < ay ) 1173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* |dx| <<< |dy| means a near-vertical segment */ 1175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov result = ( dy >= 0 ) ? PSH_DIR_UP : PSH_DIR_DOWN; 1176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return result; 1179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* load outline point coordinates into hinter glyph */ 1183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 1184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_load_points( PSH_Glyph glyph, 1185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int dimension ) 1186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Vector* vec = glyph->outline->points; 1188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point point = glyph->points; 1189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt count = glyph->num_points; 1190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( ; count > 0; count--, point++, vec++ ) 1193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->flags2 = 0; 1195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->hint = NULL; 1196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( dimension == 0 ) 1197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->org_u = vec->x; 1199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->org_v = vec->y; 1200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->org_u = vec->y; 1204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->org_v = vec->x; 1205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef DEBUG_HINTER 1208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->org_x = vec->x; 1209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->org_y = vec->y; 1210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif 1211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* save hinted point coordinates back to outline */ 1217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 1218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_save_points( PSH_Glyph glyph, 1219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int dimension ) 1220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt n; 1222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point point = glyph->points; 1223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Vector* vec = glyph->outline->points; 1224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov char* tags = glyph->outline->tags; 1225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( n = 0; n < glyph->num_points; n++ ) 1228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( dimension == 0 ) 1230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov vec[n].x = point->cur_u; 1231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov vec[n].y = point->cur_u; 1233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( psh_point_is_strong( point ) ) 1235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 ); 1236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef DEBUG_HINTER 1238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( dimension == 0 ) 1240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->cur_x = point->cur_u; 1242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->flags_x = point->flags2 | point->flags; 1243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->cur_y = point->cur_u; 1247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->flags_y = point->flags2 | point->flags; 1248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif 1251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point++; 1253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static FT_Error 1258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_init( PSH_Glyph glyph, 1259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Outline* outline, 1260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PS_Hints ps_hints, 1261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Globals globals ) 1262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Error error; 1264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Memory memory; 1265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* clear all fields */ 1268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_MEM_ZERO( glyph, sizeof ( *glyph ) ); 1269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov memory = glyph->memory = globals->memory; 1271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* allocate and setup points + contours arrays */ 1273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( FT_NEW_ARRAY( glyph->points, outline->n_points ) || 1274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_NEW_ARRAY( glyph->contours, outline->n_contours ) ) 1275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Exit; 1276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov glyph->num_points = outline->n_points; 1278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov glyph->num_contours = outline->n_contours; 1279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt first = 0, next, n; 1282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point points = glyph->points; 1283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Contour contour = glyph->contours; 1284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( n = 0; n < glyph->num_contours; n++ ) 1287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int count; 1289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point point; 1290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov next = outline->contours[n] + 1; 1293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov count = next - first; 1294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov contour->start = points + first; 1296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov contour->count = (FT_UInt)count; 1297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( count > 0 ) 1299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point = points + first; 1301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->prev = points + next - 1; 1303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->contour = contour; 1304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( ; count > 1; count-- ) 1306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point[0].next = point + 1; 1308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point[1].prev = point; 1309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point++; 1310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->contour = contour; 1311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->next = points + first; 1313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov contour++; 1316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov first = next; 1317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point points = glyph->points; 1322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point point = points; 1323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Vector* vec = outline->points; 1324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt n; 1325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( n = 0; n < glyph->num_points; n++, point++ ) 1328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int n_prev = (FT_Int)( point->prev - points ); 1330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int n_next = (FT_Int)( point->next - points ); 1331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos dxi, dyi, dxo, dyo; 1332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) ) 1335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->flags = PSH_POINT_OFF; 1336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov dxi = vec[n].x - vec[n_prev].x; 1338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov dyi = vec[n].y - vec[n_prev].y; 1339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->dir_in = (FT_Char)psh_compute_dir( dxi, dyi ); 1341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov dxo = vec[n_next].x - vec[n].x; 1343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov dyo = vec[n_next].y - vec[n].y; 1344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->dir_out = (FT_Char)psh_compute_dir( dxo, dyo ); 1346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* detect smooth points */ 1348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( point->flags & PSH_POINT_OFF ) 1349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->flags |= PSH_POINT_SMOOTH; 1350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( point->dir_in == point->dir_out ) 1352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( point->dir_out != PSH_DIR_NONE || 1354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_corner_is_flat( dxi, dyi, dxo, dyo ) ) 1355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->flags |= PSH_POINT_SMOOTH; 1356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov glyph->outline = outline; 1361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov glyph->globals = globals; 1362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef COMPUTE_INFLEXS 1364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_load_points( glyph, 0 ); 1365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_compute_inflections( glyph ); 1366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* COMPUTE_INFLEXS */ 1367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* now deal with hints tables */ 1369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov error = psh_hint_table_init( &glyph->hint_tables [0], 1370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &ps_hints->dimension[0].hints, 1371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &ps_hints->dimension[0].masks, 1372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &ps_hints->dimension[0].counters, 1373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov memory ); 1374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( error ) 1375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Exit; 1376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov error = psh_hint_table_init( &glyph->hint_tables [1], 1378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &ps_hints->dimension[1].hints, 1379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &ps_hints->dimension[1].masks, 1380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &ps_hints->dimension[1].counters, 1381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov memory ); 1382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( error ) 1383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Exit; 1384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Exit: 1386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return error; 1387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* compute all extrema in a glyph for a given dimension */ 1391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 1392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_compute_extrema( PSH_Glyph glyph ) 1393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt n; 1395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* first of all, compute all local extrema */ 1398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( n = 0; n < glyph->num_contours; n++ ) 1399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point first = glyph->contours[n].start; 1401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point point, before, after; 1402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( glyph->contours[n].count == 0 ) 1405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov continue; 1406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point = first; 1408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov before = point; 1409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov after = point; 1410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov do 1412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov before = before->prev; 1414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( before == first ) 1415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Skip; 1416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } while ( before->org_u == point->org_u ); 1418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov first = point = before->next; 1420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (;;) 1422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov after = point; 1424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov do 1425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov after = after->next; 1427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( after == first ) 1428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Next; 1429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } while ( after->org_u == point->org_u ); 1431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( before->org_u < point->org_u ) 1433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( after->org_u < point->org_u ) 1435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* local maximum */ 1437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Extremum; 1438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else /* before->org_u > point->org_u */ 1441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( after->org_u > point->org_u ) 1443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* local minimum */ 1445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Extremum: 1446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov do 1447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_point_set_extremum( point ); 1449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point = point->next; 1450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } while ( point != after ); 1452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov before = after->prev; 1456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point = after; 1457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } /* for */ 1459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Next: 1461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ; 1462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* for each extremum, determine its direction along the */ 1465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* orthogonal axis */ 1466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( n = 0; n < glyph->num_points; n++ ) 1467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point point, before, after; 1469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point = &glyph->points[n]; 1472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov before = point; 1473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov after = point; 1474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( psh_point_is_extremum( point ) ) 1476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov do 1478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov before = before->prev; 1480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( before == point ) 1481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Skip; 1482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } while ( before->org_v == point->org_v ); 1484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov do 1486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov after = after->next; 1488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( after == point ) 1489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Skip; 1490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } while ( after->org_v == point->org_v ); 1492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( before->org_v < point->org_v && 1495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov after->org_v > point->org_v ) 1496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_point_set_positive( point ); 1498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( before->org_v > point->org_v && 1500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov after->org_v < point->org_v ) 1501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_point_set_negative( point ); 1503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Skip: 1506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ; 1507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* major_dir is the direction for points on the bottom/left of the stem; */ 1512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* Points on the top/right of the stem will have a direction of */ 1513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* -major_dir. */ 1514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 1516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_find_strong_points( PSH_Hint_Table table, 1517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point point, 1518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt count, 1519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int threshold, 1520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int major_dir ) 1521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint* sort = table->sort; 1523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt num_hints = table->num_hints; 1524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( ; count > 0; count--, point++ ) 1527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int point_dir = 0; 1529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos org_u = point->org_u; 1530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( psh_point_is_strong( point ) ) 1533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov continue; 1534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( PSH_DIR_COMPARE( point->dir_in, major_dir ) ) 1536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point_dir = point->dir_in; 1537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( PSH_DIR_COMPARE( point->dir_out, major_dir ) ) 1539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point_dir = point->dir_out; 1540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( point_dir ) 1542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( point_dir == major_dir ) 1544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt nn; 1546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( nn = 0; nn < num_hints; nn++ ) 1549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint hint = sort[nn]; 1551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos d = org_u - hint->org_pos; 1552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( d < threshold && -d < threshold ) 1555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_point_set_strong( point ); 1557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->flags2 |= PSH_POINT_EDGE_MIN; 1558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->hint = hint; 1559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 1560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( point_dir == -major_dir ) 1564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt nn; 1566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( nn = 0; nn < num_hints; nn++ ) 1569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint hint = sort[nn]; 1571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos d = org_u - hint->org_pos - hint->org_len; 1572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( d < threshold && -d < threshold ) 1575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_point_set_strong( point ); 1577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->flags2 |= PSH_POINT_EDGE_MAX; 1578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->hint = hint; 1579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 1580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#if 1 1586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( psh_point_is_extremum( point ) ) 1587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* treat extrema as special cases for stem edge alignment */ 1589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt nn, min_flag, max_flag; 1590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( major_dir == PSH_DIR_HORIZONTAL ) 1593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov min_flag = PSH_POINT_POSITIVE; 1595ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov max_flag = PSH_POINT_NEGATIVE; 1596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov min_flag = PSH_POINT_NEGATIVE; 1600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov max_flag = PSH_POINT_POSITIVE; 1601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( point->flags2 & min_flag ) 1604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1605ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( nn = 0; nn < num_hints; nn++ ) 1606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1607ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint hint = sort[nn]; 1608ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos d = org_u - hint->org_pos; 1609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1610ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( d < threshold && -d < threshold ) 1612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->flags2 |= PSH_POINT_EDGE_MIN; 1614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->hint = hint; 1615ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_point_set_strong( point ); 1616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 1617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( point->flags2 & max_flag ) 1621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( nn = 0; nn < num_hints; nn++ ) 1623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint hint = sort[nn]; 1625ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos d = org_u - hint->org_pos - hint->org_len; 1626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( d < threshold && -d < threshold ) 1629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->flags2 |= PSH_POINT_EDGE_MAX; 1631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->hint = hint; 1632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_point_set_strong( point ); 1633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 1634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( point->hint == NULL ) 1639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( nn = 0; nn < num_hints; nn++ ) 1641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint hint = sort[nn]; 1643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1645ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( org_u >= hint->org_pos && 1646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov org_u <= hint->org_pos + hint->org_len ) 1647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1648ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->hint = hint; 1649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 1650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* 1 */ 1656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* the accepted shift for strong points in fractional pixels */ 1661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define PSH_STRONG_THRESHOLD 32 1662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* the maximum shift value in font units */ 1664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define PSH_STRONG_THRESHOLD_MAXIMUM 30 1665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* find strong points in a glyph */ 1668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 1669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_find_strong_points( PSH_Glyph glyph, 1670ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int dimension ) 1671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* a point is `strong' if it is located on a stem edge and */ 1673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* has an `in' or `out' tangent parallel to the hint's direction */ 1674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint_Table table = &glyph->hint_tables[dimension]; 1676ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PS_Mask mask = table->hint_masks->masks; 1677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt num_masks = table->hint_masks->num_masks; 1678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt first = 0; 1679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int major_dir = dimension == 0 ? PSH_DIR_VERTICAL 1680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov : PSH_DIR_HORIZONTAL; 1681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Dimension dim = &glyph->globals->dimension[dimension]; 1682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed scale = dim->scale_mult; 1683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int threshold; 1684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov threshold = (FT_Int)FT_DivFix( PSH_STRONG_THRESHOLD, scale ); 1687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( threshold > PSH_STRONG_THRESHOLD_MAXIMUM ) 1688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov threshold = PSH_STRONG_THRESHOLD_MAXIMUM; 1689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* process secondary hints to `selected' points */ 1691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( num_masks > 1 && glyph->num_points > 0 ) 1692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* the `endchar' op can reduce the number of points */ 1694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov first = mask->end_point > glyph->num_points 1695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ? glyph->num_points 1696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov : mask->end_point; 1697ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mask++; 1698ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( ; num_masks > 1; num_masks--, mask++ ) 1699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt next; 1701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int count; 1702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov next = mask->end_point > glyph->num_points 1705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ? glyph->num_points 1706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov : mask->end_point; 1707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov count = next - first; 1708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( count > 0 ) 1709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point point = glyph->points + first; 1711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_activate_mask( table, mask ); 1714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1715ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_find_strong_points( table, point, count, 1716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov threshold, major_dir ); 1717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov first = next; 1719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* process primary hints for all points */ 1723ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( num_masks == 1 ) 1724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt count = glyph->num_points; 1726ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point point = glyph->points; 1727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_activate_mask( table, table->hint_masks->masks ); 1730ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1731ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_find_strong_points( table, point, count, 1732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov threshold, major_dir ); 1733ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* now, certain points may have been attached to a hint and */ 1736ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* not marked as strong; update their flags then */ 1737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1738ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt count = glyph->num_points; 1739ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point point = glyph->points; 1740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( ; count > 0; count--, point++ ) 1743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( point->hint && !psh_point_is_strong( point ) ) 1744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_point_set_strong( point ); 1745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* find points in a glyph which are in a blue zone and have `in' or */ 1750ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* `out' tangents parallel to the horizontal axis */ 1751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 1752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_find_blue_points( PSH_Blues blues, 1753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Glyph glyph ) 1754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Blue_Table table; 1756ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Blue_Zone zone; 1757ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt glyph_count = glyph->num_points; 1758ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt blue_count; 1759ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point point = glyph->points; 1760ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1761ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( ; glyph_count > 0; glyph_count--, point++ ) 1763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos y; 1765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* check tangents */ 1768ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( !PSH_DIR_COMPARE( point->dir_in, PSH_DIR_HORIZONTAL ) && 1769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov !PSH_DIR_COMPARE( point->dir_out, PSH_DIR_HORIZONTAL ) ) 1770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov continue; 1771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* skip strong points */ 1773ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( psh_point_is_strong( point ) ) 1774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov continue; 1775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov y = point->org_u; 1777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* look up top zones */ 1779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov table = &blues->normal_top; 1780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov blue_count = table->count; 1781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov zone = table->zones; 1782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( ; blue_count > 0; blue_count--, zone++ ) 1784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos delta = y - zone->org_bottom; 1786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( delta < -blues->blue_fuzz ) 1789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 1790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( y <= zone->org_top + blues->blue_fuzz ) 1792ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( blues->no_overshoots || delta <= blues->blue_threshold ) 1793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1794ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->cur_u = zone->cur_bottom; 1795ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_point_set_strong( point ); 1796ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_point_set_fitted( point ); 1797ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1798ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1799ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1800ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* look up bottom zones */ 1801ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov table = &blues->normal_bottom; 1802ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov blue_count = table->count; 1803ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov zone = table->zones + blue_count - 1; 1804ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1805ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( ; blue_count > 0; blue_count--, zone-- ) 1806ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1807ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos delta = zone->org_top - y; 1808ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1809ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1810ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( delta < -blues->blue_fuzz ) 1811ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 1812ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1813ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( y >= zone->org_bottom - blues->blue_fuzz ) 1814ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( blues->no_overshoots || delta < blues->blue_threshold ) 1815ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1816ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->cur_u = zone->cur_top; 1817ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_point_set_strong( point ); 1818ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_point_set_fitted( point ); 1819ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1820ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1821ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1822ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1823ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1824ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1825ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* interpolate strong points with the help of hinted coordinates */ 1826ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 1827ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_interpolate_strong_points( PSH_Glyph glyph, 1828ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int dimension ) 1829ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1830ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Dimension dim = &glyph->globals->dimension[dimension]; 1831ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed scale = dim->scale_mult; 1832ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1833ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt count = glyph->num_points; 1834ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point point = glyph->points; 1835ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1836ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1837ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( ; count > 0; count--, point++ ) 1838ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1839ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Hint hint = point->hint; 1840ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1841ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1842ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( hint ) 1843ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1844ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos delta; 1845ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1846ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1847ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( psh_point_is_edge_min( point ) ) 1848ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->cur_u = hint->cur_pos; 1849ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1850ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( psh_point_is_edge_max( point ) ) 1851ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->cur_u = hint->cur_pos + hint->cur_len; 1852ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1853ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1854ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1855ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov delta = point->org_u - hint->org_pos; 1856ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1857ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( delta <= 0 ) 1858ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->cur_u = hint->cur_pos + FT_MulFix( delta, scale ); 1859ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1860ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( delta >= hint->org_len ) 1861ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->cur_u = hint->cur_pos + hint->cur_len + 1862ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_MulFix( delta - hint->org_len, scale ); 1863ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1864ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else /* hint->org_len > 0 */ 1865ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->cur_u = hint->cur_pos + 1866ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_MulDiv( delta, hint->cur_len, 1867ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint->org_len ); 1868ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1869ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_point_set_fitted( point ); 1870ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1871ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1872ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1873ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1874ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1875ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define PSH_MAX_STRONG_INTERNAL 16 1876ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1877ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 1878ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_interpolate_normal_points( PSH_Glyph glyph, 1879ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int dimension ) 1880ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1881ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1882ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#if 1 1883ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* first technique: a point is strong if it is a local extremum */ 1884ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1885ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Dimension dim = &glyph->globals->dimension[dimension]; 1886ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed scale = dim->scale_mult; 1887ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Memory memory = glyph->memory; 1888ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1889ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point* strongs = NULL; 1890ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point strongs_0[PSH_MAX_STRONG_INTERNAL]; 1891ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt num_strongs = 0; 1892ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1893ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point points = glyph->points; 1894ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point points_end = points + glyph->num_points; 1895ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point point; 1896ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1897ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1898ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* first count the number of strong points */ 1899ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( point = points; point < points_end; point++ ) 1900ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1901ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( psh_point_is_strong( point ) ) 1902ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov num_strongs++; 1903ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1904ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1905ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( num_strongs == 0 ) /* nothing to do here */ 1906ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 1907ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1908ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* allocate an array to store a list of points, */ 1909ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* stored in increasing org_u order */ 1910ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( num_strongs <= PSH_MAX_STRONG_INTERNAL ) 1911ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov strongs = strongs_0; 1912ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1913ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1914ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Error error; 1915ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1916ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1917ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( FT_NEW_ARRAY( strongs, num_strongs ) ) 1918ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 1919ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1920ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1921ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov num_strongs = 0; 1922ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( point = points; point < points_end; point++ ) 1923ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1924ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point* insert; 1925ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1926ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1927ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( !psh_point_is_strong( point ) ) 1928ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov continue; 1929ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1930ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( insert = strongs + num_strongs; insert > strongs; insert-- ) 1931ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1932ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( insert[-1]->org_u <= point->org_u ) 1933ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 1934ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1935ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov insert[0] = insert[-1]; 1936ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1937ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov insert[0] = point; 1938ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov num_strongs++; 1939ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1940ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1941ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* now try to interpolate all normal points */ 1942ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( point = points; point < points_end; point++ ) 1943ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1944ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( psh_point_is_strong( point ) ) 1945ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov continue; 1946ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1947ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* sometimes, some local extrema are smooth points */ 1948ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( psh_point_is_smooth( point ) ) 1949ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1950ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( point->dir_in == PSH_DIR_NONE || 1951ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->dir_in != point->dir_out ) 1952ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov continue; 1953ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1954ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( !psh_point_is_extremum( point ) && 1955ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov !psh_point_is_inflex( point ) ) 1956ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov continue; 1957ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1958ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->flags &= ~PSH_POINT_SMOOTH; 1959ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1960ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1961ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* find best enclosing point coordinates then interpolate */ 1962ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1963ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point before, after; 1964ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt nn; 1965ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1966ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1967ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( nn = 0; nn < num_strongs; nn++ ) 1968ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( strongs[nn]->org_u > point->org_u ) 1969ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 1970ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1971ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( nn == 0 ) /* point before the first strong point */ 1972ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1973ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov after = strongs[0]; 1974ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1975ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->cur_u = after->cur_u + 1976ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_MulFix( point->org_u - after->org_u, 1977ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov scale ); 1978ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1979ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1980ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1981ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov before = strongs[nn - 1]; 1982ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1983ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( nn = num_strongs; nn > 0; nn-- ) 1984ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( strongs[nn - 1]->org_u < point->org_u ) 1985ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 1986ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1987ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( nn == num_strongs ) /* point is after last strong point */ 1988ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1989ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov before = strongs[nn - 1]; 1990ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1991ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->cur_u = before->cur_u + 1992ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_MulFix( point->org_u - before->org_u, 1993ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov scale ); 1994ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1995ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1996ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1997ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos u; 1998ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1999ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2000ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov after = strongs[nn]; 2001ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2002ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* now interpolate point between before and after */ 2003ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov u = point->org_u; 2004ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2005ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( u == before->org_u ) 2006ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->cur_u = before->cur_u; 2007ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2008ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( u == after->org_u ) 2009ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->cur_u = after->cur_u; 2010ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2011ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 2012ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->cur_u = before->cur_u + 2013ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_MulDiv( u - before->org_u, 2014ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov after->cur_u - before->cur_u, 2015ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov after->org_u - before->org_u ); 2016ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2017ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2018ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_point_set_fitted( point ); 2019ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2020ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2021ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2022ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( strongs != strongs_0 ) 2023ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_FREE( strongs ); 2024ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2025ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* 1 */ 2026ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2027ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2028ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2029ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2030ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* interpolate other points */ 2031ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static void 2032ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_interpolate_other_points( PSH_Glyph glyph, 2033ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int dimension ) 2034ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2035ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Dimension dim = &glyph->globals->dimension[dimension]; 2036ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed scale = dim->scale_mult; 2037ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed delta = dim->scale_delta; 2038ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Contour contour = glyph->contours; 2039ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt num_contours = glyph->num_contours; 2040ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2041ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2042ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( ; num_contours > 0; num_contours--, contour++ ) 2043ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2044ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point start = contour->start; 2045ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Point first, next, point; 2046ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_UInt fit_count; 2047ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2048ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2049ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* count the number of strong points in this contour */ 2050ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov next = start + contour->count; 2051ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov fit_count = 0; 2052ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov first = 0; 2053ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2054ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( point = start; point < next; point++ ) 2055ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( psh_point_is_fitted( point ) ) 2056ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2057ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( !first ) 2058ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov first = point; 2059ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2060ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov fit_count++; 2061ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2062ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2063ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* if there are less than 2 fitted points in the contour, we */ 2064ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* simply scale and eventually translate the contour points */ 2065ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( fit_count < 2 ) 2066ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2067ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( fit_count == 1 ) 2068ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov delta = first->cur_u - FT_MulFix( first->org_u, scale ); 2069ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2070ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( point = start; point < next; point++ ) 2071ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( point != first ) 2072ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->cur_u = FT_MulFix( point->org_u, scale ) + delta; 2073ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2074ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Next_Contour; 2075ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2076ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2077ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* there are more than 2 strong points in this contour; we */ 2078ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* need to interpolate weak points between them */ 2079ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov start = first; 2080ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov do 2081ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2082ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point = first; 2083ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2084ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* skip consecutive fitted points */ 2085ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (;;) 2086ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2087ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov next = first->next; 2088ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( next == start ) 2089ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Next_Contour; 2090ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2091ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( !psh_point_is_fitted( next ) ) 2092ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 2093ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2094ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov first = next; 2095ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2096ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2097ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* find next fitted point after unfitted one */ 2098ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (;;) 2099ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov next = next->next; 2101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( psh_point_is_fitted( next ) ) 2102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 2103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* now interpolate between them */ 2106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos org_a, org_ab, cur_a, cur_ab; 2108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Pos org_c, org_ac, cur_c; 2109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed scale_ab; 2110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( first->org_u <= next->org_u ) 2113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov org_a = first->org_u; 2115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cur_a = first->cur_u; 2116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov org_ab = next->org_u - org_a; 2117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cur_ab = next->cur_u - cur_a; 2118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 2120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov org_a = next->org_u; 2122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cur_a = next->cur_u; 2123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov org_ab = first->org_u - org_a; 2124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cur_ab = first->cur_u - cur_a; 2125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov scale_ab = 0x10000L; 2128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( org_ab > 0 ) 2129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov scale_ab = FT_DivFix( cur_ab, org_ab ); 2130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point = first->next; 2132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov do 2133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov org_c = point->org_u; 2135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov org_ac = org_c - org_a; 2136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( org_ac <= 0 ) 2138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* on the left of the interpolation zone */ 2140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cur_c = cur_a + FT_MulFix( org_ac, scale ); 2141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else if ( org_ac >= org_ab ) 2143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* on the right on the interpolation zone */ 2145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale ); 2146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 2148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* within the interpolation zone */ 2150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cur_c = cur_a + FT_MulFix( org_ac, scale_ab ); 2151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point->cur_u = cur_c; 2154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov point = point->next; 2156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } while ( point != next ); 2158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* keep going until all points in the contours have been processed */ 2161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov first = next; 2162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } while ( first != start ); 2164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Next_Contour: 2166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ; 2167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 2172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 2173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /***** *****/ 2174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /***** HIGH-LEVEL INTERFACE *****/ 2175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /***** *****/ 2176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 2177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /*************************************************************************/ 2178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Error 2180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ps_hints_apply( PS_Hints ps_hints, 2181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Outline* outline, 2182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Globals globals, 2183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Render_Mode hint_mode ) 2184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_GlyphRec glyphrec; 2186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Glyph glyph = &glyphrec; 2187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Error error; 2188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef DEBUG_HINTER 2189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Memory memory; 2190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif 2191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Int dimension; 2192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* something to do? */ 2195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( outline->n_points == 0 || outline->n_contours == 0 ) 2196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FT_Err_Ok; 2197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef DEBUG_HINTER 2199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov memory = globals->memory; 2201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( ps_debug_glyph ) 2203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_done( ps_debug_glyph ); 2205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_FREE( ps_debug_glyph ); 2206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( FT_NEW( glyph ) ) 2209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return error; 2210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ps_debug_glyph = glyph; 2212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* DEBUG_HINTER */ 2214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov error = psh_glyph_init( glyph, outline, ps_hints, globals ); 2216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( error ) 2217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Exit; 2218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* try to optimize the y_scale so that the top of non-capital letters 2220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * is aligned on a pixel boundary whenever possible 2221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov */ 2222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Dimension dim_x = &glyph->globals->dimension[0]; 2224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PSH_Dimension dim_y = &glyph->globals->dimension[1]; 2225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed x_scale = dim_x->scale_mult; 2227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed y_scale = dim_y->scale_mult; 2228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed old_x_scale = x_scale; 2230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed old_y_scale = y_scale; 2231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed scaled; 2233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Fixed fitted; 2234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FT_Bool rescale = FALSE; 2236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov scaled = FT_MulFix( globals->blues.normal_top.zones->org_ref, y_scale ); 2239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov fitted = FT_PIX_ROUND( scaled ); 2240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( fitted != 0 && scaled != fitted ) 2242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov rescale = TRUE; 2244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov y_scale = FT_MulDiv( y_scale, fitted, scaled ); 2246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( fitted < scaled ) 2248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov x_scale -= x_scale / 50; 2249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_globals_set_scale( glyph->globals, x_scale, y_scale, 0, 0 ); 2251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov glyph->do_horz_hints = 1; 2254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov glyph->do_vert_hints = 1; 2255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov glyph->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO || 2257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint_mode == FT_RENDER_MODE_LCD ); 2258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov glyph->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO || 2260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hint_mode == FT_RENDER_MODE_LCD_V ); 2261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov glyph->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT ); 2263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for ( dimension = 0; dimension < 2; dimension++ ) 2265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 2266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* load outline coordinates into glyph */ 2267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_load_points( glyph, dimension ); 2268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* compute local extrema */ 2270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_compute_extrema( glyph ); 2271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* compute aligned stem/hints positions */ 2273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_hint_table_align_hints( &glyph->hint_tables[dimension], 2274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov glyph->globals, 2275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov dimension, 2276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov glyph ); 2277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* find strong points, align them, then interpolate others */ 2279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_find_strong_points( glyph, dimension ); 2280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( dimension == 1 ) 2281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_find_blue_points( &globals->blues, glyph ); 2282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_interpolate_strong_points( glyph, dimension ); 2283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_interpolate_normal_points( glyph, dimension ); 2284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_interpolate_other_points( glyph, dimension ); 2285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov /* save hinted coordinates back to outline */ 2287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_save_points( glyph, dimension ); 2288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ( rescale ) 2290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_globals_set_scale( glyph->globals, 2291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov old_x_scale, old_y_scale, 0, 0 ); 2292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Exit: 2296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifndef DEBUG_HINTER 2298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov psh_glyph_done( glyph ); 2299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif 2300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return error; 2302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 2303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 2305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* END */ 2306