Path: blob/master/src/java.desktop/share/classes/sun/swing/plaf/synth/Paint9Painter.java
41161 views
/*1* Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package sun.swing.plaf.synth;2526import java.awt.*;27import java.awt.image.BufferedImage;28import sun.swing.CachedPainter;2930/**31* Paint9Painter is used for painting images for both Synth and GTK's32* pixmap/blueprint engines.33*34*/35public class Paint9Painter extends CachedPainter {36/**37* Enumeration for the types of painting this class can handle.38*/39public enum PaintType {40/**41* Painting type indicating the image should be centered in42* the space provided. When used the <code>mask</code> is ignored.43*/44CENTER,4546/**47* Painting type indicating the image should be tiled across the48* specified width and height. When used the <code>mask</code> is49* ignored.50*/51TILE,5253/**54* Painting type indicating the image should be split into nine55* regions with the top, left, bottom and right areas stretched.56*/57PAINT9_STRETCH,5859/**60* Painting type indicating the image should be split into nine61* regions with the top, left, bottom and right areas tiled.62*/63PAINT9_TILE64};6566private static final Insets EMPTY_INSETS = new Insets(0, 0, 0, 0);6768public static final int PAINT_TOP_LEFT = 1;69public static final int PAINT_TOP = 2;70public static final int PAINT_TOP_RIGHT = 4;71public static final int PAINT_LEFT = 8;72public static final int PAINT_CENTER = 16;73public static final int PAINT_RIGHT = 32;74public static final int PAINT_BOTTOM_RIGHT = 64;75public static final int PAINT_BOTTOM = 128;76public static final int PAINT_BOTTOM_LEFT = 256;77/**78* Specifies that all regions should be painted. If this is set any79* other regions specified will not be painted. For example80* PAINT_ALL | PAINT_CENTER will paint all but the center.81*/82public static final int PAINT_ALL = 512;8384/**85* Convenience method for testing the validity of an image.86*87* @param image Image to check.88* @return true if <code>image</code> is non-null and has a positive89* size.90*/91public static boolean validImage(Image image) {92return (image != null && image.getWidth(null) > 0 &&93image.getHeight(null) > 0);94}959697public Paint9Painter(int cacheCount) {98super(cacheCount);99}100101/**102* Paints using the algorightm specified by <code>paintType</code>.103* NOTE that this just invokes super.paint(...) with the same104* argument ordering as this method.105*106* @param c Component rendering to107* @param g Graphics to render to108* @param x X-coordinate109* @param y Y-coordinate110* @param w Width to render to111* @param h Height to render to112* @param source Image to render from, if <code>null</code> this method113* will do nothing114* @param sInsets Insets specifying the portion of the image that115* will be stretched or tiled, if <code>null</code> empty116* <code>Insets</code> will be used.117* @param dInsets Destination insets specifying the portion of the image118* will be stretched or tiled, if <code>null</code> empty119* <code>Insets</code> will be used.120* @param type Specifies what type of algorithm to use in painting121* @param mask Specifies portion of image to render, if122* <code>PAINT_ALL</code> is specified, any other regions123* specified will not be painted, for example124* PAINT_ALL | PAINT_CENTER paints everything but the center.125*/126public void paint(Component c, Graphics g, int x,127int y, int w, int h, Image source, Insets sInsets,128Insets dInsets,129PaintType type, int mask) {130if (source == null) {131return;132}133super.paint(c, g, x, y, w, h, source, sInsets, dInsets, type, mask);134}135136protected void paintToImage(Component c, Image destImage, Graphics g,137int w, int h, Object[] args) {138int argIndex = 0;139while (argIndex < args.length) {140Image image = (Image)args[argIndex++];141Insets sInsets = (Insets)args[argIndex++];142Insets dInsets = (Insets)args[argIndex++];143PaintType type = (PaintType)args[argIndex++];144int mask = (Integer)args[argIndex++];145paint9(g, 0, 0, w, h, image, sInsets, dInsets, type, mask);146}147}148149protected void paint9(Graphics g, int x, int y, int w, int h,150Image image, Insets sInsets,151Insets dInsets, PaintType type, int componentMask) {152if (!validImage(image)) {153return;154}155if (sInsets == null) {156sInsets = EMPTY_INSETS;157}158if (dInsets == null) {159dInsets = EMPTY_INSETS;160}161int iw = image.getWidth(null);162int ih = image.getHeight(null);163164if (type == PaintType.CENTER) {165// Center the image166g.drawImage(image, x + (w - iw) / 2,167y + (h - ih) / 2, null);168}169else if (type == PaintType.TILE) {170// Tile the image171int lastIY = 0;172for (int yCounter = y, maxY = y + h; yCounter < maxY;173yCounter += (ih - lastIY), lastIY = 0) {174int lastIX = 0;175for (int xCounter = x, maxX = x + w; xCounter < maxX;176xCounter += (iw - lastIX), lastIX = 0) {177int dx2 = Math.min(maxX, xCounter + iw - lastIX);178int dy2 = Math.min(maxY, yCounter + ih - lastIY);179g.drawImage(image, xCounter, yCounter, dx2, dy2,180lastIX, lastIY, lastIX + dx2 - xCounter,181lastIY + dy2 - yCounter, null);182}183}184}185else {186int st = sInsets.top;187int sl = sInsets.left;188int sb = sInsets.bottom;189int sr = sInsets.right;190191int dt = dInsets.top;192int dl = dInsets.left;193int db = dInsets.bottom;194int dr = dInsets.right;195196// Constrain the insets to the size of the image197if (st + sb > ih) {198db = dt = sb = st = Math.max(0, ih / 2);199}200if (sl + sr > iw) {201dl = dr = sl = sr = Math.max(0, iw / 2);202}203204// Constrain the insets to the size of the region we're painting205// in.206if (dt + db > h) {207dt = db = Math.max(0, h / 2 - 1);208}209if (dl + dr > w) {210dl = dr = Math.max(0, w / 2 - 1);211}212213boolean stretch = (type == PaintType.PAINT9_STRETCH);214if ((componentMask & PAINT_ALL) != 0) {215componentMask = (PAINT_ALL - 1) & ~componentMask;216}217218if ((componentMask & PAINT_LEFT) != 0) {219drawChunk(image, g, stretch, x, y + dt, x + dl, y + h - db,2200, st, sl, ih - sb, false);221}222if ((componentMask & PAINT_TOP_LEFT) != 0) {223drawImage(image, g, x, y, x + dl, y + dt,2240, 0, sl, st);225}226if ((componentMask & PAINT_TOP) != 0) {227drawChunk(image, g, stretch, x + dl, y, x + w - dr, y + dt,228sl, 0, iw - sr, st, true);229}230if ((componentMask & PAINT_TOP_RIGHT) != 0) {231drawImage(image, g, x + w - dr, y, x + w, y + dt,232iw - sr, 0, iw, st);233}234if ((componentMask & PAINT_RIGHT) != 0) {235drawChunk(image, g, stretch,236x + w - dr, y + dt, x + w, y + h - db,237iw - sr, st, iw, ih - sb, false);238}239if ((componentMask & PAINT_BOTTOM_RIGHT) != 0) {240drawImage(image, g, x + w - dr, y + h - db, x + w, y + h,241iw - sr, ih - sb, iw, ih);242}243if ((componentMask & PAINT_BOTTOM) != 0) {244drawChunk(image, g, stretch,245x + dl, y + h - db, x + w - dr, y + h,246sl, ih - sb, iw - sr, ih, true);247}248if ((componentMask & PAINT_BOTTOM_LEFT) != 0) {249drawImage(image, g, x, y + h - db, x + dl, y + h,2500, ih - sb, sl, ih);251}252if ((componentMask & PAINT_CENTER) != 0) {253drawImage(image, g, x + dl, y + dt, x + w - dr, y + h - db,254sl, st, iw - sr, ih - sb);255}256}257}258259private void drawImage(Image image, Graphics g,260int dx1, int dy1, int dx2, int dy2, int sx1,261int sy1, int sx2, int sy2) {262// PENDING: is this necessary, will G2D do it for me?263if (dx2 - dx1 <= 0 || dy2 - dy1 <= 0 || sx2 - sx1 <= 0 ||264sy2 - sy1 <= 0) {265// Bogus location, nothing to paint266return;267}268g.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null);269}270271/**272* Draws a portion of an image, stretched or tiled.273*274* @param image Image to render.275* @param g Graphics to render to276* @param stretch Whether the image should be stretched or timed in the277* provided space.278* @param dx1 X origin to draw to279* @param dy1 Y origin to draw to280* @param dx2 End x location to draw to281* @param dy2 End y location to draw to282* @param sx1 X origin to draw from283* @param sy1 Y origin to draw from284* @param sx2 Max x location to draw from285* @param sy2 Max y location to draw from286* @param xDirection Used if the image is not stretched. If true it287* indicates the image should be tiled along the x axis.288*/289private void drawChunk(Image image, Graphics g, boolean stretch,290int dx1, int dy1, int dx2, int dy2, int sx1,291int sy1, int sx2, int sy2,292boolean xDirection) {293if (dx2 - dx1 <= 0 || dy2 - dy1 <= 0 || sx2 - sx1 <= 0 ||294sy2 - sy1 <= 0) {295// Bogus location, nothing to paint296return;297}298if (stretch) {299g.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null);300}301else {302int xSize = sx2 - sx1;303int ySize = sy2 - sy1;304int deltaX;305int deltaY;306307if (xDirection) {308deltaX = xSize;309deltaY = 0;310}311else {312deltaX = 0;313deltaY = ySize;314}315while (dx1 < dx2 && dy1 < dy2) {316int newDX2 = Math.min(dx2, dx1 + xSize);317int newDY2 = Math.min(dy2, dy1 + ySize);318319g.drawImage(image, dx1, dy1, newDX2, newDY2,320sx1, sy1, sx1 + newDX2 - dx1,321sy1 + newDY2 - dy1, null);322dx1 += deltaX;323dy1 += deltaY;324}325}326}327328/**329* Subclassed to always create a translucent image.330*/331protected Image createImage(Component c, int w, int h,332GraphicsConfiguration config,333Object[] args) {334if (config == null) {335return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);336}337return config.createCompatibleImage(w, h, Transparency.TRANSLUCENT);338}339}340341342