David Turner pushed to branch split-conic-dda at FreeType / FreeType
Commits:
-
205d1ae4
by Werner Lemberg at 2021-07-12T22:03:25+02:00
-
825b7ea2
by Werner Lemberg at 2021-07-12T22:11:24+02:00
-
c5516e0f
by Alex Richardson at 2021-07-12T22:23:42+02:00
-
e592982a
by Anuj Verma at 2021-07-13T10:00:22+02:00
-
a4c8f21a
by Oleg Oshmyan at 2021-07-13T10:44:38+02:00
-
5d27b10f
by Oleg Oshmyan at 2021-07-13T11:00:48+02:00
-
7f0cb0cb
by David Turner at 2021-07-15T12:01:09+02:00
-
da116fc4
by David Turner at 2021-07-15T12:01:55+02:00
15 changed files:
- ChangeLog
- devel/ftoption.h
- docs/CHANGES
- include/freetype/config/ftoption.h
- include/freetype/freetype.h
- include/freetype/ftdriver.h
- include/freetype/ftmodapi.h
- include/freetype/internal/fttrace.h
- meson.build
- src/autofit/afhints.c
- src/autofit/afhints.h
- src/autofit/afloader.c
- src/base/ftobjs.c
- src/sdf/ftsdf.c
- src/smooth/ftgrays.c
Changes:
1 |
+2021-07-13 David Turner <david@freetype.org>
|
|
2 |
+ |
|
3 |
+ [smooth] Implement Bezier quadratic arc flattenning with DDA
|
|
4 |
+ |
|
5 |
+ Benchmarking shows that this provides a very slighty performance
|
|
6 |
+ boost when rendering fonts with lots of quadratic bezier arcs,
|
|
7 |
+ compared to the recursive arc splitting, but only when SSE2 is
|
|
8 |
+ available, or on 64-bit CPUs.
|
|
9 |
+ |
|
10 |
+ * src/smooth/ftgrays.c (gray_render_conic): New implementation
|
|
11 |
+ based on DDA and optionally SSE2.
|
|
12 |
+ |
|
13 |
+2021-07-13 David Turner <david@freetype.org>
|
|
14 |
+ |
|
15 |
+ [smooth] Minor speedup to smooth rasterizer
|
|
16 |
+ |
|
17 |
+ This speeds up the smooth rasterizer by avoiding a conditional
|
|
18 |
+ branches in the hot path.
|
|
19 |
+ |
|
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.
|
|
24 |
+ |
|
25 |
+2021-07-13 Oleg Oshmyan <chortos@inbox.lv>
|
|
26 |
+ |
|
27 |
+ [base] Fix `FT_Open_Face`'s handling of user-supplied streams.
|
|
28 |
+ |
|
29 |
+ This was already true (though undocumented) most of the time, but
|
|
30 |
+ not if `FT_NEW` inside `FT_Stream_New` failed or if the
|
|
31 |
+ `FT_OPEN_XXX` flags were bad.
|
|
32 |
+ |
|
33 |
+ Normally, `FT_Open_Face` calls `FT_Stream_New`, which returns the
|
|
34 |
+ user-supplied stream unchanged, and in case of any subsequent error
|
|
35 |
+ in `FT_Open_Face`, the stream is closed via `FT_Stream_Free`.
|
|
36 |
+ |
|
37 |
+ Up to now, however, `FT_Stream_New` allocates a new stream even if
|
|
38 |
+ it is already given one by the user. If this allocation fails, the
|
|
39 |
+ user-supplied stream is not returned to `FT_Open_Face` and never
|
|
40 |
+ closed. Moreover, the user cannot detect this situation: all they
|
|
41 |
+ see is that `FT_Open_Face` returns `FT_Err_Out_Of_Memory`, but that
|
|
42 |
+ can also happen after a different allocation fails within the main
|
|
43 |
+ body of `FT_Open_Face`, when the user's stream has already been
|
|
44 |
+ closed by `FT_Open_Face`. It is plausible that the user stream's
|
|
45 |
+ `close` method frees memory allocated for the stream object itself,
|
|
46 |
+ so the user cannot defensively free it upon `FT_Open_Face` failure
|
|
47 |
+ lest it ends up doubly freed. All in all, this ends up leaking the
|
|
48 |
+ memory/resources used by user's stream.
|
|
49 |
+ |
|
50 |
+ Furthermore, `FT_Stream_New` simply returns an error if the
|
|
51 |
+ `FT_OPEN_XXX` flags are unsupported, which can mean either an
|
|
52 |
+ invalid combination of flags or a perfectly innocent
|
|
53 |
+ `FT_OPEN_STREAM` on a FreeType build that lacks stream support.
|
|
54 |
+ With this patch, the user-supplied stream is closed even in these
|
|
55 |
+ cases, so the user can be sure that if `FT_Open_Face` failed, the
|
|
56 |
+ stream is definitely closed.
|
|
57 |
+ |
|
58 |
+ * src/base/ftobjs.c (FT_Stream_New): Don't allocate a buffer
|
|
59 |
+ unnecessarily.
|
|
60 |
+ Move error-handling code to make the control flow more obvious.
|
|
61 |
+ Close user-supplied stream if the flags are unsupported.
|
|
62 |
+ `FT_Stream_Open` always sets `pathname.pointer`, so remove the
|
|
63 |
+ redundant (re)assignment. None of the `FT_Stream_Open...` functions
|
|
64 |
+ uses `stream->memory`, so keep just one assignment at the end,
|
|
65 |
+ shared among all possible control flow paths.
|
|
66 |
+ ('Unsupported flags' that may need a stream closure can be either an
|
|
67 |
+ invalid combination of multiple `FT_OPEN_XXX` mode flags or a clean
|
|
68 |
+ `FT_OPEN_STREAM` flag on a FreeType build that lacks stream
|
|
69 |
+ support.)
|
|
70 |
+ |
|
71 |
+2021-07-13 Oleg Oshmyan <chortos@inbox.lv>
|
|
72 |
+ |
|
73 |
+ [base] Reject combinations of incompatible `FT_OPEN_XXX` flags.
|
|
74 |
+ |
|
75 |
+ The three modes are mutually exclusive, and the documentation of the
|
|
76 |
+ `FT_OPEN_XXX` constants notes this. However, there was no check to
|
|
77 |
+ validate this in the code, and the documentation on `FT_Open_Args`
|
|
78 |
+ claimed that the corresponding bits were checked in a well-defined
|
|
79 |
+ order, implying it was valid (if useless) to specify more than one.
|
|
80 |
+ Ironically, this documented order did not agree with the actual
|
|
81 |
+ code, so it could not be relied upon; hopefully, nobody did this and
|
|
82 |
+ nobody will be hurt by the new validation.
|
|
83 |
+ |
|
84 |
+ Even if multiple mode bits were allowed, they could cause memory
|
|
85 |
+ leaks: if both `FT_OPEN_STREAM` and `stream` are set along with
|
|
86 |
+ either `FT_OPEN_MEMORY` or `FT_OPEN_PATHNAME`, then `FT_Stream_New`
|
|
87 |
+ allocated a new stream but `FT_Open_Face` marked it as an 'external'
|
|
88 |
+ stream, so the stream object was never released.
|
|
89 |
+ |
|
90 |
+ * src/base/ftobjs.c (FT_Stream_New): Reject incompatible
|
|
91 |
+ `FT_OPEN_XXX` flags.
|
|
92 |
+ |
|
93 |
+2021-07-12 Alex Richardson <Alexander.Richardson@cl.cam.ac.uk>
|
|
94 |
+ |
|
95 |
+ * meson.build: Fix build for other UNIX systems (e.g., FreeBSD).
|
|
96 |
+ |
|
97 |
+ Without this change the build of `unix/ftsystem.c` fails because the
|
|
98 |
+ `ftconfig.h` header that defines macros such as `HAVE_UNISTD_H` and
|
|
99 |
+ `HAVE_FCNTL_H` is only being generated for Linux, macOS, and Cygwin
|
|
100 |
+ systems:
|
|
101 |
+ |
|
102 |
+ ```
|
|
103 |
+ .../builds/unix/ftsystem.c:258:32: error:
|
|
104 |
+ use of undeclared identifier 'O_RDONLY'
|
|
105 |
+ file = open( filepathname, O_RDONLY );
|
|
106 |
+ ```
|
|
107 |
+ |
|
108 |
+ Instead of hardcoding a list of operating systems for this check,
|
|
109 |
+ update the logic that decides whether to build the file and set a
|
|
110 |
+ boolean flag that can be checked instead.
|
|
111 |
+ |
|
112 |
+2021-07-12 Werner Lemberg <wl@gnu.org>
|
|
113 |
+ |
|
114 |
+ [autofit] More clean-ups.
|
|
115 |
+ |
|
116 |
+ * src/autofit/afhints.h (AF_GlyphHintsRec): Remove the no longer
|
|
117 |
+ needed fields `xmin_delta` and `xmax_delta`.
|
|
118 |
+ |
|
119 |
+ * src/autofit/afhints.c (af_glyph_hints_reload),
|
|
120 |
+ src/autofit/afloader.c (af_loader_load_glyph): Updated.
|
|
121 |
+ |
|
122 |
+2021-07-12 Werner Lemberg <wl@gnu.org>
|
|
123 |
+ |
|
124 |
+ Small clean-ups for the last few commits.
|
|
125 |
+ |
|
126 |
+ * include/freetype/fttrace.h (afwarp): Removed.
|
|
127 |
+ |
|
1 | 128 |
2021-07-12 David Turner <david@freetype.org>
|
2 | 129 |
|
3 |
- Remove obsolete AF_Angle type and related sources.
|
|
130 |
+ Remove obsolete `AF_Angle` type and related sources.
|
|
4 | 131 |
|
5 |
- Move the af_sort_xxx() functions from afangles.c to afhints.c in
|
|
6 |
- order to get rid of the obsolete angle-related types, macros and
|
|
7 |
- function definitions.
|
|
132 |
+ * src/autofit/afangles.c: File removed. Functions related to
|
|
133 |
+ sorting moved to...
|
|
134 |
+ * src/autofit/afhints.c (af_sort_pos, af_sort_and_quantize_widths):
|
|
135 |
+ This file.
|
|
136 |
+ * src/autofit/afangles.h: File removed.
|
|
137 |
+ * src/autofit/aftypes.h: Updated.
|
|
138 |
+ * src/autofit/autofit.c: Updated.
|
|
8 | 139 |
|
9 |
- * src/autofit/*: Remove code.
|
|
140 |
+ * src/autofit/rules.mk (AUTOF_DRV_SRC): Updated.
|
|
10 | 141 |
|
11 | 142 |
2021-07-12 David Turner <david@freetype.org>
|
12 | 143 |
|
13 | 144 |
Remove experimental auto-hinting 'warp' mode.
|
14 | 145 |
|
15 |
- This feature was always experimental, and probably nevery worked
|
|
16 |
- properly. This patch completely removes it from the source code,
|
|
146 |
+ This feature was always experimental, and probably never worked
|
|
147 |
+ properly. This patch completely removes it from the source code,
|
|
17 | 148 |
except for a documentation block describing it for historical
|
18 |
- purpose.
|
|
149 |
+ purposes.
|
|
150 |
+ |
|
151 |
+ * devel/ftoption.h, include/freetype/config/ftoption.h: Remove
|
|
152 |
+ `AF_CONFIG_OPTION_USE_WARPER`.
|
|
153 |
+ |
|
154 |
+ * include/freetype/ftdriver.h: Document 'warping' property as
|
|
155 |
+ obsolete.
|
|
19 | 156 |
|
20 |
- * devel/ftoption.h: Remove AF_CONFIG_OPTION_USE_WARPER.
|
|
21 |
- * include/freetype/config/ftoption.h: Remove AF_CONFIG_OPTION_USE_WARPER.
|
|
22 |
- * include/freetype/ftdriver.h: Document 'warping' property as obsolete.
|
|
23 |
- * src/autofit/*: Remove any warp mode related code.
|
|
157 |
+ * src/autofit/afwarp.c, src/autofit/afwarp.h: Files removed.
|
|
158 |
+ * src/autofit/*: Remove any code related to warp mode.
|
|
24 | 159 |
|
25 | 160 |
2021-07-12 David Turner <david@freetype.org>
|
26 | 161 |
|
27 |
- Remove experimental "Latin2" writing system (FT_OPTION_AUTOFIT2)
|
|
162 |
+ Remove experimental 'Latin2' writing system (`FT_OPTION_AUTOFIT2`).
|
|
28 | 163 |
|
29 | 164 |
This code has always been experimental and was never compiled anyway
|
30 |
- (FT_OPTION_AUTOFIT2 does not appear in ftoption.h or even any of our
|
|
31 |
- build files).
|
|
32 |
- |
|
33 |
- * include/freetype/internal/fttrace.h: Remove 'FT_TRACE_DEF( aflatin2 )'.
|
|
34 |
- * src/autofit/aflatin2.[hc]: Removed.
|
|
35 |
- * src/autofit/afloader.c: Remove undocumented hook to activate Latin2 system.
|
|
36 |
- * src/autofit/afstyles.h: Remove ltn2_dflt style definition.
|
|
37 |
- * src/autofit/afwrtsys.h: Remove LATIN2 writing system definition.
|
|
165 |
+ (`FT_OPTION_AUTOFIT2` does not appear in `ftoption.h` or even any of
|
|
166 |
+ our build files).
|
|
167 |
+ |
|
168 |
+ * include/freetype/internal/fttrace.h (aflatin2): Removed.
|
|
169 |
+ * src/autofit/aflatin2.h, src/autofit/aflatin2.c: Files removed.
|
|
170 |
+ * src/autofit/afloader.c: Remove undocumented hook to activate
|
|
171 |
+ Latin2 system.
|
|
172 |
+ * src/autofit/afstyles.h: Remove `ltn2_dflt` style definition.
|
|
173 |
+ * src/autofit/afwrtsys.h: Remove `LATIN2` writing system definition.
|
|
38 | 174 |
* src/autofit/autofit.c: Updated.
|
39 | 175 |
|
40 | 176 |
2021-07-05 Werner Lemberg <wl@gnu.org>
|
... | ... | @@ -105,8 +105,7 @@ FT_BEGIN_HEADER |
105 | 105 |
*
|
106 | 106 |
* ```
|
107 | 107 |
* FREETYPE_PROPERTIES=truetype:interpreter-version=35 \
|
108 |
- * cff:no-stem-darkening=1 \
|
|
109 |
- * autofitter:warping=1
|
|
108 |
+ * cff:no-stem-darkening=1
|
|
110 | 109 |
* ```
|
111 | 110 |
*
|
112 | 111 |
*/
|
... | ... | @@ -72,6 +72,9 @@ CHANGES BETWEEN 2.10.4 and 2.11.0 |
72 | 72 |
|
73 | 73 |
This work was Priyesh Kumar's GSoC 2020 project.
|
74 | 74 |
|
75 |
+ - The experimental 'warp' mode (AF_CONFIG_OPTION_USE_WARPER) for the
|
|
76 |
+ auto-hinter has been removed.
|
|
77 |
+ |
|
75 | 78 |
- The smooth rasterizer performance has been improved by >10%.
|
76 | 79 |
|
77 | 80 |
- PCF bitmap fonts compressed with LZW (these are usually files with
|
... | ... | @@ -105,8 +105,7 @@ FT_BEGIN_HEADER |
105 | 105 |
*
|
106 | 106 |
* ```
|
107 | 107 |
* FREETYPE_PROPERTIES=truetype:interpreter-version=35 \
|
108 |
- * cff:no-stem-darkening=1 \
|
|
109 |
- * autofitter:warping=1
|
|
108 |
+ * cff:no-stem-darkening=1
|
|
110 | 109 |
* ```
|
111 | 110 |
*
|
112 | 111 |
*/
|
... | ... | @@ -2113,8 +2113,7 @@ FT_BEGIN_HEADER |
2113 | 2113 |
* Extra parameters passed to the font driver when opening a new face.
|
2114 | 2114 |
*
|
2115 | 2115 |
* @note:
|
2116 |
- * The stream type is determined by the contents of `flags` that are
|
|
2117 |
- * tested in the following order by @FT_Open_Face:
|
|
2116 |
+ * The stream type is determined by the contents of `flags`:
|
|
2118 | 2117 |
*
|
2119 | 2118 |
* If the @FT_OPEN_MEMORY bit is set, assume that this is a memory file
|
2120 | 2119 |
* of `memory_size` bytes, located at `memory_address`. The data are not
|
... | ... | @@ -2127,6 +2126,9 @@ FT_BEGIN_HEADER |
2127 | 2126 |
* Otherwise, if the @FT_OPEN_PATHNAME bit is set, assume that this is a
|
2128 | 2127 |
* normal file and use `pathname` to open it.
|
2129 | 2128 |
*
|
2129 |
+ * If none of the above bits are set or if multiple are set at the same
|
|
2130 |
+ * time, the flags are invalid and @FT_Open_Face fails.
|
|
2131 |
+ *
|
|
2130 | 2132 |
* If the @FT_OPEN_DRIVER bit is set, @FT_Open_Face only tries to open
|
2131 | 2133 |
* the file with the driver whose handler is in `driver`.
|
2132 | 2134 |
*
|
... | ... | @@ -2299,6 +2301,10 @@ FT_BEGIN_HEADER |
2299 | 2301 |
* See the discussion of reference counters in the description of
|
2300 | 2302 |
* @FT_Reference_Face.
|
2301 | 2303 |
*
|
2304 |
+ * If `FT_OPEN_STREAM` is set in `args->flags`, the stream in
|
|
2305 |
+ * `args->stream` is automatically closed before this function returns
|
|
2306 |
+ * any error (including `FT_Err_Invalid_Argument`).
|
|
2307 |
+ *
|
|
2302 | 2308 |
* @example:
|
2303 | 2309 |
* To loop over all faces, use code similar to the following snippet
|
2304 | 2310 |
* (omitting the error handling).
|
... | ... | @@ -3307,13 +3313,13 @@ FT_BEGIN_HEADER |
3307 | 3313 |
* pixels and use the @FT_PIXEL_MODE_LCD_V mode.
|
3308 | 3314 |
*
|
3309 | 3315 |
* FT_RENDER_MODE_SDF ::
|
3310 |
- * This mode corresponds to 8-bit signed distance fields (SDF)
|
|
3311 |
- * bitmaps. Each pixel in a SDF bitmap contains information about the
|
|
3312 |
- * nearest edge of the glyph outline. The distances are calculated
|
|
3313 |
- * from the center of the pixel and are positive if they are filled by
|
|
3314 |
- * the outline (i.e., inside the outline) and negative otherwise.
|
|
3315 |
- * Check the note below on how to convert the output values to usable
|
|
3316 |
- * data.
|
|
3316 |
+ * This mode corresponds to 8-bit, single-channel signed distance field
|
|
3317 |
+ * (SDF) bitmaps. Each pixel in the SDF grid is the value from the
|
|
3318 |
+ * pixel's position to the nearest glyph's outline. The distances are
|
|
3319 |
+ * calculated from the center of the pixel and are positive if they are
|
|
3320 |
+ * filled by the outline (i.e., inside the outline) and negative
|
|
3321 |
+ * otherwise. Check the note below on how to convert the output values
|
|
3322 |
+ * to usable data.
|
|
3317 | 3323 |
*
|
3318 | 3324 |
* @note:
|
3319 | 3325 |
* The selected render mode only affects vector glyphs of a font.
|
... | ... | @@ -53,10 +53,10 @@ FT_BEGIN_HEADER |
53 | 53 |
* reasons.
|
54 | 54 |
*
|
55 | 55 |
* Available properties are @increase-x-height, @no-stem-darkening
|
56 |
- * (experimental), @darkening-parameters (experimental), @warping
|
|
57 |
- * (experimental), @glyph-to-script-map (experimental), @fallback-script
|
|
58 |
- * (experimental), and @default-script (experimental), as documented in
|
|
59 |
- * the @properties section.
|
|
56 |
+ * (experimental), @darkening-parameters (experimental),
|
|
57 |
+ * @glyph-to-script-map (experimental), @fallback-script (experimental),
|
|
58 |
+ * and @default-script (experimental), as documented in the @properties
|
|
59 |
+ * section.
|
|
60 | 60 |
*
|
61 | 61 |
*/
|
62 | 62 |
|
... | ... | @@ -1165,15 +1165,15 @@ FT_BEGIN_HEADER |
1165 | 1165 |
* **Obsolete**
|
1166 | 1166 |
*
|
1167 | 1167 |
* This property was always experimental and probably never worked
|
1168 |
- * correctly. It was entirely removed from the FreeType 2 sources.
|
|
1169 |
- * This entry is only here for historical reference.
|
|
1168 |
+ * correctly. It was entirely removed from the FreeType~2 sources. This
|
|
1169 |
+ * entry is only here for historical reference.
|
|
1170 | 1170 |
*
|
1171 |
- * Warping only works in 'normal' auto-hinting mode replacing it. The
|
|
1172 |
- * idea of the code is to slightly scale and shift a glyph along the
|
|
1171 |
+ * Warping only worked in 'normal' auto-hinting mode replacing it. The
|
|
1172 |
+ * idea of the code was to slightly scale and shift a glyph along the
|
|
1173 | 1173 |
* non-hinted dimension (which is usually the horizontal axis) so that as
|
1174 |
- * much of its segments are aligned (more or less) to the grid. To find
|
|
1174 |
+ * much of its segments were aligned (more or less) to the grid. To find
|
|
1175 | 1175 |
* out a glyph's optimal scaling and shifting value, various parameter
|
1176 |
- * combinations are tried and scored.
|
|
1176 |
+ * combinations were tried and scored.
|
|
1177 | 1177 |
*
|
1178 | 1178 |
* @since:
|
1179 | 1179 |
* 2.6
|
... | ... | @@ -508,8 +508,7 @@ FT_BEGIN_HEADER |
508 | 508 |
*
|
509 | 509 |
* ```
|
510 | 510 |
* FREETYPE_PROPERTIES=truetype:interpreter-version=35 \
|
511 |
- * cff:no-stem-darkening=0 \
|
|
512 |
- * autofitter:warping=1
|
|
511 |
+ * cff:no-stem-darkening=0
|
|
513 | 512 |
* ```
|
514 | 513 |
*
|
515 | 514 |
* @inout:
|
... | ... | @@ -160,7 +160,6 @@ FT_TRACE_DEF( afhints ) |
160 | 160 |
FT_TRACE_DEF( afmodule )
|
161 | 161 |
FT_TRACE_DEF( aflatin )
|
162 | 162 |
FT_TRACE_DEF( afshaper )
|
163 |
-FT_TRACE_DEF( afwarp )
|
|
164 | 163 |
|
165 | 164 |
/* SDF components */
|
166 | 165 |
FT_TRACE_DEF( sdf ) /* signed distance raster for outlines (ftsdf.c) */
|
... | ... | @@ -193,6 +193,7 @@ has_sys_mman_h = cc.has_header('sys/mman.h') |
193 | 193 |
|
194 | 194 |
mmap_option = get_option('mmap')
|
195 | 195 |
|
196 |
+use_unix_ftsystem_c = false
|
|
196 | 197 |
if mmap_option.disabled()
|
197 | 198 |
ft2_sources += files(['src/base/ftsystem.c',])
|
198 | 199 |
elif host_machine.system() == 'windows'
|
... | ... | @@ -201,6 +202,7 @@ else |
201 | 202 |
if has_unistd_h and has_fcntl_h and has_sys_mman_h
|
202 | 203 |
# This version of `ftsystem.c` uses `mmap` to read input font files.
|
203 | 204 |
ft2_sources += files(['builds/unix/ftsystem.c',])
|
205 |
+ use_unix_ftsystem_c = true
|
|
204 | 206 |
elif mmap_option.enabled()
|
205 | 207 |
error('mmap was enabled via options but is not available,'
|
206 | 208 |
+ ' required headers were not found!')
|
... | ... | @@ -321,7 +323,7 @@ if has_fcntl_h |
321 | 323 |
ftconfig_command += '--enable=HAVE_FCNTL_H'
|
322 | 324 |
endif
|
323 | 325 |
|
324 |
-if host_machine.system() in ['linux', 'darwin', 'cygwin']
|
|
326 |
+if use_unix_ftsystem_c
|
|
325 | 327 |
ftconfig_h_in = files('builds/unix/ftconfig.h.in')
|
326 | 328 |
ftconfig_h = custom_target('ftconfig.h',
|
327 | 329 |
input: ftconfig_h_in,
|
... | ... | @@ -953,9 +953,6 @@ |
953 | 953 |
hints->x_delta = x_delta;
|
954 | 954 |
hints->y_delta = y_delta;
|
955 | 955 |
|
956 |
- hints->xmin_delta = 0;
|
|
957 |
- hints->xmax_delta = 0;
|
|
958 |
- |
|
959 | 956 |
points = hints->points;
|
960 | 957 |
if ( hints->num_points == 0 )
|
961 | 958 |
goto Exit;
|
... | ... | @@ -362,9 +362,6 @@ FT_BEGIN_HEADER |
362 | 362 |
/* implementations */
|
363 | 363 |
AF_StyleMetrics metrics;
|
364 | 364 |
|
365 |
- FT_Pos xmin_delta; /* used for warping */
|
|
366 |
- FT_Pos xmax_delta;
|
|
367 |
- |
|
368 | 365 |
/* Two arrays to avoid allocation penalty. */
|
369 | 366 |
/* The `embedded' structure must be the last element! */
|
370 | 367 |
struct
|
... | ... | @@ -473,8 +473,8 @@ |
473 | 473 |
FT_Pos pp2x = loader->pp2.x;
|
474 | 474 |
|
475 | 475 |
|
476 |
- loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta );
|
|
477 |
- loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta );
|
|
476 |
+ loader->pp1.x = FT_PIX_ROUND( pp1x );
|
|
477 |
+ loader->pp2.x = FT_PIX_ROUND( pp2x );
|
|
478 | 478 |
|
479 | 479 |
slot->lsb_delta = loader->pp1.x - pp1x;
|
480 | 480 |
slot->rsb_delta = loader->pp2.x - pp2x;
|
... | ... | @@ -197,6 +197,7 @@ |
197 | 197 |
FT_Error error;
|
198 | 198 |
FT_Memory memory;
|
199 | 199 |
FT_Stream stream = NULL;
|
200 |
+ FT_UInt mode;
|
|
200 | 201 |
|
201 | 202 |
|
202 | 203 |
*astream = NULL;
|
... | ... | @@ -208,15 +209,15 @@ |
208 | 209 |
return FT_THROW( Invalid_Argument );
|
209 | 210 |
|
210 | 211 |
memory = library->memory;
|
212 |
+ mode = args->flags &
|
|
213 |
+ ( FT_OPEN_MEMORY | FT_OPEN_STREAM | FT_OPEN_PATHNAME );
|
|
211 | 214 |
|
212 |
- if ( FT_NEW( stream ) )
|
|
213 |
- goto Exit;
|
|
214 |
- |
|
215 |
- stream->memory = memory;
|
|
216 |
- |
|
217 |
- if ( args->flags & FT_OPEN_MEMORY )
|
|
215 |
+ if ( mode == FT_OPEN_MEMORY )
|
|
218 | 216 |
{
|
219 | 217 |
/* create a memory-based stream */
|
218 |
+ if ( FT_NEW( stream ) )
|
|
219 |
+ goto Exit;
|
|
220 |
+ |
|
220 | 221 |
FT_Stream_OpenMemory( stream,
|
221 | 222 |
(const FT_Byte*)args->memory_base,
|
222 | 223 |
(FT_ULong)args->memory_size );
|
... | ... | @@ -224,33 +225,40 @@ |
224 | 225 |
|
225 | 226 |
#ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT
|
226 | 227 |
|
227 |
- else if ( args->flags & FT_OPEN_PATHNAME )
|
|
228 |
+ else if ( mode == FT_OPEN_PATHNAME )
|
|
228 | 229 |
{
|
229 | 230 |
/* create a normal system stream */
|
231 |
+ if ( FT_NEW( stream ) )
|
|
232 |
+ goto Exit;
|
|
233 |
+ |
|
230 | 234 |
error = FT_Stream_Open( stream, args->pathname );
|
231 |
- stream->pathname.pointer = args->pathname;
|
|
235 |
+ if ( error )
|
|
236 |
+ FT_FREE( stream );
|
|
232 | 237 |
}
|
233 |
- else if ( ( args->flags & FT_OPEN_STREAM ) && args->stream )
|
|
238 |
+ else if ( ( mode == FT_OPEN_STREAM ) && args->stream )
|
|
234 | 239 |
{
|
235 | 240 |
/* use an existing, user-provided stream */
|
236 | 241 |
|
237 | 242 |
/* in this case, we do not need to allocate a new stream object */
|
238 | 243 |
/* since the caller is responsible for closing it himself */
|
239 |
- FT_FREE( stream );
|
|
240 | 244 |
stream = args->stream;
|
245 |
+ error = FT_Err_Ok;
|
|
241 | 246 |
}
|
242 | 247 |
|
243 | 248 |
#endif
|
244 | 249 |
|
245 | 250 |
else
|
251 |
+ {
|
|
246 | 252 |
error = FT_THROW( Invalid_Argument );
|
253 |
+ if ( ( args->flags & FT_OPEN_STREAM ) && args->stream )
|
|
254 |
+ FT_Stream_Close( args->stream );
|
|
255 |
+ }
|
|
247 | 256 |
|
248 |
- if ( error )
|
|
249 |
- FT_FREE( stream );
|
|
250 |
- else
|
|
251 |
- stream->memory = memory; /* just to be certain */
|
|
252 |
- |
|
253 |
- *astream = stream;
|
|
257 |
+ if ( !error )
|
|
258 |
+ {
|
|
259 |
+ stream->memory = memory;
|
|
260 |
+ *astream = stream;
|
|
261 |
+ }
|
|
254 | 262 |
|
255 | 263 |
Exit:
|
256 | 264 |
return error;
|
... | ... | @@ -41,7 +41,8 @@ |
41 | 41 |
* file `ftbsdf.c` for more.
|
42 | 42 |
*
|
43 | 43 |
* * The basic idea of generating the SDF is taken from Viktor Chlumsky's
|
44 |
- * research paper.
|
|
44 |
+ * research paper. The paper explains both single and multi-channel
|
|
45 |
+ * SDF, however, this implementation only generates single-channel SDF.
|
|
45 | 46 |
*
|
46 | 47 |
* Chlumsky, Viktor: Shape Decomposition for Multi-channel Distance
|
47 | 48 |
* Fields. Master's thesis. Czech Technical University in Prague,
|
... | ... | @@ -479,19 +479,24 @@ typedef ptrdiff_t FT_PtrDist; |
479 | 479 |
{
|
480 | 480 |
ft_jmp_buf jump_buffer;
|
481 | 481 |
|
482 |
- TCoord min_ex, max_ex;
|
|
482 |
+ TCoord min_ex, max_ex; /* min and max integer pixel coordinates */
|
|
483 | 483 |
TCoord min_ey, max_ey;
|
484 |
+ TCoord count_ey; /* same as (max_ey - min_ey) */
|
|
484 | 485 |
|
485 |
- PCell cell;
|
|
486 |
- PCell* ycells;
|
|
487 |
- PCell cells;
|
|
488 |
- FT_PtrDist max_cells;
|
|
489 |
- FT_PtrDist num_cells;
|
|
486 |
+ PCell cell; /* current cell */
|
|
487 |
+ PCell cell_free; /* call allocation next free slot */
|
|
488 |
+ PCell cell_limit; /* cell allocation limit */
|
|
490 | 489 |
|
491 |
- TPos x, y;
|
|
490 |
+ PCell* ycells; /* array of cell linked-lists, one per */
|
|
491 |
+ /* vertical coordinate in the current band. */
|
|
492 | 492 |
|
493 |
- FT_Outline outline;
|
|
494 |
- TPixmap target;
|
|
493 |
+ PCell cells; /* cell storage area */
|
|
494 |
+ FT_PtrDist max_cells; /* cell storage capacity */
|
|
495 |
+ |
|
496 |
+ TPos x, y; /* last point position */
|
|
497 |
+ |
|
498 |
+ FT_Outline outline; /* input outline */
|
|
499 |
+ TPixmap target; /* target pixmap */
|
|
495 | 500 |
|
496 | 501 |
FT_Raster_Span_Func render_span;
|
497 | 502 |
void* render_span_data;
|
... | ... | @@ -502,21 +507,34 @@ typedef ptrdiff_t FT_PtrDist; |
502 | 507 |
#pragma warning( pop )
|
503 | 508 |
#endif
|
504 | 509 |
|
505 |
- |
|
506 | 510 |
#ifndef FT_STATIC_RASTER
|
507 | 511 |
#define ras (*worker)
|
508 | 512 |
#else
|
509 | 513 |
static gray_TWorker ras;
|
510 | 514 |
#endif
|
511 | 515 |
|
512 |
-#define FT_INTEGRATE( ras, a, b ) \
|
|
513 |
- if ( ras.cell ) \
|
|
514 |
- ras.cell->cover += (a), ras.cell->area += (a) * (TArea)(b)
|
|
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
|
|
522 |
+ |
|
523 |
+/* The |x| value of the null cell. Must be the largest possible */
|
|
524 |
+/* integer value stored in a TCell.x field. */
|
|
525 |
+#define CELL_MAX_X_VALUE INT_MAX
|
|
526 |
+ |
|
527 |
+/* Return true iff |cell| points to the null cell. */
|
|
528 |
+#define CELL_IS_NULL(cell) ((cell)->x == CELL_MAX_X_VALUE)
|
|
529 |
+ |
|
530 |
+ |
|
531 |
+#define FT_INTEGRATE( ras, a, b ) \
|
|
532 |
+ ras.cell->cover += (a), ras.cell->area += (a) * (TArea)(b)
|
|
515 | 533 |
|
516 | 534 |
|
517 | 535 |
typedef struct gray_TRaster_
|
518 | 536 |
{
|
519 |
- void* memory;
|
|
537 |
+ void* memory;
|
|
520 | 538 |
|
521 | 539 |
} gray_TRaster, *gray_PRaster;
|
522 | 540 |
|
... | ... | @@ -538,7 +556,7 @@ typedef ptrdiff_t FT_PtrDist; |
538 | 556 |
|
539 | 557 |
printf( "%3d:", y );
|
540 | 558 |
|
541 |
- for ( ; cell != NULL; cell = cell->next )
|
|
559 |
+ for ( ; !CELL_IS_NULL(cell); cell = cell->next )
|
|
542 | 560 |
printf( " (%3d, c:%4d, a:%6d)",
|
543 | 561 |
cell->x, cell->cover, cell->area );
|
544 | 562 |
printf( "\n" );
|
... | ... | @@ -566,11 +584,12 @@ typedef ptrdiff_t FT_PtrDist; |
566 | 584 |
/* Note that if a cell is to the left of the clipping region, it is */
|
567 | 585 |
/* actually set to the (min_ex-1) horizontal position. */
|
568 | 586 |
|
569 |
- if ( ey >= ras.max_ey || ey < ras.min_ey || ex >= ras.max_ex )
|
|
570 |
- ras.cell = NULL;
|
|
587 |
+ TCoord ey_index = ey - ras.min_ey;
|
|
588 |
+ if ( ey_index < 0 || ey_index >= ras.count_ey || ex >= ras.max_ex )
|
|
589 |
+ ras.cell = NULL_CELL_PTR(ras);
|
|
571 | 590 |
else
|
572 | 591 |
{
|
573 |
- PCell* pcell = ras.ycells + ey - ras.min_ey;
|
|
592 |
+ PCell* pcell = ras.ycells + ey_index;
|
|
574 | 593 |
PCell cell;
|
575 | 594 |
|
576 | 595 |
|
... | ... | @@ -580,7 +599,7 @@ typedef ptrdiff_t FT_PtrDist; |
580 | 599 |
{
|
581 | 600 |
cell = *pcell;
|
582 | 601 |
|
583 |
- if ( !cell || cell->x > ex )
|
|
602 |
+ if ( cell->x > ex )
|
|
584 | 603 |
break;
|
585 | 604 |
|
586 | 605 |
if ( cell->x == ex )
|
... | ... | @@ -589,11 +608,11 @@ typedef ptrdiff_t FT_PtrDist; |
589 | 608 |
pcell = &cell->next;
|
590 | 609 |
}
|
591 | 610 |
|
592 |
- if ( ras.num_cells >= ras.max_cells )
|
|
611 |
+ /* insert new cell */
|
|
612 |
+ cell = ras.cell_free++;
|
|
613 |
+ if (cell >= ras.cell_limit)
|
|
593 | 614 |
ft_longjmp( ras.jump_buffer, 1 );
|
594 | 615 |
|
595 |
- /* insert new cell */
|
|
596 |
- cell = ras.cells + ras.num_cells++;
|
|
597 | 616 |
cell->x = ex;
|
598 | 617 |
cell->area = 0;
|
599 | 618 |
cell->cover = 0;
|
... | ... | @@ -974,6 +993,188 @@ typedef ptrdiff_t FT_PtrDist; |
974 | 993 |
|
975 | 994 |
#endif
|
976 | 995 |
|
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
|
|
1006 |
+#else
|
|
1007 |
+#define BEZIER_USE_DDA 0
|
|
1008 |
+#endif
|
|
1009 |
+ |
|
1010 |
+#if BEZIER_USE_DDA
|
|
1011 |
+ |
|
1012 |
+#include <emmintrin.h>
|
|
1013 |
+ |
|
1014 |
+ static void
|
|
1015 |
+ gray_render_conic( RAS_ARG_ const FT_Vector* control,
|
|
1016 |
+ const FT_Vector* to )
|
|
1017 |
+ {
|
|
1018 |
+ FT_Vector p0, p1, p2;
|
|
1019 |
+ |
|
1020 |
+ p0.x = ras.x;
|
|
1021 |
+ p0.y = ras.y;
|
|
1022 |
+ p1.x = UPSCALE( control->x );
|
|
1023 |
+ p1.y = UPSCALE( control->y );
|
|
1024 |
+ p2.x = UPSCALE( to->x );
|
|
1025 |
+ p2.y = UPSCALE( to->y );
|
|
1026 |
+ |
|
1027 |
+ /* short-cut the arc that crosses the current band */
|
|
1028 |
+ if ( ( TRUNC( p0.y ) >= ras.max_ey &&
|
|
1029 |
+ TRUNC( p1.y ) >= ras.max_ey &&
|
|
1030 |
+ TRUNC( p2.y ) >= ras.max_ey ) ||
|
|
1031 |
+ ( TRUNC( p0.y ) < ras.min_ey &&
|
|
1032 |
+ TRUNC( p1.y ) < ras.min_ey &&
|
|
1033 |
+ TRUNC( p2.y ) < ras.min_ey ) )
|
|
1034 |
+ {
|
|
1035 |
+ ras.x = p2.x;
|
|
1036 |
+ ras.y = p2.y;
|
|
1037 |
+ return;
|
|
1038 |
+ }
|
|
1039 |
+ |
|
1040 |
+ TPos dx = FT_ABS( p0.x + p2.x - 2 * p1.x );
|
|
1041 |
+ TPos dy = FT_ABS( p0.y + p2.y - 2 * p1.y );
|
|
1042 |
+ if ( dx < dy )
|
|
1043 |
+ dx = dy;
|
|
1044 |
+ |
|
1045 |
+ if ( dx <= ONE_PIXEL / 4 )
|
|
1046 |
+ {
|
|
1047 |
+ gray_render_line( RAS_VAR_ p2.x, p2.y );
|
|
1048 |
+ return;
|
|
1049 |
+ }
|
|
1050 |
+ |
|
1051 |
+ /* We can calculate the number of necessary bisections because */
|
|
1052 |
+ /* each bisection predictably reduces deviation exactly 4-fold. */
|
|
1053 |
+ /* Even 32-bit deviation would vanish after 16 bisections. */
|
|
1054 |
+ int shift = 0;
|
|
1055 |
+ do
|
|
1056 |
+ {
|
|
1057 |
+ dx >>= 2;
|
|
1058 |
+ shift += 1;
|
|
1059 |
+ }
|
|
1060 |
+ while (dx > ONE_PIXEL / 4);
|
|
1061 |
+ |
|
1062 |
+ /*
|
|
1063 |
+ * The (P0,P1,P2) arc equation, for t in [0,1] range:
|
|
1064 |
+ *
|
|
1065 |
+ * P(t) = P0*(1-t)^2 + P1*2*t*(1-t) + P2*t^2
|
|
1066 |
+ *
|
|
1067 |
+ * P(t) = P0 + 2*(P1-P0)*t + (P0+P2-2*P1)*t^2
|
|
1068 |
+ * = P0 + 2*B*t + A*t^2
|
|
1069 |
+ *
|
|
1070 |
+ * for A = P0 + P2 - 2*P1
|
|
1071 |
+ * and B = P1 - P0
|
|
1072 |
+ *
|
|
1073 |
+ * Let's consider the difference when advancing by a small
|
|
1074 |
+ * parameter h:
|
|
1075 |
+ *
|
|
1076 |
+ * Q(h,t) = P(t+h) - P(t) = 2*B*h + A*h^2 + 2*A*h*t
|
|
1077 |
+ *
|
|
1078 |
+ * And then its own difference:
|
|
1079 |
+ *
|
|
1080 |
+ * R(h,t) = Q(h,t+h) - Q(h,t) = 2*A*h*h = R (constant)
|
|
1081 |
+ *
|
|
1082 |
+ * Since R is always a constant, it is possible to compute
|
|
1083 |
+ * successive positions with:
|
|
1084 |
+ *
|
|
1085 |
+ * P = P0
|
|
1086 |
+ * Q = Q(h,0) = 2*B*h + A*h*h
|
|
1087 |
+ * R = 2*A*h*h
|
|
1088 |
+ *
|
|
1089 |
+ * loop:
|
|
1090 |
+ * P += Q
|
|
1091 |
+ * Q += R
|
|
1092 |
+ * EMIT(P)
|
|
1093 |
+ *
|
|
1094 |
+ * To ensure accurate results, perform computations on 64-bit
|
|
1095 |
+ * values, after scaling them by 2^32:
|
|
1096 |
+ *
|
|
1097 |
+ * R << 32 = 2 * A << (32 - N - N)
|
|
1098 |
+ * = A << (33 - 2 *N)
|
|
1099 |
+ *
|
|
1100 |
+ * Q << 32 = (2 * B << (32 - N)) + (A << (32 - N - N))
|
|
1101 |
+ * = (B << (33 - N)) + (A << (32 - N - N))
|
|
1102 |
+ */
|
|
1103 |
+#ifdef __SSE2__
|
|
1104 |
+ /* Experience shows that for small shift values, SSE2 is actually slower. */
|
|
1105 |
+ if (shift > 2) {
|
|
1106 |
+ union {
|
|
1107 |
+ struct { FT_Int64 ax, ay, bx, by; } i;
|
|
1108 |
+ struct { __m128i a, b; } vec;
|
|
1109 |
+ } u;
|
|
1110 |
+ |
|
1111 |
+ u.i.ax = p0.x + p2.x - 2 * p1.x;
|
|
1112 |
+ u.i.ay = p0.y + p2.y - 2 * p1.y;
|
|
1113 |
+ u.i.bx = p1.x - p0.x;
|
|
1114 |
+ u.i.by = p1.y - p0.y;
|
|
1115 |
+ |
|
1116 |
+ __m128i a = _mm_load_si128(&u.vec.a);
|
|
1117 |
+ __m128i b = _mm_load_si128(&u.vec.b);
|
|
1118 |
+ |
|
1119 |
+ __m128i r = _mm_slli_epi64(a, 33 - 2 * shift);
|
|
1120 |
+ __m128i q = _mm_slli_epi64(b, 33 - shift);
|
|
1121 |
+ __m128i q2 = _mm_slli_epi64(a, 32 - 2 * shift);
|
|
1122 |
+ q = _mm_add_epi64(q2, q);
|
|
1123 |
+ |
|
1124 |
+ union {
|
|
1125 |
+ struct { FT_Int32 px_lo, px_hi, py_lo, py_hi; } i;
|
|
1126 |
+ __m128i vec;
|
|
1127 |
+ } v;
|
|
1128 |
+ v.i.px_lo = 0;
|
|
1129 |
+ v.i.px_hi = p0.x;
|
|
1130 |
+ v.i.py_lo = 0;
|
|
1131 |
+ v.i.py_hi = p0.y;
|
|
1132 |
+ |
|
1133 |
+ __m128i p = _mm_load_si128(&v.vec);
|
|
1134 |
+ |
|
1135 |
+ for (unsigned count = (1u << shift); count > 0; count--) {
|
|
1136 |
+ p = _mm_add_epi64(p, q);
|
|
1137 |
+ q = _mm_add_epi64(q, r);
|
|
1138 |
+ |
|
1139 |
+ _mm_store_si128(&v.vec, p);
|
|
1140 |
+ |
|
1141 |
+ gray_render_line( RAS_VAR_ v.i.px_hi, v.i.py_hi);
|
|
1142 |
+ }
|
|
1143 |
+ return;
|
|
1144 |
+ }
|
|
1145 |
+#endif /* !__SSE2__ */
|
|
1146 |
+ FT_Int64 ax = p0.x + p2.x - 2 * p1.x;
|
|
1147 |
+ FT_Int64 ay = p0.y + p2.y - 2 * p1.y;
|
|
1148 |
+ FT_Int64 bx = p1.x - p0.x;
|
|
1149 |
+ FT_Int64 by = p1.y - p0.y;
|
|
1150 |
+ |
|
1151 |
+ FT_Int64 rx = ax << (33 - 2 * shift);
|
|
1152 |
+ FT_Int64 ry = ay << (33 - 2 * shift);
|
|
1153 |
+ |
|
1154 |
+ FT_Int64 qx = (bx << (33 - shift)) + (ax << (32 - 2 * shift));
|
|
1155 |
+ FT_Int64 qy = (by << (33 - shift)) + (ay << (32 - 2 * shift));
|
|
1156 |
+ |
|
1157 |
+ FT_Int64 px = (FT_Int64)p0.x << 32;
|
|
1158 |
+ FT_Int64 py = (FT_Int64)p0.y << 32;
|
|
1159 |
+ |
|
1160 |
+ FT_UInt count = 1u << shift;
|
|
1161 |
+ |
|
1162 |
+ for (; count > 0; count--) {
|
|
1163 |
+ px += qx;
|
|
1164 |
+ py += qy;
|
|
1165 |
+ qx += rx;
|
|
1166 |
+ qy += ry;
|
|
1167 |
+ |
|
1168 |
+ gray_render_line( RAS_VAR_ (FT_Pos)(px >> 32), (FT_Pos)(py >> 32));
|
|
1169 |
+ }
|
|
1170 |
+ }
|
|
1171 |
+ |
|
1172 |
+#else /* !BEZIER_USE_DDA */
|
|
1173 |
+ |
|
1174 |
+ /* Note that multiple attempts to speed up the function below
|
|
1175 |
+ * with SSE2 intrinsics, using various data layouts, have turned
|
|
1176 |
+ * out to be slower than the non-SIMD code below.
|
|
1177 |
+ */
|
|
977 | 1178 |
static void
|
978 | 1179 |
gray_split_conic( FT_Vector* base )
|
979 | 1180 |
{
|
... | ... | @@ -1059,7 +1260,15 @@ typedef ptrdiff_t FT_PtrDist; |
1059 | 1260 |
} while ( --draw );
|
1060 | 1261 |
}
|
1061 | 1262 |
|
1263 |
+#endif /* !BEZIER_USE_DDA */
|
|
1062 | 1264 |
|
1265 |
+ /* For cubic bezier, binary splits are still faster than DDA
|
|
1266 |
+ * because the splits are adaptive to how quickly each sub-arc
|
|
1267 |
+ * approaches their chord trisection points.
|
|
1268 |
+ *
|
|
1269 |
+ * It might be useful to experiment with SSE2 to speed up
|
|
1270 |
+ * gray_split_cubic() though.
|
|
1271 |
+ */
|
|
1063 | 1272 |
static void
|
1064 | 1273 |
gray_split_cubic( FT_Vector* base )
|
1065 | 1274 |
{
|
... | ... | @@ -1150,7 +1359,6 @@ typedef ptrdiff_t FT_PtrDist; |
1150 | 1359 |
}
|
1151 | 1360 |
}
|
1152 | 1361 |
|
1153 |
- |
|
1154 | 1362 |
static int
|
1155 | 1363 |
gray_move_to( const FT_Vector* to,
|
1156 | 1364 |
gray_PWorker worker )
|
... | ... | @@ -1218,7 +1426,7 @@ typedef ptrdiff_t FT_PtrDist; |
1218 | 1426 |
unsigned char* line = ras.target.origin - ras.target.pitch * y;
|
1219 | 1427 |
|
1220 | 1428 |
|
1221 |
- for ( ; cell != NULL; cell = cell->next )
|
|
1429 |
+ for ( ; !CELL_IS_NULL(cell); cell = cell->next )
|
|
1222 | 1430 |
{
|
1223 | 1431 |
if ( cover != 0 && cell->x > x )
|
1224 | 1432 |
{
|
... | ... | @@ -1266,7 +1474,7 @@ typedef ptrdiff_t FT_PtrDist; |
1266 | 1474 |
TArea area;
|
1267 | 1475 |
|
1268 | 1476 |
|
1269 |
- for ( ; cell != NULL; cell = cell->next )
|
|
1477 |
+ for ( ; !CELL_IS_NULL(cell); cell = cell->next )
|
|
1270 | 1478 |
{
|
1271 | 1479 |
if ( cover != 0 && cell->x > x )
|
1272 | 1480 |
{
|
... | ... | @@ -1646,8 +1854,8 @@ typedef ptrdiff_t FT_PtrDist; |
1646 | 1854 |
FT_TRACE7(( "band [%d..%d]: %ld cell%s\n",
|
1647 | 1855 |
ras.min_ey,
|
1648 | 1856 |
ras.max_ey,
|
1649 |
- ras.num_cells,
|
|
1650 |
- ras.num_cells == 1 ? "" : "s" ));
|
|
1857 |
+ ras.cell_free - ras.cells.,
|
|
1858 |
+ ras.cell_free - ras.cells == 1 ? "" : "s" ));
|
|
1651 | 1859 |
}
|
1652 | 1860 |
else
|
1653 | 1861 |
{
|
... | ... | @@ -1690,8 +1898,18 @@ typedef ptrdiff_t FT_PtrDist; |
1690 | 1898 |
|
1691 | 1899 |
ras.cells = buffer + n;
|
1692 | 1900 |
ras.max_cells = (FT_PtrDist)( FT_MAX_GRAY_POOL - n );
|
1901 |
+ ras.cell_limit = ras.cells + ras.max_cells;
|
|
1693 | 1902 |
ras.ycells = (PCell*)buffer;
|
1694 | 1903 |
|
1904 |
+ /* Initialize the null cell is at the start of the 'cells' array. */
|
|
1905 |
+ /* Note that this requires ras.cell_free initialization to skip */
|
|
1906 |
+ /* over the first entry in the array. */
|
|
1907 |
+ PCell null_cell = NULL_CELL_PTR(ras);
|
|
1908 |
+ null_cell->x = CELL_MAX_X_VALUE;
|
|
1909 |
+ null_cell->area = 0;
|
|
1910 |
+ null_cell->cover = 0;
|
|
1911 |
+ null_cell->next = NULL;;
|
|
1912 |
+ |
|
1695 | 1913 |
for ( y = yMin; y < yMax; )
|
1696 | 1914 |
{
|
1697 | 1915 |
ras.min_ey = y;
|
... | ... | @@ -1705,15 +1923,17 @@ typedef ptrdiff_t FT_PtrDist; |
1705 | 1923 |
do
|
1706 | 1924 |
{
|
1707 | 1925 |
TCoord width = band[0] - band[1];
|
1926 |
+ TCoord w;
|
|
1708 | 1927 |
int error;
|
1709 | 1928 |
|
1929 |
+ for (w = 0; w < width; ++w)
|
|
1930 |
+ ras.ycells[w] = null_cell;
|
|
1710 | 1931 |
|
1711 |
- FT_MEM_ZERO( ras.ycells, height * sizeof ( PCell ) );
|
|
1712 |
- |
|
1713 |
- ras.num_cells = 0;
|
|
1714 |
- ras.cell = NULL;
|
|
1932 |
+ ras.cell_free = ras.cells + 1; /* NOTE: Skip over the null cell. */
|
|
1933 |
+ ras.cell = null_cell;
|
|
1715 | 1934 |
ras.min_ey = band[1];
|
1716 | 1935 |
ras.max_ey = band[0];
|
1936 |
+ ras.count_ey = width;
|
|
1717 | 1937 |
|
1718 | 1938 |
error = gray_convert_glyph_inner( RAS_VAR, continued );
|
1719 | 1939 |
continued = 1;
|