1/* 2 * Copyright (C) 2011 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 19import com.android.layoutlib.bridge.Bridge; 20import com.android.layoutlib.bridge.impl.DelegateManager; 21import com.android.ninepatch.NinePatchChunk; 22import com.android.resources.Density; 23import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 24 25import android.content.res.BridgeResources.NinePatchInputStream; 26import android.graphics.BitmapFactory.Options; 27import android.graphics.Bitmap_Delegate.BitmapCreateFlags; 28 29import java.io.FileDescriptor; 30import java.io.IOException; 31import java.io.InputStream; 32import java.util.EnumSet; 33import java.util.Set; 34 35/** 36 * Delegate implementing the native methods of android.graphics.BitmapFactory 37 * 38 * Through the layoutlib_create tool, the original native methods of BitmapFactory have been 39 * replaced by calls to methods of the same name in this delegate class. 40 * 41 * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager} 42 * around to map int to instance of the delegate. 43 * 44 */ 45/*package*/ class BitmapFactory_Delegate { 46 47 // ------ Java delegates ------ 48 49 @LayoutlibDelegate 50 /*package*/ static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) { 51 if (bm == null || opts == null) { 52 return bm; 53 } 54 55 final int density = opts.inDensity; 56 if (density == 0) { 57 return bm; 58 } 59 60 bm.setDensity(density); 61 final int targetDensity = opts.inTargetDensity; 62 if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) { 63 return bm; 64 } 65 66 byte[] np = bm.getNinePatchChunk(); 67 final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np); 68 // DELEGATE CHANGE: never scale 9-patch 69 if (opts.inScaled && isNinePatch == false) { 70 float scale = targetDensity / (float)density; 71 // TODO: This is very inefficient and should be done in native by Skia 72 final Bitmap oldBitmap = bm; 73 bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f), 74 (int) (bm.getHeight() * scale + 0.5f), true); 75 oldBitmap.recycle(); 76 77 if (isNinePatch) { 78 np = nativeScaleNinePatch(np, scale, outPadding); 79 bm.setNinePatchChunk(np); 80 } 81 bm.setDensity(targetDensity); 82 } 83 84 return bm; 85 } 86 87 88 // ------ Native Delegates ------ 89 90 @LayoutlibDelegate 91 /*package*/ static Bitmap nativeDecodeStream(InputStream is, byte[] storage, 92 Rect padding, Options opts) { 93 return nativeDecodeStream(is, storage, padding, opts, false, 1.f); 94 } 95 96 @LayoutlibDelegate 97 /*package*/ static Bitmap nativeDecodeStream(InputStream is, byte[] storage, 98 Rect padding, Options opts, boolean applyScale, float scale) { 99 Bitmap bm = null; 100 101 //TODO support rescaling 102 103 Density density = Density.MEDIUM; 104 Set<BitmapCreateFlags> bitmapCreateFlags = EnumSet.of(BitmapCreateFlags.MUTABLE); 105 if (opts != null) { 106 density = Density.getEnum(opts.inDensity); 107 if (opts.inPremultiplied) { 108 bitmapCreateFlags.add(BitmapCreateFlags.PREMULTIPLIED); 109 } 110 } 111 112 try { 113 if (is instanceof NinePatchInputStream) { 114 NinePatchInputStream npis = (NinePatchInputStream) is; 115 npis.disableFakeMarkSupport(); 116 117 // load the bitmap as a nine patch 118 com.android.ninepatch.NinePatch ninePatch = com.android.ninepatch.NinePatch.load( 119 npis, true /*is9Patch*/, false /*convert*/); 120 121 // get the bitmap and chunk objects. 122 bm = Bitmap_Delegate.createBitmap(ninePatch.getImage(), bitmapCreateFlags, 123 density); 124 NinePatchChunk chunk = ninePatch.getChunk(); 125 126 // put the chunk in the bitmap 127 bm.setNinePatchChunk(NinePatch_Delegate.serialize(chunk)); 128 129 // read the padding 130 int[] paddingarray = chunk.getPadding(); 131 padding.left = paddingarray[0]; 132 padding.top = paddingarray[1]; 133 padding.right = paddingarray[2]; 134 padding.bottom = paddingarray[3]; 135 } else { 136 // load the bitmap directly. 137 bm = Bitmap_Delegate.createBitmap(is, bitmapCreateFlags, density); 138 } 139 } catch (IOException e) { 140 Bridge.getLog().error(null,"Failed to load image" , e, null); 141 } 142 143 return bm; 144 } 145 146 @LayoutlibDelegate 147 /*package*/ static Bitmap nativeDecodeFileDescriptor(FileDescriptor fd, 148 Rect padding, Options opts) { 149 opts.inBitmap = null; 150 return null; 151 } 152 153 @LayoutlibDelegate 154 /*package*/ static Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts) { 155 opts.inBitmap = null; 156 return null; 157 } 158 159 @LayoutlibDelegate 160 /*package*/ static Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts, 161 boolean applyScale, float scale) { 162 opts.inBitmap = null; 163 return null; 164 } 165 166 @LayoutlibDelegate 167 /*package*/ static Bitmap nativeDecodeByteArray(byte[] data, int offset, 168 int length, Options opts) { 169 opts.inBitmap = null; 170 return null; 171 } 172 173 @LayoutlibDelegate 174 /*package*/ static byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad) { 175 // don't scale for now. This should not be called anyway since we re-implement 176 // BitmapFactory.finishDecode(); 177 return chunk; 178 } 179 180 @LayoutlibDelegate 181 /*package*/ static boolean nativeIsSeekable(FileDescriptor fd) { 182 return true; 183 } 184} 185