} } // This is padding for anti-aliasing and such. It may // be more than is needed. int x = (int)x0 - padX; int w = (int)(x1 - x0 + 2*padX); int y = (int)y0 - padY; int h = (int)(y1 - y0 + 2*padY); Rectangle clipRect = new Rectangle(x,y,w,h); result = clipRect.intersection(imageRect); } catch (NoninvertibleTransformException nte) { // Worst case bounds are the bounds of the image. result = imageRect; } return result; } /** * Draws an image, applying a transform from image space into user space * before drawing. * The transformation from user space into device space is done with * the current transform in the Graphics2D. * The given transformation is applied to the image before the * transform attribute in the Graphics2D state is applied. * The rendering attributes applied include the clip, transform, * and composite attributes. Note that the result is * undefined, if the given transform is noninvertible. * @param img The image to be drawn. Does nothing if img is null. * @param xform The transformation from image space into user space. * @see #transform * @see #setTransform * @see #setComposite * @see #clip * @see #setClip */ public void drawRenderedImage(RenderedImage img, AffineTransform xform) { if (img == null) { return; } // BufferedImage case: use a simple drawImage call if (img instanceof BufferedImage) { BufferedImage bufImg = (BufferedImage)img; drawImage(bufImg,xform,null); return; } // transformState tracks the state of transform and // transX, transY contain the integer casts of the // translation factors boolean isIntegerTranslate = (transformState <= TRANSFORM_INT_TRANSLATE) && isIntegerTranslation(xform); // Include padding for interpolation/antialiasing if necessary int pad = isIntegerTranslate ? 0 : 3; // Determine the region of the image that may contribute to // the clipped drawing area Rectangle region = getImageRegion(img, getCompClip(), transform, xform, pad, pad); if (region.width <= 0 || region.height <= 0) { return; } // Attempt to optimize integer translation of tiled images. // Although theoretically we are O.K. if the concatenation of // the user transform and the device transform is an integer // translation, we'll play it safe and only optimize the case // where both are integer translations. if (isIntegerTranslate) { // Use optimized code // Note that drawTranslatedRenderedImage calls copyImage // which takes the user space to device space transform into // account, but we need to provide the image space to user space // translations. drawTranslatedRenderedImage(img, region, (int) xform.getTranslateX(), (int) xform.getTranslateY()); return; } // General case: cobble the necessary region into a single Raster Raster raster = img.getData(region); // Make a new Raster with the same contents as raster // but starting at (0, 0). This raster is thus in the same // coordinate system as the SampleModel of the original raster. WritableRaster wRaster = Raster.createWritableRaster(raster.getSampleModel(), raster.getDataBuffer(), null); // If the original raster was in a different coordinate // system than its SampleModel, we need to perform an // additional translation in order to get the (minX, minY) // pixel of raster to be pixel (0, 0) of wRaster. We also // have to have the correct width and height. int minX = raster.getMinX(); int minY = raster.getMinY(); int width = raster.getWidth(); int height = raster.getHeight(); int px = minX - raster.getSampleModelTranslateX(); int py = minY - raster.getSampleModelTranslateY(); if (px != 0 || py != 0 || width != wRaster.getWidth() || height != wRaster.getHeight()) { wRaster = wRaster.createWritableChild(px, py, width, height, 0, 0, null); } // Now we have a BufferedImage starting at (0, 0) // with the same contents that started at (minX, minY) // in raster. So we must draw the BufferedImage with a // translation of (minX, minY). AffineTransform transXform = (AffineTransform)xform.clone(); transXform.translate(minX, minY); ColorModel cm = img.getColorModel(); BufferedImage bufImg = new BufferedImage(cm, wRaster, cm.isAlphaPremultiplied(), null); drawImage(bufImg, transXform, null); } /** * Intersects <code>destRect</code> with <code>clip</code> and * overwrites <code>destRect</code> with the result. * Returns false if the intersection was empty, true otherwise. */ private boolean clipTo(Rectangle destRect, Rectangle clip) { int x1 = Math.max(destRect.x, clip.x); int x2 = Math.min(destRect.x + destRect.width, clip.x + clip.width); int y1 = Math.max(destRect.y, clip.y); int y2 = Math.min(destRect.y + destRect.height, clip.y + clip.height); if (((x2 - x1) < 0) || ((y2 - y1) < 0)) { destRect.width = -1; // Set both just to be safe destRect.height = -1; return false; } else { destRect.x = x1; destRect.y = y1; destRect.width = x2 - x1; destRect.height = y2 - y1; return true; } } /** * Draw a portion of a RenderedImage tile-by-tile with a given * integer image to user space translation. The user to * device transform must also be an integer translation. */ private void drawTranslatedRenderedImage(RenderedImage img, Rectangle region, int i2uTransX, int i2uTransY) { // Cache tile grid info int tileGridXOffset = img.getTileGridXOffset(); int tileGridYOffset = img.getTileGridYOffset(); int tileWidth = img.getTileWidth(); int tileHeight = img.getTileHeight(); // Determine the tile index extrema in each direction int minTileX = getTileIndex(region.x, tileGridXOffset, tileWidth); int minTileY = getTileIndex(region.y, tileGridYOffset, tileHeight); int maxTileX = getTileIndex(region.x + region.width - 1, tileGridXOffset, tileWidth); int maxTileY = getTileIndex(region.y + region.height - 1, tileGridYOffset, tileHeight); // Create a single ColorModel to use for all BufferedImages ColorModel colorModel = img.getColorModel(); // Reuse the same Rectangle for each iteration Rectangle tileRect = new Rectangle(); for (int ty = minTileY; ty <= maxTileY; ty++) { for (int tx = minTileX; tx <= maxTileX; tx++) { // Get the current tile. Raster raster = img.getTile(tx, ty); // Fill in tileRect with the tile bounds tileRect.x = tx*tileWidth + tileGridXOffset; tileRect.y = ty*tileHeight + tileGridYOffset; tileRect.width = tileWidth; tileRect.height = tileHeight; // Clip the tile against the image bounds and // backwards mapped clip region // The result can't be empty clipTo(tileRect, region); // Create a WritableRaster containing the tile WritableRaster wRaster = null; if (raster instanceof WritableRaster) { wRaster = (WritableRaster)raster; } else { // Create a WritableRaster in the same coordinate system // as the original raster. wRaster = Raster.createWritableRaster(raster.getSampleModel(), raster.getDataBuffer(), null); } // Translate wRaster to start at (0, 0) and to contain // only the relevent portion of the tile wRaster = wRaster.createWritableChild(tileRect.x, tileRect.y, tileRect.width, tileRect.height, 0, 0, null); // Wrap wRaster in a BufferedImage BufferedImage bufImg = new BufferedImage(colorModel, wRaster, colorModel.isAlphaPremultiplied(), null); // Now we have a BufferedImage starting at (0, 0) that // represents data from a Raster starting at // (tileRect.x, tileRect.y). Additionally, it needs // to be translated by (i2uTransX, i2uTransY). We call // copyImage to draw just the region of interest // without needing to create a child image. copyImage(bufImg, tileRect.x + i2uTransX, tileRect.y + i2uTransY, 0, 0, tileRect.width, tileRect.height, null, null); } } } public void drawRenderableImage(RenderableImage img, AffineTransform xform) { if (img == null) { return; } AffineTransform pipeTransform = transform; AffineTransform concatTransform = new AffineTransform(xform); concatTransform.concatenate(pipeTransform); AffineTransform reverseTransform; RenderContext rc = new RenderContext(concatTransform); try { reverseTransform = pipeTransform.createInverse(); } catch (NoninvertibleTransformException nte) { rc = new RenderContext(pipeTransform); reverseTransform = new AffineTransform(); } RenderedImage rendering = img.createRendering(rc); drawRenderedImage(rendering,reverseTransform); } /* * Transform the bounding box of the BufferedImage */ protected Rectangle transformBounds(Rectangle rect, AffineTransform tx) { if (tx.isIdentity()) { return rect; } Shape s = transformShape(tx, rect); return s.getBounds(); } // text rendering methods public void drawString(String str, int x, int y) { if (str == null) { throw new NullPointerException("String is null"); } if (font.hasLayoutAttributes()) { if (str.length() == 0) { return; } new TextLayout(str, font, getFontRenderContext()).draw(this, x, y); return; } try { textpipe.drawString(this, str, x, y); } catch (InvalidPipeException e) { revalidateAll(); try { textpipe.drawString(this, str, x, y); } catch (InvalidPipeException e2) { // Still catching the exception; we are not yet ready to // validate the surfaceData correctly. Fail for now and // try again next time around. } } finally { surfaceData.markDirty(); } } public void drawString(String str, float x, float y) { if (str == null) { throw new NullPointerException("String is null"); } if (font.hasLayoutAttributes()) { if (str.length() == 0) { return; } new TextLayout(str, font, getFontRenderContext()).draw(this, x, y); return; } try { textpipe.drawString(this, str, x, y); } catch (InvalidPipeException e) { revalidateAll(); try { textpipe.drawString(this, str, x, y); } catch (InvalidPipeException e2) { // Still catching the exception; we are not yet ready to // validate the surfaceData correctly. Fail for now and // try again next time around. } } finally { surfaceData.markDirty(); } } public void drawString(AttributedCharacterIterator iterator, int x, int y) { if (iterator == null) { throw new NullPointerException("AttributedCharacterIterator is null"); } if (iterator.getBeginIndex() == iterator.getEndIndex()) { return; /* nothing to draw */ } TextLayout tl = new TextLayout(iterator, getFontRenderContext()); tl.draw(this, (float) x, (float) y); } public void drawString(AttributedCharacterIterator iterator, float x, float y) { if (iterator == null) { throw new NullPointerException("AttributedCharacterIterator is null"); } if (iterator.getBeginIndex() == iterator.getEndIndex()) { return; /* nothing to draw */ } TextLayout tl = new TextLayout(iterator, getFontRenderContext()); tl.draw(this, x, y); } public void drawGlyphVector(GlyphVector gv, float x, float y) { if (gv == null) { throw new NullPointerException("GlyphVector is null"); } try { textpipe.drawGlyphVector(this, gv, x, y); } catch (InvalidPipeException e) { revalidateAll(); try { textpipe.drawGlyphVector(this, gv, x, y); } catch (InvalidPipeException e2) { // Still catching the exception; we are not yet ready to // validate the surfaceData correctly. Fail for now and // try again next time around. } } finally { surfaceData.markDirty(); } } public void drawChars(char data[], int offset, int length, int x, int y) { if (data == null) { throw new NullPointerException("char data is null"); } if (offset < 0 || length < 0 || offset + length > data.length) { throw new ArrayIndexOutOfBoundsException("bad offset/length"); } if (font.hasLayoutAttributes()) { if (data.length == 0) { return; } new TextLayout(new String(data, offset, length), font, getFontRenderContext()).draw(this, x, y); return; } try { textpipe.drawChars(this, data, offset, length, x, y); } catch (InvalidPipeException e) { revalidateAll(); try { textpipe.drawChars(this, data, offset, length, x, y); } catch (InvalidPipeException e2) { // Still catching the exception; we are not yet ready to // validate the surfaceData correctly. Fail for now and // try again next time around. } } finally { surfaceData.markDirty(); } } public void drawBytes(byte data[], int offset, int length, int x, int y) { if (data == null) { throw new NullPointerException("byte data is null"); } if (offset < 0 || length < 0 || offset + length > data.length) { throw new ArrayIndexOutOfBoundsException("bad offset/length"); } /* Byte data is interpreted as 8-bit ASCII. Re-use drawChars loops */ char chData[] = new char[length]; for (int i = length; i-- > 0; ) { chData[i] = (char)(data[i+offset] & 0xff); } if (font.hasLayoutAttributes()) { if (data.length == 0) { return; } new TextLayout(new String(chData), font, getFontRenderContext()).draw(this, x, y); return; } try { textpipe.drawChars(this, chData, 0, length, x, y); } catch (InvalidPipeException e) { revalidateAll(); try { textpipe.drawChars(this, chData, 0, length, x, y); } catch (InvalidPipeException e2) { // Still catching the exception; we are not yet ready to // validate the surfaceData correctly. Fail for now and // try again next time around. } } finally { surfaceData.markDirty(); } }// end of text rendering methods /** * Draws an image scaled to x,y,w,h in nonblocking mode with a * callback object. */ public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { return drawImage(img, x, y, width, height, null, observer); } /** * Not part of the advertised API but a useful utility method * to call internally. This is for the case where we are * drawing to/from given coordinates using a given width/height, * but we guarantee that the weidth/height of the src and dest * areas are equal (no scale needed). */ public boolean copyImage(Image img, int dx, int dy, int sx, int sy, int width, int height, Color bgcolor, ImageObserver observer) { try { return imagepipe.copyImage(this, img, dx, dy, sx, sy, width, height, bgcolor, observer); } catch (InvalidPipeException e) { revalidateAll(); try { return imagepipe.copyImage(this, img, dx, dy, sx, sy, width, height, bgcolor, observer); } catch (InvalidPipeException e2) { // Still catching the exception; we are not yet ready to // validate the surfaceData correctly. Fail for now and // try again next time around. return false; }Lines 2501–3000 of 3310. Previous lines Load more
} } // This is padding for anti-aliasing and such. It may // be more than is needed. int x = (int)x0 - padX; int w = (int)(x1 - x0 + 2*padX); int y = (int)y0 - padY; int h = (int)(y1 - y0 + 2*padY); Rectangle clipRect = new Rectangle(x,y,w,h); result = clipRect.intersection(imageRect); } catch (NoninvertibleTransformException nte) { // Worst case bounds are the bounds of the image. result = imageRect; } return result; } /** * Draws an image, applying a transform from image space into user space * before drawing. * The transformation from user space into device space is done with * the current transform in the Graphics2D. * The given transformation is applied to the image before the * transform attribute in the Graphics2D state is applied. * The rendering attributes applied include the clip, transform, * and composite attributes. Note that the result is * undefined, if the given transform is noninvertible. * @param img The image to be drawn. Does nothing if img is null. * @param xform The transformation from image space into user space. * @see #transform * @see #setTransform * @see #setComposite * @see #clip * @see #setClip */ public void drawRenderedImage(RenderedImage img, AffineTransform xform) { if (img == null) { return; } // BufferedImage case: use a simple drawImage call if (img instanceof BufferedImage) { BufferedImage bufImg = (BufferedImage)img; drawImage(bufImg,xform,null); return; } // transformState tracks the state of transform and // transX, transY contain the integer casts of the // translation factors boolean isIntegerTranslate = (transformState <= TRANSFORM_INT_TRANSLATE) && isIntegerTranslation(xform); // Include padding for interpolation/antialiasing if necessary int pad = isIntegerTranslate ? 0 : 3; // Determine the region of the image that may contribute to // the clipped drawing area Rectangle region = getImageRegion(img, getCompClip(), transform, xform, pad, pad); if (region.width <= 0 || region.height <= 0) { return; } // Attempt to optimize integer translation of tiled images. // Although theoretically we are O.K. if the concatenation of // the user transform and the device transform is an integer // translation, we'll play it safe and only optimize the case // where both are integer translations. if (isIntegerTranslate) { // Use optimized code // Note that drawTranslatedRenderedImage calls copyImage // which takes the user space to device space transform into // account, but we need to provide the image space to user space // translations. drawTranslatedRenderedImage(img, region, (int) xform.getTranslateX(), (int) xform.getTranslateY()); return; } // General case: cobble the necessary region into a single Raster Raster raster = img.getData(region); // Make a new Raster with the same contents as raster // but starting at (0, 0). This raster is thus in the same // coordinate system as the SampleModel of the original raster. WritableRaster wRaster = Raster.createWritableRaster(raster.getSampleModel(), raster.getDataBuffer(), null); // If the original raster was in a different coordinate // system than its SampleModel, we need to perform an // additional translation in order to get the (minX, minY) // pixel of raster to be pixel (0, 0) of wRaster. We also // have to have the correct width and height. int minX = raster.getMinX(); int minY = raster.getMinY(); int width = raster.getWidth(); int height = raster.getHeight(); int px = minX - raster.getSampleModelTranslateX(); int py = minY - raster.getSampleModelTranslateY(); if (px != 0 || py != 0 || width != wRaster.getWidth() || height != wRaster.getHeight()) { wRaster = wRaster.createWritableChild(px, py, width, height, 0, 0, null); } // Now we have a BufferedImage starting at (0, 0) // with the same contents that started at (minX, minY) // in raster. So we must draw the BufferedImage with a // translation of (minX, minY). AffineTransform transXform = (AffineTransform)xform.clone(); transXform.translate(minX, minY); ColorModel cm = img.getColorModel(); BufferedImage bufImg = new BufferedImage(cm, wRaster, cm.isAlphaPremultiplied(), null); drawImage(bufImg, transXform, null); } /** * Intersects <code>destRect</code> with <code>clip</code> and * overwrites <code>destRect</code> with the result. * Returns false if the intersection was empty, true otherwise. */ private boolean clipTo(Rectangle destRect, Rectangle clip) { int x1 = Math.max(destRect.x, clip.x); int x2 = Math.min(destRect.x + destRect.width, clip.x + clip.width); int y1 = Math.max(destRect.y, clip.y); int y2 = Math.min(destRect.y + destRect.height, clip.y + clip.height); if (((x2 - x1) < 0) || ((y2 - y1) < 0)) { destRect.width = -1; // Set both just to be safe destRect.height = -1; return false; } else { destRect.x = x1; destRect.y = y1; destRect.width = x2 - x1; destRect.height = y2 - y1; return true; } } /** * Draw a portion of a RenderedImage tile-by-tile with a given * integer image to user space translation. The user to * device transform must also be an integer translation. */ private void drawTranslatedRenderedImage(RenderedImage img, Rectangle region, int i2uTransX, int i2uTransY) { // Cache tile grid info int tileGridXOffset = img.getTileGridXOffset(); int tileGridYOffset = img.getTileGridYOffset(); int tileWidth = img.getTileWidth(); int tileHeight = img.getTileHeight(); // Determine the tile index extrema in each direction int minTileX = getTileIndex(region.x, tileGridXOffset, tileWidth); int minTileY = getTileIndex(region.y, tileGridYOffset, tileHeight); int maxTileX = getTileIndex(region.x + region.width - 1, tileGridXOffset, tileWidth); int maxTileY = getTileIndex(region.y + region.height - 1, tileGridYOffset, tileHeight); // Create a single ColorModel to use for all BufferedImages ColorModel colorModel = img.getColorModel(); // Reuse the same Rectangle for each iteration Rectangle tileRect = new Rectangle(); for (int ty = minTileY; ty <= maxTileY; ty++) { for (int tx = minTileX; tx <= maxTileX; tx++) { // Get the current tile. Raster raster = img.getTile(tx, ty); // Fill in tileRect with the tile bounds tileRect.x = tx*tileWidth + tileGridXOffset; tileRect.y = ty*tileHeight + tileGridYOffset; tileRect.width = tileWidth; tileRect.height = tileHeight; // Clip the tile against the image bounds and // backwards mapped clip region // The result can't be empty clipTo(tileRect, region); // Create a WritableRaster containing the tile WritableRaster wRaster = null; if (raster instanceof WritableRaster) { wRaster = (WritableRaster)raster; } else { // Create a WritableRaster in the same coordinate system // as the original raster. wRaster = Raster.createWritableRaster(raster.getSampleModel(), raster.getDataBuffer(), null); } // Translate wRaster to start at (0, 0) and to contain // only the relevent portion of the tile wRaster = wRaster.createWritableChild(tileRect.x, tileRect.y, tileRect.width, tileRect.height, 0, 0, null); // Wrap wRaster in a BufferedImage BufferedImage bufImg = new BufferedImage(colorModel, wRaster, colorModel.isAlphaPremultiplied(), null); // Now we have a BufferedImage starting at (0, 0) that // represents data from a Raster starting at // (tileRect.x, tileRect.y). Additionally, it needs // to be translated by (i2uTransX, i2uTransY). We call // copyImage to draw just the region of interest // without needing to create a child image. copyImage(bufImg, tileRect.x + i2uTransX, tileRect.y + i2uTransY, 0, 0, tileRect.width, tileRect.height, null, null); } } } public void drawRenderableImage(RenderableImage img, AffineTransform xform) { if (img == null) { return; } AffineTransform pipeTransform = transform; AffineTransform concatTransform = new AffineTransform(xform); concatTransform.concatenate(pipeTransform); AffineTransform reverseTransform; RenderContext rc = new RenderContext(concatTransform); try { reverseTransform = pipeTransform.createInverse(); } catch (NoninvertibleTransformException nte) { rc = new RenderContext(pipeTransform); reverseTransform = new AffineTransform(); } RenderedImage rendering = img.createRendering(rc); drawRenderedImage(rendering,reverseTransform); } /* * Transform the bounding box of the BufferedImage */ protected Rectangle transformBounds(Rectangle rect, AffineTransform tx) { if (tx.isIdentity()) { return rect; } Shape s = transformShape(tx, rect); return s.getBounds(); } // text rendering methods public void drawString(String str, int x, int y) { if (str == null) { throw new NullPointerException("String is null"); } if (font.hasLayoutAttributes()) { if (str.length() == 0) { return; } new TextLayout(str, font, getFontRenderContext()).draw(this, x, y); return; } try { textpipe.drawString(this, str, x, y); } catch (InvalidPipeException e) { revalidateAll(); try { textpipe.drawString(this, str, x, y); } catch (InvalidPipeException e2) { // Still catching the exception; we are not yet ready to // validate the surfaceData correctly. Fail for now and // try again next time around. } } finally { surfaceData.markDirty(); } } public void drawString(String str, float x, float y) { if (str == null) { throw new NullPointerException("String is null"); } if (font.hasLayoutAttributes()) { if (str.length() == 0) { return; } new TextLayout(str, font, getFontRenderContext()).draw(this, x, y); return; } try { textpipe.drawString(this, str, x, y); } catch (InvalidPipeException e) { revalidateAll(); try { textpipe.drawString(this, str, x, y); } catch (InvalidPipeException e2) { // Still catching the exception; we are not yet ready to // validate the surfaceData correctly. Fail for now and // try again next time around. } } finally { surfaceData.markDirty(); } } public void drawString(AttributedCharacterIterator iterator, int x, int y) { if (iterator == null) { throw new NullPointerException("AttributedCharacterIterator is null"); } if (iterator.getBeginIndex() == iterator.getEndIndex()) { return; /* nothing to draw */ } TextLayout tl = new TextLayout(iterator, getFontRenderContext()); tl.draw(this, (float) x, (float) y); } public void drawString(AttributedCharacterIterator iterator, float x, float y) { if (iterator == null) { throw new NullPointerException("AttributedCharacterIterator is null"); } if (iterator.getBeginIndex() == iterator.getEndIndex()) { return; /* nothing to draw */ } TextLayout tl = new TextLayout(iterator, getFontRenderContext()); tl.draw(this, x, y); } public void drawGlyphVector(GlyphVector gv, float x, float y) { if (gv == null) { throw new NullPointerException("GlyphVector is null"); } try { textpipe.drawGlyphVector(this, gv, x, y); } catch (InvalidPipeException e) { revalidateAll(); try { textpipe.drawGlyphVector(this, gv, x, y); } catch (InvalidPipeException e2) { // Still catching the exception; we are not yet ready to // validate the surfaceData correctly. Fail for now and // try again next time around. } } finally { surfaceData.markDirty(); } } public void drawChars(char data[], int offset, int length, int x, int y) { if (data == null) { throw new NullPointerException("char data is null"); } if (offset < 0 || length < 0 || offset + length > data.length) { throw new ArrayIndexOutOfBoundsException("bad offset/length"); } if (font.hasLayoutAttributes()) { if (data.length == 0) { return; } new TextLayout(new String(data, offset, length), font, getFontRenderContext()).draw(this, x, y); return; } try { textpipe.drawChars(this, data, offset, length, x, y); } catch (InvalidPipeException e) { revalidateAll(); try { textpipe.drawChars(this, data, offset, length, x, y); } catch (InvalidPipeException e2) { // Still catching the exception; we are not yet ready to // validate the surfaceData correctly. Fail for now and // try again next time around. } } finally { surfaceData.markDirty(); } } public void drawBytes(byte data[], int offset, int length, int x, int y) { if (data == null) { throw new NullPointerException("byte data is null"); } if (offset < 0 || length < 0 || offset + length > data.length) { throw new ArrayIndexOutOfBoundsException("bad offset/length"); } /* Byte data is interpreted as 8-bit ASCII. Re-use drawChars loops */ char chData[] = new char[length]; for (int i = length; i-- > 0; ) { chData[i] = (char)(data[i+offset] & 0xff); } if (font.hasLayoutAttributes()) { if (data.length == 0) { return; } new TextLayout(new String(chData), font, getFontRenderContext()).draw(this, x, y); return; } try { textpipe.drawChars(this, chData, 0, length, x, y); } catch (InvalidPipeException e) { revalidateAll(); try { textpipe.drawChars(this, chData, 0, length, x, y); } catch (InvalidPipeException e2) { // Still catching the exception; we are not yet ready to // validate the surfaceData correctly. Fail for now and // try again next time around. } } finally { surfaceData.markDirty(); } } // end of text rendering methods /** * Draws an image scaled to x,y,w,h in nonblocking mode with a * callback object. */ public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { return drawImage(img, x, y, width, height, null, observer); } /** * Not part of the advertised API but a useful utility method * to call internally. This is for the case where we are * drawing to/from given coordinates using a given width/height, * but we guarantee that the weidth/height of the src and dest * areas are equal (no scale needed). */ public boolean copyImage(Image img, int dx, int dy, int sx, int sy, int width, int height, Color bgcolor, ImageObserver observer) { try { return imagepipe.copyImage(this, img, dx, dy, sx, sy, width, height, bgcolor, observer); } catch (InvalidPipeException e) { revalidateAll(); try { return imagepipe.copyImage(this, img, dx, dy, sx, sy, width, height, bgcolor, observer); } catch (InvalidPipeException e2) { // Still catching the exception; we are not yet ready to // validate the surfaceData correctly. Fail for now and // try again next time around. return false; }