1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17/**
18 * @author Igor V. Stolyarov
19 * @version $Revision$
20 * Created on 10.11.2005
21 *
22 */
23package org.apache.harmony.awt.gl;
24
25import java.awt.color.ColorSpace;
26import java.awt.image.BandedSampleModel;
27import java.awt.image.BufferedImage;
28import java.awt.image.ColorModel;
29import java.awt.image.ComponentColorModel;
30import java.awt.image.ComponentSampleModel;
31import java.awt.image.DirectColorModel;
32import java.awt.image.IndexColorModel;
33import java.awt.image.MultiPixelPackedSampleModel;
34import java.awt.image.PixelInterleavedSampleModel;
35import java.awt.image.SampleModel;
36import java.awt.image.SinglePixelPackedSampleModel;
37import java.awt.image.WritableRaster;
38
39import org.apache.harmony.awt.gl.color.LUTColorConverter;
40import org.apache.harmony.awt.gl.image.DataBufferListener;
41import org.apache.harmony.awt.internal.nls.Messages;
42
43
44/**
45 * This class represent Surface for different types of Images (BufferedImage,
46 * OffscreenImage and so on)
47 */
48public class ImageSurface extends Surface implements DataBufferListener {
49
50    boolean nativeDrawable = true;
51    int surfaceType;
52    int csType;
53    ColorModel cm;
54    WritableRaster raster;
55    Object data;
56
57    boolean needToRefresh = true;
58    boolean dataTaken = false;
59
60    private long cachedDataPtr;       // Pointer for cached Image Data
61    private boolean alphaPre;         // Cached Image Data alpha premultiplied
62
63    public ImageSurface(ColorModel cm, WritableRaster raster){
64        this(cm, raster, Surface.getType(cm, raster));
65    }
66
67    public ImageSurface(ColorModel cm, WritableRaster raster, int type){
68        if (!cm.isCompatibleRaster(raster)) {
69            // awt.4D=The raster is incompatible with this ColorModel
70            throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$
71        }
72        this.cm = cm;
73        this.raster = raster;
74        surfaceType = type;
75
76        data = AwtImageBackdoorAccessor.getInstance().
77        getData(raster.getDataBuffer());
78        ColorSpace cs = cm.getColorSpace();
79        transparency = cm.getTransparency();
80        width = raster.getWidth();
81        height = raster.getHeight();
82
83        // For the moment we can build natively only images which have
84        // sRGB, Linear_RGB, Linear_Gray Color Space and type different
85        // from BufferedImage.TYPE_CUSTOM
86        if(cs == LUTColorConverter.sRGB_CS){
87            csType = sRGB_CS;
88        }else if(cs == LUTColorConverter.LINEAR_RGB_CS){
89            csType = Linear_RGB_CS;
90        }else if(cs == LUTColorConverter.LINEAR_GRAY_CS){
91            csType = Linear_Gray_CS;
92        }else{
93            csType = Custom_CS;
94            nativeDrawable = false;
95        }
96
97        if(type == BufferedImage.TYPE_CUSTOM){
98            nativeDrawable = false;
99        }
100    }
101
102    @Override
103    public ColorModel getColorModel() {
104        return cm;
105    }
106
107    @Override
108    public WritableRaster getRaster() {
109        return raster;
110    }
111
112    @Override
113    public long getSurfaceDataPtr() {
114        if(surfaceDataPtr == 0L && nativeDrawable){
115            createSufaceStructure();
116        }
117        return surfaceDataPtr;
118    }
119
120    @Override
121    public Object getData(){
122        return data;
123    }
124
125    @Override
126    public boolean isNativeDrawable(){
127        return nativeDrawable;
128    }
129
130    @Override
131    public int getSurfaceType() {
132        return surfaceType;
133    }
134
135    /**
136     * Creates native Surface structure which used for native blitting
137     */
138    private void createSufaceStructure(){
139        int cmType = 0;
140        int numComponents = cm.getNumComponents();
141        boolean hasAlpha = cm.hasAlpha();
142        boolean isAlphaPre = cm.isAlphaPremultiplied();
143        int transparency = cm.getTransparency();
144        int bits[] = cm.getComponentSize();
145        int pixelStride = cm.getPixelSize();
146        int masks[] = null;
147        int colorMap[] = null;
148        int colorMapSize = 0;
149        int transpPixel = -1;
150        boolean isGrayPallete = false;
151        SampleModel sm = raster.getSampleModel();
152        int smType = 0;
153        int dataType = sm.getDataType();
154        int scanlineStride = 0;
155        int bankIndeces[] = null;
156        int bandOffsets[] = null;
157        int offset = raster.getDataBuffer().getOffset();
158
159        if(cm instanceof DirectColorModel){
160            cmType = DCM;
161            DirectColorModel dcm = (DirectColorModel) cm;
162            masks = dcm.getMasks();
163            smType = SPPSM;
164            SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
165            scanlineStride = sppsm.getScanlineStride();
166
167        }else if(cm instanceof IndexColorModel){
168            cmType = ICM;
169            IndexColorModel icm = (IndexColorModel) cm;
170            colorMapSize = icm.getMapSize();
171            colorMap = new int[colorMapSize];
172            icm.getRGBs(colorMap);
173            transpPixel = icm.getTransparentPixel();
174            isGrayPallete = Surface.isGrayPallete(icm);
175
176            if(sm instanceof MultiPixelPackedSampleModel){
177                smType = MPPSM;
178                MultiPixelPackedSampleModel mppsm =
179                    (MultiPixelPackedSampleModel) sm;
180                scanlineStride = mppsm.getScanlineStride();
181            }else if(sm instanceof ComponentSampleModel){
182                smType = CSM;
183                ComponentSampleModel csm =
184                    (ComponentSampleModel) sm;
185                scanlineStride = csm.getScanlineStride();
186            }else{
187                // awt.4D=The raster is incompatible with this ColorModel
188                throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$
189            }
190
191        }else if(cm instanceof ComponentColorModel){
192            cmType = CCM;
193            if(sm instanceof ComponentSampleModel){
194                ComponentSampleModel csm = (ComponentSampleModel) sm;
195                scanlineStride = csm.getScanlineStride();
196                bankIndeces = csm.getBankIndices();
197                bandOffsets = csm.getBandOffsets();
198                if(sm instanceof PixelInterleavedSampleModel){
199                    smType = PISM;
200                }else if(sm instanceof BandedSampleModel){
201                    smType = BSM;
202                }else{
203                    smType = CSM;
204                }
205            }else{
206                // awt.4D=The raster is incompatible with this ColorModel
207                throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$
208            }
209
210        }else{
211            surfaceDataPtr = 0L;
212            return;
213        }
214        surfaceDataPtr = createSurfStruct(surfaceType, width, height, cmType, csType, smType, dataType,
215                numComponents, pixelStride, scanlineStride, bits, masks, colorMapSize,
216                colorMap, transpPixel, isGrayPallete, bankIndeces, bandOffsets,
217                offset, hasAlpha, isAlphaPre, transparency);
218    }
219
220    @Override
221    public void dispose() {
222        if(surfaceDataPtr != 0L){
223            dispose(surfaceDataPtr);
224            surfaceDataPtr = 0L;
225        }
226    }
227
228    public long getCachedData(boolean alphaPre){
229        if(nativeDrawable){
230            if(cachedDataPtr == 0L || needToRefresh || this.alphaPre != alphaPre){
231                cachedDataPtr = updateCache(getSurfaceDataPtr(), data, alphaPre);
232                this.alphaPre = alphaPre;
233                validate();
234            }
235        }
236        return cachedDataPtr;
237    }
238
239    private native long createSurfStruct(int surfaceType, int width, int height,
240            int cmType, int csType, int smType, int dataType,
241            int numComponents, int pixelStride, int scanlineStride,
242            int bits[], int masks[], int colorMapSize, int colorMap[],
243            int transpPixel, boolean isGrayPalette, int bankIndeces[],
244            int bandOffsets[], int offset, boolean hasAlpha, boolean isAlphaPre,
245            int transparency);
246
247    private native void dispose(long structPtr);
248
249    private native void setImageSize(long structPtr, int width, int height);
250
251    private native long updateCache(long structPtr, Object data, boolean alphaPre);
252
253    /**
254     * Supposes that new raster is compatible with an old one
255     * @param r
256     */
257    public void setRaster(WritableRaster r) {
258        raster = r;
259        data = AwtImageBackdoorAccessor.getInstance().getData(r.getDataBuffer());
260        if (surfaceDataPtr != 0) {
261            setImageSize(surfaceDataPtr, r.getWidth(), r.getHeight());
262        }
263        this.width = r.getWidth();
264        this.height = r.getHeight();
265    }
266
267    @Override
268    public long lock() {
269        // TODO
270        return 0;
271    }
272
273    @Override
274    public void unlock() {
275        //TODO
276    }
277
278    @Override
279    public Surface getImageSurface() {
280        return this;
281    }
282
283    public void dataChanged() {
284        needToRefresh = true;
285        clearValidCaches();
286    }
287
288    public void dataTaken() {
289        dataTaken = true;
290        needToRefresh = true;
291        clearValidCaches();
292    }
293
294    public void dataReleased(){
295        dataTaken = false;
296        needToRefresh = true;
297        clearValidCaches();
298    }
299
300    @Override
301    public void invalidate(){
302        needToRefresh = true;
303        clearValidCaches();
304    }
305
306    @Override
307    public void validate(){
308        if(!needToRefresh) {
309            return;
310        }
311        if(!dataTaken){
312            needToRefresh = false;
313            AwtImageBackdoorAccessor ba = AwtImageBackdoorAccessor.getInstance();
314            ba.validate(raster.getDataBuffer());
315        }
316
317    }
318
319    @Override
320    public boolean invalidated(){
321        return needToRefresh;
322    }
323}
324