blob: 21bd2a29151f18270c25e899b700aaf0cb4a7f70 [file] [log] [blame]
Werner Lembergc3b21602001-12-05 01:22:05 +00001/***************************************************************************/
2/* */
3/* pshglob.c */
4/* */
5/* PostScript hinter global hinting management (body). */
6/* Inspired by the new auto-hinter module. */
7/* */
8/* Copyright 2001 by */
9/* David Turner, Robert Wilhelm, and Werner Lemberg. */
10/* */
11/* This file is part of the FreeType project, and may only be used */
12/* modified and distributed under the terms of the FreeType project */
13/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
14/* this file you indicate that you have read the license and */
15/* understand and accept it fully. */
16/* */
17/***************************************************************************/
18
19
David Turnera83bc082001-10-18 11:38:43 +000020#include <ft2build.h>
21#include FT_FREETYPE_H
22#include FT_INTERNAL_OBJECTS_H
23#include "pshglob.h"
24
25#ifdef DEBUG_HINTER
Werner Lembergc3b21602001-12-05 01:22:05 +000026 extern PSH_Globals ps_debug_globals = 0;
27#endif
David Turnera83bc082001-10-18 11:38:43 +000028
David Turnera83bc082001-10-18 11:38:43 +000029
Werner Lembergc3b21602001-12-05 01:22:05 +000030 /*************************************************************************/
31 /*************************************************************************/
32 /***** *****/
33 /***** STANDARD WIDTHS *****/
34 /***** *****/
35 /*************************************************************************/
36 /*************************************************************************/
David Turnera83bc082001-10-18 11:38:43 +000037
Werner Lembergc3b21602001-12-05 01:22:05 +000038
39 /* scale the widths/heights table */
David Turnera83bc082001-10-18 11:38:43 +000040 static void
Werner Lembergc3b21602001-12-05 01:22:05 +000041 psh_globals_scale_widths( PSH_Globals globals,
42 FT_UInt direction )
David Turnera83bc082001-10-18 11:38:43 +000043 {
44 PSH_Dimension dim = &globals->dimension[direction];
Werner Lemberg49bcf782002-03-06 06:05:56 +000045 PSH_Widths stdw = &dim->stdw;
46 FT_UInt count = stdw->count;
47 PSH_Width width = stdw->widths;
David Turnera83bc082001-10-18 11:38:43 +000048 FT_Fixed scale = dim->scale_mult;
49
Werner Lembergc3b21602001-12-05 01:22:05 +000050
David Turnera83bc082001-10-18 11:38:43 +000051 for ( ; count > 0; count--, width++ )
52 {
53 width->cur = FT_MulFix( width->org, scale );
54 width->fit = FT_RoundFix( width->cur );
55 }
56 }
57
58
Werner Lembergc3b21602001-12-05 01:22:05 +000059 /* org_width is is font units, result in device pixels, 26.6 format */
David Turnerbc82f1b2002-03-01 02:26:22 +000060 FT_LOCAL_DEF( FT_Pos )
David Turnera83bc082001-10-18 11:38:43 +000061 psh_dimension_snap_width( PSH_Dimension dimension,
62 FT_Int org_width )
63 {
64 FT_UInt n;
65 FT_Pos width = FT_MulFix( org_width, dimension->scale_mult );
66 FT_Pos best = 64 + 32 + 2;
67 FT_Pos reference = width;
68
Werner Lembergc3b21602001-12-05 01:22:05 +000069
Werner Lemberg49bcf782002-03-06 06:05:56 +000070 for ( n = 0; n < dimension->stdw.count; n++ )
David Turnera83bc082001-10-18 11:38:43 +000071 {
72 FT_Pos w;
73 FT_Pos dist;
74
Werner Lembergc3b21602001-12-05 01:22:05 +000075
Werner Lemberg49bcf782002-03-06 06:05:56 +000076 w = dimension->stdw.widths[n].cur;
David Turnera83bc082001-10-18 11:38:43 +000077 dist = width - w;
78 if ( dist < 0 )
79 dist = -dist;
80 if ( dist < best )
81 {
82 best = dist;
83 reference = w;
84 }
85 }
86
87 if ( width >= reference )
88 {
89 width -= 0x21;
90 if ( width < reference )
91 width = reference;
92 }
93 else
94 {
95 width += 0x21;
96 if ( width > reference )
97 width = reference;
98 }
99
100 return width;
101 }
102
103
Werner Lembergc3b21602001-12-05 01:22:05 +0000104 /*************************************************************************/
105 /*************************************************************************/
106 /***** *****/
107 /***** BLUE ZONES *****/
108 /***** *****/
109 /*************************************************************************/
110 /*************************************************************************/
David Turnera83bc082001-10-18 11:38:43 +0000111
112 static void
113 psh_blues_set_zones_0( PSH_Blues target,
114 FT_Bool is_others,
115 FT_UInt read_count,
116 FT_Short* read,
117 PSH_Blue_Table top_table,
118 PSH_Blue_Table bot_table )
119 {
Werner Lembergc3b21602001-12-05 01:22:05 +0000120 FT_UInt count_top = top_table->count;
121 FT_UInt count_bot = bot_table->count;
122 FT_Bool first = 1;
David Turner12d40da2001-10-21 15:41:11 +0000123
Werner Lembergc3b21602001-12-05 01:22:05 +0000124 FT_UNUSED( target );
125
126
David Turnera83bc082001-10-18 11:38:43 +0000127 for ( ; read_count > 0; read_count -= 2 )
128 {
129 FT_Int reference, delta;
130 FT_UInt count;
131 PSH_Blue_Zone zones, zone;
132 FT_Bool top;
Werner Lembergc3b21602001-12-05 01:22:05 +0000133
134
David Turnera83bc082001-10-18 11:38:43 +0000135 /* read blue zone entry, and select target top/bottom zone */
136 top = 0;
137 if ( first || is_others )
138 {
139 reference = read[1];
140 delta = read[0] - reference;
141
142 zones = bot_table->zones;
143 count = count_bot;
144 first = 0;
145 }
146 else
147 {
148 reference = read[0];
149 delta = read[1] - reference;
Werner Lembergc3b21602001-12-05 01:22:05 +0000150
David Turnera83bc082001-10-18 11:38:43 +0000151 zones = top_table->zones;
152 count = count_top;
153 top = 1;
154 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000155
David Turnera83bc082001-10-18 11:38:43 +0000156 /* insert into sorted table */
Werner Lembergc3b21602001-12-05 01:22:05 +0000157 zone = zones;
David Turnera83bc082001-10-18 11:38:43 +0000158 for ( ; count > 0; count--, zone++ )
159 {
160 if ( reference < zone->org_ref )
161 break;
Werner Lembergc3b21602001-12-05 01:22:05 +0000162
David Turnera83bc082001-10-18 11:38:43 +0000163 if ( reference == zone->org_ref )
164 {
165 FT_Int delta0 = zone->org_delta;
166
Werner Lembergc3b21602001-12-05 01:22:05 +0000167
168 /* we have two zones on the same reference position -- */
169 /* only keep the largest one */
David Turnera83bc082001-10-18 11:38:43 +0000170 if ( delta < 0 )
171 {
172 if ( delta < delta0 )
173 zone->org_delta = delta;
174 }
175 else
176 {
177 if ( delta > delta0 )
178 zone->org_delta = delta;
179 }
180 goto Skip;
181 }
182 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000183
David Turnera83bc082001-10-18 11:38:43 +0000184 for ( ; count > 0; count-- )
185 zone[count] = zone[count-1];
Werner Lembergc3b21602001-12-05 01:22:05 +0000186
David Turnera83bc082001-10-18 11:38:43 +0000187 zone->org_ref = reference;
188 zone->org_delta = delta;
Werner Lembergc3b21602001-12-05 01:22:05 +0000189
David Turnera83bc082001-10-18 11:38:43 +0000190 if ( top )
Werner Lembergc3b21602001-12-05 01:22:05 +0000191 count_top++;
David Turnera83bc082001-10-18 11:38:43 +0000192 else
Werner Lembergc3b21602001-12-05 01:22:05 +0000193 count_bot++;
194
David Turnera83bc082001-10-18 11:38:43 +0000195 Skip:
196 read += 2;
Werner Lembergc3b21602001-12-05 01:22:05 +0000197 }
David Turnera83bc082001-10-18 11:38:43 +0000198
199 top_table->count = count_top;
200 bot_table->count = count_bot;
Werner Lembergc3b21602001-12-05 01:22:05 +0000201 }
David Turnera83bc082001-10-18 11:38:43 +0000202
203
Werner Lembergc3b21602001-12-05 01:22:05 +0000204 /* Re-read blue zones from the original fonts and store them into out */
205 /* private structure. This function re-orders, sanitizes and */
206 /* fuzz-expands the zones as well. */
David Turnera83bc082001-10-18 11:38:43 +0000207 static void
Werner Lembergc3b21602001-12-05 01:22:05 +0000208 psh_blues_set_zones( PSH_Blues target,
209 FT_UInt count,
210 FT_Short* blues,
211 FT_UInt count_others,
212 FT_Short* other_blues,
213 FT_Int fuzz,
214 FT_Int family )
David Turnera83bc082001-10-18 11:38:43 +0000215 {
216 PSH_Blue_Table top_table, bot_table;
217 FT_Int count_top, count_bot;
Werner Lembergc3b21602001-12-05 01:22:05 +0000218
219
David Turnera83bc082001-10-18 11:38:43 +0000220 if ( family )
221 {
Werner Lembergc3b21602001-12-05 01:22:05 +0000222 top_table = &target->family_top;
223 bot_table = &target->family_bottom;
David Turnera83bc082001-10-18 11:38:43 +0000224 }
225 else
226 {
Werner Lembergc3b21602001-12-05 01:22:05 +0000227 top_table = &target->normal_top;
228 bot_table = &target->normal_bottom;
David Turnera83bc082001-10-18 11:38:43 +0000229 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000230
231 /* read the input blue zones, and build two sorted tables */
232 /* (one for the top zones, the other for the bottom zones) */
David Turnera83bc082001-10-18 11:38:43 +0000233 top_table->count = 0;
234 bot_table->count = 0;
Werner Lembergc3b21602001-12-05 01:22:05 +0000235
David Turnera83bc082001-10-18 11:38:43 +0000236 /* first, the blues */
Werner Lembergc3b21602001-12-05 01:22:05 +0000237 psh_blues_set_zones_0( target, 0,
238 count, blues, top_table, bot_table );
239 psh_blues_set_zones_0( target, 1,
240 count_others, other_blues, top_table, bot_table );
241
David Turnera83bc082001-10-18 11:38:43 +0000242 count_top = top_table->count;
243 count_bot = bot_table->count;
Werner Lembergc3b21602001-12-05 01:22:05 +0000244
David Turnera83bc082001-10-18 11:38:43 +0000245 /* sanitize top table */
246 if ( count_top > 0 )
247 {
248 PSH_Blue_Zone zone = top_table->zones;
Werner Lembergc3b21602001-12-05 01:22:05 +0000249
250
David Turnera83bc082001-10-18 11:38:43 +0000251 for ( count = count_top; count > 0; count--, zone++ )
252 {
253 FT_Int delta;
Werner Lembergc3b21602001-12-05 01:22:05 +0000254
255
David Turnera83bc082001-10-18 11:38:43 +0000256 if ( count > 1 )
257 {
258 delta = zone[1].org_ref - zone[0].org_ref;
259 if ( zone->org_delta > delta )
260 zone->org_delta = delta;
261 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000262
David Turnera83bc082001-10-18 11:38:43 +0000263 zone->org_bottom = zone->org_ref;
264 zone->org_top = zone->org_delta + zone->org_ref;
265 }
266 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000267
David Turnera83bc082001-10-18 11:38:43 +0000268 /* sanitize bottom table */
269 if ( count_bot > 0 )
270 {
271 PSH_Blue_Zone zone = bot_table->zones;
272
Werner Lembergc3b21602001-12-05 01:22:05 +0000273
David Turnera83bc082001-10-18 11:38:43 +0000274 for ( count = count_bot; count > 0; count--, zone++ )
275 {
276 FT_Int delta;
Werner Lembergc3b21602001-12-05 01:22:05 +0000277
278
David Turnera83bc082001-10-18 11:38:43 +0000279 if ( count > 1 )
280 {
281 delta = zone[0].org_ref - zone[1].org_ref;
282 if ( zone->org_delta < delta )
283 zone->org_delta = delta;
284 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000285
David Turnera83bc082001-10-18 11:38:43 +0000286 zone->org_top = zone->org_ref;
287 zone->org_bottom = zone->org_delta + zone->org_ref;
288 }
289 }
290
291 /* expand top and bottom tables with blue fuzz */
292 {
293 FT_Int dim, top, bot, delta;
294 PSH_Blue_Zone zone;
295
Werner Lembergc3b21602001-12-05 01:22:05 +0000296
David Turnera83bc082001-10-18 11:38:43 +0000297 zone = top_table->zones;
298 count = count_top;
Werner Lembergc3b21602001-12-05 01:22:05 +0000299
David Turnera83bc082001-10-18 11:38:43 +0000300 for ( dim = 1; dim >= 0; dim-- )
301 {
302 if ( count > 0 )
303 {
304 /* expand the bottom of the lowest zone normally */
305 zone->org_bottom -= fuzz;
Werner Lembergc3b21602001-12-05 01:22:05 +0000306
307 /* expand the top and bottom of intermediate zones; */
David Turnera83bc082001-10-18 11:38:43 +0000308 /* checking that the interval is smaller than the fuzz */
309 top = zone->org_top;
Werner Lembergc3b21602001-12-05 01:22:05 +0000310
David Turnera83bc082001-10-18 11:38:43 +0000311 for ( count--; count > 0; count-- )
312 {
313 bot = zone[1].org_bottom;
314 delta = bot - top;
Werner Lembergc3b21602001-12-05 01:22:05 +0000315
316 if ( delta < 2 * fuzz )
317 zone[0].org_top = zone[1].org_bottom = top + delta / 2;
David Turnera83bc082001-10-18 11:38:43 +0000318 else
319 {
320 zone[0].org_top = top + fuzz;
321 zone[1].org_bottom = bot - fuzz;
322 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000323
David Turnera83bc082001-10-18 11:38:43 +0000324 zone++;
325 top = zone->org_top;
326 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000327
David Turnera83bc082001-10-18 11:38:43 +0000328 /* expand the top of the highest zone normally */
329 zone->org_top = top + fuzz;
330 }
331 zone = bot_table->zones;
332 count = count_bot;
333 }
334 }
335 }
336
337
Werner Lembergc3b21602001-12-05 01:22:05 +0000338 /* reset the blues table when the device transform changes */
David Turnera83bc082001-10-18 11:38:43 +0000339 static void
340 psh_blues_scale_zones( PSH_Blues blues,
341 FT_Fixed scale,
342 FT_Pos delta )
343 {
344 FT_UInt count;
345 FT_UInt num;
346 PSH_Blue_Table table = 0;
Werner Lembergc3b21602001-12-05 01:22:05 +0000347
David Turner2b30c172001-12-12 16:07:29 +0000348 /* */
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000349 /* Determine whether we need to suppress overshoots or */
350 /* not. We simply need to compare the vertical scale */
351 /* parameter to the raw bluescale value. Here is why: */
David Turner2b30c172001-12-12 16:07:29 +0000352 /* */
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000353 /* We need to suppress overshoots for all pointsizes. */
354 /* At 300dpi that satisfy: */
David Turner2b30c172001-12-12 16:07:29 +0000355 /* */
356 /* pointsize < 240*bluescale + 0.49 */
357 /* */
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000358 /* This corresponds to: */
David Turner2b30c172001-12-12 16:07:29 +0000359 /* */
360 /* pixelsize < 1000*bluescale + 49/24 */
361 /* */
362 /* scale*EM_Size < 1000*bluescale + 49/24 */
363 /* */
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000364 /* However, for normal Type 1 fonts, EM_Size is 1000! */
365 /* We thus only check: */
David Turner2b30c172001-12-12 16:07:29 +0000366 /* */
367 /* scale < bluescale + 49/24000 */
368 /* */
369 /* which we shorten to */
370 /* */
371 /* "scale < bluescale" */
372 /* */
373 blues->no_overshoots = FT_BOOL( scale < blues->blue_scale );
374
375 /* */
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000376 /* The blue threshold is the font units distance under */
David Turner2b30c172001-12-12 16:07:29 +0000377 /* which overshoots are suppressed due to the BlueShift */
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000378 /* even if the scale is greater than BlueScale. */
David Turner2b30c172001-12-12 16:07:29 +0000379 /* */
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000380 /* It is the smallest distance such that */
David Turner2b30c172001-12-12 16:07:29 +0000381 /* */
382 /* dist <= BlueShift && dist*scale <= 0.5 pixels */
383 /* */
384 {
385 FT_Int threshold = blues->blue_shift;
David Turnerbce29862001-12-14 14:52:58 +0000386
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000387
David Turner2b30c172001-12-12 16:07:29 +0000388 while ( threshold > 0 && FT_MulFix( threshold, scale ) > 32 )
389 threshold --;
David Turnerbce29862001-12-14 14:52:58 +0000390
David Turner2b30c172001-12-12 16:07:29 +0000391 blues->blue_threshold = threshold;
392 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000393
David Turnera83bc082001-10-18 11:38:43 +0000394 for ( num = 0; num < 4; num++ )
395 {
396 PSH_Blue_Zone zone;
Werner Lembergc3b21602001-12-05 01:22:05 +0000397
398
399 switch ( num )
David Turnera83bc082001-10-18 11:38:43 +0000400 {
Werner Lembergc3b21602001-12-05 01:22:05 +0000401 case 0:
402 table = &blues->normal_top;
403 break;
404 case 1:
405 table = &blues->normal_bottom;
406 break;
407 case 2:
408 table = &blues->family_top;
409 break;
410 default:
411 table = &blues->family_bottom;
412 break;
David Turnera83bc082001-10-18 11:38:43 +0000413 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000414
David Turnera83bc082001-10-18 11:38:43 +0000415 zone = table->zones;
416 count = table->count;
417 for ( ; count > 0; count--, zone++ )
418 {
Werner Lembergc3b21602001-12-05 01:22:05 +0000419 zone->cur_top = FT_MulFix( zone->org_top, scale ) + delta;
David Turnera83bc082001-10-18 11:38:43 +0000420 zone->cur_bottom = FT_MulFix( zone->org_bottom, scale ) + delta;
Werner Lembergc3b21602001-12-05 01:22:05 +0000421 zone->cur_ref = FT_MulFix( zone->org_ref, scale ) + delta;
422 zone->cur_delta = FT_MulFix( zone->org_delta, scale );
423
David Turnera83bc082001-10-18 11:38:43 +0000424 /* round scaled reference position */
425 zone->cur_ref = ( zone->cur_ref + 32 ) & -64;
426
Werner Lembergc3b21602001-12-05 01:22:05 +0000427#if 0
David Turnera83bc082001-10-18 11:38:43 +0000428 if ( zone->cur_ref > zone->cur_top )
429 zone->cur_ref -= 64;
430 else if ( zone->cur_ref < zone->cur_bottom )
431 zone->cur_ref += 64;
Werner Lembergc3b21602001-12-05 01:22:05 +0000432#endif
David Turnera83bc082001-10-18 11:38:43 +0000433 }
434 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000435
David Turner2b30c172001-12-12 16:07:29 +0000436 /* process the families now */
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000437
David Turner2b30c172001-12-12 16:07:29 +0000438 for ( num = 0; num < 2; num++ )
David Turnerbce29862001-12-14 14:52:58 +0000439 {
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000440 PSH_Blue_Zone zone1, zone2;
441 FT_UInt count1, count2;
442 PSH_Blue_Table normal, family;
David Turnerbce29862001-12-14 14:52:58 +0000443
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000444
445 switch ( num )
David Turner2b30c172001-12-12 16:07:29 +0000446 {
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000447 case 0:
448 normal = &blues->normal_top;
449 family = &blues->family_top;
450 break;
David Turnerbce29862001-12-14 14:52:58 +0000451
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000452 default:
453 normal = &blues->normal_bottom;
454 family = &blues->family_bottom;
David Turner2b30c172001-12-12 16:07:29 +0000455 }
David Turnerbce29862001-12-14 14:52:58 +0000456
David Turner2b30c172001-12-12 16:07:29 +0000457 zone1 = normal->zones;
458 count1 = normal->count;
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000459
David Turner2b30c172001-12-12 16:07:29 +0000460 for ( ; count1 > 0; count1--, zone1++ )
461 {
462 /* try to find a family zone whose reference position is less */
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000463 /* than 1 pixel far from the current zone */
David Turner2b30c172001-12-12 16:07:29 +0000464 zone2 = family->zones;
465 count2 = family->count;
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000466
David Turner2b30c172001-12-12 16:07:29 +0000467 for ( ; count2 > 0; count2--, zone2++ )
468 {
469 if ( FT_MulFix( zone1->org_ref - zone2->org_ref, scale ) < 64 )
470 {
471 zone1->cur_top = zone2->cur_top;
472 zone1->cur_bottom = zone2->cur_bottom;
473 zone1->cur_ref = zone2->cur_ref;
474 zone1->cur_delta = zone2->cur_delta;
475 break;
476 }
477 }
478 }
479 }
David Turnera83bc082001-10-18 11:38:43 +0000480 }
481
482
David Turnerbc82f1b2002-03-01 02:26:22 +0000483 FT_LOCAL_DEF( void )
David Turnera83bc082001-10-18 11:38:43 +0000484 psh_blues_snap_stem( PSH_Blues blues,
485 FT_Int stem_top,
486 FT_Int stem_bot,
487 PSH_Alignment alignment )
488 {
489 PSH_Blue_Table table;
490 FT_UInt count;
David Turner2b30c172001-12-12 16:07:29 +0000491 FT_Pos delta;
David Turnera83bc082001-10-18 11:38:43 +0000492 PSH_Blue_Zone zone;
David Turner2b30c172001-12-12 16:07:29 +0000493 FT_Int no_shoots;
Werner Lembergc3b21602001-12-05 01:22:05 +0000494
495
Werner Lemberga7d2f5e2002-02-19 01:12:23 +0000496 alignment->align = PSH_BLUE_ALIGN_NONE;
Werner Lembergc3b21602001-12-05 01:22:05 +0000497
David Turner2b30c172001-12-12 16:07:29 +0000498 no_shoots = blues->no_overshoots;
499
David Turnera83bc082001-10-18 11:38:43 +0000500 /* lookup stem top in top zones table */
501 table = &blues->normal_top;
502 count = table->count;
503 zone = table->zones;
Werner Lembergc3b21602001-12-05 01:22:05 +0000504
David Turnera83bc082001-10-18 11:38:43 +0000505 for ( ; count > 0; count--, zone++ )
506 {
David Turner2b30c172001-12-12 16:07:29 +0000507 delta = stem_top - zone->org_bottom;
508 if ( delta < 0 )
David Turnera83bc082001-10-18 11:38:43 +0000509 break;
Werner Lembergc3b21602001-12-05 01:22:05 +0000510
David Turnera83bc082001-10-18 11:38:43 +0000511 if ( stem_top <= zone->org_top )
512 {
David Turner2b30c172001-12-12 16:07:29 +0000513 if ( no_shoots || delta <= blues->blue_threshold )
514 {
515 alignment->align |= PSH_BLUE_ALIGN_TOP;
516 alignment->align_top = zone->cur_ref;
517 }
David Turnera83bc082001-10-18 11:38:43 +0000518 break;
519 }
520 }
521
Werner Lembergc3b21602001-12-05 01:22:05 +0000522 /* look up stem bottom in bottom zones table */
David Turnera83bc082001-10-18 11:38:43 +0000523 table = &blues->normal_bottom;
524 count = table->count;
David Turner2b30c172001-12-12 16:07:29 +0000525 zone = table->zones + count-1;
Werner Lembergc3b21602001-12-05 01:22:05 +0000526
David Turner2b30c172001-12-12 16:07:29 +0000527 for ( ; count > 0; count--, zone-- )
David Turnera83bc082001-10-18 11:38:43 +0000528 {
David Turner2b30c172001-12-12 16:07:29 +0000529 delta = zone->org_top - stem_bot;
530 if ( delta < 0 )
David Turnera83bc082001-10-18 11:38:43 +0000531 break;
532
David Turner2b30c172001-12-12 16:07:29 +0000533 if ( stem_bot >= zone->org_bottom )
David Turnera83bc082001-10-18 11:38:43 +0000534 {
David Turner2b30c172001-12-12 16:07:29 +0000535 if ( no_shoots || delta < blues->blue_shift )
536 {
537 alignment->align |= PSH_BLUE_ALIGN_BOT;
538 alignment->align_bot = zone->cur_ref;
539 }
David Turnera83bc082001-10-18 11:38:43 +0000540 break;
541 }
542 }
543 }
544
545
Werner Lembergc3b21602001-12-05 01:22:05 +0000546 /*************************************************************************/
547 /*************************************************************************/
548 /***** *****/
549 /***** GLOBAL HINTS *****/
550 /***** *****/
551 /*************************************************************************/
552 /*************************************************************************/
David Turnera83bc082001-10-18 11:38:43 +0000553
554 static void
555 psh_globals_destroy( PSH_Globals globals )
556 {
Werner Lembergc3b21602001-12-05 01:22:05 +0000557 if ( globals )
David Turnera83bc082001-10-18 11:38:43 +0000558 {
559 FT_Memory memory;
Werner Lembergc3b21602001-12-05 01:22:05 +0000560
561
David Turnera83bc082001-10-18 11:38:43 +0000562 memory = globals->memory;
Werner Lemberg49bcf782002-03-06 06:05:56 +0000563 globals->dimension[0].stdw.count = 0;
564 globals->dimension[1].stdw.count = 0;
Werner Lembergc3b21602001-12-05 01:22:05 +0000565
David Turnera83bc082001-10-18 11:38:43 +0000566 globals->blues.normal_top.count = 0;
567 globals->blues.normal_bottom.count = 0;
568 globals->blues.family_top.count = 0;
569 globals->blues.family_bottom.count = 0;
Werner Lembergc3b21602001-12-05 01:22:05 +0000570
David Turnere459d742002-03-22 13:52:37 +0000571 FT_FREE( globals );
David Turnera83bc082001-10-18 11:38:43 +0000572
573#ifdef DEBUG_HINTER
574 ps_debug_globals = 0;
Werner Lembergc3b21602001-12-05 01:22:05 +0000575#endif
David Turnera83bc082001-10-18 11:38:43 +0000576 }
577 }
578
Werner Lembergc3b21602001-12-05 01:22:05 +0000579
David Turnera83bc082001-10-18 11:38:43 +0000580 static FT_Error
581 psh_globals_new( FT_Memory memory,
582 T1_Private* priv,
583 PSH_Globals *aglobals )
584 {
585 PSH_Globals globals;
586 FT_Error error;
Werner Lembergc3b21602001-12-05 01:22:05 +0000587
588
David Turnere459d742002-03-22 13:52:37 +0000589 if ( !FT_NEW( globals ) )
David Turnera83bc082001-10-18 11:38:43 +0000590 {
591 FT_UInt count;
592 FT_Short* read;
Werner Lembergc3b21602001-12-05 01:22:05 +0000593
594
David Turnera83bc082001-10-18 11:38:43 +0000595 globals->memory = memory;
596
Werner Lembergc3b21602001-12-05 01:22:05 +0000597 /* copy standard widths */
David Turnera83bc082001-10-18 11:38:43 +0000598 {
599 PSH_Dimension dim = &globals->dimension[1];
Werner Lemberg49bcf782002-03-06 06:05:56 +0000600 PSH_Width write = dim->stdw.widths;
Werner Lembergc3b21602001-12-05 01:22:05 +0000601
602
David Turnera83bc082001-10-18 11:38:43 +0000603 write->org = priv->standard_width[1];
604 write++;
Werner Lembergc3b21602001-12-05 01:22:05 +0000605
David Turnera83bc082001-10-18 11:38:43 +0000606 read = priv->snap_widths;
607 for ( count = priv->num_snap_widths; count > 0; count-- )
608 {
609 write->org = *read;
610 write++;
611 read++;
612 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000613
Werner Lemberg49bcf782002-03-06 06:05:56 +0000614 dim->stdw.count = write - dim->stdw.widths;
David Turnera83bc082001-10-18 11:38:43 +0000615 }
616
617 /* copy standard heights */
618 {
619 PSH_Dimension dim = &globals->dimension[0];
Werner Lemberg49bcf782002-03-06 06:05:56 +0000620 PSH_Width write = dim->stdw.widths;
Werner Lembergc3b21602001-12-05 01:22:05 +0000621
622
David Turnera83bc082001-10-18 11:38:43 +0000623 write->org = priv->standard_height[1];
624 write++;
Werner Lembergc3b21602001-12-05 01:22:05 +0000625
David Turnera83bc082001-10-18 11:38:43 +0000626 read = priv->snap_heights;
627 for ( count = priv->num_snap_heights; count > 0; count-- )
628 {
629 write->org = *read;
630 write++;
631 read++;
632 }
633
Werner Lemberg49bcf782002-03-06 06:05:56 +0000634 dim->stdw.count = write - dim->stdw.widths;
David Turnera83bc082001-10-18 11:38:43 +0000635 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000636
637 /* copy blue zones */
David Turnera83bc082001-10-18 11:38:43 +0000638 psh_blues_set_zones( &globals->blues, priv->num_blue_values,
639 priv->blue_values, priv->num_other_blues,
640 priv->other_blues, priv->blue_fuzz, 0 );
Werner Lembergc3b21602001-12-05 01:22:05 +0000641
David Turnera83bc082001-10-18 11:38:43 +0000642 psh_blues_set_zones( &globals->blues, priv->num_family_blues,
643 priv->family_blues, priv->num_family_other_blues,
644 priv->family_other_blues, priv->blue_fuzz, 1 );
645
David Turner0515c092001-12-21 04:16:42 +0000646 globals->blues.blue_scale = priv->blue_scale
Werner Lembergf05003d2001-12-21 10:57:09 +0000647 ? priv->blue_scale
648 : 0x28937L; /* 0.039625 * 0x400000L */
David Turnerbce29862001-12-14 14:52:58 +0000649
David Turner0515c092001-12-21 04:16:42 +0000650 globals->blues.blue_shift = priv->blue_shift
Werner Lembergf05003d2001-12-21 10:57:09 +0000651 ? priv->blue_shift
652 : 7;
David Turner2b30c172001-12-12 16:07:29 +0000653
David Turnera83bc082001-10-18 11:38:43 +0000654 globals->dimension[0].scale_mult = 0;
655 globals->dimension[0].scale_delta = 0;
656 globals->dimension[1].scale_mult = 0;
657 globals->dimension[1].scale_delta = 0;
658
659#ifdef DEBUG_HINTER
660 ps_debug_globals = globals;
Werner Lembergc3b21602001-12-05 01:22:05 +0000661#endif
David Turnera83bc082001-10-18 11:38:43 +0000662 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000663
David Turnera83bc082001-10-18 11:38:43 +0000664 *aglobals = globals;
665 return error;
666 }
667
668
David Turnera83bc082001-10-18 11:38:43 +0000669 static FT_Error
Werner Lembergc3b21602001-12-05 01:22:05 +0000670 psh_globals_set_scale( PSH_Globals globals,
671 FT_Fixed x_scale,
672 FT_Fixed y_scale,
673 FT_Fixed x_delta,
674 FT_Fixed y_delta )
David Turnera83bc082001-10-18 11:38:43 +0000675 {
Werner Lembergc3b21602001-12-05 01:22:05 +0000676 PSH_Dimension dim = &globals->dimension[0];
677
678
David Turnera83bc082001-10-18 11:38:43 +0000679 dim = &globals->dimension[0];
680 if ( x_scale != dim->scale_mult ||
681 x_delta != dim->scale_delta )
682 {
683 dim->scale_mult = x_scale;
684 dim->scale_delta = x_delta;
Werner Lembergc3b21602001-12-05 01:22:05 +0000685
David Turnera83bc082001-10-18 11:38:43 +0000686 psh_globals_scale_widths( globals, 0 );
687 }
688
689 dim = &globals->dimension[1];
690 if ( y_scale != dim->scale_mult ||
691 y_delta != dim->scale_delta )
692 {
693 dim->scale_mult = y_scale;
694 dim->scale_delta = y_delta;
695
696 psh_globals_scale_widths( globals, 1 );
697 psh_blues_scale_zones( &globals->blues, y_scale, y_delta );
698 }
699
700 return 0;
701 }
702
703
David Turnerbc82f1b2002-03-01 02:26:22 +0000704 FT_LOCAL_DEF( void )
David Turnera83bc082001-10-18 11:38:43 +0000705 psh_globals_funcs_init( PSH_Globals_FuncsRec* funcs )
706 {
707 funcs->create = psh_globals_new;
708 funcs->set_scale = psh_globals_set_scale;
709 funcs->destroy = psh_globals_destroy;
710 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000711
712
713/* END */