Werner Lemberg pushed to branch master at FreeType / FreeType
Commits:
-
93771d61
by Werner Lemberg at 2021-07-16T07:40:56+02:00
-
552fc97f
by Werner Lemberg at 2021-07-16T07:49:20+02:00
3 changed files:
Changes:
1 |
+2021-07-16 Werner Lemberg <wl@gnu.org>
|
|
2 |
+ |
|
3 |
+ [smooth] Minor fixes.
|
|
4 |
+ |
|
5 |
+ * src/smooth/ftgrays.c (gray_render_conic): Move variable and
|
|
6 |
+ structure declarations to beginning of function. Inspite of C99
|
|
7 |
+ compliance we still do this for the sake of backward compatibility.
|
|
8 |
+ This also avoids a shadowing declaration of `count`.
|
|
9 |
+ (gray_convert_glyph_inner): Fix typo.
|
|
10 |
+ |
|
11 |
+2021-07-15 Ben Wagner <bungeman@chromium.org>
|
|
12 |
+ |
|
13 |
+ * src/smooth/ftgrays.c: Guard inclusion of `emmintrin.h`.
|
|
14 |
+ |
|
15 |
+ Guard inclusion of `emmintrin.h` with `#ifdef __SSE2__`. The gcc
|
|
16 |
+ version of this header, `xmmintrin.h`, and `mmintrin.h` check that
|
|
17 |
+ the appropriate defines are set before defining anything (are
|
|
18 |
+ internally guarded). However, the clang versions of these includes
|
|
19 |
+ are not internally guarded. As a result of this, externally guard
|
|
20 |
+ the inclusion of these headers.
|
|
21 |
+ |
|
1 | 22 |
2021-07-15 David Turner <david@freetype.org>
|
2 | 23 |
|
3 |
- [smooth] Implement Bezier quadratic arc flattenning with DDA
|
|
24 |
+ [smooth] Implement Bézier quadratic arc flattening with DDA.
|
|
4 | 25 |
|
5 | 26 |
Benchmarking shows that this provides a very slighty performance
|
6 |
- boost when rendering fonts with lots of quadratic bezier arcs,
|
|
27 |
+ boost when rendering fonts with lots of quadratic Bézier arcs,
|
|
7 | 28 |
compared to the recursive arc splitting, but only when SSE2 is
|
8 | 29 |
available, or on 64-bit CPUs.
|
9 | 30 |
|
31 |
+ On a 2017 Core i5-7300U CPU on Linux/x86_64:
|
|
32 |
+ |
|
33 |
+ ftbench -p -s10 -t5 -cb DroidSansFallbackFull.ttf
|
|
34 |
+ |
|
35 |
+ Before: 4.033 us/op (best of 5 runs for all numbers)
|
|
36 |
+ After: 3.876 us/op
|
|
37 |
+ |
|
38 |
+ ftbench -p -s60 -t5 -cb DroidSansFallbackFull.ttf
|
|
39 |
+ |
|
40 |
+ Before: 13.467 us/op
|
|
41 |
+ After: 13.385 us/op
|
|
42 |
+ |
|
10 | 43 |
* src/smooth/ftgrays.c (gray_render_conic): New implementation
|
11 | 44 |
based on DDA and optionally SSE2.
|
12 | 45 |
|
13 | 46 |
2021-07-15 David Turner <david@freetype.org>
|
14 | 47 |
|
15 |
- [smooth] Minor speedup to smooth rasterizer
|
|
48 |
+ [smooth] Minor speedup to smooth rasterizer.
|
|
16 | 49 |
|
17 |
- This speeds up the smooth rasterizer by avoiding a conditional
|
|
50 |
+ This speeds up the smooth rasterizer by avoiding conditional
|
|
18 | 51 |
branches in the hot path.
|
19 | 52 |
|
20 |
- * src/smooth/ftgrays.c: Define a null cell used to both as a
|
|
21 |
- sentinel for all linked-lists, and to accumulate coverage and
|
|
22 |
- area values for "out-of-bounds" cell positions without a
|
|
23 |
- conditional check.
|
|
53 |
+ - Define a fixed 'null cell', which will be pointed to whenever the
|
|
54 |
+ current cell is outside of the current target region. This avoids
|
|
55 |
+ a `ras.cell != NULL` check in the `FT_INTEGRATE` macro.
|
|
56 |
+ |
|
57 |
+ - Also use the null cell as a sentinel at the end of all `ycells`
|
|
58 |
+ linked-lists, by setting its x coordinate to `INT_MAX`. This
|
|
59 |
+ avoids a `if (!cell)` check in `gray_set_cell` as well.
|
|
60 |
+ |
|
61 |
+ - Slightly change the worker struct fields to perform a little less
|
|
62 |
+ operations during rendering.
|
|
63 |
+ |
|
64 |
+ Example results (on a 2013 Corei5-3337U CPU)
|
|
65 |
+ |
|
66 |
+ out/ftbench -p -s10 -t5 -bc DroidSansFallbackFull.ttf
|
|
67 |
+ |
|
68 |
+ Before: 5.472 us/op
|
|
69 |
+ After: 5.275 us/op
|
|
70 |
+ |
|
71 |
+ out/ftbench -p -s60 -t5 -bc DroidSansFallbackFull.ttf
|
|
72 |
+ |
|
73 |
+ Before: 17.988 us/op
|
|
74 |
+ After: 17.389 us/op
|
|
75 |
+ |
|
76 |
+ * src/smooth/ftgrays.c (grat_TWorker): Replace `num_cells` field with
|
|
77 |
+ `cell_free` and `cell_limit`.
|
|
78 |
+ (NULL_CELL_PTR, CELL_MAX_X_VALUE, CELL_IS_NULL): New macros.
|
|
79 |
+ (gray_dump_cells, gray_set_cell, gray_sweep, gray_sweep_direct,
|
|
80 |
+ gray_convert_glyph_inner, gray_convert_glyph): Updated.
|
|
24 | 81 |
|
25 | 82 |
2021-07-15 David Turner <david@freetype.org>
|
26 | 83 |
|
27 |
- Replaces download-test-fonts.sh with download-test-fonts.py which
|
|
28 |
- does the same work, and also avoids downloading anything if the
|
|
29 |
- files are already installed with the right content.
|
|
84 |
+ [tests] Rewrite download script in Python3.
|
|
85 |
+ |
|
86 |
+ This commit replaces the bash script with a Python script that does
|
|
87 |
+ the same work, plus avoiding to download anything if the files are
|
|
88 |
+ already installed with the right content.
|
|
30 | 89 |
|
31 |
- Now uses the first 8 byte of each file's sha256 hash for the digest.
|
|
90 |
+ We now use the first 8 bytes of each file's sha256 hash for the
|
|
91 |
+ digest.
|
|
32 | 92 |
|
33 |
- * tests/scripts/download-test-fonts.sh: Removed
|
|
34 |
- * tests/scripts/download-test-fonts.py: New script
|
|
35 |
- * tests/README.md: Updated
|
|
93 |
+ * tests/scripts/download-test-fonts.sh: Removed.
|
|
94 |
+ * tests/scripts/download-test-fonts.py: New script.
|
|
95 |
+ * tests/README.md: Updated.
|
|
36 | 96 |
|
37 | 97 |
2021-07-15 Alex Richardson <Alexander.Richardson@cl.cam.ac.uk>
|
38 | 98 |
|
... | ... | @@ -487,8 +487,8 @@ typedef ptrdiff_t FT_PtrDist; |
487 | 487 |
PCell cell_free; /* call allocation next free slot */
|
488 | 488 |
PCell cell_limit; /* cell allocation limit */
|
489 | 489 |
|
490 |
- PCell* ycells; /* array of cell linked-lists, one per */
|
|
491 |
- /* vertical coordinate in the current band. */
|
|
490 |
+ PCell* ycells; /* array of cell linked-lists; one per */
|
|
491 |
+ /* vertical coordinate in the current band */
|
|
492 | 492 |
|
493 | 493 |
PCell cells; /* cell storage area */
|
494 | 494 |
FT_PtrDist max_cells; /* cell storage capacity */
|
... | ... | @@ -513,19 +513,21 @@ typedef ptrdiff_t FT_PtrDist; |
513 | 513 |
static gray_TWorker ras;
|
514 | 514 |
#endif
|
515 | 515 |
|
516 |
-/* Return a pointer to the "null cell", used as a sentinel at the end */
|
|
517 |
-/* of all ycells[] linked lists. Its x coordinate should be maximal */
|
|
518 |
-/* to ensure no NULL checks are necessary when looking for an insertion */
|
|
519 |
-/* point in gray_set_cell(). Other loops should check the cell pointer */
|
|
520 |
-/* with CELL_IS_NULL() to detect the end of the list. */
|
|
521 |
-#define NULL_CELL_PTR(ras) (ras).cells
|
|
516 |
+ /*
|
|
517 |
+ * Return a pointer to the 'null cell', used as a sentinel at the end of
|
|
518 |
+ * all `ycells` linked lists. Its x coordinate should be maximal to
|
|
519 |
+ * ensure no NULL checks are necessary when looking for an insertion point
|
|
520 |
+ * in `gray_set_cell`. Other loops should check the cell pointer with
|
|
521 |
+ * CELL_IS_NULL() to detect the end of the list.
|
|
522 |
+ */
|
|
523 |
+#define NULL_CELL_PTR( ras ) (ras).cells
|
|
522 | 524 |
|
523 |
-/* The |x| value of the null cell. Must be the largest possible */
|
|
524 |
-/* integer value stored in a TCell.x field. */
|
|
525 |
+ /* The |x| value of the null cell. Must be the largest possible */
|
|
526 |
+ /* integer value stored in a `TCell.x` field. */
|
|
525 | 527 |
#define CELL_MAX_X_VALUE INT_MAX
|
526 | 528 |
|
527 |
-/* Return true iff |cell| points to the null cell. */
|
|
528 |
-#define CELL_IS_NULL(cell) ((cell)->x == CELL_MAX_X_VALUE)
|
|
529 |
+ /* Return true iff |cell| points to the null cell. */
|
|
530 |
+#define CELL_IS_NULL( cell ) ( (cell)->x == CELL_MAX_X_VALUE )
|
|
529 | 531 |
|
530 | 532 |
|
531 | 533 |
#define FT_INTEGRATE( ras, a, b ) \
|
... | ... | @@ -556,7 +558,7 @@ typedef ptrdiff_t FT_PtrDist; |
556 | 558 |
|
557 | 559 |
printf( "%3d:", y );
|
558 | 560 |
|
559 |
- for ( ; !CELL_IS_NULL(cell); cell = cell->next )
|
|
561 |
+ for ( ; !CELL_IS_NULL( cell ); cell = cell->next )
|
|
560 | 562 |
printf( " (%3d, c:%4d, a:%6d)",
|
561 | 563 |
cell->x, cell->cover, cell->area );
|
562 | 564 |
printf( "\n" );
|
... | ... | @@ -584,9 +586,11 @@ typedef ptrdiff_t FT_PtrDist; |
584 | 586 |
/* Note that if a cell is to the left of the clipping region, it is */
|
585 | 587 |
/* actually set to the (min_ex-1) horizontal position. */
|
586 | 588 |
|
587 |
- TCoord ey_index = ey - ras.min_ey;
|
|
589 |
+ TCoord ey_index = ey - ras.min_ey;
|
|
590 |
+ |
|
591 |
+ |
|
588 | 592 |
if ( ey_index < 0 || ey_index >= ras.count_ey || ex >= ras.max_ex )
|
589 |
- ras.cell = NULL_CELL_PTR(ras);
|
|
593 |
+ ras.cell = NULL_CELL_PTR( ras );
|
|
590 | 594 |
else
|
591 | 595 |
{
|
592 | 596 |
PCell* pcell = ras.ycells + ey_index;
|
... | ... | @@ -610,7 +614,7 @@ typedef ptrdiff_t FT_PtrDist; |
610 | 614 |
|
611 | 615 |
/* insert new cell */
|
612 | 616 |
cell = ras.cell_free++;
|
613 |
- if (cell >= ras.cell_limit)
|
|
617 |
+ if ( cell >= ras.cell_limit )
|
|
614 | 618 |
ft_longjmp( ras.jump_buffer, 1 );
|
615 | 619 |
|
616 | 620 |
cell->x = ex;
|
... | ... | @@ -978,6 +982,7 @@ typedef ptrdiff_t FT_PtrDist; |
978 | 982 |
}
|
979 | 983 |
|
980 | 984 |
gray_set_cell( RAS_VAR_ ex1, ey1 );
|
985 |
+ |
|
981 | 986 |
} while ( ex1 != ex2 || ey1 != ey2 );
|
982 | 987 |
}
|
983 | 988 |
|
... | ... | @@ -987,30 +992,37 @@ typedef ptrdiff_t FT_PtrDist; |
987 | 992 |
FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 );
|
988 | 993 |
|
989 | 994 |
End:
|
990 |
- ras.x = to_x;
|
|
991 |
- ras.y = to_y;
|
|
995 |
+ ras.x = to_x;
|
|
996 |
+ ras.y = to_y;
|
|
992 | 997 |
}
|
993 | 998 |
|
994 | 999 |
#endif
|
995 | 1000 |
|
996 |
-/* Benchmarking shows that using DDA to flatten the quadratic bezier
|
|
997 |
- * arcs is slightly faster in the following cases:
|
|
998 |
- *
|
|
999 |
- * - When the host CPU is 64-bit.
|
|
1000 |
- * - When SSE2 SIMD registers and instructions are available (even on x86).
|
|
1001 |
- *
|
|
1002 |
- * For other cases, using binary splits is actually slightly faster.
|
|
1003 |
- */
|
|
1004 |
-#if defined(__SSE2__) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_AMD64) || defined(_M_ARM64)
|
|
1005 |
-#define BEZIER_USE_DDA 1
|
|
1001 |
+ /*
|
|
1002 |
+ * Benchmarking shows that using DDA to flatten the quadratic Bézier arcs
|
|
1003 |
+ * is slightly faster in the following cases:
|
|
1004 |
+ *
|
|
1005 |
+ * - When the host CPU is 64-bit.
|
|
1006 |
+ * - When SSE2 SIMD registers and instructions are available (even on
|
|
1007 |
+ * x86).
|
|
1008 |
+ *
|
|
1009 |
+ * For other cases, using binary splits is actually slightly faster.
|
|
1010 |
+ */
|
|
1011 |
+#if defined( __SSE2__ ) || \
|
|
1012 |
+ defined( __x86_64__ ) || \
|
|
1013 |
+ defined( __aarch64__ ) || \
|
|
1014 |
+ defined( _M_AMD64 ) || \
|
|
1015 |
+ defined( _M_ARM64 )
|
|
1016 |
+# define BEZIER_USE_DDA 1
|
|
1006 | 1017 |
#else
|
1007 |
-#define BEZIER_USE_DDA 0
|
|
1018 |
+# define BEZIER_USE_DDA 0
|
|
1008 | 1019 |
#endif
|
1009 | 1020 |
|
1021 |
+ |
|
1010 | 1022 |
#if BEZIER_USE_DDA
|
1011 | 1023 |
|
1012 | 1024 |
#ifdef __SSE2__
|
1013 |
-#include <emmintrin.h>
|
|
1025 |
+# include <emmintrin.h>
|
|
1014 | 1026 |
#endif
|
1015 | 1027 |
|
1016 | 1028 |
static void
|
... | ... | @@ -1018,6 +1030,16 @@ typedef ptrdiff_t FT_PtrDist; |
1018 | 1030 |
const FT_Vector* to )
|
1019 | 1031 |
{
|
1020 | 1032 |
FT_Vector p0, p1, p2;
|
1033 |
+ TPos dx, dy;
|
|
1034 |
+ int shift;
|
|
1035 |
+ |
|
1036 |
+ FT_Int64 ax, ay, bx, by;
|
|
1037 |
+ FT_Int64 rx, ry;
|
|
1038 |
+ FT_Int64 qx, qy;
|
|
1039 |
+ FT_Int64 px, py;
|
|
1040 |
+ |
|
1041 |
+ FT_UInt count;
|
|
1042 |
+ |
|
1021 | 1043 |
|
1022 | 1044 |
p0.x = ras.x;
|
1023 | 1045 |
p0.y = ras.y;
|
... | ... | @@ -1039,8 +1061,8 @@ typedef ptrdiff_t FT_PtrDist; |
1039 | 1061 |
return;
|
1040 | 1062 |
}
|
1041 | 1063 |
|
1042 |
- TPos dx = FT_ABS( p0.x + p2.x - 2 * p1.x );
|
|
1043 |
- TPos dy = FT_ABS( p0.y + p2.y - 2 * p1.y );
|
|
1064 |
+ dx = FT_ABS( p0.x + p2.x - 2 * p1.x );
|
|
1065 |
+ dy = FT_ABS( p0.y + p2.y - 2 * p1.y );
|
|
1044 | 1066 |
if ( dx < dy )
|
1045 | 1067 |
dx = dy;
|
1046 | 1068 |
|
... | ... | @@ -1053,13 +1075,13 @@ typedef ptrdiff_t FT_PtrDist; |
1053 | 1075 |
/* We can calculate the number of necessary bisections because */
|
1054 | 1076 |
/* each bisection predictably reduces deviation exactly 4-fold. */
|
1055 | 1077 |
/* Even 32-bit deviation would vanish after 16 bisections. */
|
1056 |
- int shift = 0;
|
|
1078 |
+ shift = 0;
|
|
1057 | 1079 |
do
|
1058 | 1080 |
{
|
1059 | 1081 |
dx >>= 2;
|
1060 | 1082 |
shift += 1;
|
1061 |
- }
|
|
1062 |
- while (dx > ONE_PIXEL / 4);
|
|
1083 |
+ |
|
1084 |
+ } while ( dx > ONE_PIXEL / 4 );
|
|
1063 | 1085 |
|
1064 | 1086 |
/*
|
1065 | 1087 |
* The (P0,P1,P2) arc equation, for t in [0,1] range:
|
... | ... | @@ -1102,78 +1124,96 @@ typedef ptrdiff_t FT_PtrDist; |
1102 | 1124 |
* Q << 32 = (2 * B << (32 - N)) + (A << (32 - N - N))
|
1103 | 1125 |
* = (B << (33 - N)) + (A << (32 - N - N))
|
1104 | 1126 |
*/
|
1127 |
+ |
|
1105 | 1128 |
#ifdef __SSE2__
|
1106 |
- /* Experience shows that for small shift values, SSE2 is actually slower. */
|
|
1107 |
- if (shift > 2) {
|
|
1108 |
- union {
|
|
1109 |
- struct { FT_Int64 ax, ay, bx, by; } i;
|
|
1110 |
- struct { __m128i a, b; } vec;
|
|
1129 |
+ /* Experience shows that for small shift values, */
|
|
1130 |
+ /* SSE2 is actually slower. */
|
|
1131 |
+ if ( shift > 2 )
|
|
1132 |
+ {
|
|
1133 |
+ union
|
|
1134 |
+ {
|
|
1135 |
+ struct { FT_Int64 ax, ay, bx, by; } i;
|
|
1136 |
+ struct { __m128i a, b; } vec;
|
|
1137 |
+ |
|
1111 | 1138 |
} u;
|
1112 | 1139 |
|
1140 |
+ union
|
|
1141 |
+ {
|
|
1142 |
+ struct { FT_Int32 px_lo, px_hi, py_lo, py_hi; } i;
|
|
1143 |
+ __m128i vec;
|
|
1144 |
+ |
|
1145 |
+ } v;
|
|
1146 |
+ |
|
1147 |
+ __m128i a, b;
|
|
1148 |
+ __m128i r, q, q2;
|
|
1149 |
+ __m128i p;
|
|
1150 |
+ |
|
1151 |
+ |
|
1113 | 1152 |
u.i.ax = p0.x + p2.x - 2 * p1.x;
|
1114 | 1153 |
u.i.ay = p0.y + p2.y - 2 * p1.y;
|
1115 | 1154 |
u.i.bx = p1.x - p0.x;
|
1116 | 1155 |
u.i.by = p1.y - p0.y;
|
1117 | 1156 |
|
1118 |
- __m128i a = _mm_load_si128(&u.vec.a);
|
|
1119 |
- __m128i b = _mm_load_si128(&u.vec.b);
|
|
1157 |
+ a = _mm_load_si128( &u.vec.a );
|
|
1158 |
+ b = _mm_load_si128( &u.vec.b );
|
|
1120 | 1159 |
|
1121 |
- __m128i r = _mm_slli_epi64(a, 33 - 2 * shift);
|
|
1122 |
- __m128i q = _mm_slli_epi64(b, 33 - shift);
|
|
1123 |
- __m128i q2 = _mm_slli_epi64(a, 32 - 2 * shift);
|
|
1124 |
- q = _mm_add_epi64(q2, q);
|
|
1160 |
+ r = _mm_slli_epi64( a, 33 - 2 * shift );
|
|
1161 |
+ q = _mm_slli_epi64( b, 33 - shift );
|
|
1162 |
+ q2 = _mm_slli_epi64( a, 32 - 2 * shift );
|
|
1163 |
+ |
|
1164 |
+ q = _mm_add_epi64( q2, q );
|
|
1125 | 1165 |
|
1126 |
- union {
|
|
1127 |
- struct { FT_Int32 px_lo, px_hi, py_lo, py_hi; } i;
|
|
1128 |
- __m128i vec;
|
|
1129 |
- } v;
|
|
1130 | 1166 |
v.i.px_lo = 0;
|
1131 | 1167 |
v.i.px_hi = p0.x;
|
1132 | 1168 |
v.i.py_lo = 0;
|
1133 | 1169 |
v.i.py_hi = p0.y;
|
1134 | 1170 |
|
1135 |
- __m128i p = _mm_load_si128(&v.vec);
|
|
1171 |
+ p = _mm_load_si128( &v.vec );
|
|
1136 | 1172 |
|
1137 |
- for (unsigned count = (1u << shift); count > 0; count--) {
|
|
1138 |
- p = _mm_add_epi64(p, q);
|
|
1139 |
- q = _mm_add_epi64(q, r);
|
|
1173 |
+ for ( count = ( 1U << shift ); count > 0; count-- )
|
|
1174 |
+ {
|
|
1175 |
+ p = _mm_add_epi64( p, q );
|
|
1176 |
+ q = _mm_add_epi64( q, r );
|
|
1140 | 1177 |
|
1141 |
- _mm_store_si128(&v.vec, p);
|
|
1178 |
+ _mm_store_si128( &v.vec, p );
|
|
1142 | 1179 |
|
1143 |
- gray_render_line( RAS_VAR_ v.i.px_hi, v.i.py_hi);
|
|
1180 |
+ gray_render_line( RAS_VAR_ v.i.px_hi, v.i.py_hi );
|
|
1144 | 1181 |
}
|
1182 |
+ |
|
1145 | 1183 |
return;
|
1146 | 1184 |
}
|
1147 |
-#endif /* !__SSE2__ */
|
|
1148 |
- FT_Int64 ax = p0.x + p2.x - 2 * p1.x;
|
|
1149 |
- FT_Int64 ay = p0.y + p2.y - 2 * p1.y;
|
|
1150 |
- FT_Int64 bx = p1.x - p0.x;
|
|
1151 |
- FT_Int64 by = p1.y - p0.y;
|
|
1185 |
+#endif /* __SSE2__ */
|
|
1152 | 1186 |
|
1153 |
- FT_Int64 rx = ax << (33 - 2 * shift);
|
|
1154 |
- FT_Int64 ry = ay << (33 - 2 * shift);
|
|
1187 |
+ ax = p0.x + p2.x - 2 * p1.x;
|
|
1188 |
+ ay = p0.y + p2.y - 2 * p1.y;
|
|
1189 |
+ bx = p1.x - p0.x;
|
|
1190 |
+ by = p1.y - p0.y;
|
|
1155 | 1191 |
|
1156 |
- FT_Int64 qx = (bx << (33 - shift)) + (ax << (32 - 2 * shift));
|
|
1157 |
- FT_Int64 qy = (by << (33 - shift)) + (ay << (32 - 2 * shift));
|
|
1192 |
+ rx = ax << ( 33 - 2 * shift );
|
|
1193 |
+ ry = ay << ( 33 - 2 * shift );
|
|
1158 | 1194 |
|
1159 |
- FT_Int64 px = (FT_Int64)p0.x << 32;
|
|
1160 |
- FT_Int64 py = (FT_Int64)p0.y << 32;
|
|
1195 |
+ qx = ( bx << ( 33 - shift ) ) + ( ax << ( 32 - 2 * shift ) );
|
|
1196 |
+ qy = ( by << ( 33 - shift ) ) + ( ay << ( 32 - 2 * shift ) );
|
|
1161 | 1197 |
|
1162 |
- FT_UInt count = 1u << shift;
|
|
1198 |
+ px = (FT_Int64)p0.x << 32;
|
|
1199 |
+ py = (FT_Int64)p0.y << 32;
|
|
1163 | 1200 |
|
1164 |
- for (; count > 0; count--) {
|
|
1201 |
+ for ( count = 1U << shift; count > 0; count-- )
|
|
1202 |
+ {
|
|
1165 | 1203 |
px += qx;
|
1166 | 1204 |
py += qy;
|
1167 | 1205 |
qx += rx;
|
1168 | 1206 |
qy += ry;
|
1169 | 1207 |
|
1170 |
- gray_render_line( RAS_VAR_ (FT_Pos)(px >> 32), (FT_Pos)(py >> 32));
|
|
1208 |
+ gray_render_line( RAS_VAR_ (FT_Pos)( px >> 32 ),
|
|
1209 |
+ (FT_Pos)( py >> 32 ) );
|
|
1171 | 1210 |
}
|
1172 | 1211 |
}
|
1173 | 1212 |
|
1174 | 1213 |
#else /* !BEZIER_USE_DDA */
|
1175 | 1214 |
|
1176 |
- /* Note that multiple attempts to speed up the function below
|
|
1215 |
+ /*
|
|
1216 |
+ * Note that multiple attempts to speed up the function below
|
|
1177 | 1217 |
* with SSE2 intrinsics, using various data layouts, have turned
|
1178 | 1218 |
* out to be slower than the non-SIMD code below.
|
1179 | 1219 |
*/
|
... | ... | @@ -1264,12 +1304,14 @@ typedef ptrdiff_t FT_PtrDist; |
1264 | 1304 |
|
1265 | 1305 |
#endif /* !BEZIER_USE_DDA */
|
1266 | 1306 |
|
1267 |
- /* For cubic bezier, binary splits are still faster than DDA
|
|
1307 |
+ |
|
1308 |
+ /*
|
|
1309 |
+ * For cubic Bézier, binary splits are still faster than DDA
|
|
1268 | 1310 |
* because the splits are adaptive to how quickly each sub-arc
|
1269 | 1311 |
* approaches their chord trisection points.
|
1270 | 1312 |
*
|
1271 | 1313 |
* It might be useful to experiment with SSE2 to speed up
|
1272 |
- * gray_split_cubic() though.
|
|
1314 |
+ * `gray_split_cubic`, though.
|
|
1273 | 1315 |
*/
|
1274 | 1316 |
static void
|
1275 | 1317 |
gray_split_cubic( FT_Vector* base )
|
... | ... | @@ -1361,6 +1403,7 @@ typedef ptrdiff_t FT_PtrDist; |
1361 | 1403 |
}
|
1362 | 1404 |
}
|
1363 | 1405 |
|
1406 |
+ |
|
1364 | 1407 |
static int
|
1365 | 1408 |
gray_move_to( const FT_Vector* to,
|
1366 | 1409 |
gray_PWorker worker )
|
... | ... | @@ -1428,7 +1471,7 @@ typedef ptrdiff_t FT_PtrDist; |
1428 | 1471 |
unsigned char* line = ras.target.origin - ras.target.pitch * y;
|
1429 | 1472 |
|
1430 | 1473 |
|
1431 |
- for ( ; !CELL_IS_NULL(cell); cell = cell->next )
|
|
1474 |
+ for ( ; !CELL_IS_NULL( cell ); cell = cell->next )
|
|
1432 | 1475 |
{
|
1433 | 1476 |
if ( cover != 0 && cell->x > x )
|
1434 | 1477 |
{
|
... | ... | @@ -1476,7 +1519,7 @@ typedef ptrdiff_t FT_PtrDist; |
1476 | 1519 |
TArea area;
|
1477 | 1520 |
|
1478 | 1521 |
|
1479 |
- for ( ; !CELL_IS_NULL(cell); cell = cell->next )
|
|
1522 |
+ for ( ; !CELL_IS_NULL( cell ); cell = cell->next )
|
|
1480 | 1523 |
{
|
1481 | 1524 |
if ( cover != 0 && cell->x > x )
|
1482 | 1525 |
{
|
... | ... | @@ -1856,7 +1899,7 @@ typedef ptrdiff_t FT_PtrDist; |
1856 | 1899 |
FT_TRACE7(( "band [%d..%d]: %ld cell%s\n",
|
1857 | 1900 |
ras.min_ey,
|
1858 | 1901 |
ras.max_ey,
|
1859 |
- ras.cell_free - ras.cells.,
|
|
1902 |
+ ras.cell_free - ras.cells,
|
|
1860 | 1903 |
ras.cell_free - ras.cells == 1 ? "" : "s" ));
|
1861 | 1904 |
}
|
1862 | 1905 |
else
|
... | ... | @@ -1898,19 +1941,19 @@ typedef ptrdiff_t FT_PtrDist; |
1898 | 1941 |
/* memory management */
|
1899 | 1942 |
n = ( height * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) / sizeof ( TCell );
|
1900 | 1943 |
|
1901 |
- ras.cells = buffer + n;
|
|
1902 |
- ras.max_cells = (FT_PtrDist)( FT_MAX_GRAY_POOL - n );
|
|
1944 |
+ ras.cells = buffer + n;
|
|
1945 |
+ ras.max_cells = (FT_PtrDist)( FT_MAX_GRAY_POOL - n );
|
|
1903 | 1946 |
ras.cell_limit = ras.cells + ras.max_cells;
|
1904 |
- ras.ycells = (PCell*)buffer;
|
|
1947 |
+ ras.ycells = (PCell*)buffer;
|
|
1905 | 1948 |
|
1906 |
- /* Initialize the null cell is at the start of the 'cells' array. */
|
|
1907 |
- /* Note that this requires ras.cell_free initialization to skip */
|
|
1908 |
- /* over the first entry in the array. */
|
|
1909 |
- PCell null_cell = NULL_CELL_PTR(ras);
|
|
1910 |
- null_cell->x = CELL_MAX_X_VALUE;
|
|
1911 |
- null_cell->area = 0;
|
|
1912 |
- null_cell->cover = 0;
|
|
1913 |
- null_cell->next = NULL;;
|
|
1949 |
+ /* Initialize the null cell at the start of the `cells` array. */
|
|
1950 |
+ /* Note that this requires `ras.cell_free` initialization to skip */
|
|
1951 |
+ /* over the first entry in the array. */
|
|
1952 |
+ PCell null_cell = NULL_CELL_PTR( ras );
|
|
1953 |
+ null_cell->x = CELL_MAX_X_VALUE;
|
|
1954 |
+ null_cell->area = 0;
|
|
1955 |
+ null_cell->cover = 0;
|
|
1956 |
+ null_cell->next = NULL;;
|
|
1914 | 1957 |
|
1915 | 1958 |
for ( y = yMin; y < yMax; )
|
1916 | 1959 |
{
|
... | ... | @@ -1928,7 +1971,8 @@ typedef ptrdiff_t FT_PtrDist; |
1928 | 1971 |
TCoord w;
|
1929 | 1972 |
int error;
|
1930 | 1973 |
|
1931 |
- for (w = 0; w < width; ++w)
|
|
1974 |
+ |
|
1975 |
+ for ( w = 0; w < width; ++w )
|
|
1932 | 1976 |
ras.ycells[w] = null_cell;
|
1933 | 1977 |
|
1934 | 1978 |
ras.cell_free = ras.cells + 1; /* NOTE: Skip over the null cell. */
|
1 | 1 |
#!/usr/bin/env python3
|
2 | 2 |
|
3 |
-"""Download test fonts used by the FreeType regression test programs.
|
|
4 |
-These will be copied to $FREETYPE/tests/data/ by default.
|
|
5 |
-"""
|
|
3 |
+"""Download test fonts used by the FreeType regression test programs. These
|
|
4 |
+will be copied to $FREETYPE/tests/data/ by default."""
|
|
6 | 5 |
|
7 | 6 |
import argparse
|
8 | 7 |
import collections
|
... | ... | @@ -15,8 +14,8 @@ import zipfile |
15 | 14 |
|
16 | 15 |
from typing import Callable, List, Optional, Tuple
|
17 | 16 |
|
18 |
-# The list of download items describing the font files to install.
|
|
19 |
-# Each download item is a dictionary with one of the following schemas:
|
|
17 |
+# The list of download items describing the font files to install. Each
|
|
18 |
+# download item is a dictionary with one of the following schemas:
|
|
20 | 19 |
#
|
21 | 20 |
# - File item:
|
22 | 21 |
#
|
... | ... | @@ -28,8 +27,8 @@ from typing import Callable, List, Optional, Tuple |
28 | 27 |
# install_name
|
29 | 28 |
# Type: file name string
|
30 | 29 |
# Required: No
|
31 |
-# Description: Installation name for the font file, only provided if it
|
|
32 |
-# must be different from the original URL's basename.
|
|
30 |
+# Description: Installation name for the font file, only provided if
|
|
31 |
+# it must be different from the original URL's basename.
|
|
33 | 32 |
#
|
34 | 33 |
# hex_digest
|
35 | 34 |
# Type: hexadecimal string
|
... | ... | @@ -39,7 +38,7 @@ from typing import Callable, List, Optional, Tuple |
39 | 38 |
# - Zip items:
|
40 | 39 |
#
|
41 | 40 |
# These items correspond to one or more font files that are embedded in a
|
42 |
-# remote zip archive. Each entry has the following fields:
|
|
41 |
+# remote zip archive. Each entry has the following fields:
|
|
43 | 42 |
#
|
44 | 43 |
# zip_url
|
45 | 44 |
# Type: URL string.
|
... | ... | @@ -52,23 +51,25 @@ from typing import Callable, List, Optional, Tuple |
52 | 51 |
# Description: A list of entries describing a single font file to be
|
53 | 52 |
# extracted from the archive
|
54 | 53 |
#
|
55 |
-# Apart from that, some schemas are used for dictionaries used inside download
|
|
56 |
-# items:
|
|
54 |
+# Apart from that, some schemas are used for dictionaries used inside
|
|
55 |
+# download items:
|
|
57 | 56 |
#
|
58 | 57 |
# - File entries:
|
59 | 58 |
#
|
60 |
-# These are dictionaries describing a single font file to extract from an archive.
|
|
59 |
+# These are dictionaries describing a single font file to extract from an
|
|
60 |
+# archive.
|
|
61 | 61 |
#
|
62 | 62 |
# filename
|
63 | 63 |
# Type: file path string
|
64 | 64 |
# Required: Yes
|
65 |
-# Description: Path of source file, relative to the archive's top-level directory.
|
|
65 |
+# Description: Path of source file, relative to the archive's
|
|
66 |
+# top-level directory.
|
|
66 | 67 |
#
|
67 | 68 |
# install_name
|
68 | 69 |
# Type: file name string
|
69 | 70 |
# Required: No
|
70 |
-# Description: Installation name for the font file, only provided if it must be
|
|
71 |
-# different from the original filename value.
|
|
71 |
+# Description: Installation name for the font file; only provided if
|
|
72 |
+# it must be different from the original filename value.
|
|
72 | 73 |
#
|
73 | 74 |
# hex_digest
|
74 | 75 |
# Type: hexadecimal string
|
... | ... | @@ -90,7 +91,8 @@ _DOWNLOAD_ITEMS = [ |
90 | 91 |
|
91 | 92 |
|
92 | 93 |
def digest_data(data: bytes):
|
93 |
- """Compute the digest of a given input byte string, which are the first 8 bytes of its sha256 hash."""
|
|
94 |
+ """Compute the digest of a given input byte string, which are the first
|
|
95 |
+ 8 bytes of its sha256 hash."""
|
|
94 | 96 |
m = hashlib.sha256()
|
95 | 97 |
m.update(data)
|
96 | 98 |
return m.digest()[:8]
|
... | ... | @@ -155,14 +157,16 @@ def extract_file_from_zip_archive( |
155 | 157 |
|
156 | 158 |
Args:
|
157 | 159 |
archive: Input ZipFile objec.
|
158 |
- archive_name: Archive name or URL, only used to generate a human-readable error
|
|
159 |
- message.
|
|
160 |
+ archive_name: Archive name or URL, only used to generate a
|
|
161 |
+ human-readable error message.
|
|
162 |
+ |
|
160 | 163 |
filepath: Input filepath in archive.
|
161 | 164 |
expected_digest: Optional digest for the file.
|
162 | 165 |
Returns:
|
163 | 166 |
A new File instance corresponding to the extract file.
|
164 | 167 |
Raises:
|
165 |
- ValueError if expected_digest is not None and does not match the extracted file.
|
|
168 |
+ ValueError if expected_digest is not None and does not match the
|
|
169 |
+ extracted file.
|
|
166 | 170 |
"""
|
167 | 171 |
file = archive.open(filepath)
|
168 | 172 |
if expected_digest is not None:
|
... | ... | @@ -181,7 +185,8 @@ def _get_and_install_file( |
181 | 185 |
force_download: bool,
|
182 | 186 |
get_content: Callable[[], bytes],
|
183 | 187 |
) -> bool:
|
184 |
- if not force_download and hex_digest is not None and os.path.exists(install_path):
|
|
188 |
+ if not force_download and hex_digest is not None \
|
|
189 |
+ and os.path.exists(install_path):
|
|
185 | 190 |
with open(install_path, "rb") as f:
|
186 | 191 |
content: bytes = f.read()
|
187 | 192 |
if bytes.fromhex(hex_digest) == digest_data(content):
|
... | ... | @@ -200,14 +205,15 @@ def download_and_install_item( |
200 | 205 |
Args:
|
201 | 206 |
item: Download item as a dictionary, see above for schema.
|
202 | 207 |
install_dir: Installation directory.
|
203 |
- force_download: Set to True to force download and installation, even if
|
|
204 |
- the font file is already installed with the right content.
|
|
208 |
+ force_download: Set to True to force download and installation, even
|
|
209 |
+ if the font file is already installed with the right content.
|
|
205 | 210 |
|
206 | 211 |
Returns:
|
207 |
- A list of (install_name, status) tuples, where 'install_name' is the file's
|
|
208 |
- installation name under 'install_dir', and 'status' is a boolean that is True
|
|
209 |
- to indicate that the file was downloaded and installed, or False to indicate that
|
|
210 |
- the file is already installed with the right content.
|
|
212 |
+ A list of (install_name, status) tuples, where 'install_name' is the
|
|
213 |
+ file's installation name under 'install_dir', and 'status' is a
|
|
214 |
+ boolean that is True to indicate that the file was downloaded and
|
|
215 |
+ installed, or False to indicate that the file is already installed
|
|
216 |
+ with the right content.
|
|
211 | 217 |
"""
|
212 | 218 |
if "file_url" in item:
|
213 | 219 |
file_url = item["file_url"]
|
... | ... | @@ -284,10 +290,13 @@ def main(): |
284 | 290 |
for install_name, status in download_and_install_item(
|
285 | 291 |
item, args.install_dir, args.force
|
286 | 292 |
):
|
287 |
- print("%s %s" % (install_name, "INSTALLED" if status else "UP-TO-DATE"))
|
|
293 |
+ print("%s %s" % (install_name,
|
|
294 |
+ "INSTALLED" if status else "UP-TO-DATE"))
|
|
288 | 295 |
|
289 | 296 |
return 0
|
290 | 297 |
|
291 | 298 |
|
292 | 299 |
if __name__ == "__main__":
|
293 | 300 |
sys.exit(main())
|
301 |
+ |
|
302 |
+# EOF
|