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