Mercurial > hg > openjdk > jigsaw > jdk
changeset 7267:ffd45b1a9c11
8004866: [macosx] HiDPI support in Aqua L&F
Reviewed-by: swingler, alexsch
author | serb |
---|---|
date | Fri, 12 Apr 2013 20:39:48 +0400 |
parents | 39ce1056694d |
children | dcdf8cd4b09e |
files | src/macosx/classes/com/apple/laf/AquaPainter.java src/macosx/classes/com/apple/laf/ImageCache.java src/macosx/native/com/apple/laf/JRSUIController.m |
diffstat | 3 files changed, 99 insertions(+), 59 deletions(-) [+] |
line wrap: on
line diff
--- a/src/macosx/classes/com/apple/laf/AquaPainter.java Fri Apr 12 15:28:49 2013 +0400 +++ b/src/macosx/classes/com/apple/laf/AquaPainter.java Fri Apr 12 20:39:48 2013 +0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,15 +41,15 @@ abstract class AquaPainter <T extends JRSUIState> { static <T extends JRSUIState> AquaPainter<T> create(final T state) { - return new AquaSingleImagePainter<T>(state); + return new AquaSingleImagePainter<>(state); } 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) { - return AquaPainter.create(state, minWidth, minHeight, westCut, eastCut, northCut, southCut, true); + return create(state, minWidth, minHeight, westCut, eastCut, northCut, southCut, true); } 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) { - return AquaPainter.create(state, minWidth, minHeight, westCut, eastCut, northCut, southCut, useMiddle, true, true); + return create(state, minWidth, minHeight, westCut, eastCut, northCut, southCut, useMiddle, true, true); } 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) { @@ -65,7 +65,7 @@ return new AquaNineSlicingImagePainter<>(state, metricsProvider); } - abstract void paint(final Graphics2D g, final T stateToPaint, final Component c); + abstract void paint(Graphics2D g, T stateToPaint); final Rectangle boundsRect = new Rectangle(); final JRSUIControl control; @@ -75,23 +75,26 @@ this.state = state; } - JRSUIControl getControl() { - control.set(state = (T)state.derive()); + final JRSUIControl getControl() { + control.set(state = state.derive()); return control; } - void paint(final Graphics g, final Component c, final int x, final int y, final int w, final int h) { + final void paint(final Graphics g, final Component c, final int x, + final int y, final int w, final int h) { boundsRect.setBounds(x, y, w, h); - final T nextState = (T)state.derive(); + final T nextState = state.derive(); final Graphics2D g2d = getGraphics2D(g); - if (g2d != null) paint(g2d, nextState, c); + if (g2d != null) paint(g2d, nextState); state = nextState; } - static class AquaNineSlicingImagePainter<T extends JRSUIState> extends AquaPainter<T> { - protected final HashMap<T, RecyclableJRSUISlicedImageControl> slicedControlImages; - protected final NineSliceMetricsProvider metricsProvider; + private static class AquaNineSlicingImagePainter<T extends JRSUIState> + extends AquaPainter<T> { + + private final HashMap<T, RecyclableJRSUISlicedImageControl> slicedControlImages; + private final NineSliceMetricsProvider metricsProvider; AquaNineSlicingImagePainter(final T state) { this(state, null); @@ -104,9 +107,9 @@ } @Override - void paint(final Graphics2D g, final T stateToPaint, final Component c) { + void paint(final Graphics2D g, final T stateToPaint) { if (metricsProvider == null) { - AquaSingleImagePainter.paintFromSingleCachedImage(g, control, stateToPaint, c, boundsRect); + AquaSingleImagePainter.paintFromSingleCachedImage(g, control, stateToPaint, boundsRect); return; } @@ -114,7 +117,7 @@ if (slicesRef == null) { final NineSliceMetrics metrics = metricsProvider.getNineSliceMetricsForState(stateToPaint); if (metrics == null) { - AquaSingleImagePainter.paintFromSingleCachedImage(g, control, stateToPaint, c, boundsRect); + AquaSingleImagePainter.paintFromSingleCachedImage(g, control, stateToPaint, boundsRect); return; } slicesRef = new RecyclableJRSUISlicedImageControl(control, stateToPaint, metrics); @@ -125,47 +128,55 @@ } } - static class AquaSingleImagePainter<T extends JRSUIState> extends AquaPainter<T> { + private static final class AquaSingleImagePainter<T extends JRSUIState> + extends AquaPainter<T> { + AquaSingleImagePainter(final T state) { super(new JRSUIControl(false), state); } @Override - void paint(Graphics2D g, T stateToPaint, Component c) { - paintFromSingleCachedImage(g, control, stateToPaint, c, boundsRect); + void paint(final Graphics2D g, final T stateToPaint) { + paintFromSingleCachedImage(g, control, stateToPaint, boundsRect); } - static void paintFromSingleCachedImage(final Graphics2D g, final JRSUIControl control, final JRSUIState controlState, final Component c, final Rectangle boundsRect) { - final Rectangle clipRect = g.getClipBounds(); - final Rectangle intersection = boundsRect.intersection(clipRect); - if (intersection.width <= 0 || intersection.height <= 0) return; + static void paintFromSingleCachedImage(final Graphics2D g, + final JRSUIControl control, final JRSUIState controlState, + final Rectangle bounds) { + if (bounds.width <= 0 || bounds.height <= 0) { + return; + } - final int imgX1 = intersection.x - boundsRect.x; - final int imgY1 = intersection.y - boundsRect.y; - + int scale = 1; + if (g instanceof SunGraphics2D) { + scale = ((SunGraphics2D) g).surfaceData.getDefaultScale(); + } final GraphicsConfiguration config = g.getDeviceConfiguration(); final ImageCache cache = ImageCache.getInstance(); - BufferedImage image = (BufferedImage)cache.getImage(config, boundsRect.width, boundsRect.height, controlState); - if (image == null) { - image = new BufferedImage(boundsRect.width, boundsRect.height, BufferedImage.TYPE_INT_ARGB_PRE); - cache.setImage(image, config, boundsRect.width, boundsRect.height, controlState); - final WritableRaster raster = image.getRaster(); - final DataBufferInt buffer = (DataBufferInt)raster.getDataBuffer(); + final int imgW = bounds.width * scale; + final int imgH = bounds.height * scale; + BufferedImage img = (BufferedImage) cache.getImage(config, imgW, imgH, scale, controlState); + if (img == null) { + img = new BufferedImage(imgW, imgH, BufferedImage.TYPE_INT_ARGB_PRE); + cache.setImage(img, config, imgW, imgH, scale, controlState); + final WritableRaster raster = img.getRaster(); + final DataBufferInt buffer = (DataBufferInt) raster.getDataBuffer(); control.set(controlState); control.paint(SunWritableRaster.stealData(buffer, 0), - image.getWidth(), image.getHeight(), 0, 0, boundsRect.width, boundsRect.height); + imgW, imgH, 0, 0, bounds.width, bounds.height); SunWritableRaster.markDirty(buffer); } - g.drawImage(image, intersection.x, intersection.y, intersection.x + intersection.width, intersection.y + intersection.height, - imgX1, imgY1, imgX1 + intersection.width, imgY1 + intersection.height, null); + g.drawImage(img, bounds.x, bounds.y, bounds.width, bounds.height, null); } } - static class RecyclableJRSUISlicedImageControl extends RecyclableSlicedImageControl { - final JRSUIControl control; - final JRSUIState state; + private static class RecyclableJRSUISlicedImageControl + extends RecyclableSlicedImageControl { + + private final JRSUIControl control; + private final JRSUIState state; RecyclableJRSUISlicedImageControl(final JRSUIControl control, final JRSUIState state, final NineSliceMetrics metrics) { super(metrics); @@ -189,17 +200,19 @@ } } - protected Graphics2D getGraphics2D(final Graphics g) { + private Graphics2D getGraphics2D(final Graphics g) { try { return (SunGraphics2D)g; // doing a blind try is faster than checking instanceof - } catch (Exception e) { + } catch (Exception ignored) { if (g instanceof PeekGraphics) { // if it is a peek just dirty the region g.fillRect(boundsRect.x, boundsRect.y, boundsRect.width, boundsRect.height); } else if (g instanceof ProxyGraphics2D) { final ProxyGraphics2D pg = (ProxyGraphics2D)g; final Graphics2D g2d = pg.getDelegate(); - if (g2d instanceof SunGraphics2D) { return (SunGraphics2D)g2d; } + if (g2d instanceof SunGraphics2D) { + return g2d; + } } else if (g instanceof Graphics2D) { return (Graphics2D) g; }
--- a/src/macosx/classes/com/apple/laf/ImageCache.java Fri Apr 12 15:28:49 2013 +0400 +++ b/src/macosx/classes/com/apple/laf/ImageCache.java Fri Apr 12 20:39:48 2013 +0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,16 +81,23 @@ } } - public Image getImage(final GraphicsConfiguration config, final int w, final int h, final JRSUIState state) { + public Image getImage(final GraphicsConfiguration config, final int w, + final int h, final int scale, + final JRSUIState state) { + final int hash = hash(config, w, h, scale, state); + final PixelCountSoftReference ref; lock.readLock().lock(); try { - final PixelCountSoftReference ref = map.get(hash(config, w, h, state)); - // check reference has not been lost and the key truly matches, in case of false positive hash match - if (ref != null && ref.equals(config, w, h, state)) return ref.get(); - return null; + ref = map.get(hash); } finally { lock.readLock().unlock(); } + // check reference has not been lost and the key truly matches, + // in case of false positive hash match + if (ref != null && ref.equals(config, w, h, scale, state)) { + return ref.get(); + } + return null; } /** @@ -100,14 +107,17 @@ * @param config The graphics configuration, needed if cached image is a Volatile Image. Used as part of cache key * @param w The image width, used as part of cache key * @param h The image height, used as part of cache key + * @param scale The image scale factor, used as part of cache key * @return true if the image could be cached, false otherwise. */ - public boolean setImage(final Image image, final GraphicsConfiguration config, final int w, final int h, final JRSUIState state) { + public boolean setImage(final Image image, + final GraphicsConfiguration config, final int w, final int h, + final int scale, final JRSUIState state) { if (state.is(JRSUIConstants.Animating.YES)) { return false; } - final int hash = hash(config, w, h, state); + final int hash = hash(config, w, h, scale, state); lock.writeLock().lock(); try { @@ -145,44 +155,60 @@ } } // finally put new in map - map.put(hash, new PixelCountSoftReference(image, referenceQueue, newPixelCount, hash, config, w, h, state)); + map.put(hash, new PixelCountSoftReference(image, referenceQueue, newPixelCount, hash, config, w, h, scale, state)); return true; } finally { lock.writeLock().unlock(); } } - private int hash(final GraphicsConfiguration config, final int w, final int h, final JRSUIState state) { - int hash = (config != null ? config.hashCode() : 0); + private static int hash(final GraphicsConfiguration config, final int w, + final int h, final int scale, + final JRSUIState state) { + int hash = config != null ? config.hashCode() : 0; hash = 31 * hash + w; hash = 31 * hash + h; + hash = 31 * hash + scale; hash = 31 * hash + state.hashCode(); return hash; } - /** Extended SoftReference that stores the pixel count even after the image is lost */ + /** + * Extended SoftReference that stores the pixel count even after the image + * is lost. + */ private static class PixelCountSoftReference extends SoftReference<Image> { - private final int pixelCount; - private final int hash; + + // default access, because access to these fields shouldn't be emulated + // by a synthetic accessor. + final int pixelCount; + final int hash; // key parts private final GraphicsConfiguration config; private final int w; private final int h; + private final int scale; private final JRSUIState state; - PixelCountSoftReference(final Image referent, final ReferenceQueue<? super Image> q, final int pixelCount, final int hash, final GraphicsConfiguration config, final int w, final int h, final JRSUIState state) { + PixelCountSoftReference(final Image referent, + final ReferenceQueue<? super Image> q, final int pixelCount, + final int hash, final GraphicsConfiguration config, final int w, + final int h, final int scale, final JRSUIState state) { super(referent, q); this.pixelCount = pixelCount; this.hash = hash; this.config = config; this.w = w; this.h = h; + this.scale = scale; this.state = state; } - public boolean equals(final GraphicsConfiguration config, final int w, final int h, final JRSUIState state) { - return config == this.config && w == this.w && h == this.h && state.equals(this.state); + boolean equals(final GraphicsConfiguration config, final int w, + final int h, final int scale, final JRSUIState state) { + return config == this.config && w == this.w && h == this.h + && scale == this.scale && state.equals(this.state); } }
--- a/src/macosx/native/com/apple/laf/JRSUIController.m Fri Apr 12 15:28:49 2013 +0400 +++ b/src/macosx/native/com/apple/laf/JRSUIController.m Fri Apr 12 20:39:48 2013 +0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -199,6 +199,7 @@ CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); CGContextRef cgRef = CGBitmapContextCreate(rawPixelData, imgW, imgH, 8, imgW * 4, colorspace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); CGColorSpaceRelease(colorspace); + CGContextScaleCTM(cgRef, imgW/w , imgH/h); jint status = doPaintCGContext(cgRef, controlPtr, oldProperties, newProperties, x, y, w, h); CGContextRelease(cgRef);