src/java.desktop/share/classes/sun/java2d/pisces/PiscesTileGenerator.java
changeset 47919 66350f079368
parent 47918 a82c9f231737
parent 47880 bbd692ad4fa3
child 47920 52c9e8d2f8d9
child 48093 2cb07c3778e1
equal deleted inserted replaced
47918:a82c9f231737 47919:66350f079368
     1 /*
       
     2  * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     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
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.java2d.pisces;
       
    27 
       
    28 import java.util.Map;
       
    29 import java.util.concurrent.ConcurrentHashMap;
       
    30 
       
    31 import sun.java2d.pipe.AATileGenerator;
       
    32 
       
    33 final class PiscesTileGenerator implements AATileGenerator {
       
    34     public static final int TILE_SIZE = PiscesCache.TILE_SIZE;
       
    35 
       
    36     // perhaps we should be using weak references here, but right now
       
    37     // that's not necessary. The way the renderer is, this map will
       
    38     // never contain more than one element - the one with key 64, since
       
    39     // we only do 8x8 supersampling.
       
    40     private static final Map<Integer, byte[]> alphaMapsCache = new
       
    41                    ConcurrentHashMap<Integer, byte[]>();
       
    42 
       
    43     PiscesCache cache;
       
    44     int x, y;
       
    45     final int maxalpha;
       
    46     private final int maxTileAlphaSum;
       
    47 
       
    48     // The alpha map used by this object (taken out of our map cache) to convert
       
    49     // pixel coverage counts gotten from PiscesCache (which are in the range
       
    50     // [0, maxalpha]) into alpha values, which are in [0,256).
       
    51     byte alphaMap[];
       
    52 
       
    53     public PiscesTileGenerator(Renderer r, int maxalpha) {
       
    54         this.cache = r.getCache();
       
    55         this.x = cache.bboxX0;
       
    56         this.y = cache.bboxY0;
       
    57         this.alphaMap = getAlphaMap(maxalpha);
       
    58         this.maxalpha = maxalpha;
       
    59         this.maxTileAlphaSum = TILE_SIZE*TILE_SIZE*maxalpha;
       
    60     }
       
    61 
       
    62     private static byte[] buildAlphaMap(int maxalpha) {
       
    63         byte[] alMap = new byte[maxalpha+1];
       
    64         int halfmaxalpha = maxalpha>>2;
       
    65         for (int i = 0; i <= maxalpha; i++) {
       
    66             alMap[i] = (byte) ((i * 255 + halfmaxalpha) / maxalpha);
       
    67         }
       
    68         return alMap;
       
    69     }
       
    70 
       
    71     public static byte[] getAlphaMap(int maxalpha) {
       
    72         if (!alphaMapsCache.containsKey(maxalpha)) {
       
    73             alphaMapsCache.put(maxalpha, buildAlphaMap(maxalpha));
       
    74         }
       
    75         return alphaMapsCache.get(maxalpha);
       
    76     }
       
    77 
       
    78     public void getBbox(int bbox[]) {
       
    79         cache.getBBox(bbox);
       
    80         //System.out.println("bbox["+bbox[0]+", "+bbox[1]+" => "+bbox[2]+", "+bbox[3]+"]");
       
    81     }
       
    82 
       
    83     /**
       
    84      * Gets the width of the tiles that the generator batches output into.
       
    85      * @return the width of the standard alpha tile
       
    86      */
       
    87     public int getTileWidth() {
       
    88         return TILE_SIZE;
       
    89     }
       
    90 
       
    91     /**
       
    92      * Gets the height of the tiles that the generator batches output into.
       
    93      * @return the height of the standard alpha tile
       
    94      */
       
    95     public int getTileHeight() {
       
    96         return TILE_SIZE;
       
    97     }
       
    98 
       
    99     /**
       
   100      * Gets the typical alpha value that will characterize the current
       
   101      * tile.
       
   102      * The answer may be 0x00 to indicate that the current tile has
       
   103      * no coverage in any of its pixels, or it may be 0xff to indicate
       
   104      * that the current tile is completely covered by the path, or any
       
   105      * other value to indicate non-trivial coverage cases.
       
   106      * @return 0x00 for no coverage, 0xff for total coverage, or any other
       
   107      *         value for partial coverage of the tile
       
   108      */
       
   109     public int getTypicalAlpha() {
       
   110         int al = cache.alphaSumInTile(x, y);
       
   111         // Note: if we have a filled rectangle that doesn't end on a tile
       
   112         // border, we could still return 0xff, even though al!=maxTileAlphaSum
       
   113         // This is because if we return 0xff, our users will fill a rectangle
       
   114         // starting at x,y that has width = Math.min(TILE_SIZE, bboxX1-x),
       
   115         // and height min(TILE_SIZE,bboxY1-y), which is what should happen.
       
   116         // However, to support this, we would have to use 2 Math.min's
       
   117         // and 2 multiplications per tile, instead of just 2 multiplications
       
   118         // to compute maxTileAlphaSum. The savings offered would probably
       
   119         // not be worth it, considering how rare this case is.
       
   120         // Note: I have not tested this, so in the future if it is determined
       
   121         // that it is worth it, it should be implemented. Perhaps this method's
       
   122         // interface should be changed to take arguments the width and height
       
   123         // of the current tile. This would eliminate the 2 Math.min calls that
       
   124         // would be needed here, since our caller needs to compute these 2
       
   125         // values anyway.
       
   126         return (al == 0x00 ? 0x00 :
       
   127             (al == maxTileAlphaSum ? 0xff : 0x80));
       
   128     }
       
   129 
       
   130     /**
       
   131      * Skips the current tile and moves on to the next tile.
       
   132      * Either this method, or the getAlpha() method should be called
       
   133      * once per tile, but not both.
       
   134      */
       
   135     public void nextTile() {
       
   136         if ((x += TILE_SIZE) >= cache.bboxX1) {
       
   137             x = cache.bboxX0;
       
   138             y += TILE_SIZE;
       
   139         }
       
   140     }
       
   141 
       
   142     /**
       
   143      * Gets the alpha coverage values for the current tile.
       
   144      * Either this method, or the nextTile() method should be called
       
   145      * once per tile, but not both.
       
   146      */
       
   147     public void getAlpha(byte tile[], int offset, int rowstride) {
       
   148         // Decode run-length encoded alpha mask data
       
   149         // The data for row j begins at cache.rowOffsetsRLE[j]
       
   150         // and is encoded as a set of 2-byte pairs (val, runLen)
       
   151         // terminated by a (0, 0) pair.
       
   152 
       
   153         int x0 = this.x;
       
   154         int x1 = x0 + TILE_SIZE;
       
   155         int y0 = this.y;
       
   156         int y1 = y0 + TILE_SIZE;
       
   157         if (x1 > cache.bboxX1) x1 = cache.bboxX1;
       
   158         if (y1 > cache.bboxY1) y1 = cache.bboxY1;
       
   159         y0 -= cache.bboxY0;
       
   160         y1 -= cache.bboxY0;
       
   161 
       
   162         int idx = offset;
       
   163         for (int cy = y0; cy < y1; cy++) {
       
   164             int[] row = cache.rowAARLE[cy];
       
   165             assert row != null;
       
   166             int cx = cache.minTouched(cy);
       
   167             if (cx > x1) cx = x1;
       
   168 
       
   169             for (int i = x0; i < cx; i++) {
       
   170                 tile[idx++] = 0x00;
       
   171             }
       
   172 
       
   173             int pos = 2;
       
   174             while (cx < x1 && pos < row[1]) {
       
   175                 byte val;
       
   176                 int runLen = 0;
       
   177                 assert row[1] > 2;
       
   178                 try {
       
   179                     val = alphaMap[row[pos]];
       
   180                     runLen = row[pos + 1];
       
   181                     assert runLen > 0;
       
   182                 } catch (RuntimeException e0) {
       
   183                     System.out.println("maxalpha = "+maxalpha);
       
   184                     System.out.println("tile["+x0+", "+y0+
       
   185                                        " => "+x1+", "+y1+"]");
       
   186                     System.out.println("cx = "+cx+", cy = "+cy);
       
   187                     System.out.println("idx = "+idx+", pos = "+pos);
       
   188                     System.out.println("len = "+runLen);
       
   189                     System.out.print(cache.toString());
       
   190                     e0.printStackTrace();
       
   191                     throw e0;
       
   192                 }
       
   193 
       
   194                 int rx0 = cx;
       
   195                 cx += runLen;
       
   196                 int rx1 = cx;
       
   197                 if (rx0 < x0) rx0 = x0;
       
   198                 if (rx1 > x1) rx1 = x1;
       
   199                 runLen = rx1 - rx0;
       
   200                 //System.out.println("M["+runLen+"]");
       
   201                 while (--runLen >= 0) {
       
   202                     try {
       
   203                         tile[idx++] = val;
       
   204                     } catch (RuntimeException e) {
       
   205                         System.out.println("maxalpha = "+maxalpha);
       
   206                         System.out.println("tile["+x0+", "+y0+
       
   207                                            " => "+x1+", "+y1+"]");
       
   208                         System.out.println("cx = "+cx+", cy = "+cy);
       
   209                         System.out.println("idx = "+idx+", pos = "+pos);
       
   210                         System.out.println("rx0 = "+rx0+", rx1 = "+rx1);
       
   211                         System.out.println("len = "+runLen);
       
   212                         System.out.print(cache.toString());
       
   213                         e.printStackTrace();
       
   214                         throw e;
       
   215                     }
       
   216                 }
       
   217                 pos += 2;
       
   218             }
       
   219             if (cx < x0) { cx = x0; }
       
   220             while (cx < x1) {
       
   221                 tile[idx++] = 0x00;
       
   222                 cx++;
       
   223             }
       
   224             /*
       
   225             for (int i = idx - (x1-x0); i < idx; i++) {
       
   226                 System.out.print(hex(tile[i], 2));
       
   227             }
       
   228             System.out.println();
       
   229             */
       
   230             idx += (rowstride - (x1-x0));
       
   231         }
       
   232         nextTile();
       
   233     }
       
   234 
       
   235     static String hex(int v, int d) {
       
   236         String s = Integer.toHexString(v);
       
   237         while (s.length() < d) {
       
   238             s = "0"+s;
       
   239         }
       
   240         return s.substring(0, d);
       
   241     }
       
   242 
       
   243     /**
       
   244      * Disposes this tile generator.
       
   245      * No further calls will be made on this instance.
       
   246      */
       
   247     public void dispose() {}
       
   248 }
       
   249