[smooth] Fix complex rendering at high ppem. We used to split large glyphs into horizontal bands and continue bisecting them still horizontally if that was not enough. This is guaranteed to fail when a single scanline cannot fit into the rendering memory pool. Now we bisect the bands vertically so that the smallest unit is a column of the band height, which is guranteed to fit into memory. * src/smooth/ftgrays.c (gray_convert_glyph): Implement it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
diff --git a/ChangeLog b/ChangeLog
index afe63fc..2f05d8e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2017-11-01 Alexei Podtelezhnikov <apodtele@gmail.com>
+
+ [smooth] Fix complex rendering at high ppem.
+
+ We used to split large glyphs into horizontal bands and continue
+ bisecting them still horizontally if that was not enough. This is
+ guaranteed to fail when a single scanline cannot fit into the
+ rendering memory pool. Now we bisect the bands vertically so that
+ the smallest unit is a column of the band height, which is guranteed
+ to fit into memory.
+
+ * src/smooth/ftgrays.c (gray_convert_glyph): Implement it.
+
2017-10-20 Alexei Podtelezhnikov <apodtele@gmail.com>
[smooth] Improve complex rendering at high ppem.
diff --git a/src/smooth/ftgrays.c b/src/smooth/ftgrays.c
index fa488ec..91ca6e3 100644
--- a/src/smooth/ftgrays.c
+++ b/src/smooth/ftgrays.c
@@ -1736,35 +1736,43 @@ typedef ptrdiff_t FT_PtrDist;
static int
gray_convert_glyph( RAS_ARG )
{
+ const TCoord yMin = ras.min_ey;
+ const TCoord yMax = ras.max_ey;
+ const TCoord xMin = ras.min_ex;
+ const TCoord xMax = ras.max_ex;
+
TCell buffer[FT_MAX_GRAY_POOL];
- TCoord band_size = FT_MAX_GRAY_POOL / 8;
- TCoord count = ras.max_ey - ras.min_ey;
- int num_bands;
- TCoord min, max, max_y;
+ size_t height = (size_t)( yMax - yMin );
+ size_t n = FT_MAX_GRAY_POOL / 8;
+ TCoord y;
TCoord bands[32]; /* enough to accommodate bisections */
TCoord* band;
/* set up vertical bands */
- if ( count > band_size )
+ if ( height > n )
{
/* two divisions rounded up */
- num_bands = (int)( ( count + band_size - 1) / band_size );
- band_size = ( count + num_bands - 1 ) / num_bands;
+ n = ( height + n - 1 ) / n;
+ height = ( height + n - 1 ) / n;
}
- min = ras.min_ey;
- max_y = ras.max_ey;
+ /* memory management */
+ n = ( height * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) / sizeof ( TCell );
+
+ ras.cells = buffer + n;
+ ras.max_cells = (FT_PtrDist)( FT_MAX_GRAY_POOL - n );
+ ras.ycells = (PCell*)buffer;
- for ( ; min < max_y; min = max )
+ for ( y = yMin; y < yMax; )
{
- max = min + band_size;
- if ( max > max_y )
- max = max_y;
+ ras.min_ey = y;
+ y += height;
+ ras.max_ey = FT_MIN( y, yMax );
band = bands;
- band[1] = min;
- band[0] = max;
+ band[1] = xMin;
+ band[0] = xMax;
do
{
@@ -1772,27 +1780,12 @@ typedef ptrdiff_t FT_PtrDist;
int error;
- /* memory management */
- {
- size_t ycount = (size_t)width;
- size_t cell_start;
-
-
- cell_start = ( ycount * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) /
- sizeof ( TCell );
-
- ras.cells = buffer + cell_start;
- ras.max_cells = (FT_PtrDist)( FT_MAX_GRAY_POOL - cell_start );
- ras.num_cells = 0;
-
- ras.ycells = (PCell*)buffer;
- while ( ycount )
- ras.ycells[--ycount] = NULL;
- }
+ FT_MEM_ZERO( ras.ycells, height * sizeof ( PCell ) );
+ ras.num_cells = 0;
ras.invalid = 1;
- ras.min_ey = band[1];
- ras.max_ey = band[0];
+ ras.min_ex = band[1];
+ ras.max_ex = band[0];
error = gray_convert_glyph_inner( RAS_VAR );
@@ -1808,8 +1801,7 @@ typedef ptrdiff_t FT_PtrDist;
/* render pool overflow; we will reduce the render band by half */
width >>= 1;
- /* This is too complex for a single scanline; there must */
- /* be some problems. */
+ /* this should never happen even with tiny rendering pool */
if ( width == 0 )
{
FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" ));