< prev index next >

src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java

Print this page


   1 /*
   2  * Copyright (c) 1996, 2017, 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


1841             return false;
1842         }
1843         if (transformState > TRANSFORM_INT_TRANSLATE) {
1844             // Note: Technically the most accurate test would be to
1845             // raster scan the parallelogram of the transformed rectangle
1846             // and do a span for span hit test against the clip, but for
1847             // speed we approximate the test with a bounding box of the
1848             // transformed rectangle.  The cost of rasterizing the
1849             // transformed rectangle is probably high enough that it is
1850             // not worth doing so to save the caller from having to call
1851             // a rendering method where we will end up discovering the
1852             // same answer in about the same amount of time anyway.
1853             // This logic breaks down if this hit test is being performed
1854             // on the bounds of a group of shapes in which case it might
1855             // be beneficial to be a little more accurate to avoid lots
1856             // of subsequent rendering calls.  In either case, this relaxed
1857             // test should not be significantly less accurate than the
1858             // optimal test for most transforms and so the conservative
1859             // answer should not cause too much extra work.
1860 
1861             double d[] = {
1862                 x, y,
1863                 x+width, y,
1864                 x, y+height,
1865                 x+width, y+height
1866             };
1867             transform.transform(d, 0, d, 0, 4);
1868             x = (int) Math.floor(Math.min(Math.min(d[0], d[2]),
1869                                           Math.min(d[4], d[6])));
1870             y = (int) Math.floor(Math.min(Math.min(d[1], d[3]),
1871                                           Math.min(d[5], d[7])));
1872             width = (int) Math.ceil(Math.max(Math.max(d[0], d[2]),
1873                                              Math.max(d[4], d[6])));
1874             height = (int) Math.ceil(Math.max(Math.max(d[1], d[3]),
1875                                               Math.max(d[5], d[7])));
1876         } else {
1877             x += transX;
1878             y += transY;
1879             width += x;
1880             height += y;
1881         }


1888             return false;
1889         }
1890         // REMIND: We could go one step further here and examine the
1891         // non-rectangular clip shape more closely if there is one.
1892         // Since the clip has already been rasterized, the performance
1893         // penalty of doing the scan is probably still within the bounds
1894         // of a good tradeoff between speed and quality of the answer.
1895         return true;
1896     }
1897 
1898     protected void validateCompClip() {
1899         int origClipState = clipState;
1900         if (usrClip == null) {
1901             clipState = CLIP_DEVICE;
1902             clipRegion = devClip;
1903         } else if (usrClip instanceof Rectangle2D) {
1904             clipState = CLIP_RECTANGULAR;
1905             clipRegion = devClip.getIntersection((Rectangle2D) usrClip);
1906         } else {
1907             PathIterator cpi = usrClip.getPathIterator(null);
1908             int box[] = new int[4];
1909             ShapeSpanIterator sr = LoopPipe.getFillSSI(this);
1910             try {
1911                 sr.setOutputArea(devClip);
1912                 sr.appendPath(cpi);
1913                 sr.getPathBox(box);
1914                 Region r = Region.getInstance(box, sr);
1915                 clipRegion = r;
1916                 clipState =
1917                     r.isRectangular() ? CLIP_RECTANGULAR : CLIP_SHAPE;
1918             } finally {
1919                 sr.dispose();
1920             }
1921         }
1922         if (origClipState != clipState &&
1923             (clipState == CLIP_SHAPE || origClipState == CLIP_SHAPE))
1924         {
1925             validFontInfo = false;
1926             invalidatePipe();
1927         }
1928     }


1975                                           rect.getHeight());
1976         }
1977 
1978         if (tx == 0 && ty == 0) {
1979             return cloneShape(s);
1980         }
1981 
1982         AffineTransform mat = AffineTransform.getTranslateInstance(tx, ty);
1983         return mat.createTransformedShape(s);
1984     }
1985 
1986     protected static Shape transformShape(AffineTransform tx, Shape clip) {
1987         if (clip == null) {
1988             return null;
1989         }
1990 
1991         if (clip instanceof Rectangle2D &&
1992             (tx.getType() & NON_RECTILINEAR_TRANSFORM_MASK) == 0)
1993         {
1994             Rectangle2D rect = (Rectangle2D) clip;
1995             double matrix[] = new double[4];
1996             matrix[0] = rect.getX();
1997             matrix[1] = rect.getY();
1998             matrix[2] = matrix[0] + rect.getWidth();
1999             matrix[3] = matrix[1] + rect.getHeight();
2000             tx.transform(matrix, 0, matrix, 0, 2);
2001             fixRectangleOrientation(matrix, rect);
2002             return new Rectangle2D.Double(matrix[0], matrix[1],
2003                                           matrix[2] - matrix[0],
2004                                           matrix[3] - matrix[1]);
2005         }
2006 
2007         if (tx.isIdentity()) {
2008             return cloneShape(clip);
2009         }
2010 
2011         return tx.createTransformedShape(clip);
2012     }
2013 
2014     /**
2015      * Sets orientation of the rectangle according to the clip.


2334     }
2335 
2336     public void fillArc(int x, int y, int w, int h,
2337                         int startAngl, int arcAngl) {
2338         try {
2339             fillpipe.fillArc(this, x, y, w, h, startAngl, arcAngl);
2340         } catch (InvalidPipeException e) {
2341             try {
2342                 revalidateAll();
2343                 fillpipe.fillArc(this, x, y, w, h, startAngl, arcAngl);
2344             } catch (InvalidPipeException e2) {
2345                 // Still catching the exception; we are not yet ready to
2346                 // validate the surfaceData correctly.  Fail for now and
2347                 // try again next time around.
2348             }
2349         } finally {
2350             surfaceData.markDirty();
2351         }
2352     }
2353 
2354     public void drawPolyline(int xPoints[], int yPoints[], int nPoints) {
2355         try {
2356             drawpipe.drawPolyline(this, xPoints, yPoints, nPoints);
2357         } catch (InvalidPipeException e) {
2358             try {
2359                 revalidateAll();
2360                 drawpipe.drawPolyline(this, xPoints, yPoints, nPoints);
2361             } catch (InvalidPipeException e2) {
2362                 // Still catching the exception; we are not yet ready to
2363                 // validate the surfaceData correctly.  Fail for now and
2364                 // try again next time around.
2365             }
2366         } finally {
2367             surfaceData.markDirty();
2368         }
2369     }
2370 
2371     public void drawPolygon(int xPoints[], int yPoints[], int nPoints) {
2372         try {
2373             drawpipe.drawPolygon(this, xPoints, yPoints, nPoints);
2374         } catch (InvalidPipeException e) {
2375             try {
2376                 revalidateAll();
2377                 drawpipe.drawPolygon(this, xPoints, yPoints, nPoints);
2378             } catch (InvalidPipeException e2) {
2379                 // Still catching the exception; we are not yet ready to
2380                 // validate the surfaceData correctly.  Fail for now and
2381                 // try again next time around.
2382             }
2383         } finally {
2384             surfaceData.markDirty();
2385         }
2386     }
2387 
2388     public void fillPolygon(int xPoints[], int yPoints[], int nPoints) {
2389         try {
2390             fillpipe.fillPolygon(this, xPoints, yPoints, nPoints);
2391         } catch (InvalidPipeException e) {
2392             try {
2393                 revalidateAll();
2394                 fillpipe.fillPolygon(this, xPoints, yPoints, nPoints);
2395             } catch (InvalidPipeException e2) {
2396                 // Still catching the exception; we are not yet ready to
2397                 // validate the surfaceData correctly.  Fail for now and
2398                 // try again next time around.
2399             }
2400         } finally {
2401             surfaceData.markDirty();
2402         }
2403     }
2404 
2405     public void drawRect (int x, int y, int w, int h) {
2406         try {
2407             drawpipe.drawRect(this, x, y, w, h);
2408         } catch (InvalidPipeException e) {


2569     }
2570 
2571     /**
2572      * Returns a rectangle in image coordinates that may be required
2573      * in order to draw the given image into the given clipping region
2574      * through a pair of AffineTransforms.  In addition, horizontal and
2575      * vertical padding factors for antialising and interpolation may
2576      * be used.
2577      */
2578     private static Rectangle getImageRegion(RenderedImage img,
2579                                             Region compClip,
2580                                             AffineTransform transform,
2581                                             AffineTransform xform,
2582                                             int padX, int padY) {
2583         Rectangle imageRect =
2584             new Rectangle(img.getMinX(), img.getMinY(),
2585                           img.getWidth(), img.getHeight());
2586 
2587         Rectangle result = null;
2588         try {
2589             double p[] = new double[8];
2590             p[0] = p[2] = compClip.getLoX();
2591             p[4] = p[6] = compClip.getHiX();
2592             p[1] = p[5] = compClip.getLoY();
2593             p[3] = p[7] = compClip.getHiY();
2594 
2595             // Inverse transform the output bounding rect
2596             transform.inverseTransform(p, 0, p, 0, 4);
2597             xform.inverseTransform(p, 0, p, 0, 4);
2598 
2599             // Determine a bounding box for the inverse transformed region
2600             double x0,x1,y0,y1;
2601             x0 = x1 = p[0];
2602             y0 = y1 = p[1];
2603 
2604             for (int i = 2; i < 8; ) {
2605                 double pt = p[i++];
2606                 if (pt < x0)  {
2607                     x0 = pt;
2608                 } else if (pt > x1) {
2609                     x1 = pt;


2999         if (gv == null) {
3000             throw new NullPointerException("GlyphVector is null");
3001         }
3002 
3003         try {
3004             textpipe.drawGlyphVector(this, gv, x, y);
3005         } catch (InvalidPipeException e) {
3006             try {
3007                 revalidateAll();
3008                 textpipe.drawGlyphVector(this, gv, x, y);
3009             } catch (InvalidPipeException e2) {
3010                 // Still catching the exception; we are not yet ready to
3011                 // validate the surfaceData correctly.  Fail for now and
3012                 // try again next time around.
3013             }
3014         } finally {
3015             surfaceData.markDirty();
3016         }
3017     }
3018 
3019     public void drawChars(char data[], int offset, int length, int x, int y) {
3020 
3021         if (data == null) {
3022             throw new NullPointerException("char data is null");
3023         }
3024         if (offset < 0 || length < 0 || offset + length > data.length) {
3025             throw new ArrayIndexOutOfBoundsException("bad offset/length");
3026         }
3027         if (font.hasLayoutAttributes()) {
3028             if (data.length == 0) {
3029                 return;
3030             }
3031             new TextLayout(new String(data, offset, length),
3032                            font, getFontRenderContext()).draw(this, x, y);
3033             return;
3034         }
3035 
3036         try {
3037             textpipe.drawChars(this, data, offset, length, x, y);
3038         } catch (InvalidPipeException e) {
3039             try {
3040                 revalidateAll();
3041                 textpipe.drawChars(this, data, offset, length, x, y);
3042             } catch (InvalidPipeException e2) {
3043                 // Still catching the exception; we are not yet ready to
3044                 // validate the surfaceData correctly.  Fail for now and
3045                 // try again next time around.
3046             }
3047         } finally {
3048             surfaceData.markDirty();
3049         }
3050     }
3051 
3052     public void drawBytes(byte data[], int offset, int length, int x, int y) {
3053         if (data == null) {
3054             throw new NullPointerException("byte data is null");
3055         }
3056         if (offset < 0 || length < 0 || offset + length > data.length) {
3057             throw new ArrayIndexOutOfBoundsException("bad offset/length");
3058         }
3059         /* Byte data is interpreted as 8-bit ASCII. Re-use drawChars loops */
3060         char chData[] = new char[length];
3061         for (int i = length; i-- > 0; ) {
3062             chData[i] = (char)(data[i+offset] & 0xff);
3063         }
3064         if (font.hasLayoutAttributes()) {
3065             if (data.length == 0) {
3066                 return;
3067             }
3068             new TextLayout(new String(chData),
3069                            font, getFontRenderContext()).draw(this, x, y);
3070             return;
3071         }
3072 
3073         try {
3074             textpipe.drawChars(this, chData, 0, length, x, y);
3075         } catch (InvalidPipeException e) {
3076             try {
3077                 revalidateAll();
3078                 textpipe.drawChars(this, chData, 0, length, x, y);
3079             } catch (InvalidPipeException e2) {
3080                 // Still catching the exception; we are not yet ready to


   1 /*
   2  * Copyright (c) 1996, 2018, 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


1841             return false;
1842         }
1843         if (transformState > TRANSFORM_INT_TRANSLATE) {
1844             // Note: Technically the most accurate test would be to
1845             // raster scan the parallelogram of the transformed rectangle
1846             // and do a span for span hit test against the clip, but for
1847             // speed we approximate the test with a bounding box of the
1848             // transformed rectangle.  The cost of rasterizing the
1849             // transformed rectangle is probably high enough that it is
1850             // not worth doing so to save the caller from having to call
1851             // a rendering method where we will end up discovering the
1852             // same answer in about the same amount of time anyway.
1853             // This logic breaks down if this hit test is being performed
1854             // on the bounds of a group of shapes in which case it might
1855             // be beneficial to be a little more accurate to avoid lots
1856             // of subsequent rendering calls.  In either case, this relaxed
1857             // test should not be significantly less accurate than the
1858             // optimal test for most transforms and so the conservative
1859             // answer should not cause too much extra work.
1860 
1861             double[] d = {
1862                 x, y,
1863                 x+width, y,
1864                 x, y+height,
1865                 x+width, y+height
1866             };
1867             transform.transform(d, 0, d, 0, 4);
1868             x = (int) Math.floor(Math.min(Math.min(d[0], d[2]),
1869                                           Math.min(d[4], d[6])));
1870             y = (int) Math.floor(Math.min(Math.min(d[1], d[3]),
1871                                           Math.min(d[5], d[7])));
1872             width = (int) Math.ceil(Math.max(Math.max(d[0], d[2]),
1873                                              Math.max(d[4], d[6])));
1874             height = (int) Math.ceil(Math.max(Math.max(d[1], d[3]),
1875                                               Math.max(d[5], d[7])));
1876         } else {
1877             x += transX;
1878             y += transY;
1879             width += x;
1880             height += y;
1881         }


1888             return false;
1889         }
1890         // REMIND: We could go one step further here and examine the
1891         // non-rectangular clip shape more closely if there is one.
1892         // Since the clip has already been rasterized, the performance
1893         // penalty of doing the scan is probably still within the bounds
1894         // of a good tradeoff between speed and quality of the answer.
1895         return true;
1896     }
1897 
1898     protected void validateCompClip() {
1899         int origClipState = clipState;
1900         if (usrClip == null) {
1901             clipState = CLIP_DEVICE;
1902             clipRegion = devClip;
1903         } else if (usrClip instanceof Rectangle2D) {
1904             clipState = CLIP_RECTANGULAR;
1905             clipRegion = devClip.getIntersection((Rectangle2D) usrClip);
1906         } else {
1907             PathIterator cpi = usrClip.getPathIterator(null);
1908             int[] box = new int[4];
1909             ShapeSpanIterator sr = LoopPipe.getFillSSI(this);
1910             try {
1911                 sr.setOutputArea(devClip);
1912                 sr.appendPath(cpi);
1913                 sr.getPathBox(box);
1914                 Region r = Region.getInstance(box, sr);
1915                 clipRegion = r;
1916                 clipState =
1917                     r.isRectangular() ? CLIP_RECTANGULAR : CLIP_SHAPE;
1918             } finally {
1919                 sr.dispose();
1920             }
1921         }
1922         if (origClipState != clipState &&
1923             (clipState == CLIP_SHAPE || origClipState == CLIP_SHAPE))
1924         {
1925             validFontInfo = false;
1926             invalidatePipe();
1927         }
1928     }


1975                                           rect.getHeight());
1976         }
1977 
1978         if (tx == 0 && ty == 0) {
1979             return cloneShape(s);
1980         }
1981 
1982         AffineTransform mat = AffineTransform.getTranslateInstance(tx, ty);
1983         return mat.createTransformedShape(s);
1984     }
1985 
1986     protected static Shape transformShape(AffineTransform tx, Shape clip) {
1987         if (clip == null) {
1988             return null;
1989         }
1990 
1991         if (clip instanceof Rectangle2D &&
1992             (tx.getType() & NON_RECTILINEAR_TRANSFORM_MASK) == 0)
1993         {
1994             Rectangle2D rect = (Rectangle2D) clip;
1995             double[] matrix = new double[4];
1996             matrix[0] = rect.getX();
1997             matrix[1] = rect.getY();
1998             matrix[2] = matrix[0] + rect.getWidth();
1999             matrix[3] = matrix[1] + rect.getHeight();
2000             tx.transform(matrix, 0, matrix, 0, 2);
2001             fixRectangleOrientation(matrix, rect);
2002             return new Rectangle2D.Double(matrix[0], matrix[1],
2003                                           matrix[2] - matrix[0],
2004                                           matrix[3] - matrix[1]);
2005         }
2006 
2007         if (tx.isIdentity()) {
2008             return cloneShape(clip);
2009         }
2010 
2011         return tx.createTransformedShape(clip);
2012     }
2013 
2014     /**
2015      * Sets orientation of the rectangle according to the clip.


2334     }
2335 
2336     public void fillArc(int x, int y, int w, int h,
2337                         int startAngl, int arcAngl) {
2338         try {
2339             fillpipe.fillArc(this, x, y, w, h, startAngl, arcAngl);
2340         } catch (InvalidPipeException e) {
2341             try {
2342                 revalidateAll();
2343                 fillpipe.fillArc(this, x, y, w, h, startAngl, arcAngl);
2344             } catch (InvalidPipeException e2) {
2345                 // Still catching the exception; we are not yet ready to
2346                 // validate the surfaceData correctly.  Fail for now and
2347                 // try again next time around.
2348             }
2349         } finally {
2350             surfaceData.markDirty();
2351         }
2352     }
2353 
2354     public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {
2355         try {
2356             drawpipe.drawPolyline(this, xPoints, yPoints, nPoints);
2357         } catch (InvalidPipeException e) {
2358             try {
2359                 revalidateAll();
2360                 drawpipe.drawPolyline(this, xPoints, yPoints, nPoints);
2361             } catch (InvalidPipeException e2) {
2362                 // Still catching the exception; we are not yet ready to
2363                 // validate the surfaceData correctly.  Fail for now and
2364                 // try again next time around.
2365             }
2366         } finally {
2367             surfaceData.markDirty();
2368         }
2369     }
2370 
2371     public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {
2372         try {
2373             drawpipe.drawPolygon(this, xPoints, yPoints, nPoints);
2374         } catch (InvalidPipeException e) {
2375             try {
2376                 revalidateAll();
2377                 drawpipe.drawPolygon(this, xPoints, yPoints, nPoints);
2378             } catch (InvalidPipeException e2) {
2379                 // Still catching the exception; we are not yet ready to
2380                 // validate the surfaceData correctly.  Fail for now and
2381                 // try again next time around.
2382             }
2383         } finally {
2384             surfaceData.markDirty();
2385         }
2386     }
2387 
2388     public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
2389         try {
2390             fillpipe.fillPolygon(this, xPoints, yPoints, nPoints);
2391         } catch (InvalidPipeException e) {
2392             try {
2393                 revalidateAll();
2394                 fillpipe.fillPolygon(this, xPoints, yPoints, nPoints);
2395             } catch (InvalidPipeException e2) {
2396                 // Still catching the exception; we are not yet ready to
2397                 // validate the surfaceData correctly.  Fail for now and
2398                 // try again next time around.
2399             }
2400         } finally {
2401             surfaceData.markDirty();
2402         }
2403     }
2404 
2405     public void drawRect (int x, int y, int w, int h) {
2406         try {
2407             drawpipe.drawRect(this, x, y, w, h);
2408         } catch (InvalidPipeException e) {


2569     }
2570 
2571     /**
2572      * Returns a rectangle in image coordinates that may be required
2573      * in order to draw the given image into the given clipping region
2574      * through a pair of AffineTransforms.  In addition, horizontal and
2575      * vertical padding factors for antialising and interpolation may
2576      * be used.
2577      */
2578     private static Rectangle getImageRegion(RenderedImage img,
2579                                             Region compClip,
2580                                             AffineTransform transform,
2581                                             AffineTransform xform,
2582                                             int padX, int padY) {
2583         Rectangle imageRect =
2584             new Rectangle(img.getMinX(), img.getMinY(),
2585                           img.getWidth(), img.getHeight());
2586 
2587         Rectangle result = null;
2588         try {
2589             double[] p = new double[8];
2590             p[0] = p[2] = compClip.getLoX();
2591             p[4] = p[6] = compClip.getHiX();
2592             p[1] = p[5] = compClip.getLoY();
2593             p[3] = p[7] = compClip.getHiY();
2594 
2595             // Inverse transform the output bounding rect
2596             transform.inverseTransform(p, 0, p, 0, 4);
2597             xform.inverseTransform(p, 0, p, 0, 4);
2598 
2599             // Determine a bounding box for the inverse transformed region
2600             double x0,x1,y0,y1;
2601             x0 = x1 = p[0];
2602             y0 = y1 = p[1];
2603 
2604             for (int i = 2; i < 8; ) {
2605                 double pt = p[i++];
2606                 if (pt < x0)  {
2607                     x0 = pt;
2608                 } else if (pt > x1) {
2609                     x1 = pt;


2999         if (gv == null) {
3000             throw new NullPointerException("GlyphVector is null");
3001         }
3002 
3003         try {
3004             textpipe.drawGlyphVector(this, gv, x, y);
3005         } catch (InvalidPipeException e) {
3006             try {
3007                 revalidateAll();
3008                 textpipe.drawGlyphVector(this, gv, x, y);
3009             } catch (InvalidPipeException e2) {
3010                 // Still catching the exception; we are not yet ready to
3011                 // validate the surfaceData correctly.  Fail for now and
3012                 // try again next time around.
3013             }
3014         } finally {
3015             surfaceData.markDirty();
3016         }
3017     }
3018 
3019     public void drawChars(char[] data, int offset, int length, int x, int y) {
3020 
3021         if (data == null) {
3022             throw new NullPointerException("char data is null");
3023         }
3024         if (offset < 0 || length < 0 || offset + length > data.length) {
3025             throw new ArrayIndexOutOfBoundsException("bad offset/length");
3026         }
3027         if (font.hasLayoutAttributes()) {
3028             if (data.length == 0) {
3029                 return;
3030             }
3031             new TextLayout(new String(data, offset, length),
3032                            font, getFontRenderContext()).draw(this, x, y);
3033             return;
3034         }
3035 
3036         try {
3037             textpipe.drawChars(this, data, offset, length, x, y);
3038         } catch (InvalidPipeException e) {
3039             try {
3040                 revalidateAll();
3041                 textpipe.drawChars(this, data, offset, length, x, y);
3042             } catch (InvalidPipeException e2) {
3043                 // Still catching the exception; we are not yet ready to
3044                 // validate the surfaceData correctly.  Fail for now and
3045                 // try again next time around.
3046             }
3047         } finally {
3048             surfaceData.markDirty();
3049         }
3050     }
3051 
3052     public void drawBytes(byte[] data, int offset, int length, int x, int y) {
3053         if (data == null) {
3054             throw new NullPointerException("byte data is null");
3055         }
3056         if (offset < 0 || length < 0 || offset + length > data.length) {
3057             throw new ArrayIndexOutOfBoundsException("bad offset/length");
3058         }
3059         /* Byte data is interpreted as 8-bit ASCII. Re-use drawChars loops */
3060         char[] chData = new char[length];
3061         for (int i = length; i-- > 0; ) {
3062             chData[i] = (char)(data[i+offset] & 0xff);
3063         }
3064         if (font.hasLayoutAttributes()) {
3065             if (data.length == 0) {
3066                 return;
3067             }
3068             new TextLayout(new String(chData),
3069                            font, getFontRenderContext()).draw(this, x, y);
3070             return;
3071         }
3072 
3073         try {
3074             textpipe.drawChars(this, chData, 0, length, x, y);
3075         } catch (InvalidPipeException e) {
3076             try {
3077                 revalidateAll();
3078                 textpipe.drawChars(this, chData, 0, length, x, y);
3079             } catch (InvalidPipeException e2) {
3080                 // Still catching the exception; we are not yet ready to


< prev index next >