From 161dccf85f878eac6965eb261330d9faf2487cb0 Mon Sep 17 00:00:00 2001 From: Vassiliy Kudryashov Date: Wed, 16 Jan 2013 16:53:49 +0400 Subject: [PATCH] JBGradientPaint --- .../src/com/intellij/ui/JBGradientPaint.java | 284 ++++++++++++++++- .../intellij/ui/JBGradientPaintContext.java | 291 ------------------ 2 files changed, 280 insertions(+), 295 deletions(-) delete mode 100644 platform/platform-api/src/com/intellij/ui/JBGradientPaintContext.java diff --git a/platform/platform-api/src/com/intellij/ui/JBGradientPaint.java b/platform/platform-api/src/com/intellij/ui/JBGradientPaint.java index 24d177e3a68c..6e0fe38b41df 100644 --- a/platform/platform-api/src/com/intellij/ui/JBGradientPaint.java +++ b/platform/platform-api/src/com/intellij/ui/JBGradientPaint.java @@ -15,13 +15,23 @@ */ package com.intellij.ui; +import sun.awt.image.IntegerComponentRaster; + import javax.swing.*; import java.awt.*; import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.Raster; +import java.lang.ref.WeakReference; +/** + * This class provides gradient paint with dithering (run main() to see the difference)

+ * Note, it doesn't support "cyclic" mode. + */ public class JBGradientPaint extends GradientPaint { public JBGradientPaint(float x1, float y1, Color color1, float x2, float y2, Color color2) { super(x1, y1, color1, x2, y2, color2); @@ -47,9 +57,9 @@ public class JBGradientPaint extends GradientPaint { JFrame f = new JFrame("JBGradientPaint"); JPanel contentPane = new JPanel(new GridLayout(1, 2, 1, 1)); f.setContentPane(contentPane); - JPanel leftPanel = new JPanel(){ + JPanel leftPanel = new JPanel(new BorderLayout()){ @Override - public void paint(Graphics g) { + public void paintComponent(Graphics g) { ((Graphics2D)g).setPaint(new GradientPaint(0, 0, c1, size/2, size, c2)); g.fillRect(0, 0, size, size); } @@ -59,9 +69,9 @@ public class JBGradientPaint extends GradientPaint { return new Dimension(size, size); } }; - JPanel rightPanel = new JPanel(){ + JPanel rightPanel = new JPanel(new BorderLayout()){ @Override - public void paint(Graphics g) { + public void paintComponent(Graphics g) { ((Graphics2D)g).setPaint(new JBGradientPaint(0, 0, c1, size/2, size, c2)); g.fillRect(0, 0, size, size); } @@ -71,6 +81,8 @@ public class JBGradientPaint extends GradientPaint { return new Dimension(size, size); } }; + leftPanel.add(new JLabel("Standard gradient"), BorderLayout.NORTH); + rightPanel.add(new JLabel("Dithered gradient"), BorderLayout.NORTH); leftPanel.setOpaque(true); rightPanel.setOpaque(true); contentPane.add(leftPanel); @@ -80,4 +92,268 @@ public class JBGradientPaint extends GradientPaint { f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); f.setVisible(true); } + + /** + * Most of the code copied from java.awt.GradientPaintContext + */ + private static class JBGradientPaintContext implements PaintContext { + private static final ColorModel RGBMODEL = new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff); + private static final ColorModel BGRMODEL = new DirectColorModel(24, 0x000000ff, 0x0000ff00, 0x00ff0000); + private static final ThreadLocal RGB_ARRAYS = new ThreadLocal() { + @Override + protected int[][] initialValue() { + return new int[3][256]; + } + }; + private static final ThreadLocal DITHER_ARRAYS = new ThreadLocal() { + @Override + protected int[][][][] initialValue() { + return new int[3][256][][]; + } + }; + //Dithering + private static final double GR = (Math.sqrt(5) - 1) / 2; + private static final int[] IDENTITY_FUNC = new int[256]; + private static final int[] SHIFT_FUNC = new int[256]; + private static final int[][][] DITHER_MATRIX = new int[256][256][]; + static { + for (int i = 0; i < 256; i++) { + IDENTITY_FUNC[i] = i; + SHIFT_FUNC[i] = i + 1; + } + SHIFT_FUNC[255] = 255; + int iter = 0; + for (int i = 0; i < DITHER_MATRIX.length; i++) { + int[][] row = DITHER_MATRIX[i]; + for (int j = 0; j < row.length; j++) { + row[j] = IDENTITY_FUNC; + } + for (int j = 0; j < i; j++) { + int pos = (int)(1604419 * GR * iter) % (256 - j); + row[getIndex(row, pos)] = SHIFT_FUNC; + iter++; + } + } + } + private static ColorModel cachedModel; + private static WeakReference cached; + + private final double myX1; + private final double myY1; + private final double myDx; + private final double myDy; + private final int myRgb1; + private final int myRgb2; + private Raster saved; + private final ColorModel model; + + JBGradientPaintContext(ColorModel cm, + Point2D p1, Point2D p2, AffineTransform xform, + Color c1, Color c2) { + Point2D xvec = new Point2D.Double(1, 0); + Point2D yvec = new Point2D.Double(0, 1); + try { + AffineTransform inverse = xform.createInverse(); + inverse.deltaTransform(xvec, xvec); + inverse.deltaTransform(yvec, yvec); + } + catch (NoninvertibleTransformException e) { + xvec.setLocation(0, 0); + yvec.setLocation(0, 0); + } + + double udx = p2.getX() - p1.getX(); + double udy = p2.getY() - p1.getY(); + double ulenSq = udx * udx + udy * udy; + + if (ulenSq <= Double.MIN_VALUE) { + myDx = 0; + myDy = 0; + } + else { + double dxx = (xvec.getX() * udx + xvec.getY() * udy) / ulenSq; + double dyy = (yvec.getX() * udx + yvec.getY() * udy) / ulenSq; + + if (dxx < 0) { + p1 = p2; + Color c = c1; + c1 = c2; + c2 = c; + myDx = -dxx; + myDy = -dyy; + } + else { + myDx = dxx; + myDy = dyy; + } + } + + Point2D dp1 = xform.transform(p1, null); + this.myX1 = dp1.getX(); + this.myY1 = dp1.getY(); + + myRgb1 = c1.getRGB(); + myRgb2 = c2.getRGB(); + int a1 = (myRgb1 >> 24) & 0xff; + int r1 = (myRgb1 >> 16) & 0xff; + int g1 = (myRgb1 >> 8) & 0xff; + int b1 = (myRgb1) & 0xff; + int da = ((myRgb2 >> 24) & 0xff) - a1; + int dr = ((myRgb2 >> 16) & 0xff) - r1; + int dg = ((myRgb2 >> 8) & 0xff) - g1; + int db = ((myRgb2) & 0xff) - b1; + ColorModel m; + if (a1 == 0xff && da == 0) { + m = RGBMODEL; + if (cm instanceof DirectColorModel) { + DirectColorModel dcm = (DirectColorModel)cm; + int tmp = dcm.getAlphaMask(); + if ((tmp == 0 || tmp == 0xff) && + dcm.getRedMask() == 0xff && + dcm.getGreenMask() == 0xff00 && + dcm.getBlueMask() == 0xff0000) { + m = BGRMODEL; + tmp = r1; + r1 = b1; + b1 = tmp; + tmp = dr; + dr = db; + db = tmp; + } + } + } + else { + m = ColorModel.getRGBdefault(); + } + model = m; + + for (int i = 0; i < 256; i++) { + double rel = i / 256.0f; + double rValue = r1 + dr * rel; + double gValue = g1 + dg * rel; + double bValue = b1 + db * rel; + + DITHER_ARRAYS.get()[0][i] = DITHER_MATRIX[(int)(rValue * 256) % 256]; + DITHER_ARRAYS.get()[1][i] = DITHER_MATRIX[(int)(gValue * 256) % 256]; + DITHER_ARRAYS.get()[2][i] = DITHER_MATRIX[(int)(bValue * 256) % 256]; + + RGB_ARRAYS.get()[0][i] = (int)rValue; + RGB_ARRAYS.get()[1][i] = (int)gValue; + RGB_ARRAYS.get()[2][i] = (int)bValue; + } + } + + static synchronized Raster getCachedRaster(ColorModel cm, int w, int h) { + if (cm == cachedModel) { + if (cached != null) { + Raster ras = cached.get(); + if (ras != null && + ras.getWidth() >= w && + ras.getHeight() >= h) { + cached = null; + return ras; + } + } + } + return cm.createCompatibleWritableRaster(w, h); + } + + static synchronized void putCachedRaster(ColorModel cm, Raster ras) { + if (cached != null) { + Raster raster = cached.get(); + if (raster != null) { + int cw = raster.getWidth(); + int ch = raster.getHeight(); + int iw = ras.getWidth(); + int ih = ras.getHeight(); + if (cw >= iw && ch >= ih) { + return; + } + if (cw * ch >= iw * ih) { + return; + } + } + } + cachedModel = cm; + cached = new WeakReference(ras); + } + + private static int getIndex(int[][] arr, int pos) { + for (int i = 0; i < arr.length; i++) { + int[] f = arr[i]; + if (f == IDENTITY_FUNC) { + pos--; + } + if (pos < 0) { + return i; + } + } + throw new IllegalArgumentException(); + } + + public void dispose() { + if (saved != null) { + putCachedRaster(model, saved); + saved = null; + } + } + + public ColorModel getColorModel() { + return model; + } + + public Raster getRaster(int x, int y, int w, int h) { + double rowrel = (x - myX1) * myDx + (y - myY1) * myDy; + + Raster rast = saved; + if (rast == null || rast.getWidth() < w || rast.getHeight() < h) { + rast = getCachedRaster(model, w, h); + saved = rast; + } + IntegerComponentRaster irast = (IntegerComponentRaster)rast; + int off = irast.getDataOffset(0); + int adjust = irast.getScanlineStride() - w; + int[] pixels = irast.getDataStorage(); + + clipFillRaster(pixels, off, adjust, w, h, rowrel, myDx, myDy); + + return rast; + } + + void clipFillRaster(int[] pixels, int off, int adjust, int w, int h, double rowrel, double dx, double dy) { + while (--h >= 0) { + double colrel = rowrel; + int j = w; + if (colrel <= 0.0) { + int rgb = myRgb1; + do { + pixels[off++] = rgb; + colrel += dx; + } + while (--j > 0 && colrel <= 0.0); + } + while (colrel < 1.0 && --j >= 0) { + int offrel = off & 0xFF; + int idx = (int)(colrel * 256); + + int rresult = DITHER_ARRAYS.get()[0][idx][offrel][RGB_ARRAYS.get()[0][idx]]; + int gresult = DITHER_ARRAYS.get()[1][idx][offrel][RGB_ARRAYS.get()[1][idx]]; + int bresult = DITHER_ARRAYS.get()[2][idx][offrel][RGB_ARRAYS.get()[2][idx]]; + + pixels[off++] = (rresult << 16) | (gresult << 8) | bresult; + colrel += dx; + } + if (j > 0) { + int rgb = myRgb2; + do { + pixels[off++] = rgb; + } + while (--j > 0); + } + + off += adjust; + rowrel += dy; + } + } + } } diff --git a/platform/platform-api/src/com/intellij/ui/JBGradientPaintContext.java b/platform/platform-api/src/com/intellij/ui/JBGradientPaintContext.java deleted file mode 100644 index 6ece75baba60..000000000000 --- a/platform/platform-api/src/com/intellij/ui/JBGradientPaintContext.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright 2000-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.ui; - -import sun.awt.image.IntegerComponentRaster; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.NoninvertibleTransformException; -import java.awt.geom.Point2D; -import java.awt.image.ColorModel; -import java.awt.image.DirectColorModel; -import java.awt.image.Raster; -import java.lang.ref.WeakReference; - -/** - * Most of the code copied from java.awt.GradientPaintContext - */ -class JBGradientPaintContext implements PaintContext { - private static final ColorModel RGBMODEL = new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff); - private static final ColorModel BGRMODEL = new DirectColorModel(24, 0x000000ff, 0x0000ff00, 0x00ff0000); - private static final ThreadLocal RGB_ARRAYS = new ThreadLocal() { - @Override - protected int[][] initialValue() { - return new int[3][256]; - } - }; - private static final ThreadLocal DITHER_ARRAYS = new ThreadLocal() { - @Override - protected int[][][][] initialValue() { - return new int[3][256][][]; - } - }; - //Dithering - private static final double GR = (Math.sqrt(5) - 1) / 2; - private static final int[] IDENTITY_FUNC = new int[256]; - private static final int[] SHIFT_FUNC = new int[256]; - private static final int[][][] DITHER_MATRIX = new int[256][256][]; - static { - for (int i = 0; i < 256; i++) { - IDENTITY_FUNC[i] = i; - SHIFT_FUNC[i] = i + 1; - } - SHIFT_FUNC[255] = 255; - int iter = 0; - for (int i = 0; i < DITHER_MATRIX.length; i++) { - int[][] row = DITHER_MATRIX[i]; - for (int j = 0; j < row.length; j++) { - row[j] = IDENTITY_FUNC; - } - for (int j = 0; j < i; j++) { - int pos = (int)(1604419 * GR * iter) % (256 - j); - row[getIndex(row, pos)] = SHIFT_FUNC; - iter++; - } - } - } - private static ColorModel cachedModel; - private static WeakReference cached; - - private final double myX1; - private final double myY1; - private final double myDx; - private final double myDy; - private final int myRgb1; - private final int myRgb2; - private Raster saved; - private final ColorModel model; - - JBGradientPaintContext(ColorModel cm, - Point2D p1, Point2D p2, AffineTransform xform, - Color c1, Color c2) { - Point2D xvec = new Point2D.Double(1, 0); - Point2D yvec = new Point2D.Double(0, 1); - try { - AffineTransform inverse = xform.createInverse(); - inverse.deltaTransform(xvec, xvec); - inverse.deltaTransform(yvec, yvec); - } - catch (NoninvertibleTransformException e) { - xvec.setLocation(0, 0); - yvec.setLocation(0, 0); - } - - double udx = p2.getX() - p1.getX(); - double udy = p2.getY() - p1.getY(); - double ulenSq = udx * udx + udy * udy; - - if (ulenSq <= Double.MIN_VALUE) { - myDx = 0; - myDy = 0; - } - else { - double dxx = (xvec.getX() * udx + xvec.getY() * udy) / ulenSq; - double dyy = (yvec.getX() * udx + yvec.getY() * udy) / ulenSq; - - if (dxx < 0) { - p1 = p2; - Color c = c1; - c1 = c2; - c2 = c; - myDx = -dxx; - myDy = -dyy; - } - else { - myDx = dxx; - myDy = dyy; - } - } - - Point2D dp1 = xform.transform(p1, null); - this.myX1 = dp1.getX(); - this.myY1 = dp1.getY(); - - myRgb1 = c1.getRGB(); - myRgb2 = c2.getRGB(); - int a1 = (myRgb1 >> 24) & 0xff; - int r1 = (myRgb1 >> 16) & 0xff; - int g1 = (myRgb1 >> 8) & 0xff; - int b1 = (myRgb1) & 0xff; - int da = ((myRgb2 >> 24) & 0xff) - a1; - int dr = ((myRgb2 >> 16) & 0xff) - r1; - int dg = ((myRgb2 >> 8) & 0xff) - g1; - int db = ((myRgb2) & 0xff) - b1; - ColorModel m; - if (a1 == 0xff && da == 0) { - m = RGBMODEL; - if (cm instanceof DirectColorModel) { - DirectColorModel dcm = (DirectColorModel)cm; - int tmp = dcm.getAlphaMask(); - if ((tmp == 0 || tmp == 0xff) && - dcm.getRedMask() == 0xff && - dcm.getGreenMask() == 0xff00 && - dcm.getBlueMask() == 0xff0000) { - m = BGRMODEL; - tmp = r1; - r1 = b1; - b1 = tmp; - tmp = dr; - dr = db; - db = tmp; - } - } - } - else { - m = ColorModel.getRGBdefault(); - } - model = m; - - for (int i = 0; i < 256; i++) { - double rel = i / 256.0f; - double rValue = r1 + dr * rel; - double gValue = g1 + dg * rel; - double bValue = b1 + db * rel; - - DITHER_ARRAYS.get()[0][i] = DITHER_MATRIX[(int)(rValue * 256) % 256]; - DITHER_ARRAYS.get()[1][i] = DITHER_MATRIX[(int)(gValue * 256) % 256]; - DITHER_ARRAYS.get()[2][i] = DITHER_MATRIX[(int)(bValue * 256) % 256]; - - RGB_ARRAYS.get()[0][i] = (int)rValue; - RGB_ARRAYS.get()[1][i] = (int)gValue; - RGB_ARRAYS.get()[2][i] = (int)bValue; - } - } - - static synchronized Raster getCachedRaster(ColorModel cm, int w, int h) { - if (cm == cachedModel) { - if (cached != null) { - Raster ras = cached.get(); - if (ras != null && - ras.getWidth() >= w && - ras.getHeight() >= h) { - cached = null; - return ras; - } - } - } - return cm.createCompatibleWritableRaster(w, h); - } - - static synchronized void putCachedRaster(ColorModel cm, Raster ras) { - if (cached != null) { - Raster raster = cached.get(); - if (raster != null) { - int cw = raster.getWidth(); - int ch = raster.getHeight(); - int iw = ras.getWidth(); - int ih = ras.getHeight(); - if (cw >= iw && ch >= ih) { - return; - } - if (cw * ch >= iw * ih) { - return; - } - } - } - cachedModel = cm; - cached = new WeakReference(ras); - } - - private static int getIndex(int[][] arr, int pos) { - for (int i = 0; i < arr.length; i++) { - int[] f = arr[i]; - if (f == IDENTITY_FUNC) { - pos--; - } - if (pos < 0) { - return i; - } - } - throw new IllegalArgumentException(); - } - - public void dispose() { - if (saved != null) { - putCachedRaster(model, saved); - saved = null; - } - } - - public ColorModel getColorModel() { - return model; - } - - public Raster getRaster(int x, int y, int w, int h) { - double rowrel = (x - myX1) * myDx + (y - myY1) * myDy; - - Raster rast = saved; - if (rast == null || rast.getWidth() < w || rast.getHeight() < h) { - rast = getCachedRaster(model, w, h); - saved = rast; - } - IntegerComponentRaster irast = (IntegerComponentRaster)rast; - int off = irast.getDataOffset(0); - int adjust = irast.getScanlineStride() - w; - int[] pixels = irast.getDataStorage(); - - clipFillRaster(pixels, off, adjust, w, h, rowrel, myDx, myDy); - - return rast; - } - - void clipFillRaster(int[] pixels, int off, int adjust, int w, int h, double rowrel, double dx, double dy) { - while (--h >= 0) { - double colrel = rowrel; - int j = w; - if (colrel <= 0.0) { - int rgb = myRgb1; - do { - pixels[off++] = rgb; - colrel += dx; - } - while (--j > 0 && colrel <= 0.0); - } - while (colrel < 1.0 && --j >= 0) { - int offrel = off & 0xFF; - int idx = (int)(colrel * 256); - - int rresult = DITHER_ARRAYS.get()[0][idx][offrel][RGB_ARRAYS.get()[0][idx]]; - int gresult = DITHER_ARRAYS.get()[1][idx][offrel][RGB_ARRAYS.get()[1][idx]]; - int bresult = DITHER_ARRAYS.get()[2][idx][offrel][RGB_ARRAYS.get()[2][idx]]; - - pixels[off++] = (rresult << 16) | (gresult << 8) | bresult; - colrel += dx; - } - if (j > 0) { - int rgb = myRgb2; - do { - pixels[off++] = rgb; - } - while (--j > 0); - } - - off += adjust; - rowrel += dy; - } - } -} \ No newline at end of file