1 /* 2 * Copyright (c) 2004, 2013, 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 package sun.swing.plaf.synth; 26 27 import java.awt.*; 28 import java.awt.image.BufferedImage; 29 import sun.swing.CachedPainter; 30 31 /** 32 * Paint9Painter is used for painting images for both Synth and GTK's 33 * pixmap/blueprint engines. 34 * 35 */ 36 public class Paint9Painter extends CachedPainter { 37 /** 38 * Enumeration for the types of painting this class can handle. 39 */ 40 public enum PaintType { 41 /** 42 * Painting type indicating the image should be centered in 43 * the space provided. When used the <code>mask</code> is ignored. 44 */ 45 CENTER, 46 47 /** 48 * Painting type indicating the image should be tiled across the 49 * specified width and height. When used the <code>mask</code> is 50 * ignored. 51 */ 52 TILE, 53 54 /** 55 * Painting type indicating the image should be split into nine 56 * regions with the top, left, bottom and right areas stretched. 57 */ 58 PAINT9_STRETCH, 59 60 /** 61 * Painting type indicating the image should be split into nine 62 * regions with the top, left, bottom and right areas tiled. 63 */ 64 PAINT9_TILE 65 }; 66 67 private static final Insets EMPTY_INSETS = new Insets(0, 0, 0, 0); 68 69 public static final int PAINT_TOP_LEFT = 1; 70 public static final int PAINT_TOP = 2; 71 public static final int PAINT_TOP_RIGHT = 4; 72 public static final int PAINT_LEFT = 8; 73 public static final int PAINT_CENTER = 16; 74 public static final int PAINT_RIGHT = 32; 75 public static final int PAINT_BOTTOM_RIGHT = 64; 76 public static final int PAINT_BOTTOM = 128; 77 public static final int PAINT_BOTTOM_LEFT = 256; 78 /** 79 * Specifies that all regions should be painted. If this is set any 80 * other regions specified will not be painted. For example 81 * PAINT_ALL | PAINT_CENTER will paint all but the center. 82 */ 83 public static final int PAINT_ALL = 512; 84 85 /** 86 * Convenience method for testing the validity of an image. 87 * 88 * @param image Image to check. 89 * @return true if <code>image</code> is non-null and has a positive 90 * size. 91 */ validImage(Image image)92 public static boolean validImage(Image image) { 93 return (image != null && image.getWidth(null) > 0 && 94 image.getHeight(null) > 0); 95 } 96 97 Paint9Painter(int cacheCount)98 public Paint9Painter(int cacheCount) { 99 super(cacheCount); 100 } 101 102 /** 103 * Paints using the algorightm specified by <code>paintType</code>. 104 * NOTE that this just invokes super.paint(...) with the same 105 * argument ordering as this method. 106 * 107 * @param c Component rendering to 108 * @param g Graphics to render to 109 * @param x X-coordinate 110 * @param y Y-coordinate 111 * @param w Width to render to 112 * @param h Height to render to 113 * @param source Image to render from, if <code>null</code> this method 114 * will do nothing 115 * @param sInsets Insets specifying the portion of the image that 116 * will be stretched or tiled, if <code>null</code> empty 117 * <code>Insets</code> will be used. 118 * @param dInsets Destination insets specifying the portion of the image 119 * will be stretched or tiled, if <code>null</code> empty 120 * <code>Insets</code> will be used. 121 * @param type Specifies what type of algorithm to use in painting 122 * @param mask Specifies portion of image to render, if 123 * <code>PAINT_ALL</code> is specified, any other regions 124 * specified will not be painted, for example 125 * PAINT_ALL | PAINT_CENTER paints everything but the center. 126 */ paint(Component c, Graphics g, int x, int y, int w, int h, Image source, Insets sInsets, Insets dInsets, PaintType type, int mask)127 public void paint(Component c, Graphics g, int x, 128 int y, int w, int h, Image source, Insets sInsets, 129 Insets dInsets, 130 PaintType type, int mask) { 131 if (source == null) { 132 return; 133 } 134 super.paint(c, g, x, y, w, h, source, sInsets, dInsets, type, mask); 135 } 136 paintToImage(Component c, Image destImage, Graphics g, int w, int h, Object[] args)137 protected void paintToImage(Component c, Image destImage, Graphics g, 138 int w, int h, Object[] args) { 139 int argIndex = 0; 140 while (argIndex < args.length) { 141 Image image = (Image)args[argIndex++]; 142 Insets sInsets = (Insets)args[argIndex++]; 143 Insets dInsets = (Insets)args[argIndex++]; 144 PaintType type = (PaintType)args[argIndex++]; 145 int mask = (Integer)args[argIndex++]; 146 paint9(g, 0, 0, w, h, image, sInsets, dInsets, type, mask); 147 } 148 } 149 paint9(Graphics g, int x, int y, int w, int h, Image image, Insets sInsets, Insets dInsets, PaintType type, int componentMask)150 protected void paint9(Graphics g, int x, int y, int w, int h, 151 Image image, Insets sInsets, 152 Insets dInsets, PaintType type, int componentMask) { 153 if (!validImage(image)) { 154 return; 155 } 156 if (sInsets == null) { 157 sInsets = EMPTY_INSETS; 158 } 159 if (dInsets == null) { 160 dInsets = EMPTY_INSETS; 161 } 162 int iw = image.getWidth(null); 163 int ih = image.getHeight(null); 164 165 if (type == PaintType.CENTER) { 166 // Center the image 167 g.drawImage(image, x + (w - iw) / 2, 168 y + (h - ih) / 2, null); 169 } 170 else if (type == PaintType.TILE) { 171 // Tile the image 172 int lastIY = 0; 173 for (int yCounter = y, maxY = y + h; yCounter < maxY; 174 yCounter += (ih - lastIY), lastIY = 0) { 175 int lastIX = 0; 176 for (int xCounter = x, maxX = x + w; xCounter < maxX; 177 xCounter += (iw - lastIX), lastIX = 0) { 178 int dx2 = Math.min(maxX, xCounter + iw - lastIX); 179 int dy2 = Math.min(maxY, yCounter + ih - lastIY); 180 g.drawImage(image, xCounter, yCounter, dx2, dy2, 181 lastIX, lastIY, lastIX + dx2 - xCounter, 182 lastIY + dy2 - yCounter, null); 183 } 184 } 185 } 186 else { 187 int st = sInsets.top; 188 int sl = sInsets.left; 189 int sb = sInsets.bottom; 190 int sr = sInsets.right; 191 192 int dt = dInsets.top; 193 int dl = dInsets.left; 194 int db = dInsets.bottom; 195 int dr = dInsets.right; 196 197 // Constrain the insets to the size of the image 198 if (st + sb > ih) { 199 db = dt = sb = st = Math.max(0, ih / 2); 200 } 201 if (sl + sr > iw) { 202 dl = dr = sl = sr = Math.max(0, iw / 2); 203 } 204 205 // Constrain the insets to the size of the region we're painting 206 // in. 207 if (dt + db > h) { 208 dt = db = Math.max(0, h / 2 - 1); 209 } 210 if (dl + dr > w) { 211 dl = dr = Math.max(0, w / 2 - 1); 212 } 213 214 boolean stretch = (type == PaintType.PAINT9_STRETCH); 215 if ((componentMask & PAINT_ALL) != 0) { 216 componentMask = (PAINT_ALL - 1) & ~componentMask; 217 } 218 219 if ((componentMask & PAINT_LEFT) != 0) { 220 drawChunk(image, g, stretch, x, y + dt, x + dl, y + h - db, 221 0, st, sl, ih - sb, false); 222 } 223 if ((componentMask & PAINT_TOP_LEFT) != 0) { 224 drawImage(image, g, x, y, x + dl, y + dt, 225 0, 0, sl, st); 226 } 227 if ((componentMask & PAINT_TOP) != 0) { 228 drawChunk(image, g, stretch, x + dl, y, x + w - dr, y + dt, 229 sl, 0, iw - sr, st, true); 230 } 231 if ((componentMask & PAINT_TOP_RIGHT) != 0) { 232 drawImage(image, g, x + w - dr, y, x + w, y + dt, 233 iw - sr, 0, iw, st); 234 } 235 if ((componentMask & PAINT_RIGHT) != 0) { 236 drawChunk(image, g, stretch, 237 x + w - dr, y + dt, x + w, y + h - db, 238 iw - sr, st, iw, ih - sb, false); 239 } 240 if ((componentMask & PAINT_BOTTOM_RIGHT) != 0) { 241 drawImage(image, g, x + w - dr, y + h - db, x + w, y + h, 242 iw - sr, ih - sb, iw, ih); 243 } 244 if ((componentMask & PAINT_BOTTOM) != 0) { 245 drawChunk(image, g, stretch, 246 x + dl, y + h - db, x + w - dr, y + h, 247 sl, ih - sb, iw - sr, ih, true); 248 } 249 if ((componentMask & PAINT_BOTTOM_LEFT) != 0) { 250 drawImage(image, g, x, y + h - db, x + dl, y + h, 251 0, ih - sb, sl, ih); 252 } 253 if ((componentMask & PAINT_CENTER) != 0) { 254 drawImage(image, g, x + dl, y + dt, x + w - dr, y + h - db, 255 sl, st, iw - sr, ih - sb); 256 } 257 } 258 } 259 drawImage(Image image, Graphics g, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2)260 private void drawImage(Image image, Graphics g, 261 int dx1, int dy1, int dx2, int dy2, int sx1, 262 int sy1, int sx2, int sy2) { 263 // PENDING: is this necessary, will G2D do it for me? 264 if (dx2 - dx1 <= 0 || dy2 - dy1 <= 0 || sx2 - sx1 <= 0 || 265 sy2 - sy1 <= 0) { 266 // Bogus location, nothing to paint 267 return; 268 } 269 g.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null); 270 } 271 272 /** 273 * Draws a portion of an image, stretched or tiled. 274 * 275 * @param image Image to render. 276 * @param g Graphics to render to 277 * @param stretch Whether the image should be stretched or timed in the 278 * provided space. 279 * @param dx1 X origin to draw to 280 * @param dy1 Y origin to draw to 281 * @param dx2 End x location to draw to 282 * @param dy2 End y location to draw to 283 * @param sx1 X origin to draw from 284 * @param sy1 Y origin to draw from 285 * @param sx2 Max x location to draw from 286 * @param sy2 Max y location to draw from 287 * @param xDirection Used if the image is not stretched. If true it 288 * indicates the image should be tiled along the x axis. 289 */ drawChunk(Image image, Graphics g, boolean stretch, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, boolean xDirection)290 private void drawChunk(Image image, Graphics g, boolean stretch, 291 int dx1, int dy1, int dx2, int dy2, int sx1, 292 int sy1, int sx2, int sy2, 293 boolean xDirection) { 294 if (dx2 - dx1 <= 0 || dy2 - dy1 <= 0 || sx2 - sx1 <= 0 || 295 sy2 - sy1 <= 0) { 296 // Bogus location, nothing to paint 297 return; 298 } 299 if (stretch) { 300 g.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null); 301 } 302 else { 303 int xSize = sx2 - sx1; 304 int ySize = sy2 - sy1; 305 int deltaX; 306 int deltaY; 307 308 if (xDirection) { 309 deltaX = xSize; 310 deltaY = 0; 311 } 312 else { 313 deltaX = 0; 314 deltaY = ySize; 315 } 316 while (dx1 < dx2 && dy1 < dy2) { 317 int newDX2 = Math.min(dx2, dx1 + xSize); 318 int newDY2 = Math.min(dy2, dy1 + ySize); 319 320 g.drawImage(image, dx1, dy1, newDX2, newDY2, 321 sx1, sy1, sx1 + newDX2 - dx1, 322 sy1 + newDY2 - dy1, null); 323 dx1 += deltaX; 324 dy1 += deltaY; 325 } 326 } 327 } 328 329 /** 330 * Subclassed to always create a translucent image. 331 */ createImage(Component c, int w, int h, GraphicsConfiguration config, Object[] args)332 protected Image createImage(Component c, int w, int h, 333 GraphicsConfiguration config, 334 Object[] args) { 335 if (config == null) { 336 return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); 337 } 338 return config.createCompatibleImage(w, h, Transparency.TRANSLUCENT); 339 } 340 } 341