1d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet/*
2d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * Copyright (C) 2010 The Android Open Source Project
3d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet *
4d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License");
5d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * you may not use this file except in compliance with the License.
6d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * You may obtain a copy of the License at
7d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet *
8d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet *      http://www.apache.org/licenses/LICENSE-2.0
9d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet *
10d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * Unless required by applicable law or agreed to in writing, software
11d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS,
12d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * See the License for the specific language governing permissions and
14d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * limitations under the License.
15d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet */
16d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
17d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohetpackage android.graphics;
18d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
19918aaa5717fce6081557c82ce1c439b6922737d5Xavier Ducrohetimport com.android.ide.common.rendering.api.LayoutLog;
20d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohetimport com.android.layoutlib.bridge.Bridge;
21d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohetimport com.android.layoutlib.bridge.impl.DelegateManager;
229a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohetimport com.android.tools.layoutlib.annotations.LayoutlibDelegate;
23d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
24d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohetimport android.graphics.Shader.TileMode;
25d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
26d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet/**
27d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * Delegate implementing the native methods of android.graphics.BitmapShader
28d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet *
29d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * Through the layoutlib_create tool, the original native methods of BitmapShader have been
30d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * replaced by calls to methods of the same name in this delegate class.
31d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet *
32d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * This class behaves like the original native implementation, but in Java, keeping previously
33d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * native data into its own objects and mapping them to int that are sent back and forth between
34d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * it and the original BitmapShader class.
35d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet *
36d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
37d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
38d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet *
39d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet * @see Shader_Delegate
40d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet *
41d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet */
42d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohetpublic class BitmapShader_Delegate extends Shader_Delegate {
43d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
44d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    // ---- delegate data ----
45d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    private java.awt.Paint mJavaPaint;
46d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
47d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    // ---- Public Helper methods ----
48d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
49d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    @Override
50d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    public java.awt.Paint getJavaPaint() {
51d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        return mJavaPaint;
52d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    }
53d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
54d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    @Override
55d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    public boolean isSupported() {
56d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        return true;
57d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    }
58d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
59d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    @Override
60d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    public String getSupportMessage() {
61d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        // no message since isSupported returns true;
62d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        return null;
63d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    }
64d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
65d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    // ---- native methods ----
66d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
679a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohet    @LayoutlibDelegate
68d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    /*package*/ static int nativeCreate(int native_bitmap, int shaderTileModeX,
69d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            int shaderTileModeY) {
70d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        Bitmap_Delegate bitmap = Bitmap_Delegate.getDelegate(native_bitmap);
71d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        if (bitmap == null) {
72d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            return 0;
73d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        }
74d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
75d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        BitmapShader_Delegate newDelegate = new BitmapShader_Delegate(
76d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                bitmap.getImage(),
77d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                Shader_Delegate.getTileMode(shaderTileModeX),
78d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                Shader_Delegate.getTileMode(shaderTileModeY));
79cc4977d0fdaf657907912fd6cc2f9426dc8d2e36Xavier Ducrohet        return sManager.addNewDelegate(newDelegate);
80d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    }
81d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
829a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohet    @LayoutlibDelegate
83d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    /*package*/ static int nativePostCreate(int native_shader, int native_bitmap,
84d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            int shaderTileModeX, int shaderTileModeY) {
85d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        // pass, not needed.
86d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        return 0;
87d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    }
88d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
89d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    // ---- Private delegate/helper methods ----
90d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
91d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    private BitmapShader_Delegate(java.awt.image.BufferedImage image,
92d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            TileMode tileModeX, TileMode tileModeY) {
93d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        mJavaPaint = new BitmapShaderPaint(image, tileModeX, tileModeY);
94d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    }
95d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
96d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    private class BitmapShaderPaint implements java.awt.Paint {
97d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        private final java.awt.image.BufferedImage mImage;
98d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        private final TileMode mTileModeX;
99d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        private final TileMode mTileModeY;
100d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
101d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        BitmapShaderPaint(java.awt.image.BufferedImage image,
102d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                TileMode tileModeX, TileMode tileModeY) {
103d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            mImage = image;
104d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            mTileModeX = tileModeX;
105d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            mTileModeY = tileModeY;
106d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        }
107d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
10846d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet        @Override
109d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        public java.awt.PaintContext createContext(
110d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                java.awt.image.ColorModel      colorModel,
111d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                java.awt.Rectangle             deviceBounds,
112d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                java.awt.geom.Rectangle2D      userBounds,
113d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                java.awt.geom.AffineTransform  xform,
114d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                java.awt.RenderingHints        hints) {
115d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
116d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            java.awt.geom.AffineTransform canvasMatrix;
117d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            try {
118d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                canvasMatrix = xform.createInverse();
119d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            } catch (java.awt.geom.NoninvertibleTransformException e) {
120918aaa5717fce6081557c82ce1c439b6922737d5Xavier Ducrohet                Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
12151a7e5447de94791c464cda5cc6ebbf616d73c80Xavier Ducrohet                        "Unable to inverse matrix in BitmapShader", e, null /*data*/);
122d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                canvasMatrix = new java.awt.geom.AffineTransform();
123d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            }
124d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
125d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
126d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            try {
127d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                localMatrix = localMatrix.createInverse();
128d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            } catch (java.awt.geom.NoninvertibleTransformException e) {
129918aaa5717fce6081557c82ce1c439b6922737d5Xavier Ducrohet                Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
13051a7e5447de94791c464cda5cc6ebbf616d73c80Xavier Ducrohet                        "Unable to inverse matrix in BitmapShader", e, null /*data*/);
131d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                localMatrix = new java.awt.geom.AffineTransform();
132d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            }
133d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
134d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            return new BitmapShaderContext(canvasMatrix, localMatrix, colorModel);
135d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        }
136d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
137d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        private class BitmapShaderContext implements java.awt.PaintContext {
138d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
139d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            private final java.awt.geom.AffineTransform mCanvasMatrix;
140d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            private final java.awt.geom.AffineTransform mLocalMatrix;
141d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            private final java.awt.image.ColorModel mColorModel;
142d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
143d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            public BitmapShaderContext(
144d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                    java.awt.geom.AffineTransform canvasMatrix,
145d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                    java.awt.geom.AffineTransform localMatrix,
146d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                    java.awt.image.ColorModel colorModel) {
147d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                mCanvasMatrix = canvasMatrix;
148d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                mLocalMatrix = localMatrix;
149d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                mColorModel = colorModel;
150d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            }
151d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
15246d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet            @Override
153d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            public void dispose() {
154d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            }
155d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
15646d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet            @Override
157d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            public java.awt.image.ColorModel getColorModel() {
158d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                return mColorModel;
159d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            }
160d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
16146d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet            @Override
162d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
163d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
164d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        java.awt.image.BufferedImage.TYPE_INT_ARGB);
165d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
166d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                int[] data = new int[w*h];
167d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
168d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                int index = 0;
169d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                float[] pt1 = new float[2];
170d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                float[] pt2 = new float[2];
171d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                for (int iy = 0 ; iy < h ; iy++) {
172d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                    for (int ix = 0 ; ix < w ; ix++) {
173d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        // handle the canvas transform
174d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        pt1[0] = x + ix;
175d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        pt1[1] = y + iy;
176d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
177d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
178d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        // handle the local matrix.
179d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        pt1[0] = pt2[0];
180d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        pt1[1] = pt2[1];
181d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
182d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
183d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        data[index++] = getColor(pt2[0], pt2[1]);
184d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                    }
185d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                }
186d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
187d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
188d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
189d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                return image.getRaster();
190d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            }
191d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        }
192d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
193d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        /**
194d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet         * Returns a color for an arbitrary point.
195d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet         */
196d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        private int getColor(float fx, float fy) {
197d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            int x = getCoordinate(Math.round(fx), mImage.getWidth(), mTileModeX);
198d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            int y = getCoordinate(Math.round(fy), mImage.getHeight(), mTileModeY);
199d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
200d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            return mImage.getRGB(x, y);
201d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        }
202d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
203d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        private int getCoordinate(int i, int size, TileMode mode) {
204d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            if (i < 0) {
205d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                switch (mode) {
206d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                    case CLAMP:
207d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        i = 0;
208d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        break;
209d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                    case REPEAT:
210d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        i = size - 1 - (-i % size);
211d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        break;
212d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                    case MIRROR:
213d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        // this is the same as the positive side, just make the value positive
214d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        // first.
215d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        i = -i;
216d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        int count = i / size;
217d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        i = i % size;
218d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
219d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        if ((count % 2) == 1) {
220d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                            i = size - 1 - i;
221d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        }
222d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        break;
223d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                }
224d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            } else if (i >= size) {
225d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                switch (mode) {
226d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                    case CLAMP:
227d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        i = size - 1;
228d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        break;
229d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                    case REPEAT:
230d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        i = i % size;
231d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        break;
232d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                    case MIRROR:
233d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        int count = i / size;
234d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        i = i % size;
235d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
236d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        if ((count % 2) == 1) {
237d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                            i = size - 1 - i;
238d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        }
239d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                        break;
240d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                }
241d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            }
242d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
243d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            return i;
244d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        }
245d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
246d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
24746d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet        @Override
248d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        public int getTransparency() {
249d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            return java.awt.Paint.TRANSLUCENT;
250d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        }
251d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    }
252d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet}
253