jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java
changeset 47126 188ef162f019
parent 40421 d5ee65e2b0fb
equal deleted inserted replaced
45093:c42dc7b58b4d 47126:188ef162f019
     1 /*
     1 /*
     2  * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 package sun.java2d.marlin;
    26 package sun.java2d.marlin;
    27 
    27 
    28 import java.util.Arrays;
       
    29 import sun.awt.geom.PathConsumer2D;
    28 import sun.awt.geom.PathConsumer2D;
    30 import static sun.java2d.marlin.OffHeapArray.SIZE_INT;
    29 import static sun.java2d.marlin.OffHeapArray.SIZE_INT;
    31 import jdk.internal.misc.Unsafe;
    30 import jdk.internal.misc.Unsafe;
    32 
    31 
    33 final class Renderer implements PathConsumer2D, MarlinConst {
    32 final class Renderer implements PathConsumer2D, MarlinRenderer {
    34 
    33 
    35     static final boolean DISABLE_RENDER = false;
    34     static final boolean DISABLE_RENDER = false;
    36 
    35 
    37     static final boolean ENABLE_BLOCK_FLAGS = MarlinProperties.isUseTileFlags();
    36     static final boolean ENABLE_BLOCK_FLAGS = MarlinProperties.isUseTileFlags();
    38     static final boolean ENABLE_BLOCK_FLAGS_HEURISTICS = MarlinProperties.isUseTileFlagsWithHeuristics();
    37     static final boolean ENABLE_BLOCK_FLAGS_HEURISTICS = MarlinProperties.isUseTileFlagsWithHeuristics();
    39 
    38 
    40     private static final int ALL_BUT_LSB = 0xfffffffe;
    39     private static final int ALL_BUT_LSB = 0xFFFFFFFE;
    41     private static final int ERR_STEP_MAX = 0x7fffffff; // = 2^31 - 1
    40     private static final int ERR_STEP_MAX = 0x7FFFFFFF; // = 2^31 - 1
    42 
    41 
    43     private static final double POWER_2_TO_32 = 0x1.0p32;
    42     private static final double POWER_2_TO_32 = 0x1.0p32d;
    44 
    43 
    45     // use float to make tosubpix methods faster (no int to float conversion)
    44     // use float to make tosubpix methods faster (no int to float conversion)
    46     public static final float F_SUBPIXEL_POSITIONS_X
    45     static final float SUBPIXEL_SCALE_X = (float) SUBPIXEL_POSITIONS_X;
    47         = (float) SUBPIXEL_POSITIONS_X;
    46     static final float SUBPIXEL_SCALE_Y = (float) SUBPIXEL_POSITIONS_Y;
    48     public static final float F_SUBPIXEL_POSITIONS_Y
    47     static final int SUBPIXEL_MASK_X = SUBPIXEL_POSITIONS_X - 1;
    49         = (float) SUBPIXEL_POSITIONS_Y;
    48     static final int SUBPIXEL_MASK_Y = SUBPIXEL_POSITIONS_Y - 1;
    50     public static final int SUBPIXEL_MASK_X = SUBPIXEL_POSITIONS_X - 1;
       
    51     public static final int SUBPIXEL_MASK_Y = SUBPIXEL_POSITIONS_Y - 1;
       
    52 
    49 
    53     // number of subpixels corresponding to a tile line
    50     // number of subpixels corresponding to a tile line
    54     private static final int SUBPIXEL_TILE
    51     private static final int SUBPIXEL_TILE
    55         = TILE_SIZE << SUBPIXEL_LG_POSITIONS_Y;
    52         = TILE_H << SUBPIXEL_LG_POSITIONS_Y;
    56 
    53 
    57     // 2048 (pixelSize) pixels (height) x 8 subpixels = 64K
    54     // 2048 (pixelSize) pixels (height) x 8 subpixels = 64K
    58     static final int INITIAL_BUCKET_ARRAY
    55     static final int INITIAL_BUCKET_ARRAY
    59         = INITIAL_PIXEL_DIM * SUBPIXEL_POSITIONS_Y;
    56         = INITIAL_PIXEL_DIM * SUBPIXEL_POSITIONS_Y;
    60 
    57 
    61     // crossing capacity = edges count / 8 ~ 512
    58     // crossing capacity = edges count / 4 ~ 1024
    62     static final int INITIAL_CROSSING_COUNT = INITIAL_EDGES_COUNT >> 3;
    59     static final int INITIAL_CROSSING_COUNT = INITIAL_EDGES_COUNT >> 2;
    63 
    60 
    64     public static final int WIND_EVEN_ODD = 0;
    61     public static final int WIND_EVEN_ODD = 0;
    65     public static final int WIND_NON_ZERO = 1;
    62     public static final int WIND_NON_ZERO = 1;
    66 
    63 
    67     // common to all types of input path segments.
    64     // common to all types of input path segments.
    78     public static final int SIZEOF_EDGE_BYTES = (int)(OFF_YMAX + SIZE_INT);
    75     public static final int SIZEOF_EDGE_BYTES = (int)(OFF_YMAX + SIZE_INT);
    79 
    76 
    80     // curve break into lines
    77     // curve break into lines
    81     // cubic error in subpixels to decrement step
    78     // cubic error in subpixels to decrement step
    82     private static final float CUB_DEC_ERR_SUBPIX
    79     private static final float CUB_DEC_ERR_SUBPIX
    83         = 2.5f * (NORM_SUBPIXELS / 8f); // 2.5 subpixel for typical 8x8 subpixels
    80         = MarlinProperties.getCubicDecD2() * (NORM_SUBPIXELS / 8.0f); // 1 pixel
    84     // cubic error in subpixels to increment step
    81     // cubic error in subpixels to increment step
    85     private static final float CUB_INC_ERR_SUBPIX
    82     private static final float CUB_INC_ERR_SUBPIX
    86         = 1f * (NORM_SUBPIXELS / 8f); // 1 subpixel for typical 8x8 subpixels
    83         = MarlinProperties.getCubicIncD1() * (NORM_SUBPIXELS / 8.0f); // 0.4 pixel
    87 
    84 
    88     // cubic bind length to decrement step = 8 * error in subpixels
    85     // TestNonAARasterization (JDK-8170879): cubics
    89     // pisces: 20 / 8
    86     // bad paths (59294/100000 == 59,29%, 94335 bad pixels (avg = 1,59), 3966 warnings (avg = 0,07)
    90     // openjfx pisces: 8 / 3.2
    87 
    91     // multiply by 8 = error scale factor:
    88     // cubic bind length to decrement step
    92     public static final float CUB_DEC_BND
    89     public static final float CUB_DEC_BND
    93         = 8f * CUB_DEC_ERR_SUBPIX; // 20f means 2.5 subpixel error
    90         = 8.0f * CUB_DEC_ERR_SUBPIX;
    94     // cubic bind length to increment step = 8 * error in subpixels
    91     // cubic bind length to increment step
    95     public static final float CUB_INC_BND
    92     public static final float CUB_INC_BND
    96         = 8f * CUB_INC_ERR_SUBPIX; // 8f means 1 subpixel error
    93         = 8.0f * CUB_INC_ERR_SUBPIX;
    97 
    94 
    98     // cubic countlg
    95     // cubic countlg
    99     public static final int CUB_COUNT_LG = 2;
    96     public static final int CUB_COUNT_LG = 2;
   100     // cubic count = 2^countlg
    97     // cubic count = 2^countlg
   101     private static final int CUB_COUNT = 1 << CUB_COUNT_LG;
    98     private static final int CUB_COUNT = 1 << CUB_COUNT_LG;
   102     // cubic count^2 = 4^countlg
    99     // cubic count^2 = 4^countlg
   103     private static final int CUB_COUNT_2 = 1 << (2 * CUB_COUNT_LG);
   100     private static final int CUB_COUNT_2 = 1 << (2 * CUB_COUNT_LG);
   104     // cubic count^3 = 8^countlg
   101     // cubic count^3 = 8^countlg
   105     private static final int CUB_COUNT_3 = 1 << (3 * CUB_COUNT_LG);
   102     private static final int CUB_COUNT_3 = 1 << (3 * CUB_COUNT_LG);
   106     // cubic dt = 1 / count
   103     // cubic dt = 1 / count
   107     private static final float CUB_INV_COUNT = 1f / CUB_COUNT;
   104     private static final float CUB_INV_COUNT = 1.0f / CUB_COUNT;
   108     // cubic dt^2 = 1 / count^2 = 1 / 4^countlg
   105     // cubic dt^2 = 1 / count^2 = 1 / 4^countlg
   109     private static final float CUB_INV_COUNT_2 = 1f / CUB_COUNT_2;
   106     private static final float CUB_INV_COUNT_2 = 1.0f / CUB_COUNT_2;
   110     // cubic dt^3 = 1 / count^3 = 1 / 8^countlg
   107     // cubic dt^3 = 1 / count^3 = 1 / 8^countlg
   111     private static final float CUB_INV_COUNT_3 = 1f / CUB_COUNT_3;
   108     private static final float CUB_INV_COUNT_3 = 1.0f / CUB_COUNT_3;
   112 
   109 
   113     // quad break into lines
   110     // quad break into lines
   114     // quadratic error in subpixels
   111     // quadratic error in subpixels
   115     private static final float QUAD_DEC_ERR_SUBPIX
   112     private static final float QUAD_DEC_ERR_SUBPIX
   116         = 1f * (NORM_SUBPIXELS / 8f); // 1 subpixel for typical 8x8 subpixels
   113         = MarlinProperties.getQuadDecD2() * (NORM_SUBPIXELS / 8.0f); // 0.5 pixel
   117 
   114 
   118     // quadratic bind length to decrement step = 8 * error in subpixels
   115     // TestNonAARasterization (JDK-8170879): quads
   119     // pisces and openjfx pisces: 32
   116     // bad paths (62916/100000 == 62,92%, 103818 bad pixels (avg = 1,65), 6514 warnings (avg = 0,10)
       
   117 
       
   118     // quadratic bind length to decrement step
   120     public static final float QUAD_DEC_BND
   119     public static final float QUAD_DEC_BND
   121         = 8f * QUAD_DEC_ERR_SUBPIX; // 8f means 1 subpixel error
   120         = 8.0f * QUAD_DEC_ERR_SUBPIX;
   122 
   121 
   123 //////////////////////////////////////////////////////////////////////////////
   122 //////////////////////////////////////////////////////////////////////////////
   124 //  SCAN LINE
   123 //  SCAN LINE
   125 //////////////////////////////////////////////////////////////////////////////
   124 //////////////////////////////////////////////////////////////////////////////
   126     // crossings ie subpixel edge x coordinates
   125     // crossings ie subpixel edge x coordinates
   155     private int edgeMinY = Integer.MAX_VALUE;
   154     private int edgeMinY = Integer.MAX_VALUE;
   156     private int edgeMaxY = Integer.MIN_VALUE;
   155     private int edgeMaxY = Integer.MIN_VALUE;
   157     private float edgeMinX = Float.POSITIVE_INFINITY;
   156     private float edgeMinX = Float.POSITIVE_INFINITY;
   158     private float edgeMaxX = Float.NEGATIVE_INFINITY;
   157     private float edgeMaxX = Float.NEGATIVE_INFINITY;
   159 
   158 
   160     // edges [floats|ints] stored in off-heap memory
   159     // edges [ints] stored in off-heap memory
   161     private final OffHeapArray edges;
   160     private final OffHeapArray edges;
   162 
   161 
   163     private int[] edgeBuckets;
   162     private int[] edgeBuckets;
   164     private int[] edgeBucketCounts; // 2*newedges + (1 if pruning needed)
   163     private int[] edgeBucketCounts; // 2*newedges + (1 if pruning needed)
   165     // used range for edgeBuckets / edgeBucketCounts
   164     // used range for edgeBuckets / edgeBucketCounts
   166     private int buckets_minY;
   165     private int buckets_minY;
   167     private int buckets_maxY;
   166     private int buckets_maxY;
   168     // sum of each edge delta Y (subpixels)
       
   169     private int edgeSumDeltaY;
       
   170 
   167 
   171     // edgeBuckets ref (clean)
   168     // edgeBuckets ref (clean)
   172     private final IntArrayCache.Reference edgeBuckets_ref;
   169     private final IntArrayCache.Reference edgeBuckets_ref;
   173     // edgeBucketCounts ref (clean)
   170     // edgeBucketCounts ref (clean)
   174     private final IntArrayCache.Reference edgeBucketCounts_ref;
   171     private final IntArrayCache.Reference edgeBucketCounts_ref;
   181                                           final float x2, final float y2)
   178                                           final float x2, final float y2)
   182     {
   179     {
   183         int count = 1; // dt = 1 / count
   180         int count = 1; // dt = 1 / count
   184 
   181 
   185         // maximum(ddX|Y) = norm(dbx, dby) * dt^2 (= 1)
   182         // maximum(ddX|Y) = norm(dbx, dby) * dt^2 (= 1)
   186         float maxDD = FloatMath.max(Math.abs(c.dbx), Math.abs(c.dby));
   183         float maxDD = Math.abs(c.dbx) + Math.abs(c.dby);
   187 
   184 
   188         final float _DEC_BND = QUAD_DEC_BND;
   185         final float _DEC_BND = QUAD_DEC_BND;
   189 
   186 
   190         while (maxDD >= _DEC_BND) {
   187         while (maxDD >= _DEC_BND) {
   191             // divide step by half:
   188             // divide step by half:
   192             maxDD /= 4f; // error divided by 2^2 = 4
   189             maxDD /= 4.0f; // error divided by 2^2 = 4
   193 
   190 
   194             count <<= 1;
   191             count <<= 1;
   195             if (DO_STATS) {
   192             if (DO_STATS) {
   196                 rdrCtx.stats.stat_rdr_quadBreak_dec.add(count);
   193                 rdrCtx.stats.stat_rdr_quadBreak_dec.add(count);
   197             }
   194             }
   198         }
   195         }
   199 
   196 
   200         int nL = 0; // line count
   197         int nL = 0; // line count
   201         if (count > 1) {
   198         if (count > 1) {
   202             final float icount = 1f / count; // dt
   199             final float icount = 1.0f / count; // dt
   203             final float icount2 = icount * icount; // dt^2
   200             final float icount2 = icount * icount; // dt^2
   204 
   201 
   205             final float ddx = c.dbx * icount2;
   202             final float ddx = c.dbx * icount2;
   206             final float ddy = c.dby * icount2;
   203             final float ddy = c.dby * icount2;
   207             float dx = c.bx * icount2 + c.cx * icount;
   204             float dx = c.bx * icount2 + c.cx * icount;
   244         final float icount3 = CUB_INV_COUNT_3; // dt^3
   241         final float icount3 = CUB_INV_COUNT_3; // dt^3
   245 
   242 
   246         // the dx and dy refer to forward differencing variables, not the last
   243         // the dx and dy refer to forward differencing variables, not the last
   247         // coefficients of the "points" polynomial
   244         // coefficients of the "points" polynomial
   248         float dddx, dddy, ddx, ddy, dx, dy;
   245         float dddx, dddy, ddx, ddy, dx, dy;
   249         dddx = 2f * c.dax * icount3;
   246         dddx = 2.0f * c.dax * icount3;
   250         dddy = 2f * c.day * icount3;
   247         dddy = 2.0f * c.day * icount3;
   251         ddx = dddx + c.dbx * icount2;
   248         ddx = dddx + c.dbx * icount2;
   252         ddy = dddy + c.dby * icount2;
   249         ddy = dddy + c.dby * icount2;
   253         dx = c.ax * icount3 + c.bx * icount2 + c.cx * icount;
   250         dx = c.ax * icount3 + c.bx * icount2 + c.cx * icount;
   254         dy = c.ay * icount3 + c.by * icount2 + c.cy * icount;
   251         dy = c.ay * icount3 + c.by * icount2 + c.cy * icount;
   255 
   252 
   260         final float _DEC_BND = CUB_DEC_BND;
   257         final float _DEC_BND = CUB_DEC_BND;
   261         final float _INC_BND = CUB_INC_BND;
   258         final float _INC_BND = CUB_INC_BND;
   262 
   259 
   263         while (count > 0) {
   260         while (count > 0) {
   264             // divide step by half:
   261             // divide step by half:
   265             while (Math.abs(ddx) >= _DEC_BND || Math.abs(ddy) >= _DEC_BND) {
   262             while (Math.abs(ddx) + Math.abs(ddy) >= _DEC_BND) {
   266                 dddx /= 8f;
   263                 dddx /= 8.0f;
   267                 dddy /= 8f;
   264                 dddy /= 8.0f;
   268                 ddx = ddx/4f - dddx;
   265                 ddx = ddx / 4.0f - dddx;
   269                 ddy = ddy/4f - dddy;
   266                 ddy = ddy / 4.0f - dddy;
   270                 dx = (dx - ddx) / 2f;
   267                 dx = (dx - ddx) / 2.0f;
   271                 dy = (dy - ddy) / 2f;
   268                 dy = (dy - ddy) / 2.0f;
   272 
   269 
   273                 count <<= 1;
   270                 count <<= 1;
   274                 if (DO_STATS) {
   271                 if (DO_STATS) {
   275                     rdrCtx.stats.stat_rdr_curveBreak_dec.add(count);
   272                     rdrCtx.stats.stat_rdr_curveBreak_dec.add(count);
   276                 }
   273                 }
   277             }
   274             }
   278 
   275 
   279             // double step:
   276             // double step:
   280             // TODO: why use first derivative dX|Y instead of second ddX|Y ?
       
   281             // both scale changes should use speed or acceleration to have the same metric.
       
   282 
       
   283             // can only do this on even "count" values, because we must divide count by 2
   277             // can only do this on even "count" values, because we must divide count by 2
   284             while (count % 2 == 0
   278             while (count % 2 == 0
   285                    && Math.abs(dx) <= _INC_BND && Math.abs(dy) <= _INC_BND)
   279                    && Math.abs(dx) + Math.abs(dy) <= _INC_BND)
   286             {
   280             {
   287                 dx = 2f * dx + ddx;
   281                 dx = 2.0f * dx + ddx;
   288                 dy = 2f * dy + ddy;
   282                 dy = 2.0f * dy + ddy;
   289                 ddx = 4f * (ddx + dddx);
   283                 ddx = 4.0f * (ddx + dddx);
   290                 ddy = 4f * (ddy + dddy);
   284                 ddy = 4.0f * (ddy + dddy);
   291                 dddx *= 8f;
   285                 dddx *= 8.0f;
   292                 dddy *= 8f;
   286                 dddy *= 8.0f;
   293 
   287 
   294                 count >>= 1;
   288                 count >>= 1;
   295                 if (DO_STATS) {
   289                 if (DO_STATS) {
   296                     rdrCtx.stats.stat_rdr_curveBreak_inc.add(count);
   290                     rdrCtx.stats.stat_rdr_curveBreak_inc.add(count);
   297                 }
   291                 }
   335             tmp = x2;
   329             tmp = x2;
   336             x2 = x1;
   330             x2 = x1;
   337             x1 = tmp;
   331             x1 = tmp;
   338         }
   332         }
   339 
   333 
   340         // convert subpixel coordinates (float) into pixel positions (int)
   334         // convert subpixel coordinates [float] into pixel positions [int]
   341 
   335 
   342         // The index of the pixel that holds the next HPC is at ceil(trueY - 0.5)
   336         // The index of the pixel that holds the next HPC is at ceil(trueY - 0.5)
   343         // Since y1 and y2 are biased by -0.5 in tosubpixy(), this is simply
   337         // Since y1 and y2 are biased by -0.5 in tosubpixy(), this is simply
   344         // ceil(y1) or ceil(y2)
   338         // ceil(y1) or ceil(y2)
   345         // upper integer (inclusive)
   339         // upper integer (inclusive)
   359                 rdrCtx.stats.stat_rdr_addLine_skip.add(1);
   353                 rdrCtx.stats.stat_rdr_addLine_skip.add(1);
   360             }
   354             }
   361             return;
   355             return;
   362         }
   356         }
   363 
   357 
   364         // edge min/max X/Y are in subpixel space (inclusive) within bounds:
   358         // edge min/max X/Y are in subpixel space (half-open interval):
   365         // note: Use integer crossings to ensure consistent range within
   359         // note: Use integer crossings to ensure consistent range within
   366         // edgeBuckets / edgeBucketCounts arrays in case of NaN values (int = 0)
   360         // edgeBuckets / edgeBucketCounts arrays in case of NaN values (int = 0)
   367         if (firstCrossing < edgeMinY) {
   361         if (firstCrossing < edgeMinY) {
   368             edgeMinY = firstCrossing;
   362             edgeMinY = firstCrossing;
   369         }
   363         }
   374         // Use double-precision for improved accuracy:
   368         // Use double-precision for improved accuracy:
   375         final double x1d   = x1;
   369         final double x1d   = x1;
   376         final double y1d   = y1;
   370         final double y1d   = y1;
   377         final double slope = (x1d - x2) / (y1d - y2);
   371         final double slope = (x1d - x2) / (y1d - y2);
   378 
   372 
   379         if (slope >= 0.0) { // <==> x1 < x2
   373         if (slope >= 0.0d) { // <==> x1 < x2
   380             if (x1 < edgeMinX) {
   374             if (x1 < edgeMinX) {
   381                 edgeMinX = x1;
   375                 edgeMinX = x1;
   382             }
   376             }
   383             if (x2 > edgeMaxX) {
   377             if (x2 > edgeMaxX) {
   384                 edgeMaxX = x2;
   378                 edgeMaxX = x2;
   437         // epsilon is hard to pin down in floating point, but easy in fixed point, so if
   431         // epsilon is hard to pin down in floating point, but easy in fixed point, so if
   438         // we convert to fixed point then these operations get easier:
   432         // we convert to fixed point then these operations get easier:
   439         // long x1_fixed = x1_intercept * 2^32;  (fixed point 32.32 format)
   433         // long x1_fixed = x1_intercept * 2^32;  (fixed point 32.32 format)
   440         // curx = next VPC = fixed_floor(x1_fixed - 2^31 + 2^32 - 1)
   434         // curx = next VPC = fixed_floor(x1_fixed - 2^31 + 2^32 - 1)
   441         //                 = fixed_floor(x1_fixed + 2^31 - 1)
   435         //                 = fixed_floor(x1_fixed + 2^31 - 1)
   442         //                 = fixed_floor(x1_fixed + 0x7fffffff)
   436         //                 = fixed_floor(x1_fixed + 0x7FFFFFFF)
   443         // and error       = fixed_fract(x1_fixed + 0x7fffffff)
   437         // and error       = fixed_fract(x1_fixed + 0x7FFFFFFF)
   444         final double x1_intercept = x1d + (firstCrossing - y1d) * slope;
   438         final double x1_intercept = x1d + (firstCrossing - y1d) * slope;
   445 
   439 
   446         // inlined scalb(x1_intercept, 32):
   440         // inlined scalb(x1_intercept, 32):
   447         final long x1_fixed_biased = ((long) (POWER_2_TO_32 * x1_intercept))
   441         final long x1_fixed_biased = ((long) (POWER_2_TO_32 * x1_intercept))
   448                                      + 0x7fffffffL;
   442                                      + 0x7FFFFFFFL;
   449         // curx:
   443         // curx:
   450         // last bit corresponds to the orientation
   444         // last bit corresponds to the orientation
   451         _unsafe.putInt(addr, (((int) (x1_fixed_biased >> 31L)) & ALL_BUT_LSB) | or);
   445         _unsafe.putInt(addr, (((int) (x1_fixed_biased >> 31L)) & ALL_BUT_LSB) | or);
   452         addr += SIZE_INT;
   446         addr += SIZE_INT;
   453         _unsafe.putInt(addr,  ((int)  x1_fixed_biased) >>> 1);
   447         _unsafe.putInt(addr,  ((int)  x1_fixed_biased) >>> 1);
   472         final int bucketIdx = firstCrossing - _boundsMinY;
   466         final int bucketIdx = firstCrossing - _boundsMinY;
   473 
   467 
   474         // pointer from bucket
   468         // pointer from bucket
   475         _unsafe.putInt(addr, _edgeBuckets[bucketIdx]);
   469         _unsafe.putInt(addr, _edgeBuckets[bucketIdx]);
   476         addr += SIZE_INT;
   470         addr += SIZE_INT;
   477         // y max (inclusive)
   471         // y max (exclusive)
   478         _unsafe.putInt(addr,  lastCrossing);
   472         _unsafe.putInt(addr,  lastCrossing);
   479 
   473 
   480         // Update buckets:
   474         // Update buckets:
   481         // directly the edge struct "pointer"
   475         // directly the edge struct "pointer"
   482         _edgeBuckets[bucketIdx]       = edgePtr;
   476         _edgeBuckets[bucketIdx]       = edgePtr;
   483         _edgeBucketCounts[bucketIdx] += 2; // 1 << 1
   477         _edgeBucketCounts[bucketIdx] += 2; // 1 << 1
   484         // last bit means edge end
   478         // last bit means edge end
   485         _edgeBucketCounts[lastCrossing - _boundsMinY] |= 0x1;
   479         _edgeBucketCounts[lastCrossing - _boundsMinY] |= 0x1;
   486 
   480 
   487         // update sum of delta Y (subpixels):
       
   488         edgeSumDeltaY += (lastCrossing - firstCrossing);
       
   489 
       
   490         // update free pointer (ie length in bytes)
   481         // update free pointer (ie length in bytes)
   491         _edges.used += _SIZEOF_EDGE_BYTES;
   482         _edges.used += _SIZEOF_EDGE_BYTES;
   492 
   483 
   493         if (DO_MONITORS) {
   484         if (DO_MONITORS) {
   494             rdrCtx.stats.mon_rdr_addLine.stop();
   485             rdrCtx.stats.mon_rdr_addLine.stop();
   566         blkFlags     = blkFlags_ref.initial;
   557         blkFlags     = blkFlags_ref.initial;
   567     }
   558     }
   568 
   559 
   569     Renderer init(final int pix_boundsX, final int pix_boundsY,
   560     Renderer init(final int pix_boundsX, final int pix_boundsY,
   570                   final int pix_boundsWidth, final int pix_boundsHeight,
   561                   final int pix_boundsWidth, final int pix_boundsHeight,
   571                   final int windingRule) {
   562                   final int windingRule)
   572 
   563     {
   573         this.windingRule = windingRule;
   564         this.windingRule = windingRule;
   574 
   565 
   575         // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
   566         // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
   576         this.boundsMinX =  pix_boundsX << SUBPIXEL_LG_POSITIONS_X;
   567         this.boundsMinX =  pix_boundsX << SUBPIXEL_LG_POSITIONS_X;
   577         this.boundsMaxX =
   568         this.boundsMaxX =
   608 
   599 
   609         // reset used mark:
   600         // reset used mark:
   610         edgeCount = 0;
   601         edgeCount = 0;
   611         activeEdgeMaxUsed = 0;
   602         activeEdgeMaxUsed = 0;
   612         edges.used = 0;
   603         edges.used = 0;
   613 
       
   614         edgeSumDeltaY = 0;
       
   615 
   604 
   616         return this; // fluent API
   605         return this; // fluent API
   617     }
   606     }
   618 
   607 
   619     /**
   608     /**
   667             edges.fill(BYTE_0);
   656             edges.fill(BYTE_0);
   668         }
   657         }
   669         if (DO_MONITORS) {
   658         if (DO_MONITORS) {
   670             rdrCtx.stats.mon_rdr_endRendering.stop();
   659             rdrCtx.stats.mon_rdr_endRendering.stop();
   671         }
   660         }
       
   661         // recycle the RendererContext instance
       
   662         MarlinRenderingEngine.returnRendererContext(rdrCtx);
   672     }
   663     }
   673 
   664 
   674     private static float tosubpixx(final float pix_x) {
   665     private static float tosubpixx(final float pix_x) {
   675         return F_SUBPIXEL_POSITIONS_X * pix_x;
   666         return SUBPIXEL_SCALE_X * pix_x;
   676     }
   667     }
   677 
   668 
   678     private static float tosubpixy(final float pix_y) {
   669     private static float tosubpixy(final float pix_y) {
   679         // shift y by -0.5 for fast ceil(y - 0.5):
   670         // shift y by -0.5 for fast ceil(y - 0.5):
   680         return F_SUBPIXEL_POSITIONS_Y * pix_y - 0.5f;
   671         return SUBPIXEL_SCALE_Y * pix_y - 0.5f;
   681     }
   672     }
   682 
   673 
   683     @Override
   674     @Override
   684     public void moveTo(float pix_x0, float pix_y0) {
   675     public void moveTo(float pix_x0, float pix_y0) {
   685         closePath();
   676         closePath();
   700         y0 = y1;
   691         y0 = y1;
   701     }
   692     }
   702 
   693 
   703     @Override
   694     @Override
   704     public void curveTo(float x1, float y1,
   695     public void curveTo(float x1, float y1,
   705             float x2, float y2,
   696                         float x2, float y2,
   706             float x3, float y3)
   697                         float x3, float y3)
   707     {
   698     {
   708         final float xe = tosubpixx(x3);
   699         final float xe = tosubpixx(x3);
   709         final float ye = tosubpixy(y3);
   700         final float ye = tosubpixy(y3);
   710         curve.set(x0, y0, tosubpixx(x1), tosubpixy(y1),
   701         curve.set(x0, y0, tosubpixx(x1), tosubpixy(y1),
   711                           tosubpixx(x2), tosubpixy(y2), xe, ye);
   702                           tosubpixx(x2), tosubpixy(y2), xe, ye);
   967 
   958 
   968                     for (i = 0; i < numCrossings; i++) {
   959                     for (i = 0; i < numCrossings; i++) {
   969                         // get the pointer to the edge
   960                         // get the pointer to the edge
   970                         ecur = _edgePtrs[i];
   961                         ecur = _edgePtrs[i];
   971 
   962 
   972                         /* convert subpixel coordinates (float) into pixel
   963                         /* convert subpixel coordinates into pixel
   973                             positions (int) for coming scanline */
   964                             positions for coming scanline */
   974                         /* note: it is faster to always update edges even
   965                         /* note: it is faster to always update edges even
   975                            if it is removed from AEL for coming or last scanline */
   966                            if it is removed from AEL for coming or last scanline */
   976 
   967 
   977                         // random access so use unsafe:
   968                         // random access so use unsafe:
   978                         addr = addr0 + ecur; // ecur + OFF_F_CURX
   969                         addr = addr0 + ecur; // ecur + OFF_F_CURX
  1067 
  1058 
  1068                     for (i = 0; i < numCrossings; i++) {
  1059                     for (i = 0; i < numCrossings; i++) {
  1069                         // get the pointer to the edge
  1060                         // get the pointer to the edge
  1070                         ecur = _edgePtrs[i];
  1061                         ecur = _edgePtrs[i];
  1071 
  1062 
  1072                         /* convert subpixel coordinates (float) into pixel
  1063                         /* convert subpixel coordinates into pixel
  1073                             positions (int) for coming scanline */
  1064                             positions for coming scanline */
  1074                         /* note: it is faster to always update edges even
  1065                         /* note: it is faster to always update edges even
  1075                            if it is removed from AEL for coming or last scanline */
  1066                            if it is removed from AEL for coming or last scanline */
  1076 
  1067 
  1077                         // random access so use unsafe:
  1068                         // random access so use unsafe:
  1078                         addr = addr0 + ecur; // ecur + OFF_F_CURX
  1069                         addr = addr0 + ecur; // ecur + OFF_F_CURX
  1174 
  1165 
  1175                         if ((sum & 0x1) != 0) {
  1166                         if ((sum & 0x1) != 0) {
  1176                             // TODO: perform line clipping on left-right sides
  1167                             // TODO: perform line clipping on left-right sides
  1177                             // to avoid such bound checks:
  1168                             // to avoid such bound checks:
  1178                             x0 = (prev > bboxx0) ? prev : bboxx0;
  1169                             x0 = (prev > bboxx0) ? prev : bboxx0;
  1179                             x1 = (curx < bboxx1) ? curx : bboxx1;
  1170 
       
  1171                             if (curx < bboxx1) {
       
  1172                                 x1 = curx;
       
  1173                             } else {
       
  1174                                 x1 = bboxx1;
       
  1175                                 // skip right side (fast exit loop):
       
  1176                                 i = numCrossings;
       
  1177                             }
  1180 
  1178 
  1181                             if (x0 < x1) {
  1179                             if (x0 < x1) {
  1182                                 x0 -= bboxx0; // turn x0, x1 from coords to indices
  1180                                 x0 -= bboxx0; // turn x0, x1 from coords to indices
  1183                                 x1 -= bboxx0; // in the alpha array.
  1181                                 x1 -= bboxx0; // in the alpha array.
  1184 
  1182 
  1191                                     _alpha[pix_x    ] += tmp;
  1189                                     _alpha[pix_x    ] += tmp;
  1192                                     _alpha[pix_x + 1] -= tmp;
  1190                                     _alpha[pix_x + 1] -= tmp;
  1193 
  1191 
  1194                                     if (useBlkFlags) {
  1192                                     if (useBlkFlags) {
  1195                                         // flag used blocks:
  1193                                         // flag used blocks:
  1196                                         _blkFlags[pix_x >> _BLK_SIZE_LG] = 1;
  1194                                         // note: block processing handles extra pixel:
       
  1195                                         _blkFlags[pix_x    >> _BLK_SIZE_LG] = 1;
  1197                                     }
  1196                                     }
  1198                                 } else {
  1197                                 } else {
  1199                                     tmp = (x0 & _SUBPIXEL_MASK_X);
  1198                                     tmp = (x0 & _SUBPIXEL_MASK_X);
  1200                                     _alpha[pix_x    ]
  1199                                     _alpha[pix_x    ]
  1201                                         += (_SUBPIXEL_POSITIONS_X - tmp);
  1200                                         += (_SUBPIXEL_POSITIONS_X - tmp);
  1210                                     _alpha[pix_xmax + 1]
  1209                                     _alpha[pix_xmax + 1]
  1211                                         -= tmp;
  1210                                         -= tmp;
  1212 
  1211 
  1213                                     if (useBlkFlags) {
  1212                                     if (useBlkFlags) {
  1214                                         // flag used blocks:
  1213                                         // flag used blocks:
       
  1214                                         // note: block processing handles extra pixel:
  1215                                         _blkFlags[pix_x    >> _BLK_SIZE_LG] = 1;
  1215                                         _blkFlags[pix_x    >> _BLK_SIZE_LG] = 1;
  1216                                         _blkFlags[pix_xmax >> _BLK_SIZE_LG] = 1;
  1216                                         _blkFlags[pix_xmax >> _BLK_SIZE_LG] = 1;
  1217                                     }
  1217                                     }
  1218                                 }
  1218                                 }
  1219                             }
  1219                             }
  1235                             }
  1235                             }
  1236                         } else {
  1236                         } else {
  1237                             // TODO: perform line clipping on left-right sides
  1237                             // TODO: perform line clipping on left-right sides
  1238                             // to avoid such bound checks:
  1238                             // to avoid such bound checks:
  1239                             x0 = (prev > bboxx0) ? prev : bboxx0;
  1239                             x0 = (prev > bboxx0) ? prev : bboxx0;
  1240                             x1 = (curx < bboxx1) ? curx : bboxx1;
  1240 
       
  1241                             if (curx < bboxx1) {
       
  1242                                 x1 = curx;
       
  1243                             } else {
       
  1244                                 x1 = bboxx1;
       
  1245                                 // skip right side (fast exit loop):
       
  1246                                 i = numCrossings;
       
  1247                             }
  1241 
  1248 
  1242                             if (x0 < x1) {
  1249                             if (x0 < x1) {
  1243                                 x0 -= bboxx0; // turn x0, x1 from coords to indices
  1250                                 x0 -= bboxx0; // turn x0, x1 from coords to indices
  1244                                 x1 -= bboxx0; // in the alpha array.
  1251                                 x1 -= bboxx0; // in the alpha array.
  1245 
  1252 
  1252                                     _alpha[pix_x    ] += tmp;
  1259                                     _alpha[pix_x    ] += tmp;
  1253                                     _alpha[pix_x + 1] -= tmp;
  1260                                     _alpha[pix_x + 1] -= tmp;
  1254 
  1261 
  1255                                     if (useBlkFlags) {
  1262                                     if (useBlkFlags) {
  1256                                         // flag used blocks:
  1263                                         // flag used blocks:
  1257                                         _blkFlags[pix_x >> _BLK_SIZE_LG] = 1;
  1264                                         // note: block processing handles extra pixel:
       
  1265                                         _blkFlags[pix_x    >> _BLK_SIZE_LG] = 1;
  1258                                     }
  1266                                     }
  1259                                 } else {
  1267                                 } else {
  1260                                     tmp = (x0 & _SUBPIXEL_MASK_X);
  1268                                     tmp = (x0 & _SUBPIXEL_MASK_X);
  1261                                     _alpha[pix_x    ]
  1269                                     _alpha[pix_x    ]
  1262                                         += (_SUBPIXEL_POSITIONS_X - tmp);
  1270                                         += (_SUBPIXEL_POSITIONS_X - tmp);
  1271                                     _alpha[pix_xmax + 1]
  1279                                     _alpha[pix_xmax + 1]
  1272                                         -= tmp;
  1280                                         -= tmp;
  1273 
  1281 
  1274                                     if (useBlkFlags) {
  1282                                     if (useBlkFlags) {
  1275                                         // flag used blocks:
  1283                                         // flag used blocks:
       
  1284                                         // note: block processing handles extra pixel:
  1276                                         _blkFlags[pix_x    >> _BLK_SIZE_LG] = 1;
  1285                                         _blkFlags[pix_x    >> _BLK_SIZE_LG] = 1;
  1277                                         _blkFlags[pix_xmax >> _BLK_SIZE_LG] = 1;
  1286                                         _blkFlags[pix_xmax >> _BLK_SIZE_LG] = 1;
  1278                                     }
  1287                                     }
  1279                                 }
  1288                                 }
  1280                             }
  1289                             }
  1304                 minX = FloatMath.max(minX, bboxx0) >> _SUBPIXEL_LG_POSITIONS_X;
  1313                 minX = FloatMath.max(minX, bboxx0) >> _SUBPIXEL_LG_POSITIONS_X;
  1305                 maxX = FloatMath.min(maxX, bboxx1) >> _SUBPIXEL_LG_POSITIONS_X;
  1314                 maxX = FloatMath.min(maxX, bboxx1) >> _SUBPIXEL_LG_POSITIONS_X;
  1306 
  1315 
  1307                 if (maxX >= minX) {
  1316                 if (maxX >= minX) {
  1308                     // note: alpha array will be zeroed by copyAARow()
  1317                     // note: alpha array will be zeroed by copyAARow()
  1309                     // +2 because alpha [pix_minX; pix_maxX+1]
  1318                     // +1 because alpha [pix_minX; pix_maxX[
  1310                     // fix range [x0; x1[
  1319                     // fix range [x0; x1[
  1311                     copyAARow(_alpha, lastY, minX, maxX + 2, useBlkFlags);
  1320                     // note: if x1=bboxx1, then alpha is written up to bboxx1+1
       
  1321                     // inclusive: alpha[bboxx1] ignored, alpha[bboxx1+1] == 0
       
  1322                     // (normally so never cleared below)
       
  1323                     copyAARow(_alpha, lastY, minX, maxX + 1, useBlkFlags);
  1312 
  1324 
  1313                     // speculative for next pixel row (scanline coherence):
  1325                     // speculative for next pixel row (scanline coherence):
  1314                     if (_enableBlkFlagsHeuristics) {
  1326                     if (_enableBlkFlagsHeuristics) {
  1315                         // Use block flags if large pixel span and few crossings:
  1327                         // Use block flags if large pixel span and few crossings:
  1316                         // ie mean(distance between crossings) is larger than
  1328                         // ie mean(distance between crossings) is larger than
  1348         minX = FloatMath.max(minX, bboxx0) >> _SUBPIXEL_LG_POSITIONS_X;
  1360         minX = FloatMath.max(minX, bboxx0) >> _SUBPIXEL_LG_POSITIONS_X;
  1349         maxX = FloatMath.min(maxX, bboxx1) >> _SUBPIXEL_LG_POSITIONS_X;
  1361         maxX = FloatMath.min(maxX, bboxx1) >> _SUBPIXEL_LG_POSITIONS_X;
  1350 
  1362 
  1351         if (maxX >= minX) {
  1363         if (maxX >= minX) {
  1352             // note: alpha array will be zeroed by copyAARow()
  1364             // note: alpha array will be zeroed by copyAARow()
  1353             // +2 because alpha [pix_minX; pix_maxX+1]
  1365             // +1 because alpha [pix_minX; pix_maxX[
  1354             // fix range [x0; x1[
  1366             // fix range [x0; x1[
  1355             copyAARow(_alpha, y, minX, maxX + 2, useBlkFlags);
  1367             // note: if x1=bboxx1, then alpha is written up to bboxx1+1
       
  1368             // inclusive: alpha[bboxx1] ignored then cleared and
       
  1369             // alpha[bboxx1+1] == 0 (normally so never cleared after)
       
  1370             copyAARow(_alpha, y, minX, maxX + 1, useBlkFlags);
  1356         } else if (y != lastY) {
  1371         } else if (y != lastY) {
  1357             _cache.clearAARow(y);
  1372             _cache.clearAARow(y);
  1358         }
  1373         }
  1359 
  1374 
  1360         // update member:
  1375         // update member:
  1373         }
  1388         }
  1374         if (edgeMinY == Integer.MAX_VALUE) {
  1389         if (edgeMinY == Integer.MAX_VALUE) {
  1375             return false; // undefined edges bounds
  1390             return false; // undefined edges bounds
  1376         }
  1391         }
  1377 
  1392 
  1378         final int _boundsMinY = boundsMinY;
  1393         // bounds as half-open intervals
  1379         final int _boundsMaxY = boundsMaxY;
       
  1380 
       
  1381         // bounds as inclusive intervals
       
  1382         final int spminX = FloatMath.max(FloatMath.ceil_int(edgeMinX - 0.5f), boundsMinX);
  1394         final int spminX = FloatMath.max(FloatMath.ceil_int(edgeMinX - 0.5f), boundsMinX);
  1383         final int spmaxX = FloatMath.min(FloatMath.ceil_int(edgeMaxX - 0.5f), boundsMaxX - 1);
  1395         final int spmaxX = FloatMath.min(FloatMath.ceil_int(edgeMaxX - 0.5f), boundsMaxX);
  1384 
  1396 
  1385         // edge Min/Max Y are already rounded to subpixels within bounds:
  1397         // edge Min/Max Y are already rounded to subpixels within bounds:
  1386         final int spminY = edgeMinY;
  1398         final int spminY = edgeMinY;
  1387         final int spmaxY;
  1399         final int spmaxY = edgeMaxY;
  1388         int maxY = edgeMaxY;
  1400 
  1389 
  1401         buckets_minY = spminY - boundsMinY;
  1390         if (maxY <= _boundsMaxY - 1) {
  1402         buckets_maxY = spmaxY - boundsMinY;
  1391             spmaxY = maxY;
       
  1392         } else {
       
  1393             spmaxY = _boundsMaxY - 1;
       
  1394             maxY   = _boundsMaxY;
       
  1395         }
       
  1396         buckets_minY = spminY - _boundsMinY;
       
  1397         buckets_maxY = maxY   - _boundsMinY;
       
  1398 
  1403 
  1399         if (DO_LOG_BOUNDS) {
  1404         if (DO_LOG_BOUNDS) {
  1400             MarlinUtils.logInfo("edgesXY = [" + edgeMinX + " ... " + edgeMaxX
  1405             MarlinUtils.logInfo("edgesXY = [" + edgeMinX + " ... " + edgeMaxX
  1401                                 + "][" + edgeMinY + " ... " + edgeMaxY + "]");
  1406                                 + "[ [" + edgeMinY + " ... " + edgeMaxY + "[");
  1402             MarlinUtils.logInfo("spXY    = [" + spminX + " ... " + spmaxX
  1407             MarlinUtils.logInfo("spXY    = [" + spminX + " ... " + spmaxX
  1403                                 + "][" + spminY + " ... " + spmaxY + "]");
  1408                                 + "[ [" + spminY + " ... " + spmaxY + "[");
  1404         }
  1409         }
  1405 
  1410 
  1406         // test clipping for shapes out of bounds
  1411         // test clipping for shapes out of bounds
  1407         if ((spminX > spmaxX) || (spminY > spmaxY)) {
  1412         if ((spminX >= spmaxX) || (spminY >= spmaxY)) {
  1408             return false;
  1413             return false;
  1409         }
  1414         }
  1410 
  1415 
  1411         // half open intervals
  1416         // half open intervals
  1412         // inclusive:
  1417         // inclusive:
  1417         final int pminY =  spminY                    >> SUBPIXEL_LG_POSITIONS_Y;
  1422         final int pminY =  spminY                    >> SUBPIXEL_LG_POSITIONS_Y;
  1418         // exclusive:
  1423         // exclusive:
  1419         final int pmaxY = (spmaxY + SUBPIXEL_MASK_Y) >> SUBPIXEL_LG_POSITIONS_Y;
  1424         final int pmaxY = (spmaxY + SUBPIXEL_MASK_Y) >> SUBPIXEL_LG_POSITIONS_Y;
  1420 
  1425 
  1421         // store BBox to answer ptg.getBBox():
  1426         // store BBox to answer ptg.getBBox():
  1422         this.cache.init(pminX, pminY, pmaxX, pmaxY, edgeSumDeltaY);
  1427         this.cache.init(pminX, pminY, pmaxX, pmaxY);
  1423 
  1428 
  1424         // Heuristics for using block flags:
  1429         // Heuristics for using block flags:
  1425         if (ENABLE_BLOCK_FLAGS) {
  1430         if (ENABLE_BLOCK_FLAGS) {
  1426             enableBlkFlags = this.cache.useRLE;
  1431             enableBlkFlags = this.cache.useRLE;
  1427             prevUseBlkFlags = enableBlkFlags && !ENABLE_BLOCK_FLAGS_HEURISTICS;
  1432             prevUseBlkFlags = enableBlkFlags && !ENABLE_BLOCK_FLAGS_HEURISTICS;
  1428 
  1433 
  1429             if (enableBlkFlags) {
  1434             if (enableBlkFlags) {
  1430                 // ensure blockFlags array is large enough:
  1435                 // ensure blockFlags array is large enough:
  1431                 // note: +2 to ensure enough space left at end
  1436                 // note: +2 to ensure enough space left at end
  1432                 final int nxTiles = ((pmaxX - pminX) >> TILE_SIZE_LG) + 2;
  1437                 final int blkLen = ((pmaxX - pminX) >> BLOCK_SIZE_LG) + 2;
  1433                 if (nxTiles > INITIAL_ARRAY) {
  1438                 if (blkLen > INITIAL_ARRAY) {
  1434                     blkFlags = blkFlags_ref.getArray(nxTiles);
  1439                     blkFlags = blkFlags_ref.getArray(blkLen);
  1435                 }
  1440                 }
  1436             }
  1441             }
  1437         }
  1442         }
  1438 
  1443 
  1439         // memorize the rendering bounding box:
  1444         // memorize the rendering bounding box:
  1444         // exclusive:
  1449         // exclusive:
  1445         bbox_spmaxX = pmaxX << SUBPIXEL_LG_POSITIONS_X;
  1450         bbox_spmaxX = pmaxX << SUBPIXEL_LG_POSITIONS_X;
  1446         // inclusive:
  1451         // inclusive:
  1447         bbox_spminY = spminY;
  1452         bbox_spminY = spminY;
  1448         // exclusive:
  1453         // exclusive:
  1449         bbox_spmaxY = FloatMath.min(spmaxY + 1, pmaxY << SUBPIXEL_LG_POSITIONS_Y);
  1454         bbox_spmaxY = spmaxY;
  1450 
  1455 
  1451         if (DO_LOG_BOUNDS) {
  1456         if (DO_LOG_BOUNDS) {
  1452             MarlinUtils.logInfo("pXY       = [" + pminX + " ... " + pmaxX
  1457             MarlinUtils.logInfo("pXY       = [" + pminX + " ... " + pmaxX
  1453                                 + "[ [" + pminY + " ... " + pmaxY + "[");
  1458                                 + "[ [" + pminY + " ... " + pmaxY + "[");
  1454             MarlinUtils.logInfo("bbox_spXY = [" + bbox_spminX + " ... "
  1459             MarlinUtils.logInfo("bbox_spXY = [" + bbox_spminX + " ... "
  1502 
  1507 
  1503     void copyAARow(final int[] alphaRow,
  1508     void copyAARow(final int[] alphaRow,
  1504                    final int pix_y, final int pix_from, final int pix_to,
  1509                    final int pix_y, final int pix_from, final int pix_to,
  1505                    final boolean useBlockFlags)
  1510                    final boolean useBlockFlags)
  1506     {
  1511     {
       
  1512         if (DO_MONITORS) {
       
  1513             rdrCtx.stats.mon_rdr_copyAARow.start();
       
  1514         }
  1507         if (useBlockFlags) {
  1515         if (useBlockFlags) {
  1508             if (DO_STATS) {
  1516             if (DO_STATS) {
  1509                 rdrCtx.stats.hist_tile_generator_encoding.add(1);
  1517                 rdrCtx.stats.hist_tile_generator_encoding.add(1);
  1510             }
  1518             }
  1511             cache.copyAARowRLE_WithBlockFlags(blkFlags, alphaRow, pix_y, pix_from, pix_to);
  1519             cache.copyAARowRLE_WithBlockFlags(blkFlags, alphaRow, pix_y, pix_from, pix_to);
  1513             if (DO_STATS) {
  1521             if (DO_STATS) {
  1514                 rdrCtx.stats.hist_tile_generator_encoding.add(0);
  1522                 rdrCtx.stats.hist_tile_generator_encoding.add(0);
  1515             }
  1523             }
  1516             cache.copyAARowNoRLE(alphaRow, pix_y, pix_from, pix_to);
  1524             cache.copyAARowNoRLE(alphaRow, pix_y, pix_from, pix_to);
  1517         }
  1525         }
       
  1526         if (DO_MONITORS) {
       
  1527             rdrCtx.stats.mon_rdr_copyAARow.stop();
       
  1528         }
  1518     }
  1529     }
  1519 }
  1530 }