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 com.apple.laf; 27 28 import java.awt.*; 29 import java.awt.image.*; 30 import java.util.HashMap; 31 32 import com.apple.laf.AquaImageFactory.RecyclableSlicedImageControl; 33 import com.apple.laf.AquaImageFactory.NineSliceMetrics; 34 import com.apple.laf.AquaImageFactory.SlicedImageControl; 35 36 import sun.awt.image.*; 37 import sun.java2d.*; 38 import sun.print.*; 39 import apple.laf.*; 40 import apple.laf.JRSUIUtils.NineSliceMetricsProvider; 41 import sun.awt.image.ImageCache; 42 43 abstract class AquaPainter <T extends JRSUIState> { 44 static <T extends JRSUIState> AquaPainter<T> create(final T state) { 45 return new AquaSingleImagePainter<>(state); 46 } 47 48 static <T extends JRSUIState> AquaPainter<T> create(final T state, final int minWidth, final int minHeight, final int westCut, final int eastCut, final int northCut, final int southCut) { 49 return create(state, minWidth, minHeight, westCut, eastCut, northCut, southCut, true); 50 } 51 52 static <T extends JRSUIState> AquaPainter<T> create(final T state, final int minWidth, final int minHeight, final int westCut, final int eastCut, final int northCut, final int southCut, final boolean useMiddle) { 53 return create(state, minWidth, minHeight, westCut, eastCut, northCut, southCut, useMiddle, true, true); 54 } 55 56 static <T extends JRSUIState> AquaPainter<T> create(final T state, final int minWidth, final int minHeight, final int westCut, final int eastCut, final int northCut, final int southCut, final boolean useMiddle, final boolean stretchHorizontally, final boolean stretchVertically) { 57 return create(state, new NineSliceMetricsProvider() { 58 @Override 59 public NineSliceMetrics getNineSliceMetricsForState(JRSUIState state) { 60 return new NineSliceMetrics(minWidth, minHeight, westCut, eastCut, northCut, southCut, useMiddle, stretchHorizontally, stretchVertically); 131 132 private static final class AquaSingleImagePainter<T extends JRSUIState> 133 extends AquaPainter<T> { 134 135 AquaSingleImagePainter(final T state) { 136 super(new JRSUIControl(false), state); 137 } 138 139 @Override 140 void paint(final Graphics2D g, final T stateToPaint) { 141 paintFromSingleCachedImage(g, control, stateToPaint, boundsRect); 142 } 143 144 static void paintFromSingleCachedImage(final Graphics2D g, 145 final JRSUIControl control, final JRSUIState controlState, 146 final Rectangle bounds) { 147 if (bounds.width <= 0 || bounds.height <= 0) { 148 return; 149 } 150 151 int scale = 1; 152 if (g instanceof SunGraphics2D) { 153 scale = ((SunGraphics2D) g).surfaceData.getDefaultScale(); 154 } 155 final GraphicsConfiguration config = g.getDeviceConfiguration(); 156 final ImageCache cache = ImageCache.getInstance(); 157 final int imgW = bounds.width * scale; 158 final int imgH = bounds.height * scale; 159 AquaPixelsKey key = new AquaPixelsKey(config, 160 imgW, imgH, scale, controlState); 161 BufferedImage img = (BufferedImage) cache.getImage(key); 162 if (img == null) { 163 img = new BufferedImage(imgW, imgH, BufferedImage.TYPE_INT_ARGB_PRE); 164 if (!controlState.is(JRSUIConstants.Animating.YES)) { 165 cache.setImage(key, img); 166 } 167 168 final WritableRaster raster = img.getRaster(); 169 final DataBufferInt buffer = (DataBufferInt) raster.getDataBuffer(); 170 171 control.set(controlState); 172 control.paint(SunWritableRaster.stealData(buffer, 0), 173 imgW, imgH, 0, 0, bounds.width, bounds.height); 174 SunWritableRaster.markDirty(buffer); 175 } 176 177 g.drawImage(img, bounds.x, bounds.y, bounds.width, bounds.height, null); 178 } 179 } 180 181 private static class AquaPixelsKey implements ImageCache.PixelsKey { 182 183 private final int pixelCount; 184 private final int hash; 185 186 // key parts 187 private final GraphicsConfiguration config; 188 private final int w; 189 private final int h; 190 private final int scale; 191 private final JRSUIState state; 192 193 AquaPixelsKey(final GraphicsConfiguration config, 194 final int w, final int h, final int scale, 195 final JRSUIState state) { 196 this.pixelCount = w * h; 197 this.config = config; 198 this.w = w; 199 this.h = h; 200 this.scale = scale; 201 this.state = state; 202 this.hash = hash(); 203 } 204 205 public int getPixelCount() { 206 return pixelCount; 207 } 208 209 private int hash() { 210 int hash = config != null ? config.hashCode() : 0; 211 hash = 31 * hash + w; 212 hash = 31 * hash + h; 213 hash = 31 * hash + scale; 214 hash = 31 * hash + state.hashCode(); 215 return hash; 216 } 217 218 @Override 219 public int hashCode() { 220 return hash; 221 } 222 223 @Override 224 public boolean equals(Object obj) { 225 if (obj instanceof AquaPixelsKey) { 226 AquaPixelsKey key = (AquaPixelsKey) obj; 227 return config == key.config && w == key.w && h == key.h 228 && scale == key.scale && state.equals(key.state); 229 } 230 return false; 231 } 232 } 233 234 private static class RecyclableJRSUISlicedImageControl 235 extends RecyclableSlicedImageControl { 236 237 private final JRSUIControl control; 238 private final JRSUIState state; 239 240 RecyclableJRSUISlicedImageControl(final JRSUIControl control, final JRSUIState state, final NineSliceMetrics metrics) { 241 super(metrics); 242 this.control = control; 243 this.state = state; 244 } 245 246 @Override 247 protected Image createTemplateImage(int width, int height) { 248 BufferedImage image = new BufferedImage(metrics.minW, metrics.minH, BufferedImage.TYPE_INT_ARGB_PRE); | 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 com.apple.laf; 27 28 import java.awt.*; 29 import java.awt.image.*; 30 import java.util.HashMap; 31 32 import com.apple.laf.AquaImageFactory.RecyclableSlicedImageControl; 33 import com.apple.laf.AquaImageFactory.NineSliceMetrics; 34 import com.apple.laf.AquaImageFactory.SlicedImageControl; 35 36 import sun.awt.image.*; 37 import sun.java2d.*; 38 import sun.print.*; 39 import apple.laf.*; 40 import apple.laf.JRSUIUtils.NineSliceMetricsProvider; 41 import java.awt.geom.AffineTransform; 42 import static java.awt.geom.AffineTransform.TYPE_FLIP; 43 import static java.awt.geom.AffineTransform.TYPE_MASK_SCALE; 44 import static java.awt.geom.AffineTransform.TYPE_TRANSLATION; 45 import sun.awt.image.ImageCache; 46 47 abstract class AquaPainter <T extends JRSUIState> { 48 static <T extends JRSUIState> AquaPainter<T> create(final T state) { 49 return new AquaSingleImagePainter<>(state); 50 } 51 52 static <T extends JRSUIState> AquaPainter<T> create(final T state, final int minWidth, final int minHeight, final int westCut, final int eastCut, final int northCut, final int southCut) { 53 return create(state, minWidth, minHeight, westCut, eastCut, northCut, southCut, true); 54 } 55 56 static <T extends JRSUIState> AquaPainter<T> create(final T state, final int minWidth, final int minHeight, final int westCut, final int eastCut, final int northCut, final int southCut, final boolean useMiddle) { 57 return create(state, minWidth, minHeight, westCut, eastCut, northCut, southCut, useMiddle, true, true); 58 } 59 60 static <T extends JRSUIState> AquaPainter<T> create(final T state, final int minWidth, final int minHeight, final int westCut, final int eastCut, final int northCut, final int southCut, final boolean useMiddle, final boolean stretchHorizontally, final boolean stretchVertically) { 61 return create(state, new NineSliceMetricsProvider() { 62 @Override 63 public NineSliceMetrics getNineSliceMetricsForState(JRSUIState state) { 64 return new NineSliceMetrics(minWidth, minHeight, westCut, eastCut, northCut, southCut, useMiddle, stretchHorizontally, stretchVertically); 135 136 private static final class AquaSingleImagePainter<T extends JRSUIState> 137 extends AquaPainter<T> { 138 139 AquaSingleImagePainter(final T state) { 140 super(new JRSUIControl(false), state); 141 } 142 143 @Override 144 void paint(final Graphics2D g, final T stateToPaint) { 145 paintFromSingleCachedImage(g, control, stateToPaint, boundsRect); 146 } 147 148 static void paintFromSingleCachedImage(final Graphics2D g, 149 final JRSUIControl control, final JRSUIState controlState, 150 final Rectangle bounds) { 151 if (bounds.width <= 0 || bounds.height <= 0) { 152 return; 153 } 154 155 int imgW = bounds.width; 156 int imgH = bounds.height; 157 158 if (g instanceof SunGraphics2D) { 159 AffineTransform transform = ((SunGraphics2D) g).transform; 160 int type = transform.getType(); 161 162 if ((type & ~(TYPE_TRANSLATION | TYPE_FLIP)) == 0) { 163 // identity scale 164 } else if ((type & ~(TYPE_TRANSLATION | TYPE_FLIP 165 | TYPE_MASK_SCALE)) == 0) { 166 imgW = (int) (bounds.width * transform.getScaleX()); 167 imgH = (int) (bounds.height * transform.getScaleY()); 168 } else { 169 imgW = (int) (bounds.width * Math.hypot( 170 transform.getScaleX(), transform.getShearY())); 171 imgH = (int) (bounds.height * Math.hypot( 172 transform.getShearX(), transform.getScaleY())); 173 } 174 } 175 176 final GraphicsConfiguration config = g.getDeviceConfiguration(); 177 final ImageCache cache = ImageCache.getInstance(); 178 AquaPixelsKey key = new AquaPixelsKey(config, 179 imgW, imgH, controlState); 180 BufferedImage img = (BufferedImage) cache.getImage(key); 181 if (img == null) { 182 img = new BufferedImage(imgW, imgH, BufferedImage.TYPE_INT_ARGB_PRE); 183 if (!controlState.is(JRSUIConstants.Animating.YES)) { 184 cache.setImage(key, img); 185 } 186 187 final WritableRaster raster = img.getRaster(); 188 final DataBufferInt buffer = (DataBufferInt) raster.getDataBuffer(); 189 190 control.set(controlState); 191 control.paint(SunWritableRaster.stealData(buffer, 0), 192 imgW, imgH, 0, 0, bounds.width, bounds.height); 193 SunWritableRaster.markDirty(buffer); 194 } 195 196 g.drawImage(img, bounds.x, bounds.y, bounds.width, bounds.height, null); 197 } 198 } 199 200 private static class AquaPixelsKey implements ImageCache.PixelsKey { 201 202 private final int pixelCount; 203 private final int hash; 204 205 // key parts 206 private final GraphicsConfiguration config; 207 private final int w; 208 private final int h; 209 private final JRSUIState state; 210 211 AquaPixelsKey(final GraphicsConfiguration config, 212 final int w, final int h, 213 final JRSUIState state) { 214 this.pixelCount = w * h; 215 this.config = config; 216 this.w = w; 217 this.h = h; 218 this.state = state; 219 this.hash = hash(); 220 } 221 222 public int getPixelCount() { 223 return pixelCount; 224 } 225 226 private int hash() { 227 int hash = config != null ? config.hashCode() : 0; 228 hash = 31 * hash + w; 229 hash = 31 * hash + h; 230 hash = 31 * hash + state.hashCode(); 231 return hash; 232 } 233 234 @Override 235 public int hashCode() { 236 return hash; 237 } 238 239 @Override 240 public boolean equals(Object obj) { 241 if (obj instanceof AquaPixelsKey) { 242 AquaPixelsKey key = (AquaPixelsKey) obj; 243 return config == key.config && w == key.w && h == key.h 244 && state.equals(key.state); 245 } 246 return false; 247 } 248 } 249 250 private static class RecyclableJRSUISlicedImageControl 251 extends RecyclableSlicedImageControl { 252 253 private final JRSUIControl control; 254 private final JRSUIState state; 255 256 RecyclableJRSUISlicedImageControl(final JRSUIControl control, final JRSUIState state, final NineSliceMetrics metrics) { 257 super(metrics); 258 this.control = control; 259 this.state = state; 260 } 261 262 @Override 263 protected Image createTemplateImage(int width, int height) { 264 BufferedImage image = new BufferedImage(metrics.minW, metrics.minH, BufferedImage.TYPE_INT_ARGB_PRE); |