001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Denis M. Kishenko
019: * @version $Revision$
020: */package java.awt;
021:
022: import java.awt.geom.AffineTransform;
023: import java.awt.geom.Point2D;
024: import java.awt.image.ColorModel;
025: import java.awt.image.DataBufferInt;
026: import java.awt.image.Raster;
027: import java.awt.image.WritableRaster;
028:
029: class GradientPaintContext implements PaintContext {
030:
031: /**
032: * The size of noncyclic part of color lookup table
033: */
034: static int LOOKUP_SIZE = 256;
035:
036: /**
037: * The index mask to lookup color in the table
038: */
039: static int LOOKUP_MASK = 0x1FF;
040:
041: /**
042: * The min value equivalent to zero. If absolute value less then ZERO it considered as zero.
043: */
044: static double ZERO = 1E-10;
045:
046: /**
047: * The ColorModel user defined for PaintContext
048: */
049: ColorModel cm;
050:
051: /**
052: * The indicator of cycle filling.
053: */
054: boolean cyclic;
055:
056: /**
057: * The integer color value of the start point
058: */
059: int c1;
060:
061: /**
062: * The integer color value of the end point
063: */
064: int c2;
065:
066: /**
067: * The lookup gradient color table
068: */
069: int[] table;
070:
071: /**
072: * The tempopary pre-calculated value to evalutae color index
073: */
074: int dx;
075:
076: /**
077: * The tempopary pre-calculated value to evalutae color index
078: */
079: int dy;
080:
081: /**
082: * The tempopary pre-calculated value to evalutae color index
083: */
084: int delta;
085:
086: /**
087: * Constructs a new GradientPaintcontext
088: * @param cm - not used
089: * @param t - the fill transformation
090: * @param point1 - the start fill point
091: * @param color1 - color of the start point
092: * @param point2 - the end fill point
093: * @param color2 - color of the end point
094: * @param cyclic - the indicator of cycle filling
095: */
096: GradientPaintContext(ColorModel cm, AffineTransform t,
097: Point2D point1, Color color1, Point2D point2, Color color2,
098: boolean cyclic) {
099: this .cyclic = cyclic;
100: this .cm = ColorModel.getRGBdefault();
101:
102: c1 = color1.getRGB();
103: c2 = color2.getRGB();
104:
105: double px = point2.getX() - point1.getX();
106: double py = point2.getY() - point1.getY();
107:
108: Point2D p = t.transform(point1, null);
109: Point2D bx = new Point2D.Double(px, py);
110: Point2D by = new Point2D.Double(py, -px);
111:
112: t.deltaTransform(bx, bx);
113: t.deltaTransform(by, by);
114:
115: double vec = bx.getX() * by.getY() - bx.getY() * by.getX();
116:
117: if (Math.abs(vec) < ZERO) {
118: dx = dy = delta = 0;
119: table = new int[1];
120: table[0] = c1;
121: } else {
122: double mult = LOOKUP_SIZE * 256 / vec;
123: dx = (int) (by.getX() * mult);
124: dy = (int) (by.getY() * mult);
125: delta = (int) ((p.getX() * by.getY() - p.getY() * by.getX()) * mult);
126: createTable();
127: }
128: }
129:
130: /**
131: * Create color index lookup table. Calculate 256 step trasformation from
132: * the start point color to the end point color. Colors multiplied by 256 to do integer calculations.
133: */
134: void createTable() {
135: double ca = (c1 >> 24) & 0xFF;
136: double cr = (c1 >> 16) & 0xFF;
137: double cg = (c1 >> 8) & 0xFF;
138: double cb = c1 & 0xFF;
139:
140: double k = 1.0 / LOOKUP_SIZE;
141: double da = (((c2 >> 24) & 0xFF) - ca) * k;
142: double dr = (((c2 >> 16) & 0xFF) - cr) * k;
143: double dg = (((c2 >> 8) & 0xFF) - cg) * k;
144: double db = ((c2 & 0xFF) - cb) * k;
145:
146: table = new int[cyclic ? LOOKUP_SIZE + LOOKUP_SIZE
147: : LOOKUP_SIZE];
148: for (int i = 0; i < LOOKUP_SIZE; i++) {
149: table[i] = (int) ca << 24 | (int) cr << 16 | (int) cg << 8
150: | (int) cb;
151: ca += da;
152: cr += dr;
153: cg += dg;
154: cb += db;
155: }
156: if (cyclic) {
157: for (int i = 0; i < LOOKUP_SIZE; i++) {
158: table[LOOKUP_SIZE + LOOKUP_SIZE - 1 - i] = table[i];
159: }
160: }
161: }
162:
163: public ColorModel getColorModel() {
164: return cm;
165: }
166:
167: public void dispose() {
168: }
169:
170: public Raster getRaster(int x, int y, int w, int h) {
171: WritableRaster rast = cm.createCompatibleWritableRaster(w, h);
172:
173: int[] buf = ((DataBufferInt) rast.getDataBuffer()).getData();
174:
175: int c = x * dy - y * dx - delta;
176: int cx = dy;
177: int cy = -w * dy - dx;
178: int k = 0;
179:
180: if (cyclic) {
181: for (int j = 0; j < h; j++) {
182: for (int i = 0; i < w; i++) {
183: buf[k++] = table[(c >> 8) & LOOKUP_MASK];
184: c += cx;
185: }
186: c += cy;
187: }
188: } else {
189: for (int j = 0; j < h; j++) {
190: for (int i = 0; i < w; i++) {
191: int index = c >> 8;
192: buf[k++] = index < 0 ? c1
193: : index >= LOOKUP_SIZE ? c2 : table[index];
194: c += cx;
195: }
196: c += cy;
197: }
198: }
199:
200: return rast;
201: }
202:
203: }
|