| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.java2d.marlin;  | 
 | 
 | 
 | 
import sun.java2d.pipe.AATileGenerator;  | 
 | 
import sun.misc.Unsafe;  | 
 | 
 | 
 | 
final class MarlinTileGenerator implements AATileGenerator, MarlinConst { | 
 | 
 | 
 | 
    private static final int MAX_TILE_ALPHA_SUM = TILE_SIZE * TILE_SIZE  | 
 | 
                                                      * MAX_AA_ALPHA;  | 
 | 
 | 
 | 
    private final Renderer rdr;  | 
 | 
    private final MarlinCache cache;  | 
 | 
    private int x, y;  | 
 | 
 | 
 | 
    MarlinTileGenerator(Renderer r) { | 
 | 
        this.rdr = r;  | 
 | 
        this.cache = r.cache;  | 
 | 
    }  | 
 | 
 | 
 | 
    MarlinTileGenerator init() { | 
 | 
        this.x = cache.bboxX0;  | 
 | 
        this.y = cache.bboxY0;  | 
 | 
 | 
 | 
        return this;   | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    @Override  | 
 | 
    public void dispose() { | 
 | 
        if (doMonitors) { | 
 | 
              | 
 | 
            RendererContext.stats.mon_pipe_renderTiles.stop();  | 
 | 
        }  | 
 | 
          | 
 | 
        cache.dispose();  | 
 | 
          | 
 | 
        rdr.dispose();  | 
 | 
          | 
 | 
        MarlinRenderingEngine.returnRendererContext(rdr.rdrCtx);  | 
 | 
    }  | 
 | 
 | 
 | 
    void getBbox(int bbox[]) { | 
 | 
        bbox[0] = cache.bboxX0;  | 
 | 
        bbox[1] = cache.bboxY0;  | 
 | 
        bbox[2] = cache.bboxX1;  | 
 | 
        bbox[3] = cache.bboxY1;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    @Override  | 
 | 
    public int getTileWidth() { | 
 | 
        if (doMonitors) { | 
 | 
              | 
 | 
            RendererContext.stats.mon_pipe_renderTiles.start();  | 
 | 
        }  | 
 | 
        return TILE_SIZE;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    @Override  | 
 | 
    public int getTileHeight() { | 
 | 
        return TILE_SIZE;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    @Override  | 
 | 
    public int getTypicalAlpha() { | 
 | 
        int al = cache.alphaSumInTile(x);  | 
 | 
        // Note: if we have a filled rectangle that doesn't end on a tile  | 
 | 
        // border, we could still return 0xff, even though al!=maxTileAlphaSum  | 
 | 
        // This is because if we return 0xff, our users will fill a rectangle  | 
 | 
        // starting at x,y that has width = Math.min(TILE_SIZE, bboxX1-x),  | 
 | 
        // and height min(TILE_SIZE,bboxY1-y), which is what should happen.  | 
 | 
        // However, to support this, we would have to use 2 Math.min's  | 
 | 
        // and 2 multiplications per tile, instead of just 2 multiplications  | 
 | 
        // to compute maxTileAlphaSum. The savings offered would probably  | 
 | 
        // not be worth it, considering how rare this case is.  | 
 | 
        // Note: I have not tested this, so in the future if it is determined  | 
 | 
        // that it is worth it, it should be implemented. Perhaps this method's  | 
 | 
        // interface should be changed to take arguments the width and height  | 
 | 
        // of the current tile. This would eliminate the 2 Math.min calls that  | 
 | 
        // would be needed here, since our caller needs to compute these 2  | 
 | 
          | 
 | 
        final int alpha = (al == 0x00 ? 0x00  | 
 | 
                              : (al == MAX_TILE_ALPHA_SUM ? 0xff : 0x80));  | 
 | 
        if (doStats) { | 
 | 
            RendererContext.stats.hist_tile_generator_alpha.add(alpha);  | 
 | 
        }  | 
 | 
        return alpha;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    @Override  | 
 | 
    public void nextTile() { | 
 | 
        if ((x += TILE_SIZE) >= cache.bboxX1) { | 
 | 
            x = cache.bboxX0;  | 
 | 
            y += TILE_SIZE;  | 
 | 
 | 
 | 
            if (y < cache.bboxY1) { | 
 | 
                // compute for the tile line  | 
 | 
                  | 
 | 
                this.rdr.endRendering(y);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    @Override  | 
 | 
    public void getAlpha(final byte tile[], final int offset,  | 
 | 
                                            final int rowstride)  | 
 | 
    { | 
 | 
        if (cache.useRLE) { | 
 | 
            getAlphaRLE(tile, offset, rowstride);  | 
 | 
        } else { | 
 | 
            getAlphaNoRLE(tile, offset, rowstride);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private void getAlphaNoRLE(final byte tile[], final int offset,  | 
 | 
                               final int rowstride)  | 
 | 
    { | 
 | 
        if (doMonitors) { | 
 | 
            RendererContext.stats.mon_ptg_getAlpha.start();  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        final MarlinCache _cache = this.cache;  | 
 | 
        final long[] rowAAChunkIndex = _cache.rowAAChunkIndex;  | 
 | 
        final int[] rowAAx0 = _cache.rowAAx0;  | 
 | 
        final int[] rowAAx1 = _cache.rowAAx1;  | 
 | 
 | 
 | 
        final int x0 = this.x;  | 
 | 
        final int x1 = FloatMath.min(x0 + TILE_SIZE, _cache.bboxX1);  | 
 | 
 | 
 | 
          | 
 | 
        final int y0 = 0;  | 
 | 
        final int y1 = FloatMath.min(this.y + TILE_SIZE, _cache.bboxY1) - this.y;  | 
 | 
 | 
 | 
        if (doLogBounds) { | 
 | 
            MarlinUtils.logInfo("getAlpha = [" + x0 + " ... " + x1 | 
 | 
                                + "[ [" + y0 + " ... " + y1 + "[");  | 
 | 
        }  | 
 | 
 | 
 | 
        final Unsafe _unsafe = OffHeapArray.unsafe;  | 
 | 
        final long SIZE = 1L;  | 
 | 
        final long addr_rowAA = _cache.rowAAChunk.address;  | 
 | 
        long addr;  | 
 | 
 | 
 | 
        final int skipRowPixels = (rowstride - (x1 - x0));  | 
 | 
 | 
 | 
        int aax0, aax1, end;  | 
 | 
        int idx = offset;  | 
 | 
 | 
 | 
        for (int cy = y0, cx; cy < y1; cy++) { | 
 | 
              | 
 | 
            cx = x0;  | 
 | 
 | 
 | 
            aax1 = rowAAx1[cy];   | 
 | 
 | 
 | 
            // quick check if there is AA data  | 
 | 
              | 
 | 
            if (aax1 > x0) { | 
 | 
                aax0 = rowAAx0[cy];   | 
 | 
 | 
 | 
                if (aax0 < x1) { | 
 | 
                    // note: cx is the cursor pointer in the tile array  | 
 | 
                      | 
 | 
                    cx = aax0;  | 
 | 
 | 
 | 
                      | 
 | 
                    if (cx <= x0) { | 
 | 
                        cx = x0;  | 
 | 
                    } else { | 
 | 
                          | 
 | 
                        for (end = x0; end < cx; end++) { | 
 | 
                            tile[idx++] = 0;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
 | 
 | 
                    // now: cx >= x0 but cx < aax0 (x1 < aax0)  | 
 | 
 | 
 | 
                      | 
 | 
                    addr = addr_rowAA + rowAAChunkIndex[cy] + (cx - aax0);  | 
 | 
 | 
 | 
                    for (end = (aax1 <= x1) ? aax1 : x1; cx < end; cx++) { | 
 | 
                        // cx inside tile[x0; x1[ :  | 
 | 
                        tile[idx++] = _unsafe.getByte(addr);   | 
 | 
                        addr += SIZE;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            while (cx < x1) { | 
 | 
                tile[idx++] = 0;  | 
 | 
                cx++;  | 
 | 
            }  | 
 | 
 | 
 | 
            if (doTrace) { | 
 | 
                for (int i = idx - (x1 - x0); i < idx; i++) { | 
 | 
                    System.out.print(hex(tile[i], 2));  | 
 | 
                }  | 
 | 
                System.out.println();  | 
 | 
            }  | 
 | 
 | 
 | 
            idx += skipRowPixels;  | 
 | 
        }  | 
 | 
 | 
 | 
        nextTile();  | 
 | 
 | 
 | 
        if (doMonitors) { | 
 | 
            RendererContext.stats.mon_ptg_getAlpha.stop();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private void getAlphaRLE(final byte tile[], final int offset,  | 
 | 
                             final int rowstride)  | 
 | 
    { | 
 | 
        if (doMonitors) { | 
 | 
            RendererContext.stats.mon_ptg_getAlpha.start();  | 
 | 
        }  | 
 | 
 | 
 | 
        // Decode run-length encoded alpha mask data  | 
 | 
        // The data for row j begins at cache.rowOffsetsRLE[j]  | 
 | 
        // and is encoded as a set of 2-byte pairs (val, runLen)  | 
 | 
        // terminated by a (0, 0) pair.  | 
 | 
 | 
 | 
          | 
 | 
        final MarlinCache _cache = this.cache;  | 
 | 
        final long[] rowAAChunkIndex = _cache.rowAAChunkIndex;  | 
 | 
        final int[] rowAAx0 = _cache.rowAAx0;  | 
 | 
        final int[] rowAAx1 = _cache.rowAAx1;  | 
 | 
        final int[] rowAAEnc = _cache.rowAAEnc;  | 
 | 
        final long[] rowAALen = _cache.rowAALen;  | 
 | 
        final long[] rowAAPos = _cache.rowAAPos;  | 
 | 
 | 
 | 
        final int x0 = this.x;  | 
 | 
        final int x1 = FloatMath.min(x0 + TILE_SIZE, _cache.bboxX1);  | 
 | 
 | 
 | 
          | 
 | 
        final int y0 = 0;  | 
 | 
        final int y1 = FloatMath.min(this.y + TILE_SIZE, _cache.bboxY1) - this.y;  | 
 | 
 | 
 | 
        if (doLogBounds) { | 
 | 
            MarlinUtils.logInfo("getAlpha = [" + x0 + " ... " + x1 | 
 | 
                                + "[ [" + y0 + " ... " + y1 + "[");  | 
 | 
        }  | 
 | 
 | 
 | 
        final Unsafe _unsafe = OffHeapArray.unsafe;  | 
 | 
        final long SIZE_BYTE = 1L;  | 
 | 
        final long SIZE_INT = 4L;  | 
 | 
        final long addr_rowAA = _cache.rowAAChunk.address;  | 
 | 
        long addr, addr_row, last_addr, addr_end;  | 
 | 
 | 
 | 
        final int skipRowPixels = (rowstride - (x1 - x0));  | 
 | 
 | 
 | 
        int cx, cy, cx1;  | 
 | 
        int rx0, rx1, runLen, end;  | 
 | 
        int packed;  | 
 | 
        byte val;  | 
 | 
        int idx = offset;  | 
 | 
 | 
 | 
        for (cy = y0; cy < y1; cy++) { | 
 | 
              | 
 | 
            cx = x0;  | 
 | 
 | 
 | 
            if (rowAAEnc[cy] == 0) { | 
 | 
                // Raw encoding:  | 
 | 
 | 
 | 
                final int aax1 = rowAAx1[cy];   | 
 | 
 | 
 | 
                // quick check if there is AA data  | 
 | 
                  | 
 | 
                if (aax1 > x0) { | 
 | 
                    final int aax0 = rowAAx0[cy];   | 
 | 
 | 
 | 
                    if (aax0 < x1) { | 
 | 
                        // note: cx is the cursor pointer in the tile array  | 
 | 
                          | 
 | 
                        cx = aax0;  | 
 | 
 | 
 | 
                          | 
 | 
                        if (cx <= x0) { | 
 | 
                            cx = x0;  | 
 | 
                        } else { | 
 | 
                              | 
 | 
                            for (end = x0; end < cx; end++) { | 
 | 
                                tile[idx++] = 0;  | 
 | 
                            }  | 
 | 
                        }  | 
 | 
 | 
 | 
                        // now: cx >= x0 but cx < aax0 (x1 < aax0)  | 
 | 
 | 
 | 
                          | 
 | 
                        addr = addr_rowAA + rowAAChunkIndex[cy] + (cx - aax0);  | 
 | 
 | 
 | 
                        for (end = (aax1 <= x1) ? aax1 : x1; cx < end; cx++) { | 
 | 
                            tile[idx++] = _unsafe.getByte(addr);   | 
 | 
                            addr += SIZE_BYTE;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            } else { | 
 | 
                // RLE encoding:  | 
 | 
 | 
 | 
                // quick check if there is AA data  | 
 | 
                  | 
 | 
                if (rowAAx1[cy] > x0) { // last pixel exclusive | 
 | 
 | 
 | 
                    cx = rowAAx0[cy];   | 
 | 
                    if (cx > x1) { | 
 | 
                        cx = x1;  | 
 | 
                    }  | 
 | 
 | 
 | 
                      | 
 | 
                    for (int i = x0; i < cx; i++) { | 
 | 
                        tile[idx++] = 0;  | 
 | 
                    }  | 
 | 
 | 
 | 
                      | 
 | 
                    addr_row = addr_rowAA + rowAAChunkIndex[cy];  | 
 | 
                    // get row end address:  | 
 | 
                    addr_end = addr_row + rowAALen[cy];   | 
 | 
 | 
 | 
                      | 
 | 
                    addr = addr_row + rowAAPos[cy];  | 
 | 
 | 
 | 
                    last_addr = 0L;  | 
 | 
 | 
 | 
                    while ((cx < x1) && (addr < addr_end)) { | 
 | 
                          | 
 | 
                        last_addr = addr;  | 
 | 
 | 
 | 
                          | 
 | 
                        packed = _unsafe.getInt(addr);  | 
 | 
 | 
 | 
                          | 
 | 
                        cx1 = (packed >> 8);  | 
 | 
                          | 
 | 
                        addr += SIZE_INT;  | 
 | 
 | 
 | 
                        rx0 = cx;  | 
 | 
                        if (rx0 < x0) { | 
 | 
                            rx0 = x0;  | 
 | 
                        }  | 
 | 
                        rx1 = cx = cx1;  | 
 | 
                        if (rx1 > x1) { | 
 | 
                            rx1 = x1;  | 
 | 
                            cx  = x1;   | 
 | 
                        }  | 
 | 
                          | 
 | 
                        runLen = rx1 - rx0;  | 
 | 
 | 
 | 
                          | 
 | 
                        if (runLen > 0) { | 
 | 
                            val = (byte)(packed & 0xFF);   | 
 | 
 | 
 | 
                            do { | 
 | 
                                tile[idx++] = val;  | 
 | 
                            } while (--runLen > 0);  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
 | 
 | 
                      | 
 | 
                    if (last_addr != 0L) { | 
 | 
                        // Fix x0:  | 
 | 
                        rowAAx0[cy]  = cx;   | 
 | 
                          | 
 | 
                        rowAAPos[cy] = (last_addr - addr_row);  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            while (cx < x1) { | 
 | 
                tile[idx++] = 0;  | 
 | 
                cx++;  | 
 | 
            }  | 
 | 
 | 
 | 
            if (doTrace) { | 
 | 
                for (int i = idx - (x1 - x0); i < idx; i++) { | 
 | 
                    System.out.print(hex(tile[i], 2));  | 
 | 
                }  | 
 | 
                System.out.println();  | 
 | 
            }  | 
 | 
 | 
 | 
            idx += skipRowPixels;  | 
 | 
        }  | 
 | 
 | 
 | 
        nextTile();  | 
 | 
 | 
 | 
        if (doMonitors) { | 
 | 
            RendererContext.stats.mon_ptg_getAlpha.stop();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    static String hex(int v, int d) { | 
 | 
        String s = Integer.toHexString(v);  | 
 | 
        while (s.length() < d) { | 
 | 
            s = "0" + s;  | 
 | 
        }  | 
 | 
        return s.substring(0, d);  | 
 | 
    }  | 
 | 
}  |