Path: blob/master/src/java.desktop/share/classes/java/awt/GradientPaintContext.java
41152 views
/*1* Copyright (c) 1997, 2018, 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*/2425package java.awt;2627import java.awt.image.Raster;28import sun.awt.image.IntegerComponentRaster;29import java.awt.image.ColorModel;30import java.awt.image.DirectColorModel;31import java.awt.geom.Point2D;32import java.awt.geom.AffineTransform;33import java.awt.geom.NoninvertibleTransformException;34import java.lang.ref.WeakReference;3536class GradientPaintContext implements PaintContext {37static ColorModel xrgbmodel =38new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff);39static ColorModel xbgrmodel =40new DirectColorModel(24, 0x000000ff, 0x0000ff00, 0x00ff0000);4142static ColorModel cachedModel;43static WeakReference<Raster> cached;4445static synchronized Raster getCachedRaster(ColorModel cm, int w, int h) {46if (cm == cachedModel) {47if (cached != null) {48Raster ras = cached.get();49if (ras != null &&50ras.getWidth() >= w &&51ras.getHeight() >= h)52{53cached = null;54return ras;55}56}57}58return cm.createCompatibleWritableRaster(w, h);59}6061static synchronized void putCachedRaster(ColorModel cm, Raster ras) {62if (cached != null) {63Raster cras = cached.get();64if (cras != null) {65int cw = cras.getWidth();66int ch = cras.getHeight();67int iw = ras.getWidth();68int ih = ras.getHeight();69if (cw >= iw && ch >= ih) {70return;71}72if (cw * ch >= iw * ih) {73return;74}75}76}77cachedModel = cm;78cached = new WeakReference<>(ras);79}8081double x1;82double y1;83double dx;84double dy;85boolean cyclic;86int[] interp;87Raster saved;88ColorModel model;8990public GradientPaintContext(ColorModel cm,91Point2D p1, Point2D p2, AffineTransform xform,92Color c1, Color c2, boolean cyclic) {93// First calculate the distance moved in user space when94// we move a single unit along the X & Y axes in device space.95Point2D xvec = new Point2D.Double(1, 0);96Point2D yvec = new Point2D.Double(0, 1);97try {98AffineTransform inverse = xform.createInverse();99inverse.deltaTransform(xvec, xvec);100inverse.deltaTransform(yvec, yvec);101} catch (NoninvertibleTransformException e) {102xvec.setLocation(0, 0);103yvec.setLocation(0, 0);104}105106// Now calculate the (square of the) user space distance107// between the anchor points. This value equals:108// (UserVec . UserVec)109double udx = p2.getX() - p1.getX();110double udy = p2.getY() - p1.getY();111double ulenSq = udx * udx + udy * udy;112113if (ulenSq <= Double.MIN_VALUE) {114dx = 0;115dy = 0;116} else {117// Now calculate the proportional distance moved along the118// vector from p1 to p2 when we move a unit along X & Y in119// device space.120//121// The length of the projection of the Device Axis Vector is122// its dot product with the Unit User Vector:123// (DevAxisVec . (UserVec / Len(UserVec))124//125// The "proportional" length is that length divided again126// by the length of the User Vector:127// (DevAxisVec . (UserVec / Len(UserVec))) / Len(UserVec)128// which simplifies to:129// ((DevAxisVec . UserVec) / Len(UserVec)) / Len(UserVec)130// which simplifies to:131// (DevAxisVec . UserVec) / LenSquared(UserVec)132dx = (xvec.getX() * udx + xvec.getY() * udy) / ulenSq;133dy = (yvec.getX() * udx + yvec.getY() * udy) / ulenSq;134135if (cyclic) {136dx = dx % 1.0;137dy = dy % 1.0;138} else {139// We are acyclic140if (dx < 0) {141// If we are using the acyclic form below, we need142// dx to be non-negative for simplicity of scanning143// across the scan lines for the transition points.144// To ensure that constraint, we negate the dx/dy145// values and swap the points and colors.146Point2D p = p1; p1 = p2; p2 = p;147Color c = c1; c1 = c2; c2 = c;148dx = -dx;149dy = -dy;150}151}152}153154Point2D dp1 = xform.transform(p1, null);155this.x1 = dp1.getX();156this.y1 = dp1.getY();157158this.cyclic = cyclic;159int rgb1 = c1.getRGB();160int rgb2 = c2.getRGB();161int a1 = (rgb1 >> 24) & 0xff;162int r1 = (rgb1 >> 16) & 0xff;163int g1 = (rgb1 >> 8) & 0xff;164int b1 = (rgb1 ) & 0xff;165int da = ((rgb2 >> 24) & 0xff) - a1;166int dr = ((rgb2 >> 16) & 0xff) - r1;167int dg = ((rgb2 >> 8) & 0xff) - g1;168int db = ((rgb2 ) & 0xff) - b1;169if (a1 == 0xff && da == 0) {170model = xrgbmodel;171if (cm instanceof DirectColorModel) {172DirectColorModel dcm = (DirectColorModel) cm;173int tmp = dcm.getAlphaMask();174if ((tmp == 0 || tmp == 0xff) &&175dcm.getRedMask() == 0xff &&176dcm.getGreenMask() == 0xff00 &&177dcm.getBlueMask() == 0xff0000)178{179model = xbgrmodel;180tmp = r1; r1 = b1; b1 = tmp;181tmp = dr; dr = db; db = tmp;182}183}184} else {185model = ColorModel.getRGBdefault();186}187interp = new int[cyclic ? 513 : 257];188for (int i = 0; i <= 256; i++) {189float rel = i / 256.0f;190int rgb =191(((int) (a1 + da * rel)) << 24) |192(((int) (r1 + dr * rel)) << 16) |193(((int) (g1 + dg * rel)) << 8) |194(((int) (b1 + db * rel)) );195interp[i] = rgb;196if (cyclic) {197interp[512 - i] = rgb;198}199}200}201202/**203* Release the resources allocated for the operation.204*/205public void dispose() {206if (saved != null) {207putCachedRaster(model, saved);208saved = null;209}210}211212/**213* Return the ColorModel of the output.214*/215public ColorModel getColorModel() {216return model;217}218219/**220* Return a Raster containing the colors generated for the graphics221* operation.222* @param x,y,w,h The area in device space for which colors are223* generated.224*/225public Raster getRaster(int x, int y, int w, int h) {226double rowrel = (x - x1) * dx + (y - y1) * dy;227228Raster rast = saved;229if (rast == null || rast.getWidth() < w || rast.getHeight() < h) {230rast = getCachedRaster(model, w, h);231saved = rast;232}233IntegerComponentRaster irast = (IntegerComponentRaster) rast;234int off = irast.getDataOffset(0);235int adjust = irast.getScanlineStride() - w;236int[] pixels = irast.getDataStorage();237238if (cyclic) {239cycleFillRaster(pixels, off, adjust, w, h, rowrel, dx, dy);240} else {241clipFillRaster(pixels, off, adjust, w, h, rowrel, dx, dy);242}243244irast.markDirty();245246return rast;247}248249void cycleFillRaster(int[] pixels, int off, int adjust, int w, int h,250double rowrel, double dx, double dy) {251rowrel = rowrel % 2.0;252int irowrel = ((int) (rowrel * (1 << 30))) << 1;253int idx = (int) (-dx * (1 << 31));254int idy = (int) (-dy * (1 << 31));255while (--h >= 0) {256int icolrel = irowrel;257for (int j = w; j > 0; j--) {258pixels[off++] = interp[icolrel >>> 23];259icolrel += idx;260}261262off += adjust;263irowrel += idy;264}265}266267void clipFillRaster(int[] pixels, int off, int adjust, int w, int h,268double rowrel, double dx, double dy) {269while (--h >= 0) {270double colrel = rowrel;271int j = w;272if (colrel <= 0.0) {273int rgb = interp[0];274do {275pixels[off++] = rgb;276colrel += dx;277} while (--j > 0 && colrel <= 0.0);278}279while (colrel < 1.0 && --j >= 0) {280pixels[off++] = interp[(int) (colrel * 256)];281colrel += dx;282}283if (j > 0) {284int rgb = interp[256];285do {286pixels[off++] = rgb;287} while (--j > 0);288}289290off += adjust;291rowrel += dy;292}293}294}295296297