"Fossies" - the Fresh Open Source Software Archive 
Member "SDL2_ttf-2.20.2/external/freetype/src/autofit/afloader.c" (25 May 2022, 24105 Bytes) of package /linux/misc/SDL2_ttf-2.20.2.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "afloader.c" see the
Fossies "Dox" file reference documentation.
1 /****************************************************************************
2 *
3 * afloader.c
4 *
5 * Auto-fitter glyph loading routines (body).
6 *
7 * Copyright (C) 2003-2022 by
8 * David Turner, Robert Wilhelm, and Werner Lemberg.
9 *
10 * This file is part of the FreeType project, and may only be used,
11 * modified, and distributed under the terms of the FreeType project
12 * license, LICENSE.TXT. By continuing to use, modify, or distribute
13 * this file you indicate that you have read the license and
14 * understand and accept it fully.
15 *
16 */
17
18
19 #include "afglobal.h"
20 #include "afloader.h"
21 #include "afhints.h"
22 #include "aferrors.h"
23 #include "afmodule.h"
24
25 #include <freetype/internal/ftcalc.h>
26
27
28 /* Initialize glyph loader. */
29
30 FT_LOCAL_DEF( void )
31 af_loader_init( AF_Loader loader,
32 AF_GlyphHints hints )
33 {
34 FT_ZERO( loader );
35
36 loader->hints = hints;
37 }
38
39
40 /* Reset glyph loader and compute globals if necessary. */
41
42 FT_LOCAL_DEF( FT_Error )
43 af_loader_reset( AF_Loader loader,
44 AF_Module module,
45 FT_Face face )
46 {
47 FT_Error error = FT_Err_Ok;
48
49
50 loader->face = face;
51 loader->globals = (AF_FaceGlobals)face->autohint.data;
52
53 if ( !loader->globals )
54 {
55 error = af_face_globals_new( face, &loader->globals, module );
56 if ( !error )
57 {
58 face->autohint.data =
59 (FT_Pointer)loader->globals;
60 face->autohint.finalizer =
61 (FT_Generic_Finalizer)af_face_globals_free;
62 }
63 }
64
65 return error;
66 }
67
68
69 /* Finalize glyph loader. */
70
71 FT_LOCAL_DEF( void )
72 af_loader_done( AF_Loader loader )
73 {
74 loader->face = NULL;
75 loader->globals = NULL;
76 loader->hints = NULL;
77 }
78
79
80 #define af_intToFixed( i ) \
81 ( (FT_Fixed)( (FT_UInt32)(i) << 16 ) )
82 #define af_fixedToInt( x ) \
83 ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) )
84 #define af_floatToFixed( f ) \
85 ( (FT_Fixed)( (f) * 65536.0 + 0.5 ) )
86
87
88 static FT_Error
89 af_loader_embolden_glyph_in_slot( AF_Loader loader,
90 FT_Face face,
91 AF_StyleMetrics style_metrics )
92 {
93 FT_Error error = FT_Err_Ok;
94
95 FT_GlyphSlot slot = face->glyph;
96 AF_FaceGlobals globals = loader->globals;
97 AF_WritingSystemClass writing_system_class;
98
99 FT_Size_Metrics* size_metrics = &face->size->internal->autohint_metrics;
100
101 FT_Pos stdVW = 0;
102 FT_Pos stdHW = 0;
103
104 FT_Bool size_changed = size_metrics->x_ppem !=
105 globals->stem_darkening_for_ppem;
106
107 FT_Fixed em_size = af_intToFixed( face->units_per_EM );
108
109 FT_Matrix scale_down_matrix = { 0x10000L, 0, 0, 0x10000L };
110
111
112 /* Skip stem darkening for broken fonts. */
113 if ( !face->units_per_EM )
114 {
115 error = FT_ERR( Corrupted_Font_Header );
116 goto Exit;
117 }
118
119 /*
120 * We depend on the writing system (script analyzers) to supply
121 * standard widths for the script of the glyph we are looking at. If
122 * it can't deliver, stem darkening is disabled.
123 */
124 writing_system_class =
125 af_writing_system_classes[style_metrics->style_class->writing_system];
126
127 if ( writing_system_class->style_metrics_getstdw )
128 writing_system_class->style_metrics_getstdw( style_metrics,
129 &stdHW,
130 &stdVW );
131 else
132 {
133 error = FT_ERR( Unimplemented_Feature );
134 goto Exit;
135 }
136
137 if ( size_changed ||
138 ( stdVW > 0 && stdVW != globals->standard_vertical_width ) )
139 {
140 FT_Fixed darken_by_font_units_x, darken_x;
141
142
143 darken_by_font_units_x =
144 af_loader_compute_darkening( loader,
145 face,
146 stdVW ) ;
147 darken_x = FT_MulFix( darken_by_font_units_x,
148 size_metrics->x_scale );
149
150 globals->standard_vertical_width = stdVW;
151 globals->stem_darkening_for_ppem = size_metrics->x_ppem;
152 globals->darken_x = af_fixedToInt( darken_x );
153 }
154
155 if ( size_changed ||
156 ( stdHW > 0 && stdHW != globals->standard_horizontal_width ) )
157 {
158 FT_Fixed darken_by_font_units_y, darken_y;
159
160
161 darken_by_font_units_y =
162 af_loader_compute_darkening( loader,
163 face,
164 stdHW ) ;
165 darken_y = FT_MulFix( darken_by_font_units_y,
166 size_metrics->y_scale );
167
168 globals->standard_horizontal_width = stdHW;
169 globals->stem_darkening_for_ppem = size_metrics->x_ppem;
170 globals->darken_y = af_fixedToInt( darken_y );
171
172 /*
173 * Scale outlines down on the Y-axis to keep them inside their blue
174 * zones. The stronger the emboldening, the stronger the downscaling
175 * (plus heuristical padding to prevent outlines still falling out
176 * their zones due to rounding).
177 *
178 * Reason: `FT_Outline_Embolden' works by shifting the rightmost
179 * points of stems farther to the right, and topmost points farther
180 * up. This positions points on the Y-axis outside their
181 * pre-computed blue zones and leads to distortion when applying the
182 * hints in the code further below. Code outside this emboldening
183 * block doesn't know we are presenting it with modified outlines the
184 * analyzer didn't see!
185 *
186 * An unfortunate side effect of downscaling is that the emboldening
187 * effect is slightly decreased. The loss becomes more pronounced
188 * versus the CFF driver at smaller sizes, e.g., at 9ppem and below.
189 */
190 globals->scale_down_factor =
191 FT_DivFix( em_size - ( darken_by_font_units_y + af_intToFixed( 8 ) ),
192 em_size );
193 }
194
195 FT_Outline_EmboldenXY( &slot->outline,
196 globals->darken_x,
197 globals->darken_y );
198
199 scale_down_matrix.yy = globals->scale_down_factor;
200 FT_Outline_Transform( &slot->outline, &scale_down_matrix );
201
202 Exit:
203 return error;
204 }
205
206
207 /* Load the glyph at index into the current slot of a face and hint it. */
208
209 FT_LOCAL_DEF( FT_Error )
210 af_loader_load_glyph( AF_Loader loader,
211 AF_Module module,
212 FT_Face face,
213 FT_UInt glyph_index,
214 FT_Int32 load_flags )
215 {
216 FT_Error error;
217
218 FT_Size size = face->size;
219 FT_Size_Internal size_internal = size->internal;
220 FT_GlyphSlot slot = face->glyph;
221 FT_Slot_Internal slot_internal = slot->internal;
222 FT_GlyphLoader gloader = slot_internal->loader;
223
224 AF_GlyphHints hints = loader->hints;
225 AF_ScalerRec scaler;
226 AF_StyleMetrics style_metrics;
227 FT_UInt style_options = AF_STYLE_NONE_DFLT;
228 AF_StyleClass style_class;
229 AF_WritingSystemClass writing_system_class;
230
231
232 if ( !size )
233 return FT_THROW( Invalid_Size_Handle );
234
235 FT_ZERO( &scaler );
236
237 if ( !size_internal->autohint_metrics.x_scale ||
238 size_internal->autohint_mode != FT_LOAD_TARGET_MODE( load_flags ) )
239 {
240 /* switching between hinting modes usually means different scaling */
241 /* values; this later on enforces recomputation of everything */
242 /* related to the current size */
243
244 size_internal->autohint_mode = FT_LOAD_TARGET_MODE( load_flags );
245 size_internal->autohint_metrics = size->metrics;
246
247 #ifdef AF_CONFIG_OPTION_TT_SIZE_METRICS
248 {
249 FT_Size_Metrics* size_metrics = &size_internal->autohint_metrics;
250
251
252 /* set metrics to integer values and adjust scaling accordingly; */
253 /* this is the same setup as with TrueType fonts, cf. function */
254 /* `tt_size_reset' in file `ttobjs.c' */
255 size_metrics->ascender = FT_PIX_ROUND(
256 FT_MulFix( face->ascender,
257 size_metrics->y_scale ) );
258 size_metrics->descender = FT_PIX_ROUND(
259 FT_MulFix( face->descender,
260 size_metrics->y_scale ) );
261 size_metrics->height = FT_PIX_ROUND(
262 FT_MulFix( face->height,
263 size_metrics->y_scale ) );
264
265 size_metrics->x_scale = FT_DivFix( size_metrics->x_ppem << 6,
266 face->units_per_EM );
267 size_metrics->y_scale = FT_DivFix( size_metrics->y_ppem << 6,
268 face->units_per_EM );
269 size_metrics->max_advance = FT_PIX_ROUND(
270 FT_MulFix( face->max_advance_width,
271 size_metrics->x_scale ) );
272 }
273 #endif /* AF_CONFIG_OPTION_TT_SIZE_METRICS */
274 }
275
276 /*
277 * TODO: This code currently doesn't support fractional advance widths,
278 * i.e., placing hinted glyphs at anything other than integer
279 * x-positions. This is only relevant for the warper code, which
280 * scales and shifts glyphs to optimize blackness of stems (hinting on
281 * the x-axis by nature places things on pixel integers, hinting on the
282 * y-axis only, i.e., LIGHT mode, doesn't touch the x-axis). The delta
283 * values of the scaler would need to be adjusted.
284 */
285 scaler.face = face;
286 scaler.x_scale = size_internal->autohint_metrics.x_scale;
287 scaler.x_delta = 0;
288 scaler.y_scale = size_internal->autohint_metrics.y_scale;
289 scaler.y_delta = 0;
290
291 scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags );
292 scaler.flags = 0;
293
294 /* note that the fallback style can't be changed anymore */
295 /* after the first call of `af_loader_load_glyph' */
296 error = af_loader_reset( loader, module, face );
297 if ( error )
298 goto Exit;
299
300 /*
301 * Glyphs (really code points) are assigned to scripts. Script
302 * analysis is done lazily: For each glyph that passes through here,
303 * the corresponding script analyzer is called, but returns immediately
304 * if it has been run already.
305 */
306 error = af_face_globals_get_metrics( loader->globals, glyph_index,
307 style_options, &style_metrics );
308 if ( error )
309 goto Exit;
310
311 style_class = style_metrics->style_class;
312 writing_system_class =
313 af_writing_system_classes[style_class->writing_system];
314
315 loader->metrics = style_metrics;
316
317 if ( writing_system_class->style_metrics_scale )
318 writing_system_class->style_metrics_scale( style_metrics, &scaler );
319 else
320 style_metrics->scaler = scaler;
321
322 if ( writing_system_class->style_hints_init )
323 {
324 error = writing_system_class->style_hints_init( hints,
325 style_metrics );
326 if ( error )
327 goto Exit;
328 }
329
330 /*
331 * Do the main work of `af_loader_load_glyph'. Note that we never have
332 * to deal with composite glyphs as those get loaded into
333 * FT_GLYPH_FORMAT_OUTLINE by the recursed `FT_Load_Glyph' function.
334 * In the rare cases where FT_LOAD_NO_RECURSE is set, it implies
335 * FT_LOAD_NO_SCALE and as such the auto-hinter is never called.
336 */
337 load_flags |= FT_LOAD_NO_SCALE |
338 FT_LOAD_IGNORE_TRANSFORM |
339 FT_LOAD_LINEAR_DESIGN;
340 load_flags &= ~FT_LOAD_RENDER;
341
342 error = FT_Load_Glyph( face, glyph_index, load_flags );
343 if ( error )
344 goto Exit;
345
346 /*
347 * Apply stem darkening (emboldening) here before hints are applied to
348 * the outline. Glyphs are scaled down proportionally to the
349 * emboldening so that curve points don't fall outside their
350 * precomputed blue zones.
351 *
352 * Any emboldening done by the font driver (e.g., the CFF driver)
353 * doesn't reach here because the autohinter loads the unprocessed
354 * glyphs in font units for analysis (functions `af_*_metrics_init_*')
355 * and then above to prepare it for the rasterizers by itself,
356 * independently of the font driver. So emboldening must be done here,
357 * within the autohinter.
358 *
359 * All glyphs to be autohinted pass through here one by one. The
360 * standard widths can therefore change from one glyph to the next,
361 * depending on what script a glyph is assigned to (each script has its
362 * own set of standard widths and other metrics). The darkening amount
363 * must therefore be recomputed for each size and
364 * `standard_{vertical,horizontal}_width' change.
365 *
366 * Ignore errors and carry on without emboldening.
367 *
368 */
369
370 /* stem darkening only works well in `light' mode */
371 if ( scaler.render_mode == FT_RENDER_MODE_LIGHT &&
372 ( !face->internal->no_stem_darkening ||
373 ( face->internal->no_stem_darkening < 0 &&
374 !module->no_stem_darkening ) ) )
375 af_loader_embolden_glyph_in_slot( loader, face, style_metrics );
376
377 loader->transformed = slot_internal->glyph_transformed;
378 if ( loader->transformed )
379 {
380 FT_Matrix inverse;
381
382
383 loader->trans_matrix = slot_internal->glyph_matrix;
384 loader->trans_delta = slot_internal->glyph_delta;
385
386 inverse = loader->trans_matrix;
387 if ( !FT_Matrix_Invert( &inverse ) )
388 FT_Vector_Transform( &loader->trans_delta, &inverse );
389 }
390
391 switch ( slot->format )
392 {
393 case FT_GLYPH_FORMAT_OUTLINE:
394 /* translate the loaded glyph when an internal transform is needed */
395 if ( loader->transformed )
396 FT_Outline_Translate( &slot->outline,
397 loader->trans_delta.x,
398 loader->trans_delta.y );
399
400 /* compute original horizontal phantom points */
401 /* (and ignore vertical ones) */
402 loader->pp1.x = hints->x_delta;
403 loader->pp1.y = hints->y_delta;
404 loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance,
405 hints->x_scale ) + hints->x_delta;
406 loader->pp2.y = hints->y_delta;
407
408 /* be sure to check for spacing glyphs */
409 if ( slot->outline.n_points == 0 )
410 goto Hint_Metrics;
411
412 /* now load the slot image into the auto-outline */
413 /* and run the automatic hinting process */
414 if ( writing_system_class->style_hints_apply )
415 {
416 error = writing_system_class->style_hints_apply(
417 glyph_index,
418 hints,
419 &gloader->base.outline,
420 style_metrics );
421 if ( error )
422 goto Exit;
423 }
424
425 /* we now need to adjust the metrics according to the change in */
426 /* width/positioning that occurred during the hinting process */
427 if ( scaler.render_mode != FT_RENDER_MODE_LIGHT )
428 {
429 AF_AxisHints axis = &hints->axis[AF_DIMENSION_HORZ];
430
431
432 if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) )
433 {
434 AF_Edge edge1 = axis->edges; /* leftmost edge */
435 AF_Edge edge2 = edge1 +
436 axis->num_edges - 1; /* rightmost edge */
437
438 FT_Pos old_rsb = loader->pp2.x - edge2->opos;
439 /* loader->pp1.x is always zero at this point of time */
440 FT_Pos old_lsb = edge1->opos; /* - loader->pp1.x */
441 FT_Pos new_lsb = edge1->pos;
442
443 /* remember unhinted values to later account */
444 /* for rounding errors */
445 FT_Pos pp1x_uh = new_lsb - old_lsb;
446 FT_Pos pp2x_uh = edge2->pos + old_rsb;
447
448
449 /* prefer too much space over too little space */
450 /* for very small sizes */
451
452 if ( old_lsb < 24 )
453 pp1x_uh -= 8;
454
455 if ( old_rsb < 24 )
456 pp2x_uh += 8;
457
458 loader->pp1.x = FT_PIX_ROUND( pp1x_uh );
459 loader->pp2.x = FT_PIX_ROUND( pp2x_uh );
460
461 if ( loader->pp1.x >= new_lsb && old_lsb > 0 )
462 loader->pp1.x -= 64;
463
464 if ( loader->pp2.x <= edge2->pos && old_rsb > 0 )
465 loader->pp2.x += 64;
466
467 slot->lsb_delta = loader->pp1.x - pp1x_uh;
468 slot->rsb_delta = loader->pp2.x - pp2x_uh;
469 }
470 else
471 {
472 FT_Pos pp1x = loader->pp1.x;
473 FT_Pos pp2x = loader->pp2.x;
474
475
476 loader->pp1.x = FT_PIX_ROUND( pp1x );
477 loader->pp2.x = FT_PIX_ROUND( pp2x );
478
479 slot->lsb_delta = loader->pp1.x - pp1x;
480 slot->rsb_delta = loader->pp2.x - pp2x;
481 }
482 }
483 /* `light' mode uses integer advance widths */
484 /* but sets `lsb_delta' and `rsb_delta' */
485 else
486 {
487 FT_Pos pp1x = loader->pp1.x;
488 FT_Pos pp2x = loader->pp2.x;
489
490
491 loader->pp1.x = FT_PIX_ROUND( pp1x );
492 loader->pp2.x = FT_PIX_ROUND( pp2x );
493
494 slot->lsb_delta = loader->pp1.x - pp1x;
495 slot->rsb_delta = loader->pp2.x - pp2x;
496 }
497
498 break;
499
500 default:
501 /* we don't support other formats (yet?) */
502 error = FT_THROW( Unimplemented_Feature );
503 }
504
505 Hint_Metrics:
506 {
507 FT_BBox bbox;
508 FT_Vector vvector;
509
510
511 vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX;
512 vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY;
513 vvector.x = FT_MulFix( vvector.x, style_metrics->scaler.x_scale );
514 vvector.y = FT_MulFix( vvector.y, style_metrics->scaler.y_scale );
515
516 /* transform the hinted outline if needed */
517 if ( loader->transformed )
518 {
519 FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix );
520 FT_Vector_Transform( &vvector, &loader->trans_matrix );
521 }
522
523 /* we must translate our final outline by -pp1.x and compute */
524 /* the new metrics */
525 if ( loader->pp1.x )
526 FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 );
527
528 FT_Outline_Get_CBox( &gloader->base.outline, &bbox );
529
530 bbox.xMin = FT_PIX_FLOOR( bbox.xMin );
531 bbox.yMin = FT_PIX_FLOOR( bbox.yMin );
532 bbox.xMax = FT_PIX_CEIL( bbox.xMax );
533 bbox.yMax = FT_PIX_CEIL( bbox.yMax );
534
535 slot->metrics.width = bbox.xMax - bbox.xMin;
536 slot->metrics.height = bbox.yMax - bbox.yMin;
537 slot->metrics.horiBearingX = bbox.xMin;
538 slot->metrics.horiBearingY = bbox.yMax;
539
540 slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x );
541 slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y );
542
543 /* for mono-width fonts (like Andale, Courier, etc.) we need */
544 /* to keep the original rounded advance width; ditto for */
545 /* digits if all have the same advance width */
546 if ( scaler.render_mode != FT_RENDER_MODE_LIGHT &&
547 ( FT_IS_FIXED_WIDTH( slot->face ) ||
548 ( af_face_globals_is_digit( loader->globals, glyph_index ) &&
549 style_metrics->digits_have_same_width ) ) )
550 {
551 slot->metrics.horiAdvance =
552 FT_MulFix( slot->metrics.horiAdvance,
553 style_metrics->scaler.x_scale );
554
555 /* Set delta values to 0. Otherwise code that uses them is */
556 /* going to ruin the fixed advance width. */
557 slot->lsb_delta = 0;
558 slot->rsb_delta = 0;
559 }
560 else
561 {
562 /* non-spacing glyphs must stay as-is */
563 if ( slot->metrics.horiAdvance )
564 slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
565 }
566
567 slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance,
568 style_metrics->scaler.y_scale );
569
570 slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
571 slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance );
572
573 slot->format = FT_GLYPH_FORMAT_OUTLINE;
574 }
575
576 Exit:
577 return error;
578 }
579
580
581 /*
582 * Compute amount of font units the face should be emboldened by, in
583 * analogy to the CFF driver's `cf2_computeDarkening' function. See there
584 * for details of the algorithm.
585 *
586 * XXX: Currently a crude adaption of the original algorithm. Do better?
587 */
588 FT_LOCAL_DEF( FT_Fixed )
589 af_loader_compute_darkening( AF_Loader loader,
590 FT_Face face,
591 FT_Pos standard_width )
592 {
593 AF_Module module = loader->globals->module;
594
595 FT_UShort units_per_EM;
596 FT_Fixed ppem, em_ratio;
597 FT_Fixed stem_width, stem_width_per_1000, scaled_stem, darken_amount;
598 FT_Int log_base_2;
599 FT_Int x1, y1, x2, y2, x3, y3, x4, y4;
600
601
602 ppem = FT_MAX( af_intToFixed( 4 ),
603 af_intToFixed( face->size->metrics.x_ppem ) );
604 units_per_EM = face->units_per_EM;
605
606 em_ratio = FT_DivFix( af_intToFixed( 1000 ),
607 af_intToFixed ( units_per_EM ) );
608 if ( em_ratio < af_floatToFixed( .01 ) )
609 {
610 /* If something goes wrong, don't embolden. */
611 return 0;
612 }
613
614 x1 = module->darken_params[0];
615 y1 = module->darken_params[1];
616 x2 = module->darken_params[2];
617 y2 = module->darken_params[3];
618 x3 = module->darken_params[4];
619 y3 = module->darken_params[5];
620 x4 = module->darken_params[6];
621 y4 = module->darken_params[7];
622
623 if ( standard_width <= 0 )
624 {
625 stem_width = af_intToFixed( 75 ); /* taken from cf2font.c */
626 stem_width_per_1000 = stem_width;
627 }
628 else
629 {
630 stem_width = af_intToFixed( standard_width );
631 stem_width_per_1000 = FT_MulFix( stem_width, em_ratio );
632 }
633
634 log_base_2 = FT_MSB( (FT_UInt32)stem_width_per_1000 ) +
635 FT_MSB( (FT_UInt32)ppem );
636
637 if ( log_base_2 >= 46 )
638 {
639 /* possible overflow */
640 scaled_stem = af_intToFixed( x4 );
641 }
642 else
643 scaled_stem = FT_MulFix( stem_width_per_1000, ppem );
644
645 /* now apply the darkening parameters */
646 if ( scaled_stem < af_intToFixed( x1 ) )
647 darken_amount = FT_DivFix( af_intToFixed( y1 ), ppem );
648
649 else if ( scaled_stem < af_intToFixed( x2 ) )
650 {
651 FT_Int xdelta = x2 - x1;
652 FT_Int ydelta = y2 - y1;
653 FT_Int x = stem_width_per_1000 -
654 FT_DivFix( af_intToFixed( x1 ), ppem );
655
656
657 if ( !xdelta )
658 goto Try_x3;
659
660 darken_amount = FT_MulDiv( x, ydelta, xdelta ) +
661 FT_DivFix( af_intToFixed( y1 ), ppem );
662 }
663
664 else if ( scaled_stem < af_intToFixed( x3 ) )
665 {
666 Try_x3:
667 {
668 FT_Int xdelta = x3 - x2;
669 FT_Int ydelta = y3 - y2;
670 FT_Int x = stem_width_per_1000 -
671 FT_DivFix( af_intToFixed( x2 ), ppem );
672
673
674 if ( !xdelta )
675 goto Try_x4;
676
677 darken_amount = FT_MulDiv( x, ydelta, xdelta ) +
678 FT_DivFix( af_intToFixed( y2 ), ppem );
679 }
680 }
681
682 else if ( scaled_stem < af_intToFixed( x4 ) )
683 {
684 Try_x4:
685 {
686 FT_Int xdelta = x4 - x3;
687 FT_Int ydelta = y4 - y3;
688 FT_Int x = stem_width_per_1000 -
689 FT_DivFix( af_intToFixed( x3 ), ppem );
690
691
692 if ( !xdelta )
693 goto Use_y4;
694
695 darken_amount = FT_MulDiv( x, ydelta, xdelta ) +
696 FT_DivFix( af_intToFixed( y3 ), ppem );
697 }
698 }
699
700 else
701 {
702 Use_y4:
703 darken_amount = FT_DivFix( af_intToFixed( y4 ), ppem );
704 }
705
706 /* Convert darken_amount from per 1000 em to true character space. */
707 return FT_DivFix( darken_amount, em_ratio );
708 }
709
710
711 /* END */