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