1779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet/*
2779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet * Copyright (C) 2011 The Android Open Source Project
3779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet *
4779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License");
5779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet * you may not use this file except in compliance with the License.
6779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet * You may obtain a copy of the License at
7779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet *
8779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet *      http://www.apache.org/licenses/LICENSE-2.0
9779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet *
10779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet * Unless required by applicable law or agreed to in writing, software
11779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS,
12779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet * See the License for the specific language governing permissions and
14779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet * limitations under the License.
15779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet */
16779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
17779c906592b67867fee83a6527d474c333a701ffXavier Ducrohetpackage android.graphics;
18779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
19779c906592b67867fee83a6527d474c333a701ffXavier Ducrohetimport com.android.layoutlib.bridge.Bridge;
20779c906592b67867fee83a6527d474c333a701ffXavier Ducrohetimport com.android.layoutlib.bridge.impl.DelegateManager;
21779c906592b67867fee83a6527d474c333a701ffXavier Ducrohetimport com.android.ninepatch.NinePatchChunk;
22779c906592b67867fee83a6527d474c333a701ffXavier Ducrohetimport com.android.resources.Density;
239a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohetimport com.android.tools.layoutlib.annotations.LayoutlibDelegate;
24779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
25d2f664d42cc29507b01a98622298b69131463825Xavier Ducrohetimport android.content.res.BridgeResources.NinePatchInputStream;
26779c906592b67867fee83a6527d474c333a701ffXavier Ducrohetimport android.graphics.BitmapFactory.Options;
27779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
28779c906592b67867fee83a6527d474c333a701ffXavier Ducrohetimport java.io.FileDescriptor;
29779c906592b67867fee83a6527d474c333a701ffXavier Ducrohetimport java.io.IOException;
30779c906592b67867fee83a6527d474c333a701ffXavier Ducrohetimport java.io.InputStream;
31779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
32779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet/**
33779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet * Delegate implementing the native methods of android.graphics.BitmapFactory
34779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet *
35779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet * Through the layoutlib_create tool, the original native methods of BitmapFactory have been
36779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet * replaced by calls to methods of the same name in this delegate class.
37779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet *
38779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
39779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet * around to map int to instance of the delegate.
40779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet *
41779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet */
42779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet/*package*/ class BitmapFactory_Delegate {
43779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
4413bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet    // ------ Java delegates ------
4513bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet
469a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohet    @LayoutlibDelegate
4713bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet    /*package*/ static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) {
4813bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet        if (bm == null || opts == null) {
4913bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet            return bm;
5013bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet        }
5113bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet
5213bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet        final int density = opts.inDensity;
5313bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet        if (density == 0) {
5413bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet            return bm;
5513bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet        }
5613bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet
5713bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet        bm.setDensity(density);
5813bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet        final int targetDensity = opts.inTargetDensity;
5913bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet        if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {
6013bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet            return bm;
6113bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet        }
6213bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet
6313bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet        byte[] np = bm.getNinePatchChunk();
6413bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet        final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
6513bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet        // DELEGATE CHANGE: never scale 9-patch
6613bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet        if (opts.inScaled && isNinePatch == false) {
6713bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet            float scale = targetDensity / (float)density;
6813bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet            // TODO: This is very inefficient and should be done in native by Skia
6913bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet            final Bitmap oldBitmap = bm;
7013bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet            bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
7113bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet                    (int) (bm.getHeight() * scale + 0.5f), true);
7213bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet            oldBitmap.recycle();
7313bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet
7413bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet            if (isNinePatch) {
7513bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet                np = nativeScaleNinePatch(np, scale, outPadding);
7613bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet                bm.setNinePatchChunk(np);
7713bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet            }
7813bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet            bm.setDensity(targetDensity);
7913bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet        }
8013bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet
8113bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet        return bm;
8213bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet    }
8313bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet
8413bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet
85779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet    // ------ Native Delegates ------
86779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
879a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohet    @LayoutlibDelegate
8822f700a1b8fb9d2ac7b261e30a46a040928c23bcXavier Ducrohet    /*package*/ static Bitmap nativeDecodeStream(InputStream is, byte[] storage,
8922f700a1b8fb9d2ac7b261e30a46a040928c23bcXavier Ducrohet            Rect padding, Options opts) {
9022f700a1b8fb9d2ac7b261e30a46a040928c23bcXavier Ducrohet        return nativeDecodeStream(is, storage, padding, opts, false, 1.f);
91779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet    }
92779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
939a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohet    @LayoutlibDelegate
9422f700a1b8fb9d2ac7b261e30a46a040928c23bcXavier Ducrohet    /*package*/ static  Bitmap nativeDecodeStream(InputStream is, byte[] storage,
9522f700a1b8fb9d2ac7b261e30a46a040928c23bcXavier Ducrohet            Rect padding, Options opts, boolean applyScale, float scale) {
96779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet        Bitmap bm = null;
97779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
9822f700a1b8fb9d2ac7b261e30a46a040928c23bcXavier Ducrohet        //TODO support rescaling
9922f700a1b8fb9d2ac7b261e30a46a040928c23bcXavier Ducrohet
100779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet        Density density = Density.MEDIUM;
101779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet        if (opts != null) {
102779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet            density = Density.getEnum(opts.inDensity);
103779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet        }
104779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
105779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet        try {
106779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet            if (is instanceof NinePatchInputStream) {
107779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                NinePatchInputStream npis = (NinePatchInputStream) is;
108779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                npis.disableFakeMarkSupport();
109779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
110779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                // load the bitmap as a nine patch
111779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                com.android.ninepatch.NinePatch ninePatch = com.android.ninepatch.NinePatch.load(
112779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                        npis, true /*is9Patch*/, false /*convert*/);
113779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
114779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                // get the bitmap and chunk objects.
115779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                bm = Bitmap_Delegate.createBitmap(ninePatch.getImage(), true /*isMutable*/,
116779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                        density);
117779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                NinePatchChunk chunk = ninePatch.getChunk();
118779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
119779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                // put the chunk in the bitmap
120779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                bm.setNinePatchChunk(NinePatch_Delegate.serialize(chunk));
121779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
122779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                // read the padding
123779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                int[] paddingarray = chunk.getPadding();
124779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                padding.left = paddingarray[0];
125779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                padding.top = paddingarray[1];
126779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                padding.right = paddingarray[2];
127779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                padding.bottom = paddingarray[3];
128779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet            } else {
129779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                // load the bitmap directly.
130779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet                bm = Bitmap_Delegate.createBitmap(is, true, density);
131779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet            }
132779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet        } catch (IOException e) {
133779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet            Bridge.getLog().error(null,"Failed to load image" , e, null);
134779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet        }
135779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
136779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet        return bm;
137779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet    }
138779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
1399a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohet    @LayoutlibDelegate
140779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet    /*package*/ static Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
141779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet            Rect padding, Options opts) {
142779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet        opts.inBitmap = null;
143779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet        return null;
144779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet    }
145779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
1469a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohet    @LayoutlibDelegate
147779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet    /*package*/ static Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts) {
148779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet        opts.inBitmap = null;
149779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet        return null;
150779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet    }
151779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
1529a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohet    @LayoutlibDelegate
15322f700a1b8fb9d2ac7b261e30a46a040928c23bcXavier Ducrohet    /*package*/ static Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts,
15422f700a1b8fb9d2ac7b261e30a46a040928c23bcXavier Ducrohet            boolean applyScale, float scale) {
15522f700a1b8fb9d2ac7b261e30a46a040928c23bcXavier Ducrohet        opts.inBitmap = null;
15622f700a1b8fb9d2ac7b261e30a46a040928c23bcXavier Ducrohet        return null;
15722f700a1b8fb9d2ac7b261e30a46a040928c23bcXavier Ducrohet    }
15822f700a1b8fb9d2ac7b261e30a46a040928c23bcXavier Ducrohet
15922f700a1b8fb9d2ac7b261e30a46a040928c23bcXavier Ducrohet    @LayoutlibDelegate
160779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet    /*package*/ static Bitmap nativeDecodeByteArray(byte[] data, int offset,
161779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet            int length, Options opts) {
162779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet        opts.inBitmap = null;
163779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet        return null;
164779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet    }
165779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
1669a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohet    @LayoutlibDelegate
167779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet    /*package*/ static byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad) {
16813bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet        // don't scale for now. This should not be called anyway since we re-implement
16913bdc3355c781dc2614f2810a42d3a9e73f5bed9Xavier Ducrohet        // BitmapFactory.finishDecode();
170779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet        return chunk;
171779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet    }
172779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet
1739a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohet    @LayoutlibDelegate
174779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet    /*package*/ static boolean nativeIsSeekable(FileDescriptor fd) {
175779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet        return true;
176779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet    }
177779c906592b67867fee83a6527d474c333a701ffXavier Ducrohet}
178