1 /***************************************************************************/
2 /* */
3 /* afhints.c */
4 /* */
5 /* Auto-fitter hinting routines (body). */
6 /* */
7 /* Copyright 2003-2018 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 "afhints.h"
20 #include "aferrors.h"
21 #include FT_INTERNAL_CALC_H
22 #include FT_INTERNAL_DEBUG_H
23
24
25 /*************************************************************************/
26 /* */
27 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
28 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
29 /* messages during execution. */
30 /* */
31 #undef FT_COMPONENT
32 #define FT_COMPONENT trace_afhints
33
34
35 /* Get new segment for given axis. */
36
37 FT_LOCAL_DEF( FT_Error )
38 af_axis_hints_new_segment( AF_AxisHints axis,
39 FT_Memory memory,
40 AF_Segment *asegment )
41 {
42 FT_Error error = FT_Err_Ok;
43 AF_Segment segment = NULL;
44
45
46 if ( axis->num_segments < AF_SEGMENTS_EMBEDDED )
47 {
48 if ( !axis->segments )
49 {
50 axis->segments = axis->embedded.segments;
51 axis->max_segments = AF_SEGMENTS_EMBEDDED;
52 }
280 return -1;
281
282 return (int)( segment - segments );
283 }
284
285
286 static int
287 af_get_edge_index( AF_GlyphHints hints,
288 int segment_idx,
289 int dimension )
290 {
291 AF_AxisHints axis = &hints->axis[dimension];
292 AF_Edge edges = axis->edges;
293 AF_Segment segment = axis->segments + segment_idx;
294
295
296 return segment_idx == -1 ? -1 : AF_INDEX_NUM( segment->edge, edges );
297 }
298
299
300 #ifdef __cplusplus
301 extern "C" {
302 #endif
303 void
304 af_glyph_hints_dump_points( AF_GlyphHints hints,
305 FT_Bool to_stdout )
306 {
307 AF_Point points = hints->points;
308 AF_Point limit = points + hints->num_points;
309 AF_Point* contour = hints->contours;
310 AF_Point* climit = contour + hints->num_contours;
311 AF_Point point;
312
313
314 AF_DUMP(( "Table of points:\n" ));
315
316 if ( hints->num_points )
317 {
318 AF_DUMP(( " index hedge hseg vedge vseg flags "
319 /* " XXXXX XXXXX XXXXX XXXXX XXXXX XXXXXX" */
320 " xorg yorg xscale yscale xfit yfit" ));
321 /* " XXXXX XXXXX XXXX.XX XXXX.XX XXXX.XX XXXX.XX" */
322 }
323 else
324 AF_DUMP(( " (none)\n" ));
325
326 for ( point = points; point < limit; point++ )
327 {
328 int point_idx = AF_INDEX_NUM( point, points );
329 int segment_idx_0 = af_get_segment_index( hints, point_idx, 0 );
330 int segment_idx_1 = af_get_segment_index( hints, point_idx, 1 );
331
332 char buf1[16], buf2[16], buf3[16], buf4[16];
333
334
335 /* insert extra newline at the beginning of a contour */
336 if ( contour < climit && *contour == point )
337 {
338 AF_DUMP(( "\n" ));
339 contour++;
340 }
341
342 AF_DUMP(( " %5d %5s %5s %5s %5s %s"
343 " %5d %5d %7.2f %7.2f %7.2f %7.2f\n",
344 point_idx,
345 af_print_idx( buf1,
346 af_get_edge_index( hints, segment_idx_1, 1 ) ),
347 af_print_idx( buf2, segment_idx_1 ),
348 af_print_idx( buf3,
349 af_get_edge_index( hints, segment_idx_0, 0 ) ),
350 af_print_idx( buf4, segment_idx_0 ),
351 ( point->flags & AF_FLAG_NEAR )
352 ? " near "
353 : ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
354 ? " weak "
355 : "strong",
356
357 point->fx,
358 point->fy,
359 point->ox / 64.0,
360 point->oy / 64.0,
361 point->x / 64.0,
362 point->y / 64.0 ));
363 }
364 AF_DUMP(( "\n" ));
365 }
366 #ifdef __cplusplus
367 }
368 #endif
369
370
371 static const char*
372 af_edge_flags_to_string( FT_UInt flags )
373 {
374 static char temp[32];
375 int pos = 0;
376
377
378 if ( flags & AF_EDGE_ROUND )
379 {
380 ft_memcpy( temp + pos, "round", 5 );
381 pos += 5;
382 }
502 {
503 AF_Dimension dim;
504 AF_AxisHints axis;
505 AF_Segment seg;
506
507
508 if ( !offset )
509 return FT_THROW( Invalid_Argument );
510
511 dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT;
512
513 axis = &hints->axis[dim];
514
515 if ( idx < 0 || idx >= axis->num_segments )
516 return FT_THROW( Invalid_Argument );
517
518 seg = &axis->segments[idx];
519 *offset = ( dim == AF_DIMENSION_HORZ ) ? seg->first->fx
520 : seg->first->fy;
521 if ( seg->edge )
522 *is_blue = (FT_Bool)( seg->edge->blue_edge != 0 );
523 else
524 *is_blue = FALSE;
525
526 if ( *is_blue )
527 *blue_offset = seg->edge->blue_edge->org;
528 else
529 *blue_offset = 0;
530
531 return FT_Err_Ok;
532 }
533 #ifdef __cplusplus
534 }
535 #endif
536
537
538 /* Dump the array of linked edges. */
539
540 #ifdef __cplusplus
541 extern "C" {
542 #endif
881
882 out_x = point->fx - prev->fx;
883 out_y = point->fy - prev->fy;
884
885 if ( FT_ABS( out_x ) + FT_ABS( out_y ) < near_limit )
886 prev->flags |= AF_FLAG_NEAR;
887
888 point->prev = prev;
889 prev->next = point;
890 prev = point;
891
892 if ( point == end )
893 {
894 if ( ++contour_index < outline->n_contours )
895 {
896 endpoint = outline->contours[contour_index];
897 end = points + endpoint;
898 prev = end;
899 }
900 }
901 }
902 }
903
904 /* set up the contours array */
905 {
906 AF_Point* contour = hints->contours;
907 AF_Point* contour_limit = contour + hints->num_contours;
908 short* end = outline->contours;
909 short idx = 0;
910
911
912 for ( ; contour < contour_limit; contour++, end++ )
913 {
914 contour[0] = points + idx;
915 idx = (short)( end[0] + 1 );
916 }
917 }
918
919 {
920 /*
1292
1293 if ( dim == AF_DIMENSION_VERT )
1294 {
1295 u = point->fy;
1296 ou = point->oy;
1297 }
1298 else
1299 {
1300 u = point->fx;
1301 ou = point->ox;
1302 }
1303
1304 fu = u;
1305
1306 /* is the point before the first edge? */
1307 edge = edges;
1308 delta = edge->fpos - u;
1309 if ( delta >= 0 )
1310 {
1311 u = edge->pos - ( edge->opos - ou );
1312 goto Store_Point;
1313 }
1314
1315 /* is the point after the last edge? */
1316 edge = edge_limit - 1;
1317 delta = u - edge->fpos;
1318 if ( delta >= 0 )
1319 {
1320 u = edge->pos + ( ou - edge->opos );
1321 goto Store_Point;
1322 }
1323
1324 {
1325 FT_PtrDist min, max, mid;
1326 FT_Pos fpos;
1327
1328
1329 /* find enclosing edges */
1330 min = 0;
1331 max = edge_limit - edges;
1332
1333 #if 1
1334 /* for a small number of edges, a linear search is better */
1335 if ( max <= 8 )
1336 {
1337 FT_PtrDist nn;
1338
1339
1340 for ( nn = 0; nn < max; nn++ )
1347 goto Store_Point;
1348 }
1349 min = nn;
1350 }
1351 else
1352 #endif
1353 while ( min < max )
1354 {
1355 mid = ( max + min ) >> 1;
1356 edge = edges + mid;
1357 fpos = edge->fpos;
1358
1359 if ( u < fpos )
1360 max = mid;
1361 else if ( u > fpos )
1362 min = mid + 1;
1363 else
1364 {
1365 /* we are on the edge */
1366 u = edge->pos;
1367 goto Store_Point;
1368 }
1369 }
1370
1371 /* point is not on an edge */
1372 {
1373 AF_Edge before = edges + min - 1;
1374 AF_Edge after = edges + min + 0;
1375
1376
1377 /* assert( before && after && before != after ) */
1378 if ( before->scale == 0 )
1379 before->scale = FT_DivFix( after->pos - before->pos,
1380 after->fpos - before->fpos );
1381
1382 u = before->pos + FT_MulFix( fu - before->fpos,
1383 before->scale );
1384 }
1385 }
1386
1387 Store_Point:
1388 /* save the point position */
1389 if ( dim == AF_DIMENSION_HORZ )
1390 point->x = u;
1391 else
1392 point->y = u;
1393
1394 point->flags |= touch_flag;
1395 }
|
1 /****************************************************************************
2 *
3 * afhints.c
4 *
5 * Auto-fitter hinting routines (body).
6 *
7 * Copyright (C) 2003-2019 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 "afhints.h"
20 #include "aferrors.h"
21 #include FT_INTERNAL_CALC_H
22 #include FT_INTERNAL_DEBUG_H
23
24
25 /**************************************************************************
26 *
27 * The macro FT_COMPONENT is used in trace mode. It is an implicit
28 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
29 * messages during execution.
30 */
31 #undef FT_COMPONENT
32 #define FT_COMPONENT afhints
33
34
35 /* Get new segment for given axis. */
36
37 FT_LOCAL_DEF( FT_Error )
38 af_axis_hints_new_segment( AF_AxisHints axis,
39 FT_Memory memory,
40 AF_Segment *asegment )
41 {
42 FT_Error error = FT_Err_Ok;
43 AF_Segment segment = NULL;
44
45
46 if ( axis->num_segments < AF_SEGMENTS_EMBEDDED )
47 {
48 if ( !axis->segments )
49 {
50 axis->segments = axis->embedded.segments;
51 axis->max_segments = AF_SEGMENTS_EMBEDDED;
52 }
280 return -1;
281
282 return (int)( segment - segments );
283 }
284
285
286 static int
287 af_get_edge_index( AF_GlyphHints hints,
288 int segment_idx,
289 int dimension )
290 {
291 AF_AxisHints axis = &hints->axis[dimension];
292 AF_Edge edges = axis->edges;
293 AF_Segment segment = axis->segments + segment_idx;
294
295
296 return segment_idx == -1 ? -1 : AF_INDEX_NUM( segment->edge, edges );
297 }
298
299
300 static int
301 af_get_strong_edge_index( AF_GlyphHints hints,
302 AF_Edge* strong_edges,
303 int dimension )
304 {
305 AF_AxisHints axis = &hints->axis[dimension];
306 AF_Edge edges = axis->edges;
307
308
309 return AF_INDEX_NUM( strong_edges[dimension], edges );
310 }
311
312
313 #ifdef __cplusplus
314 extern "C" {
315 #endif
316 void
317 af_glyph_hints_dump_points( AF_GlyphHints hints,
318 FT_Bool to_stdout )
319 {
320 AF_Point points = hints->points;
321 AF_Point limit = points + hints->num_points;
322 AF_Point* contour = hints->contours;
323 AF_Point* climit = contour + hints->num_contours;
324 AF_Point point;
325
326
327 AF_DUMP(( "Table of points:\n" ));
328
329 if ( hints->num_points )
330 {
331 AF_DUMP(( " index hedge hseg vedge vseg flags "
332 /* " XXXXX XXXXX XXXXX XXXXX XXXXX XXXXXX" */
333 " xorg yorg xscale yscale xfit yfit "
334 /* " XXXXX XXXXX XXXX.XX XXXX.XX XXXX.XX XXXX.XX" */
335 " hbef haft vbef vaft" ));
336 /* " XXXXX XXXXX XXXXX XXXXX" */
337 }
338 else
339 AF_DUMP(( " (none)\n" ));
340
341 for ( point = points; point < limit; point++ )
342 {
343 int point_idx = AF_INDEX_NUM( point, points );
344 int segment_idx_0 = af_get_segment_index( hints, point_idx, 0 );
345 int segment_idx_1 = af_get_segment_index( hints, point_idx, 1 );
346
347 char buf1[16], buf2[16], buf3[16], buf4[16];
348 char buf5[16], buf6[16], buf7[16], buf8[16];
349
350
351 /* insert extra newline at the beginning of a contour */
352 if ( contour < climit && *contour == point )
353 {
354 AF_DUMP(( "\n" ));
355 contour++;
356 }
357
358 AF_DUMP(( " %5d %5s %5s %5s %5s %s"
359 " %5d %5d %7.2f %7.2f %7.2f %7.2f"
360 " %5s %5s %5s %5s\n",
361 point_idx,
362 af_print_idx( buf1,
363 af_get_edge_index( hints, segment_idx_1, 1 ) ),
364 af_print_idx( buf2, segment_idx_1 ),
365 af_print_idx( buf3,
366 af_get_edge_index( hints, segment_idx_0, 0 ) ),
367 af_print_idx( buf4, segment_idx_0 ),
368 ( point->flags & AF_FLAG_NEAR )
369 ? " near "
370 : ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
371 ? " weak "
372 : "strong",
373
374 point->fx,
375 point->fy,
376 point->ox / 64.0,
377 point->oy / 64.0,
378 point->x / 64.0,
379 point->y / 64.0,
380
381 af_print_idx( buf5, af_get_strong_edge_index( hints,
382 point->before,
383 1 ) ),
384 af_print_idx( buf6, af_get_strong_edge_index( hints,
385 point->after,
386 1 ) ),
387 af_print_idx( buf7, af_get_strong_edge_index( hints,
388 point->before,
389 0 ) ),
390 af_print_idx( buf8, af_get_strong_edge_index( hints,
391 point->after,
392 0 ) ) ));
393 }
394 AF_DUMP(( "\n" ));
395 }
396 #ifdef __cplusplus
397 }
398 #endif
399
400
401 static const char*
402 af_edge_flags_to_string( FT_UInt flags )
403 {
404 static char temp[32];
405 int pos = 0;
406
407
408 if ( flags & AF_EDGE_ROUND )
409 {
410 ft_memcpy( temp + pos, "round", 5 );
411 pos += 5;
412 }
532 {
533 AF_Dimension dim;
534 AF_AxisHints axis;
535 AF_Segment seg;
536
537
538 if ( !offset )
539 return FT_THROW( Invalid_Argument );
540
541 dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT;
542
543 axis = &hints->axis[dim];
544
545 if ( idx < 0 || idx >= axis->num_segments )
546 return FT_THROW( Invalid_Argument );
547
548 seg = &axis->segments[idx];
549 *offset = ( dim == AF_DIMENSION_HORZ ) ? seg->first->fx
550 : seg->first->fy;
551 if ( seg->edge )
552 *is_blue = FT_BOOL( seg->edge->blue_edge );
553 else
554 *is_blue = FALSE;
555
556 if ( *is_blue )
557 *blue_offset = seg->edge->blue_edge->org;
558 else
559 *blue_offset = 0;
560
561 return FT_Err_Ok;
562 }
563 #ifdef __cplusplus
564 }
565 #endif
566
567
568 /* Dump the array of linked edges. */
569
570 #ifdef __cplusplus
571 extern "C" {
572 #endif
911
912 out_x = point->fx - prev->fx;
913 out_y = point->fy - prev->fy;
914
915 if ( FT_ABS( out_x ) + FT_ABS( out_y ) < near_limit )
916 prev->flags |= AF_FLAG_NEAR;
917
918 point->prev = prev;
919 prev->next = point;
920 prev = point;
921
922 if ( point == end )
923 {
924 if ( ++contour_index < outline->n_contours )
925 {
926 endpoint = outline->contours[contour_index];
927 end = points + endpoint;
928 prev = end;
929 }
930 }
931
932 #ifdef FT_DEBUG_AUTOFIT
933 point->before[0] = NULL;
934 point->before[1] = NULL;
935 point->after[0] = NULL;
936 point->after[1] = NULL;
937 #endif
938
939 }
940 }
941
942 /* set up the contours array */
943 {
944 AF_Point* contour = hints->contours;
945 AF_Point* contour_limit = contour + hints->num_contours;
946 short* end = outline->contours;
947 short idx = 0;
948
949
950 for ( ; contour < contour_limit; contour++, end++ )
951 {
952 contour[0] = points + idx;
953 idx = (short)( end[0] + 1 );
954 }
955 }
956
957 {
958 /*
1330
1331 if ( dim == AF_DIMENSION_VERT )
1332 {
1333 u = point->fy;
1334 ou = point->oy;
1335 }
1336 else
1337 {
1338 u = point->fx;
1339 ou = point->ox;
1340 }
1341
1342 fu = u;
1343
1344 /* is the point before the first edge? */
1345 edge = edges;
1346 delta = edge->fpos - u;
1347 if ( delta >= 0 )
1348 {
1349 u = edge->pos - ( edge->opos - ou );
1350
1351 #ifdef FT_DEBUG_AUTOFIT
1352 point->before[dim] = edge;
1353 point->after[dim] = NULL;
1354 #endif
1355
1356 goto Store_Point;
1357 }
1358
1359 /* is the point after the last edge? */
1360 edge = edge_limit - 1;
1361 delta = u - edge->fpos;
1362 if ( delta >= 0 )
1363 {
1364 u = edge->pos + ( ou - edge->opos );
1365
1366 #ifdef FT_DEBUG_AUTOFIT
1367 point->before[dim] = NULL;
1368 point->after[dim] = edge;
1369 #endif
1370
1371 goto Store_Point;
1372 }
1373
1374 {
1375 FT_PtrDist min, max, mid;
1376 FT_Pos fpos;
1377
1378
1379 /* find enclosing edges */
1380 min = 0;
1381 max = edge_limit - edges;
1382
1383 #if 1
1384 /* for a small number of edges, a linear search is better */
1385 if ( max <= 8 )
1386 {
1387 FT_PtrDist nn;
1388
1389
1390 for ( nn = 0; nn < max; nn++ )
1397 goto Store_Point;
1398 }
1399 min = nn;
1400 }
1401 else
1402 #endif
1403 while ( min < max )
1404 {
1405 mid = ( max + min ) >> 1;
1406 edge = edges + mid;
1407 fpos = edge->fpos;
1408
1409 if ( u < fpos )
1410 max = mid;
1411 else if ( u > fpos )
1412 min = mid + 1;
1413 else
1414 {
1415 /* we are on the edge */
1416 u = edge->pos;
1417
1418 #ifdef FT_DEBUG_AUTOFIT
1419 point->before[dim] = NULL;
1420 point->after[dim] = NULL;
1421 #endif
1422
1423 goto Store_Point;
1424 }
1425 }
1426
1427 /* point is not on an edge */
1428 {
1429 AF_Edge before = edges + min - 1;
1430 AF_Edge after = edges + min + 0;
1431
1432
1433 #ifdef FT_DEBUG_AUTOFIT
1434 point->before[dim] = before;
1435 point->after[dim] = after;
1436 #endif
1437
1438 /* assert( before && after && before != after ) */
1439 if ( before->scale == 0 )
1440 before->scale = FT_DivFix( after->pos - before->pos,
1441 after->fpos - before->fpos );
1442
1443 u = before->pos + FT_MulFix( fu - before->fpos,
1444 before->scale );
1445 }
1446 }
1447
1448 Store_Point:
1449 /* save the point position */
1450 if ( dim == AF_DIMENSION_HORZ )
1451 point->x = u;
1452 else
1453 point->y = u;
1454
1455 point->flags |= touch_flag;
1456 }
|