19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  this work for additional information regarding copyright ownership.
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  (the "License"); you may not use this file except in compliance with
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  the License.  You may obtain a copy of the License at
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  See the License for the specific language governing permissions and
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  limitations under the License.
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @author Denis M. Kishenko
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @version $Revision$
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage java.awt;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.awt.geom.AffineTransform;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.awt.geom.Point2D;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.awt.image.ColorModel;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.awt.image.DataBufferInt;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.awt.image.Raster;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.awt.image.WritableRaster;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass GradientPaintContext implements PaintContext {
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The size of noncyclic part of color lookup table
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static int LOOKUP_SIZE = 256;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The index mask to lookup color in the table
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static int LOOKUP_MASK = 0x1FF;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The min value equivalent to zero. If absolute value less then ZERO it considered as zero.
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static double ZERO = 1E-10;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The ColorModel user defined for PaintContext
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ColorModel cm;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The indicator of cycle filling.
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean cyclic;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The integer color value of the start point
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int c1;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The integer color value of the end point
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int c2;
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The lookup gradient color table
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int[] table;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The tempopary pre-calculated value to evalutae color index
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int dx;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The tempopary pre-calculated value to evalutae color index
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int dy;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The tempopary pre-calculated value to evalutae color index
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int delta;
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Constructs a new GradientPaintcontext
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param cm - not used
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param t - the fill transformation
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param point1 - the start fill point
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param color1 - color of the start point
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param point2 - the end fill point
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param color2 - color of the end point
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param cyclic - the indicator of cycle filling
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    GradientPaintContext(ColorModel cm, AffineTransform t, Point2D point1, Color color1, Point2D point2, Color color2, boolean cyclic) {
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this.cyclic = cyclic;
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this.cm = ColorModel.getRGBdefault();
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        c1 = color1.getRGB();
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        c2 = color2.getRGB();
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        double px = point2.getX() - point1.getX();
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        double py = point2.getY() - point1.getY();
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Point2D p = t.transform(point1, null);
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Point2D bx = new Point2D.Double(px, py);
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Point2D by = new Point2D.Double(py, -px);
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        t.deltaTransform(bx, bx);
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        t.deltaTransform(by, by);
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        double vec = bx.getX() * by.getY() - bx.getY() * by.getX();
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (Math.abs(vec) < ZERO) {
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dx = dy = delta = 0;
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            table = new int[1];
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            table[0] = c1;
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            double mult = LOOKUP_SIZE * 256 / vec;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dx = (int)(by.getX() * mult);
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dy = (int)(by.getY() * mult);
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            delta = (int)((p.getX() * by.getY() - p.getY() * by.getX()) * mult);
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            createTable();
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create color index lookup table. Calculate 256 step trasformation from
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the start point color to the end point color. Colors multiplied by 256 to do integer calculations.
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void createTable() {
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        double ca = (c1 >> 24) & 0xFF;
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        double cr = (c1 >> 16) & 0xFF;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        double cg = (c1 >> 8) & 0xFF;
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        double cb = c1 & 0xFF;
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        double k = 1.0 / LOOKUP_SIZE;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        double da = (((c2 >> 24) & 0xFF) - ca) * k;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        double dr = (((c2 >> 16) & 0xFF) - cr) * k;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        double dg = (((c2 >> 8) & 0xFF) - cg) * k;
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        double db = ((c2 & 0xFF) - cb) * k;
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        table = new int[cyclic ? LOOKUP_SIZE + LOOKUP_SIZE : LOOKUP_SIZE];
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for(int i = 0; i < LOOKUP_SIZE; i++) {
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            table[i] =
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                (int)ca << 24 |
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                (int)cr << 16 |
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                (int)cg << 8 |
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                (int)cb;
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ca += da;
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cr += dr;
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cg += dg;
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cb += db;
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (cyclic) {
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for(int i = 0; i < LOOKUP_SIZE; i++) {
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                table[LOOKUP_SIZE + LOOKUP_SIZE - 1 - i] = table[i];
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ColorModel getColorModel() {
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return cm;
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void dispose() {
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Raster getRaster(int x, int y, int w, int h) {
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        WritableRaster rast = cm.createCompatibleWritableRaster(w, h);
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] buf = ((DataBufferInt)rast.getDataBuffer()).getData();
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int c = x * dy - y * dx - delta;
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int cx = dy;
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int cy = - w * dy - dx;
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int k = 0;
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (cyclic) {
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for(int j = 0; j < h; j++) {
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for(int i = 0; i < w; i++) {
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    buf[k++] = table[(c >> 8) & LOOKUP_MASK];
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    c += cx;
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                c += cy;
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for(int j = 0; j < h; j++) {
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for(int i = 0; i < w; i++) {
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int index = c >> 8;
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    buf[k++] = index < 0 ? c1 : index >= LOOKUP_SIZE ? c2 : table[index];
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    c += cx;
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                c += cy;
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return rast;
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
205