blob: 89d7e238593f814755cc78d17e5a5ca3fb6c6b45 [file] [log] [blame]
Xavier Ducrohet5de11a12010-10-29 16:01:40 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.graphics;
18
Xavier Ducrohet918aaa52011-01-13 10:59:34 -080019import com.android.ide.common.rendering.api.LayoutLog;
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -080020import com.android.layoutlib.bridge.Bridge;
Xavier Ducrohetc2e96512010-11-09 18:25:03 -080021import com.android.layoutlib.bridge.impl.DelegateManager;
Xavier Ducrohet16584222011-01-27 15:30:39 -080022import com.android.resources.Density;
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -080023import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
Xavier Ducrohet5de11a12010-10-29 16:01:40 -070024
25import android.graphics.Bitmap.Config;
26import android.os.Parcel;
27
28import java.awt.Graphics2D;
29import java.awt.image.BufferedImage;
30import java.io.File;
31import java.io.IOException;
32import java.io.InputStream;
33import java.io.OutputStream;
34import java.nio.Buffer;
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -080035import java.util.Arrays;
Deepanshu Gupta490efa82013-09-03 17:51:48 -070036import java.util.EnumSet;
37import java.util.Set;
Xavier Ducrohet5de11a12010-10-29 16:01:40 -070038
39import javax.imageio.ImageIO;
40
41/**
42 * Delegate implementing the native methods of android.graphics.Bitmap
43 *
44 * Through the layoutlib_create tool, the original native methods of Bitmap have been replaced
45 * by calls to methods of the same name in this delegate class.
46 *
47 * This class behaves like the original native implementation, but in Java, keeping previously
48 * native data into its own objects and mapping them to int that are sent back and forth between
49 * it and the original Bitmap class.
50 *
51 * @see DelegateManager
52 *
53 */
Xavier Ducrohetd348b6e2010-12-20 08:22:47 -080054public final class Bitmap_Delegate {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -070055
Deepanshu Gupta490efa82013-09-03 17:51:48 -070056 public enum BitmapCreateFlags {
57 PREMULTIPLIED, MUTABLE
58 }
59
Xavier Ducrohet5de11a12010-10-29 16:01:40 -070060 // ---- delegate manager ----
61 private static final DelegateManager<Bitmap_Delegate> sManager =
Xavier Ducrohetf0a53432011-02-23 16:51:08 -080062 new DelegateManager<Bitmap_Delegate>(Bitmap_Delegate.class);
Xavier Ducrohet5de11a12010-10-29 16:01:40 -070063
64 // ---- delegate helper data ----
65
66 // ---- delegate data ----
Xavier Ducrohet63fd8712010-12-21 01:33:04 -080067 private final Config mConfig;
Xavier Ducrohet5de11a12010-10-29 16:01:40 -070068 private BufferedImage mImage;
69 private boolean mHasAlpha = true;
Deepanshu Gupta279c00e2013-05-23 15:20:04 -070070 private boolean mHasMipMap = false; // TODO: check the default.
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -080071 private int mGenerationId = 0;
Xavier Ducrohet5de11a12010-10-29 16:01:40 -070072
Xavier Ducrohet63fd8712010-12-21 01:33:04 -080073
Xavier Ducrohet5de11a12010-10-29 16:01:40 -070074 // ---- Public Helper methods ----
75
76 /**
Xavier Ducrohet9f63ff22010-10-28 11:52:00 -070077 * Returns the native delegate associated to a given {@link Bitmap_Delegate} object.
78 */
79 public static Bitmap_Delegate getDelegate(Bitmap bitmap) {
80 return sManager.getDelegate(bitmap.mNativeBitmap);
81 }
82
83 /**
84 * Returns the native delegate associated to a given an int referencing a {@link Bitmap} object.
85 */
Narayan Kamath84151432014-01-27 14:24:16 +000086 public static Bitmap_Delegate getDelegate(long native_bitmap) {
Xavier Ducrohet9f63ff22010-10-28 11:52:00 -070087 return sManager.getDelegate(native_bitmap);
88 }
89
90 /**
Xavier Ducrohet5de11a12010-10-29 16:01:40 -070091 * Creates and returns a {@link Bitmap} initialized with the given file content.
Xavier Ducrohet2d56b272010-11-22 20:09:55 -080092 *
93 * @param input the file from which to read the bitmap content
94 * @param isMutable whether the bitmap is mutable
95 * @param density the density associated with the bitmap
96 *
97 * @see Bitmap#isMutable()
98 * @see Bitmap#getDensity()
Xavier Ducrohet5de11a12010-10-29 16:01:40 -070099 */
Xavier Ducrohet16584222011-01-27 15:30:39 -0800100 public static Bitmap createBitmap(File input, boolean isMutable, Density density)
Xavier Ducrohet2d56b272010-11-22 20:09:55 -0800101 throws IOException {
Deepanshu Gupta490efa82013-09-03 17:51:48 -0700102 return createBitmap(input, getPremultipliedBitmapCreateFlags(isMutable), density);
103 }
104
105 /**
106 * Creates and returns a {@link Bitmap} initialized with the given file content.
107 *
108 * @param input the file from which to read the bitmap content
109 * @param density the density associated with the bitmap
110 *
111 * @see Bitmap#isPremultiplied()
112 * @see Bitmap#isMutable()
113 * @see Bitmap#getDensity()
114 */
115 public static Bitmap createBitmap(File input, Set<BitmapCreateFlags> createFlags,
116 Density density) throws IOException {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700117 // create a delegate with the content of the file.
Xavier Ducrohet63fd8712010-12-21 01:33:04 -0800118 Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input), Config.ARGB_8888);
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700119
Deepanshu Gupta490efa82013-09-03 17:51:48 -0700120 return createBitmap(delegate, createFlags, density.getDpiValue());
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700121 }
122
123 /**
124 * Creates and returns a {@link Bitmap} initialized with the given stream content.
Xavier Ducrohet2d56b272010-11-22 20:09:55 -0800125 *
126 * @param input the stream from which to read the bitmap content
127 * @param isMutable whether the bitmap is mutable
128 * @param density the density associated with the bitmap
129 *
130 * @see Bitmap#isMutable()
131 * @see Bitmap#getDensity()
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700132 */
Xavier Ducrohet16584222011-01-27 15:30:39 -0800133 public static Bitmap createBitmap(InputStream input, boolean isMutable, Density density)
Xavier Ducrohet2d56b272010-11-22 20:09:55 -0800134 throws IOException {
Deepanshu Gupta490efa82013-09-03 17:51:48 -0700135 return createBitmap(input, getPremultipliedBitmapCreateFlags(isMutable), density);
136 }
137
138 /**
139 * Creates and returns a {@link Bitmap} initialized with the given stream content.
140 *
141 * @param input the stream from which to read the bitmap content
142 * @param createFlags
143 * @param density the density associated with the bitmap
144 *
145 * @see Bitmap#isPremultiplied()
146 * @see Bitmap#isMutable()
147 * @see Bitmap#getDensity()
148 */
149 public static Bitmap createBitmap(InputStream input, Set<BitmapCreateFlags> createFlags,
150 Density density) throws IOException {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700151 // create a delegate with the content of the stream.
Xavier Ducrohet63fd8712010-12-21 01:33:04 -0800152 Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input), Config.ARGB_8888);
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700153
Deepanshu Gupta490efa82013-09-03 17:51:48 -0700154 return createBitmap(delegate, createFlags, density.getDpiValue());
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700155 }
156
157 /**
158 * Creates and returns a {@link Bitmap} initialized with the given {@link BufferedImage}
Xavier Ducrohet2d56b272010-11-22 20:09:55 -0800159 *
160 * @param image the bitmap content
161 * @param isMutable whether the bitmap is mutable
162 * @param density the density associated with the bitmap
163 *
164 * @see Bitmap#isMutable()
165 * @see Bitmap#getDensity()
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700166 */
Xavier Ducrohetffb42f62010-12-09 18:26:01 -0800167 public static Bitmap createBitmap(BufferedImage image, boolean isMutable,
Xavier Ducrohet16584222011-01-27 15:30:39 -0800168 Density density) throws IOException {
Deepanshu Gupta490efa82013-09-03 17:51:48 -0700169 return createBitmap(image, getPremultipliedBitmapCreateFlags(isMutable), density);
170 }
171
172 /**
173 * Creates and returns a {@link Bitmap} initialized with the given {@link BufferedImage}
174 *
175 * @param image the bitmap content
176 * @param createFlags
177 * @param density the density associated with the bitmap
178 *
179 * @see Bitmap#isPremultiplied()
180 * @see Bitmap#isMutable()
181 * @see Bitmap#getDensity()
182 */
183 public static Bitmap createBitmap(BufferedImage image, Set<BitmapCreateFlags> createFlags,
184 Density density) throws IOException {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700185 // create a delegate with the given image.
Xavier Ducrohet63fd8712010-12-21 01:33:04 -0800186 Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ARGB_8888);
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700187
Deepanshu Gupta490efa82013-09-03 17:51:48 -0700188 return createBitmap(delegate, createFlags, density.getDpiValue());
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700189 }
190
191 /**
192 * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}.
193 */
194 public static BufferedImage getImage(Bitmap bitmap) {
195 // get the delegate from the native int.
196 Bitmap_Delegate delegate = sManager.getDelegate(bitmap.mNativeBitmap);
197 if (delegate == null) {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700198 return null;
199 }
200
201 return delegate.mImage;
202 }
203
204 public static int getBufferedImageType(int nativeBitmapConfig) {
Xavier Ducrohet7f9f99ea2011-08-11 10:16:17 -0700205 switch (Config.nativeToConfig(nativeBitmapConfig)) {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700206 case ALPHA_8:
207 return BufferedImage.TYPE_INT_ARGB;
208 case RGB_565:
209 return BufferedImage.TYPE_INT_ARGB;
210 case ARGB_4444:
211 return BufferedImage.TYPE_INT_ARGB;
212 case ARGB_8888:
213 return BufferedImage.TYPE_INT_ARGB;
214 }
215
216 return BufferedImage.TYPE_INT_ARGB;
217 }
218
Xavier Ducrohet9f63ff22010-10-28 11:52:00 -0700219 /**
220 * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}.
221 */
222 public BufferedImage getImage() {
223 return mImage;
224 }
225
Xavier Ducrohet63fd8712010-12-21 01:33:04 -0800226 /**
227 * Returns the Android bitmap config. Note that this not the config of the underlying
228 * Java2D bitmap.
229 */
230 public Config getConfig() {
231 return mConfig;
232 }
233
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800234 /**
235 * Returns the hasAlpha rendering hint
236 * @return true if the bitmap alpha should be used at render time
237 */
238 public boolean hasAlpha() {
239 return mHasAlpha && mConfig != Config.RGB_565;
240 }
241
Deepanshu Gupta279c00e2013-05-23 15:20:04 -0700242 public boolean hasMipMap() {
243 // TODO: check if more checks are required as in hasAlpha.
244 return mHasMipMap;
245 }
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800246 /**
247 * Update the generationId.
248 *
249 * @see Bitmap#getGenerationId()
250 */
251 public void change() {
252 mGenerationId++;
253 }
Xavier Ducrohet63fd8712010-12-21 01:33:04 -0800254
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700255 // ---- native methods ----
256
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800257 @LayoutlibDelegate
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700258 /*package*/ static Bitmap nativeCreate(int[] colors, int offset, int stride, int width,
Deepanshu Gupta490efa82013-09-03 17:51:48 -0700259 int height, int nativeConfig, boolean isMutable) {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700260 int imageType = getBufferedImageType(nativeConfig);
261
262 // create the image
263 BufferedImage image = new BufferedImage(width, height, imageType);
264
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800265 if (colors != null) {
266 image.setRGB(0, 0, width, height, colors, offset, stride);
267 }
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700268
269 // create a delegate with the content of the stream.
Xavier Ducrohet7f9f99ea2011-08-11 10:16:17 -0700270 Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.nativeToConfig(nativeConfig));
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700271
Deepanshu Gupta490efa82013-09-03 17:51:48 -0700272 return createBitmap(delegate, getPremultipliedBitmapCreateFlags(isMutable),
273 Bitmap.getDefaultDensity());
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700274 }
275
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800276 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000277 /*package*/ static Bitmap nativeCopy(long srcBitmap, int nativeConfig, boolean isMutable) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800278 Bitmap_Delegate srcBmpDelegate = sManager.getDelegate(srcBitmap);
279 if (srcBmpDelegate == null) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800280 return null;
281 }
282
283 BufferedImage srcImage = srcBmpDelegate.getImage();
284
285 int width = srcImage.getWidth();
286 int height = srcImage.getHeight();
287
288 int imageType = getBufferedImageType(nativeConfig);
289
290 // create the image
291 BufferedImage image = new BufferedImage(width, height, imageType);
292
293 // copy the source image into the image.
294 int[] argb = new int[width * height];
295 srcImage.getRGB(0, 0, width, height, argb, 0, width);
296 image.setRGB(0, 0, width, height, argb, 0, width);
297
298 // create a delegate with the content of the stream.
Xavier Ducrohet7f9f99ea2011-08-11 10:16:17 -0700299 Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.nativeToConfig(nativeConfig));
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800300
Deepanshu Gupta490efa82013-09-03 17:51:48 -0700301 return createBitmap(delegate, getPremultipliedBitmapCreateFlags(isMutable),
302 Bitmap.getDefaultDensity());
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700303 }
304
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800305 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000306 /*package*/ static void nativeDestructor(long nativeBitmap) {
Xavier Ducrohetcc4977d2011-02-22 11:54:37 -0800307 sManager.removeJavaReferenceFor(nativeBitmap);
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700308 }
309
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800310 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000311 /*package*/ static boolean nativeRecycle(long nativeBitmap) {
Xavier Ducrohetcc4977d2011-02-22 11:54:37 -0800312 sManager.removeJavaReferenceFor(nativeBitmap);
Deepanshu Gupta78cfdf32013-11-11 19:44:11 +0530313 return true;
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700314 }
315
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800316 @LayoutlibDelegate
Narayan Kamath8773d512014-01-28 19:47:58 +0000317 /*package*/ static void nativeReconfigure(long nativeBitmap, int width, int height,
Deepanshu Gupta24541252013-11-25 19:59:54 -0800318 int config, int allocSize) {
319 Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
320 "Bitmap.reconfigure() is not supported", null /*data*/);
321 }
322
323 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000324 /*package*/ static boolean nativeCompress(long nativeBitmap, int format, int quality,
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700325 OutputStream stream, byte[] tempStorage) {
Xavier Ducrohet918aaa52011-01-13 10:59:34 -0800326 Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
Xavier Ducrohet51a7e542011-01-14 16:40:43 -0800327 "Bitmap.compress() is not supported", null /*data*/);
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800328 return true;
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700329 }
330
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800331 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000332 /*package*/ static void nativeErase(long nativeBitmap, int color) {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700333 // get the delegate from the native int.
334 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
335 if (delegate == null) {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700336 return;
337 }
338
339 BufferedImage image = delegate.mImage;
340
341 Graphics2D g = image.createGraphics();
342 try {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800343 g.setColor(new java.awt.Color(color, true));
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700344
345 g.fillRect(0, 0, image.getWidth(), image.getHeight());
346 } finally {
347 g.dispose();
348 }
349 }
350
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800351 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000352 /*package*/ static int nativeRowBytes(long nativeBitmap) {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700353 // get the delegate from the native int.
354 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
355 if (delegate == null) {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700356 return 0;
357 }
358
359 return delegate.mImage.getWidth();
360 }
361
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800362 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000363 /*package*/ static int nativeConfig(long nativeBitmap) {
Xavier Ducrohet63fd8712010-12-21 01:33:04 -0800364 // get the delegate from the native int.
365 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
366 if (delegate == null) {
Xavier Ducrohet63fd8712010-12-21 01:33:04 -0800367 return 0;
368 }
369
370 return delegate.mConfig.nativeInt;
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700371 }
372
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800373 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000374 /*package*/ static boolean nativeHasAlpha(long nativeBitmap) {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700375 // get the delegate from the native int.
376 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
377 if (delegate == null) {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700378 return true;
379 }
380
381 return delegate.mHasAlpha;
382 }
383
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800384 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000385 /*package*/ static boolean nativeHasMipMap(long nativeBitmap) {
Deepanshu Gupta279c00e2013-05-23 15:20:04 -0700386 // get the delegate from the native int.
387 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
388 if (delegate == null) {
389 return true;
390 }
391
392 return delegate.mHasMipMap;
393 }
394
395 @LayoutlibDelegate
Narayan Kamath8773d512014-01-28 19:47:58 +0000396 /*package*/ static int nativeGetPixel(long nativeBitmap, int x, int y,
Deepanshu Gupta24541252013-11-25 19:59:54 -0800397 boolean isPremultiplied) {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700398 // get the delegate from the native int.
399 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
400 if (delegate == null) {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700401 return 0;
402 }
403
Deepanshu Gupta24541252013-11-25 19:59:54 -0800404 // TODO: Support isPremultiplied.
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700405 return delegate.mImage.getRGB(x, y);
406 }
407
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800408 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000409 /*package*/ static void nativeGetPixels(long nativeBitmap, int[] pixels, int offset,
Deepanshu Gupta24541252013-11-25 19:59:54 -0800410 int stride, int x, int y, int width, int height, boolean isPremultiplied) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800411 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
412 if (delegate == null) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800413 return;
414 }
415
416 delegate.getImage().getRGB(x, y, width, height, pixels, offset, stride);
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700417 }
418
419
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800420 @LayoutlibDelegate
Narayan Kamath8773d512014-01-28 19:47:58 +0000421 /*package*/ static void nativeSetPixel(long nativeBitmap, int x, int y, int color,
Deepanshu Gupta24541252013-11-25 19:59:54 -0800422 boolean isPremultiplied) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800423 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
424 if (delegate == null) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800425 return;
426 }
427
428 delegate.getImage().setRGB(x, y, color);
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700429 }
430
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800431 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000432 /*package*/ static void nativeSetPixels(long nativeBitmap, int[] colors, int offset,
Deepanshu Gupta24541252013-11-25 19:59:54 -0800433 int stride, int x, int y, int width, int height, boolean isPremultiplied) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800434 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
435 if (delegate == null) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800436 return;
437 }
438
439 delegate.getImage().setRGB(x, y, width, height, colors, offset, stride);
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700440 }
441
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800442 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000443 /*package*/ static void nativeCopyPixelsToBuffer(long nativeBitmap, Buffer dst) {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700444 // FIXME implement native delegate
Xavier Ducrohet8a80a852011-02-09 19:39:52 -0800445 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
446 "Bitmap.copyPixelsToBuffer is not supported.", null, null /*data*/);
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700447 }
448
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800449 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000450 /*package*/ static void nativeCopyPixelsFromBuffer(long nb, Buffer src) {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700451 // FIXME implement native delegate
Xavier Ducrohet8a80a852011-02-09 19:39:52 -0800452 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
453 "Bitmap.copyPixelsFromBuffer is not supported.", null, null /*data*/);
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700454 }
455
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800456 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000457 /*package*/ static int nativeGenerationId(long nativeBitmap) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800458 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
459 if (delegate == null) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800460 return 0;
461 }
462
463 return delegate.mGenerationId;
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700464 }
465
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800466 @LayoutlibDelegate
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700467 /*package*/ static Bitmap nativeCreateFromParcel(Parcel p) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800468 // This is only called by Bitmap.CREATOR (Parcelable.Creator<Bitmap>), which is only
469 // used during aidl call so really this should not be called.
Xavier Ducrohet918aaa52011-01-13 10:59:34 -0800470 Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
Xavier Ducrohet51a7e542011-01-14 16:40:43 -0800471 "AIDL is not suppored, and therefore Bitmaps cannot be created from parcels.",
472 null /*data*/);
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800473 return null;
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700474 }
475
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800476 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000477 /*package*/ static boolean nativeWriteToParcel(long nativeBitmap, boolean isMutable,
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700478 int density, Parcel p) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800479 // This is only called when sending a bitmap through aidl, so really this should not
480 // be called.
Xavier Ducrohet918aaa52011-01-13 10:59:34 -0800481 Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
Xavier Ducrohet51a7e542011-01-14 16:40:43 -0800482 "AIDL is not suppored, and therefore Bitmaps cannot be written to parcels.",
483 null /*data*/);
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800484 return false;
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700485 }
486
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800487 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000488 /*package*/ static Bitmap nativeExtractAlpha(long nativeBitmap, long nativePaint,
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700489 int[] offsetXY) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800490 Bitmap_Delegate bitmap = sManager.getDelegate(nativeBitmap);
491 if (bitmap == null) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800492 return null;
493 }
494
Xavier Ducrohetd43909c2010-12-23 07:16:21 -0800495 // get the paint which can be null if nativePaint is 0.
496 Paint_Delegate paint = Paint_Delegate.getDelegate(nativePaint);
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800497
Xavier Ducrohetd43909c2010-12-23 07:16:21 -0800498 if (paint != null && paint.getMaskFilter() != null) {
Xavier Ducrohet918aaa52011-01-13 10:59:34 -0800499 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER,
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800500 "MaskFilter not supported in Bitmap.extractAlpha",
Xavier Ducrohet51a7e542011-01-14 16:40:43 -0800501 null, null /*data*/);
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800502 }
503
504 int alpha = paint != null ? paint.getAlpha() : 0xFF;
505 BufferedImage image = createCopy(bitmap.getImage(), BufferedImage.TYPE_INT_ARGB, alpha);
506
507 // create the delegate. The actual Bitmap config is only an alpha channel
508 Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ALPHA_8);
509
510 // the density doesn't matter, it's set by the Java method.
Deepanshu Gupta490efa82013-09-03 17:51:48 -0700511 return createBitmap(delegate, EnumSet.of(BitmapCreateFlags.MUTABLE),
Xavier Ducrohet16584222011-01-27 15:30:39 -0800512 Density.DEFAULT_DENSITY /*density*/);
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700513 }
514
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800515 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000516 /*package*/ static void nativePrepareToDraw(long nativeBitmap) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800517 // nothing to be done here.
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700518 }
519
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800520 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000521 /*package*/ static void nativeSetHasAlpha(long nativeBitmap, boolean hasAlpha) {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700522 // get the delegate from the native int.
523 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
524 if (delegate == null) {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700525 return;
526 }
527
528 delegate.mHasAlpha = hasAlpha;
529 }
530
Xavier Ducrohet9a4fe292011-02-09 17:17:49 -0800531 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000532 /*package*/ static void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap) {
Deepanshu Gupta279c00e2013-05-23 15:20:04 -0700533 // get the delegate from the native int.
534 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
535 if (delegate == null) {
536 return;
537 }
538
539 delegate.mHasMipMap = hasMipMap;
540 }
541
542 @LayoutlibDelegate
Narayan Kamath84151432014-01-27 14:24:16 +0000543 /*package*/ static boolean nativeSameAs(long nb0, long nb1) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800544 Bitmap_Delegate delegate1 = sManager.getDelegate(nb0);
545 if (delegate1 == null) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800546 return false;
547 }
548
549 Bitmap_Delegate delegate2 = sManager.getDelegate(nb1);
550 if (delegate2 == null) {
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800551 return false;
552 }
553
554 BufferedImage image1 = delegate1.getImage();
555 BufferedImage image2 = delegate2.getImage();
556 if (delegate1.mConfig != delegate2.mConfig ||
557 image1.getWidth() != image2.getWidth() ||
558 image1.getHeight() != image2.getHeight()) {
559 return false;
560 }
561
562 // get the internal data
563 int w = image1.getWidth();
564 int h = image2.getHeight();
565 int[] argb1 = new int[w*h];
566 int[] argb2 = new int[w*h];
567
568 image1.getRGB(0, 0, w, h, argb1, 0, w);
569 image2.getRGB(0, 0, w, h, argb2, 0, w);
570
571 // compares
572 if (delegate1.mConfig == Config.ALPHA_8) {
573 // in this case we have to manually compare the alpha channel as the rest is garbage.
574 final int length = w*h;
575 for (int i = 0 ; i < length ; i++) {
576 if ((argb1[i] & 0xFF000000) != (argb2[i] & 0xFF000000)) {
577 return false;
578 }
579 }
580 return true;
581 }
582
583 return Arrays.equals(argb1, argb2);
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700584 }
585
586 // ---- Private delegate/helper methods ----
587
Xavier Ducrohet63fd8712010-12-21 01:33:04 -0800588 private Bitmap_Delegate(BufferedImage image, Config config) {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700589 mImage = image;
Xavier Ducrohet63fd8712010-12-21 01:33:04 -0800590 mConfig = config;
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700591 }
592
Deepanshu Gupta490efa82013-09-03 17:51:48 -0700593 private static Bitmap createBitmap(Bitmap_Delegate delegate,
594 Set<BitmapCreateFlags> createFlags, int density) {
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700595 // get its native_int
Narayan Kamath84151432014-01-27 14:24:16 +0000596 long nativeInt = sManager.addNewDelegate(delegate);
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700597
Deepanshu Gupta490efa82013-09-03 17:51:48 -0700598 int width = delegate.mImage.getWidth();
599 int height = delegate.mImage.getHeight();
600 boolean isMutable = createFlags.contains(BitmapCreateFlags.MUTABLE);
601 boolean isPremultiplied = createFlags.contains(BitmapCreateFlags.PREMULTIPLIED);
602
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700603 // and create/return a new Bitmap with it
Deepanshu Gupta490efa82013-09-03 17:51:48 -0700604 return new Bitmap(nativeInt, null /* buffer */, width, height, density, isMutable,
605 isPremultiplied, null /*ninePatchChunk*/, null /* layoutBounds */);
606 }
607
608 private static Set<BitmapCreateFlags> getPremultipliedBitmapCreateFlags(boolean isMutable) {
609 Set<BitmapCreateFlags> createFlags = EnumSet.of(BitmapCreateFlags.PREMULTIPLIED);
610 if (isMutable) {
611 createFlags.add(BitmapCreateFlags.MUTABLE);
612 }
613 return createFlags;
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700614 }
Xavier Ducrohetb1da1af2010-12-22 10:13:23 -0800615
616 /**
617 * Creates and returns a copy of a given BufferedImage.
618 * <p/>
619 * if alpha is different than 255, then it is applied to the alpha channel of each pixel.
620 *
621 * @param image the image to copy
622 * @param imageType the type of the new image
623 * @param alpha an optional alpha modifier
624 * @return a new BufferedImage
625 */
626 /*package*/ static BufferedImage createCopy(BufferedImage image, int imageType, int alpha) {
627 int w = image.getWidth();
628 int h = image.getHeight();
629
630 BufferedImage result = new BufferedImage(w, h, imageType);
631
632 int[] argb = new int[w * h];
633 image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth());
634
635 if (alpha != 255) {
636 final int length = argb.length;
637 for (int i = 0 ; i < length; i++) {
638 int a = (argb[i] >>> 24 * alpha) / 255;
639 argb[i] = (a << 24) | (argb[i] & 0x00FFFFFF);
640 }
641 }
642
643 result.setRGB(0, 0, w, h, argb, 0, w);
644
645 return result;
646 }
647
Xavier Ducrohet5de11a12010-10-29 16:01:40 -0700648}