1 | /**************************************************************************** |
2 | * |
3 | * pshglob.c |
4 | * |
5 | * PostScript hinter global hinting management (body). |
6 | * Inspired by the new auto-hinter module. |
7 | * |
8 | * Copyright (C) 2001-2023 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 | |
20 | #include <freetype/freetype.h> |
21 | #include <freetype/internal/ftobjs.h> |
22 | #include <freetype/internal/ftcalc.h> |
23 | #include "pshglob.h" |
24 | |
25 | #ifdef DEBUG_HINTER |
26 | PSH_Globals ps_debug_globals = NULL; |
27 | #endif |
28 | |
29 | |
30 | /*************************************************************************/ |
31 | /*************************************************************************/ |
32 | /***** *****/ |
33 | /***** STANDARD WIDTHS *****/ |
34 | /***** *****/ |
35 | /*************************************************************************/ |
36 | /*************************************************************************/ |
37 | |
38 | |
39 | /* scale the widths/heights table */ |
40 | static void |
41 | psh_globals_scale_widths( PSH_Globals globals, |
42 | FT_UInt direction ) |
43 | { |
44 | PSH_Dimension dim = &globals->dimension[direction]; |
45 | PSH_Widths stdw = &dim->stdw; |
46 | FT_UInt count = stdw->count; |
47 | PSH_Width width = stdw->widths; |
48 | PSH_Width stand = width; /* standard width/height */ |
49 | FT_Fixed scale = dim->scale_mult; |
50 | |
51 | |
52 | if ( count > 0 ) |
53 | { |
54 | width->cur = FT_MulFix( width->org, scale ); |
55 | width->fit = FT_PIX_ROUND( width->cur ); |
56 | |
57 | width++; |
58 | count--; |
59 | |
60 | for ( ; count > 0; count--, width++ ) |
61 | { |
62 | FT_Pos w, dist; |
63 | |
64 | |
65 | w = FT_MulFix( width->org, scale ); |
66 | dist = w - stand->cur; |
67 | |
68 | if ( dist < 0 ) |
69 | dist = -dist; |
70 | |
71 | if ( dist < 128 ) |
72 | w = stand->cur; |
73 | |
74 | width->cur = w; |
75 | width->fit = FT_PIX_ROUND( w ); |
76 | } |
77 | } |
78 | } |
79 | |
80 | |
81 | #if 0 |
82 | |
83 | /* org_width is in font units, result in device pixels, 26.6 format */ |
84 | FT_LOCAL_DEF( FT_Pos ) |
85 | psh_dimension_snap_width( PSH_Dimension dimension, |
86 | FT_Int org_width ) |
87 | { |
88 | FT_UInt n; |
89 | FT_Pos width = FT_MulFix( org_width, dimension->scale_mult ); |
90 | FT_Pos best = 64 + 32 + 2; |
91 | FT_Pos reference = width; |
92 | |
93 | |
94 | for ( n = 0; n < dimension->stdw.count; n++ ) |
95 | { |
96 | FT_Pos w; |
97 | FT_Pos dist; |
98 | |
99 | |
100 | w = dimension->stdw.widths[n].cur; |
101 | dist = width - w; |
102 | if ( dist < 0 ) |
103 | dist = -dist; |
104 | if ( dist < best ) |
105 | { |
106 | best = dist; |
107 | reference = w; |
108 | } |
109 | } |
110 | |
111 | if ( width >= reference ) |
112 | { |
113 | width -= 0x21; |
114 | if ( width < reference ) |
115 | width = reference; |
116 | } |
117 | else |
118 | { |
119 | width += 0x21; |
120 | if ( width > reference ) |
121 | width = reference; |
122 | } |
123 | |
124 | return width; |
125 | } |
126 | |
127 | #endif /* 0 */ |
128 | |
129 | |
130 | /*************************************************************************/ |
131 | /*************************************************************************/ |
132 | /***** *****/ |
133 | /***** BLUE ZONES *****/ |
134 | /***** *****/ |
135 | /*************************************************************************/ |
136 | /*************************************************************************/ |
137 | |
138 | static void |
139 | psh_blues_set_zones_0( PSH_Blues target, |
140 | FT_Bool is_others, |
141 | FT_UInt read_count, |
142 | FT_Short* read, |
143 | PSH_Blue_Table top_table, |
144 | PSH_Blue_Table bot_table ) |
145 | { |
146 | FT_UInt count_top = top_table->count; |
147 | FT_UInt count_bot = bot_table->count; |
148 | FT_Bool first = 1; |
149 | |
150 | FT_UNUSED( target ); |
151 | |
152 | |
153 | for ( ; read_count > 1; read_count -= 2 ) |
154 | { |
155 | FT_Int reference, delta; |
156 | FT_UInt count; |
157 | PSH_Blue_Zone zones, zone; |
158 | FT_Bool top; |
159 | |
160 | |
161 | /* read blue zone entry, and select target top/bottom zone */ |
162 | top = 0; |
163 | if ( first || is_others ) |
164 | { |
165 | reference = read[1]; |
166 | delta = read[0] - reference; |
167 | |
168 | zones = bot_table->zones; |
169 | count = count_bot; |
170 | first = 0; |
171 | } |
172 | else |
173 | { |
174 | reference = read[0]; |
175 | delta = read[1] - reference; |
176 | |
177 | zones = top_table->zones; |
178 | count = count_top; |
179 | top = 1; |
180 | } |
181 | |
182 | /* insert into sorted table */ |
183 | zone = zones; |
184 | for ( ; count > 0; count--, zone++ ) |
185 | { |
186 | if ( reference < zone->org_ref ) |
187 | break; |
188 | |
189 | if ( reference == zone->org_ref ) |
190 | { |
191 | FT_Int delta0 = zone->org_delta; |
192 | |
193 | |
194 | /* we have two zones on the same reference position -- */ |
195 | /* only keep the largest one */ |
196 | if ( delta < 0 ) |
197 | { |
198 | if ( delta < delta0 ) |
199 | zone->org_delta = delta; |
200 | } |
201 | else |
202 | { |
203 | if ( delta > delta0 ) |
204 | zone->org_delta = delta; |
205 | } |
206 | goto Skip; |
207 | } |
208 | } |
209 | |
210 | for ( ; count > 0; count-- ) |
211 | zone[count] = zone[count-1]; |
212 | |
213 | zone->org_ref = reference; |
214 | zone->org_delta = delta; |
215 | |
216 | if ( top ) |
217 | count_top++; |
218 | else |
219 | count_bot++; |
220 | |
221 | Skip: |
222 | read += 2; |
223 | } |
224 | |
225 | top_table->count = count_top; |
226 | bot_table->count = count_bot; |
227 | } |
228 | |
229 | |
230 | /* Re-read blue zones from the original fonts and store them into our */ |
231 | /* private structure. This function re-orders, sanitizes, and */ |
232 | /* fuzz-expands the zones as well. */ |
233 | static void |
234 | psh_blues_set_zones( PSH_Blues target, |
235 | FT_UInt count, |
236 | FT_Short* blues, |
237 | FT_UInt count_others, |
238 | FT_Short* other_blues, |
239 | FT_Int fuzz, |
240 | FT_Int family ) |
241 | { |
242 | PSH_Blue_Table top_table, bot_table; |
243 | FT_UInt count_top, count_bot; |
244 | |
245 | |
246 | if ( family ) |
247 | { |
248 | top_table = &target->family_top; |
249 | bot_table = &target->family_bottom; |
250 | } |
251 | else |
252 | { |
253 | top_table = &target->normal_top; |
254 | bot_table = &target->normal_bottom; |
255 | } |
256 | |
257 | /* read the input blue zones, and build two sorted tables */ |
258 | /* (one for the top zones, the other for the bottom zones) */ |
259 | top_table->count = 0; |
260 | bot_table->count = 0; |
261 | |
262 | /* first, the blues */ |
263 | psh_blues_set_zones_0( target, 0, |
264 | count, blues, top_table, bot_table ); |
265 | psh_blues_set_zones_0( target, 1, |
266 | count_others, other_blues, top_table, bot_table ); |
267 | |
268 | count_top = top_table->count; |
269 | count_bot = bot_table->count; |
270 | |
271 | /* sanitize top table */ |
272 | if ( count_top > 0 ) |
273 | { |
274 | PSH_Blue_Zone zone = top_table->zones; |
275 | |
276 | |
277 | for ( count = count_top; count > 0; count--, zone++ ) |
278 | { |
279 | FT_Int delta; |
280 | |
281 | |
282 | if ( count > 1 ) |
283 | { |
284 | delta = zone[1].org_ref - zone[0].org_ref; |
285 | if ( zone->org_delta > delta ) |
286 | zone->org_delta = delta; |
287 | } |
288 | |
289 | zone->org_bottom = zone->org_ref; |
290 | zone->org_top = zone->org_delta + zone->org_ref; |
291 | } |
292 | } |
293 | |
294 | /* sanitize bottom table */ |
295 | if ( count_bot > 0 ) |
296 | { |
297 | PSH_Blue_Zone zone = bot_table->zones; |
298 | |
299 | |
300 | for ( count = count_bot; count > 0; count--, zone++ ) |
301 | { |
302 | FT_Int delta; |
303 | |
304 | |
305 | if ( count > 1 ) |
306 | { |
307 | delta = zone[0].org_ref - zone[1].org_ref; |
308 | if ( zone->org_delta < delta ) |
309 | zone->org_delta = delta; |
310 | } |
311 | |
312 | zone->org_top = zone->org_ref; |
313 | zone->org_bottom = zone->org_delta + zone->org_ref; |
314 | } |
315 | } |
316 | |
317 | /* expand top and bottom tables with blue fuzz */ |
318 | { |
319 | FT_Int dim, top, bot, delta; |
320 | PSH_Blue_Zone zone; |
321 | |
322 | |
323 | zone = top_table->zones; |
324 | count = count_top; |
325 | |
326 | for ( dim = 1; dim >= 0; dim-- ) |
327 | { |
328 | if ( count > 0 ) |
329 | { |
330 | /* expand the bottom of the lowest zone normally */ |
331 | zone->org_bottom -= fuzz; |
332 | |
333 | /* expand the top and bottom of intermediate zones; */ |
334 | /* checking that the interval is smaller than the fuzz */ |
335 | top = zone->org_top; |
336 | |
337 | for ( count--; count > 0; count-- ) |
338 | { |
339 | bot = zone[1].org_bottom; |
340 | delta = bot - top; |
341 | |
342 | if ( delta / 2 < fuzz ) |
343 | zone[0].org_top = zone[1].org_bottom = top + delta / 2; |
344 | else |
345 | { |
346 | zone[0].org_top = top + fuzz; |
347 | zone[1].org_bottom = bot - fuzz; |
348 | } |
349 | |
350 | zone++; |
351 | top = zone->org_top; |
352 | } |
353 | |
354 | /* expand the top of the highest zone normally */ |
355 | zone->org_top = top + fuzz; |
356 | } |
357 | zone = bot_table->zones; |
358 | count = count_bot; |
359 | } |
360 | } |
361 | } |
362 | |
363 | |
364 | /* reset the blues table when the device transform changes */ |
365 | static void |
366 | psh_blues_scale_zones( PSH_Blues blues, |
367 | FT_Fixed scale, |
368 | FT_Pos delta ) |
369 | { |
370 | FT_UInt count; |
371 | FT_UInt num; |
372 | PSH_Blue_Table table = NULL; |
373 | |
374 | /* */ |
375 | /* Determine whether we need to suppress overshoots or */ |
376 | /* not. We simply need to compare the vertical scale */ |
377 | /* parameter to the raw bluescale value. Here is why: */ |
378 | /* */ |
379 | /* We need to suppress overshoots for all pointsizes. */ |
380 | /* At 300dpi that satisfies: */ |
381 | /* */ |
382 | /* pointsize < 240*bluescale + 0.49 */ |
383 | /* */ |
384 | /* This corresponds to: */ |
385 | /* */ |
386 | /* pixelsize < 1000*bluescale + 49/24 */ |
387 | /* */ |
388 | /* scale*EM_Size < 1000*bluescale + 49/24 */ |
389 | /* */ |
390 | /* However, for normal Type 1 fonts, EM_Size is 1000! */ |
391 | /* We thus only check: */ |
392 | /* */ |
393 | /* scale < bluescale + 49/24000 */ |
394 | /* */ |
395 | /* which we shorten to */ |
396 | /* */ |
397 | /* "scale < bluescale" */ |
398 | /* */ |
399 | /* Note that `blue_scale' is stored 1000 times its real */ |
400 | /* value, and that `scale' converts from font units to */ |
401 | /* fractional pixels. */ |
402 | /* */ |
403 | |
404 | /* 1000 / 64 = 125 / 8 */ |
405 | if ( scale >= 0x20C49BAL ) |
406 | blues->no_overshoots = FT_BOOL( scale < blues->blue_scale * 8 / 125 ); |
407 | else |
408 | blues->no_overshoots = FT_BOOL( scale * 125 < blues->blue_scale * 8 ); |
409 | |
410 | /* */ |
411 | /* The blue threshold is the font units distance under */ |
412 | /* which overshoots are suppressed due to the BlueShift */ |
413 | /* even if the scale is greater than BlueScale. */ |
414 | /* */ |
415 | /* It is the smallest distance such that */ |
416 | /* */ |
417 | /* dist <= BlueShift && dist*scale <= 0.5 pixels */ |
418 | /* */ |
419 | { |
420 | FT_Int threshold = blues->blue_shift; |
421 | |
422 | |
423 | while ( threshold > 0 && FT_MulFix( threshold, scale ) > 32 ) |
424 | threshold--; |
425 | |
426 | blues->blue_threshold = threshold; |
427 | } |
428 | |
429 | for ( num = 0; num < 4; num++ ) |
430 | { |
431 | PSH_Blue_Zone zone; |
432 | |
433 | |
434 | switch ( num ) |
435 | { |
436 | case 0: |
437 | table = &blues->normal_top; |
438 | break; |
439 | case 1: |
440 | table = &blues->normal_bottom; |
441 | break; |
442 | case 2: |
443 | table = &blues->family_top; |
444 | break; |
445 | default: |
446 | table = &blues->family_bottom; |
447 | break; |
448 | } |
449 | |
450 | zone = table->zones; |
451 | count = table->count; |
452 | for ( ; count > 0; count--, zone++ ) |
453 | { |
454 | zone->cur_top = FT_MulFix( zone->org_top, scale ) + delta; |
455 | zone->cur_bottom = FT_MulFix( zone->org_bottom, scale ) + delta; |
456 | zone->cur_ref = FT_MulFix( zone->org_ref, scale ) + delta; |
457 | zone->cur_delta = FT_MulFix( zone->org_delta, scale ); |
458 | |
459 | /* round scaled reference position */ |
460 | zone->cur_ref = FT_PIX_ROUND( zone->cur_ref ); |
461 | |
462 | #if 0 |
463 | if ( zone->cur_ref > zone->cur_top ) |
464 | zone->cur_ref -= 64; |
465 | else if ( zone->cur_ref < zone->cur_bottom ) |
466 | zone->cur_ref += 64; |
467 | #endif |
468 | } |
469 | } |
470 | |
471 | /* process the families now */ |
472 | |
473 | for ( num = 0; num < 2; num++ ) |
474 | { |
475 | PSH_Blue_Zone zone1, zone2; |
476 | FT_UInt count1, count2; |
477 | PSH_Blue_Table normal, family; |
478 | |
479 | |
480 | switch ( num ) |
481 | { |
482 | case 0: |
483 | normal = &blues->normal_top; |
484 | family = &blues->family_top; |
485 | break; |
486 | |
487 | default: |
488 | normal = &blues->normal_bottom; |
489 | family = &blues->family_bottom; |
490 | } |
491 | |
492 | zone1 = normal->zones; |
493 | count1 = normal->count; |
494 | |
495 | for ( ; count1 > 0; count1--, zone1++ ) |
496 | { |
497 | /* try to find a family zone whose reference position is less */ |
498 | /* than 1 pixel far from the current zone */ |
499 | zone2 = family->zones; |
500 | count2 = family->count; |
501 | |
502 | for ( ; count2 > 0; count2--, zone2++ ) |
503 | { |
504 | FT_Pos Delta; |
505 | |
506 | |
507 | Delta = zone1->org_ref - zone2->org_ref; |
508 | if ( Delta < 0 ) |
509 | Delta = -Delta; |
510 | |
511 | if ( FT_MulFix( Delta, scale ) < 64 ) |
512 | { |
513 | zone1->cur_top = zone2->cur_top; |
514 | zone1->cur_bottom = zone2->cur_bottom; |
515 | zone1->cur_ref = zone2->cur_ref; |
516 | zone1->cur_delta = zone2->cur_delta; |
517 | break; |
518 | } |
519 | } |
520 | } |
521 | } |
522 | } |
523 | |
524 | |
525 | /* calculate the maximum height of given blue zones */ |
526 | static FT_Short |
527 | psh_calc_max_height( FT_UInt num, |
528 | const FT_Short* values, |
529 | FT_Short cur_max ) |
530 | { |
531 | FT_UInt count; |
532 | |
533 | |
534 | for ( count = 0; count < num; count += 2 ) |
535 | { |
536 | FT_Short cur_height = values[count + 1] - values[count]; |
537 | |
538 | |
539 | if ( cur_height > cur_max ) |
540 | cur_max = cur_height; |
541 | } |
542 | |
543 | return cur_max; |
544 | } |
545 | |
546 | |
547 | FT_LOCAL_DEF( void ) |
548 | psh_blues_snap_stem( PSH_Blues blues, |
549 | FT_Int stem_top, |
550 | FT_Int stem_bot, |
551 | PSH_Alignment alignment ) |
552 | { |
553 | PSH_Blue_Table table; |
554 | FT_UInt count; |
555 | FT_Pos delta; |
556 | PSH_Blue_Zone zone; |
557 | FT_Int no_shoots; |
558 | |
559 | |
560 | alignment->align = PSH_BLUE_ALIGN_NONE; |
561 | |
562 | no_shoots = blues->no_overshoots; |
563 | |
564 | /* look up stem top in top zones table */ |
565 | table = &blues->normal_top; |
566 | count = table->count; |
567 | zone = table->zones; |
568 | |
569 | for ( ; count > 0; count--, zone++ ) |
570 | { |
571 | delta = SUB_LONG( stem_top, zone->org_bottom ); |
572 | if ( delta < -blues->blue_fuzz ) |
573 | break; |
574 | |
575 | if ( stem_top <= zone->org_top + blues->blue_fuzz ) |
576 | { |
577 | if ( no_shoots || delta <= blues->blue_threshold ) |
578 | { |
579 | alignment->align |= PSH_BLUE_ALIGN_TOP; |
580 | alignment->align_top = zone->cur_ref; |
581 | } |
582 | break; |
583 | } |
584 | } |
585 | |
586 | /* look up stem bottom in bottom zones table */ |
587 | table = &blues->normal_bottom; |
588 | count = table->count; |
589 | zone = table->zones + count-1; |
590 | |
591 | for ( ; count > 0; count--, zone-- ) |
592 | { |
593 | delta = SUB_LONG( zone->org_top, stem_bot ); |
594 | if ( delta < -blues->blue_fuzz ) |
595 | break; |
596 | |
597 | if ( stem_bot >= zone->org_bottom - blues->blue_fuzz ) |
598 | { |
599 | if ( no_shoots || delta < blues->blue_threshold ) |
600 | { |
601 | alignment->align |= PSH_BLUE_ALIGN_BOT; |
602 | alignment->align_bot = zone->cur_ref; |
603 | } |
604 | break; |
605 | } |
606 | } |
607 | } |
608 | |
609 | |
610 | /*************************************************************************/ |
611 | /*************************************************************************/ |
612 | /***** *****/ |
613 | /***** GLOBAL HINTS *****/ |
614 | /***** *****/ |
615 | /*************************************************************************/ |
616 | /*************************************************************************/ |
617 | |
618 | static void |
619 | psh_globals_destroy( PSH_Globals globals ) |
620 | { |
621 | if ( globals ) |
622 | { |
623 | FT_Memory memory; |
624 | |
625 | |
626 | memory = globals->memory; |
627 | globals->dimension[0].stdw.count = 0; |
628 | globals->dimension[1].stdw.count = 0; |
629 | |
630 | globals->blues.normal_top.count = 0; |
631 | globals->blues.normal_bottom.count = 0; |
632 | globals->blues.family_top.count = 0; |
633 | globals->blues.family_bottom.count = 0; |
634 | |
635 | FT_FREE( globals ); |
636 | |
637 | #ifdef DEBUG_HINTER |
638 | ps_debug_globals = NULL; |
639 | #endif |
640 | } |
641 | } |
642 | |
643 | |
644 | static FT_Error |
645 | psh_globals_new( FT_Memory memory, |
646 | T1_Private* priv, |
647 | PSH_Globals *aglobals ) |
648 | { |
649 | PSH_Globals globals = NULL; |
650 | FT_Error error; |
651 | |
652 | |
653 | if ( !FT_QNEW( globals ) ) |
654 | { |
655 | FT_UInt count; |
656 | FT_Short* read; |
657 | |
658 | |
659 | globals->memory = memory; |
660 | |
661 | /* copy standard widths */ |
662 | { |
663 | PSH_Dimension dim = &globals->dimension[1]; |
664 | PSH_Width write = dim->stdw.widths; |
665 | |
666 | |
667 | write->org = priv->standard_width[0]; |
668 | write++; |
669 | |
670 | read = priv->snap_widths; |
671 | for ( count = priv->num_snap_widths; count > 0; count-- ) |
672 | { |
673 | write->org = *read; |
674 | write++; |
675 | read++; |
676 | } |
677 | |
678 | dim->stdw.count = priv->num_snap_widths + 1; |
679 | } |
680 | |
681 | /* copy standard heights */ |
682 | { |
683 | PSH_Dimension dim = &globals->dimension[0]; |
684 | PSH_Width write = dim->stdw.widths; |
685 | |
686 | |
687 | write->org = priv->standard_height[0]; |
688 | write++; |
689 | read = priv->snap_heights; |
690 | for ( count = priv->num_snap_heights; count > 0; count-- ) |
691 | { |
692 | write->org = *read; |
693 | write++; |
694 | read++; |
695 | } |
696 | |
697 | dim->stdw.count = priv->num_snap_heights + 1; |
698 | } |
699 | |
700 | /* copy blue zones */ |
701 | psh_blues_set_zones( &globals->blues, priv->num_blue_values, |
702 | priv->blue_values, priv->num_other_blues, |
703 | priv->other_blues, priv->blue_fuzz, 0 ); |
704 | |
705 | psh_blues_set_zones( &globals->blues, priv->num_family_blues, |
706 | priv->family_blues, priv->num_family_other_blues, |
707 | priv->family_other_blues, priv->blue_fuzz, 1 ); |
708 | |
709 | /* limit the BlueScale value to `1 / max_of_blue_zone_heights' */ |
710 | { |
711 | FT_Fixed max_scale; |
712 | FT_Short max_height = 1; |
713 | |
714 | |
715 | max_height = psh_calc_max_height( priv->num_blue_values, |
716 | priv->blue_values, |
717 | max_height ); |
718 | max_height = psh_calc_max_height( priv->num_other_blues, |
719 | priv->other_blues, |
720 | max_height ); |
721 | max_height = psh_calc_max_height( priv->num_family_blues, |
722 | priv->family_blues, |
723 | max_height ); |
724 | max_height = psh_calc_max_height( priv->num_family_other_blues, |
725 | priv->family_other_blues, |
726 | max_height ); |
727 | |
728 | /* BlueScale is scaled 1000 times */ |
729 | max_scale = FT_DivFix( 1000, max_height ); |
730 | globals->blues.blue_scale = priv->blue_scale < max_scale |
731 | ? priv->blue_scale |
732 | : max_scale; |
733 | } |
734 | |
735 | globals->blues.blue_shift = priv->blue_shift; |
736 | globals->blues.blue_fuzz = priv->blue_fuzz; |
737 | |
738 | globals->dimension[0].scale_mult = 0; |
739 | globals->dimension[0].scale_delta = 0; |
740 | globals->dimension[1].scale_mult = 0; |
741 | globals->dimension[1].scale_delta = 0; |
742 | |
743 | #ifdef DEBUG_HINTER |
744 | ps_debug_globals = globals; |
745 | #endif |
746 | } |
747 | |
748 | *aglobals = globals; |
749 | return error; |
750 | } |
751 | |
752 | |
753 | FT_LOCAL_DEF( void ) |
754 | psh_globals_set_scale( PSH_Globals globals, |
755 | FT_Fixed x_scale, |
756 | FT_Fixed y_scale, |
757 | FT_Fixed x_delta, |
758 | FT_Fixed y_delta ) |
759 | { |
760 | PSH_Dimension dim; |
761 | |
762 | |
763 | dim = &globals->dimension[0]; |
764 | if ( x_scale != dim->scale_mult || |
765 | x_delta != dim->scale_delta ) |
766 | { |
767 | dim->scale_mult = x_scale; |
768 | dim->scale_delta = x_delta; |
769 | |
770 | psh_globals_scale_widths( globals, 0 ); |
771 | } |
772 | |
773 | dim = &globals->dimension[1]; |
774 | if ( y_scale != dim->scale_mult || |
775 | y_delta != dim->scale_delta ) |
776 | { |
777 | dim->scale_mult = y_scale; |
778 | dim->scale_delta = y_delta; |
779 | |
780 | psh_globals_scale_widths( globals, 1 ); |
781 | psh_blues_scale_zones( &globals->blues, y_scale, y_delta ); |
782 | } |
783 | } |
784 | |
785 | |
786 | FT_LOCAL_DEF( void ) |
787 | psh_globals_funcs_init( PSH_Globals_FuncsRec* funcs ) |
788 | { |
789 | funcs->create = psh_globals_new; |
790 | funcs->set_scale = psh_globals_set_scale; |
791 | funcs->destroy = psh_globals_destroy; |
792 | } |
793 | |
794 | |
795 | /* END */ |
796 | |