19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.graphics;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.InputStream;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStream;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A picture records drawing calls (via the canvas returned by beginRecording)
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and can then play them back (via picture.draw(canvas) or canvas.drawPicture).
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The picture's contents can also be written to a stream, and then later
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * restored to a new picture (via writeToStream / createFromStream). For most
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * content (esp. text, lines, rectangles), drawing a sequence from a picture can
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * be faster than the equivalent API calls, since the picture performs its
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * playback without incurring any java-call overhead.
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class Picture {
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Canvas mRecordingCanvas;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final int mNativePicture;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy    /**
36f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy     * @hide
37f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy     */
38f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy    public final boolean createdFromStream;
39f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int WORKING_STREAM_STORAGE = 16 * 1024;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Picture() {
43f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy        this(nativeConstructor(0), false);
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create a picture by making a copy of what has already been recorded in
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * src. The contents of src are unchanged, and if src changes later, those
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * changes will not be reflected in this picture.
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Picture(Picture src) {
52f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy        this(nativeConstructor(src != null ? src.mNativePicture : 0), false);
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * To record a picture, call beginRecording() and then draw into the Canvas
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * that is returned. Nothing we appear on screen, but all of the draw
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * commands (e.g. drawRect(...)) will be recorded. To stop recording, call
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * endRecording(). At this point the Canvas that was returned must no longer
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * be referenced, and nothing should be drawn into it.
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Canvas beginRecording(int width, int height) {
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int ni = nativeBeginRecording(mNativePicture, width, height);
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mRecordingCanvas = new RecordingCanvas(this, ni);
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mRecordingCanvas;
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Call endRecording when the picture is built. After this call, the picture
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * may be drawn, but the canvas that was returned by beginRecording must not
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * be referenced anymore. This is automatically called if Picture.draw() or
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Canvas.drawPicture() is called.
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void endRecording() {
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mRecordingCanvas != null) {
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mRecordingCanvas = null;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            nativeEndRecording(mNativePicture);
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the width of the picture as passed to beginRecording. This
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * does not reflect (per se) the content of the picture.
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public native int getWidth();
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the height of the picture as passed to beginRecording. This
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * does not reflect (per se) the content of the picture.
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public native int getHeight();
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Draw this picture on the canvas. The picture may have the side effect
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * of changing the matrix and clip of the canvas.
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param canvas  The picture is drawn to this canvas
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void draw(Canvas canvas) {
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mRecordingCanvas != null) {
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            endRecording();
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        nativeDraw(canvas.mNativeCanvas, mNativePicture);
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create a new picture (already recorded) from the data in the stream. This
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * data was generated by a previous call to writeToStream().
109f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy     *
110f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy     * <strong>Note:</strong> a picture created from an input stream cannot be
111f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy     * replayed on a hardware accelerated canvas.
112f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy     *
113f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy     * @see #writeToStream(java.io.OutputStream)
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static Picture createFromStream(InputStream stream) {
116f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy        return new Picture(nativeCreateFromStream(stream, new byte[WORKING_STREAM_STORAGE]), true);
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Write the picture contents to a stream. The data can be used to recreate
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the picture in this or another process by calling createFromStream.
122f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy     *
123f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy     * <strong>Note:</strong> a picture created from an input stream cannot be
124f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy     * replayed on a hardware accelerated canvas.
125f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy     *
126f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy     * @see #createFromStream(java.io.InputStream)
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void writeToStream(OutputStream stream) {
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // do explicit check before calling the native method
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (stream == null) {
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new NullPointerException();
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!nativeWriteToStream(mNativePicture, stream,
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                             new byte[WORKING_STREAM_STORAGE])) {
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new RuntimeException();
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() throws Throwable {
14084fce187b0ae79adc5b4e64c26f72c8ed59e9703Romain Guy        try {
14184fce187b0ae79adc5b4e64c26f72c8ed59e9703Romain Guy            nativeDestructor(mNativePicture);
14284fce187b0ae79adc5b4e64c26f72c8ed59e9703Romain Guy        } finally {
14384fce187b0ae79adc5b4e64c26f72c8ed59e9703Romain Guy            super.finalize();
14484fce187b0ae79adc5b4e64c26f72c8ed59e9703Romain Guy        }
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
146f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy
147f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy    final int ni() {
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mNativePicture;
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
151f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy    private Picture(int nativePicture, boolean fromStream) {
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (nativePicture == 0) {
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new RuntimeException();
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mNativePicture = nativePicture;
156f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy        createdFromStream = fromStream;
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // return empty picture if src is 0, or a copy of the native src
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native int nativeConstructor(int nativeSrcOr0);
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native int nativeCreateFromStream(InputStream stream,
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                byte[] storage);
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native int nativeBeginRecording(int nativeCanvas,
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                    int w, int h);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native void nativeEndRecording(int nativeCanvas);
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native void nativeDraw(int nativeCanvas, int nativePicture);
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native boolean nativeWriteToStream(int nativePicture,
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                           OutputStream stream, byte[] storage);
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native void nativeDestructor(int nativePicture);
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static class RecordingCanvas extends Canvas {
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final Picture mPicture;
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public RecordingCanvas(Picture pict, int nativeCanvas) {
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(nativeCanvas);
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPicture = pict;
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void setBitmap(Bitmap bitmap) {
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new RuntimeException(
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                "Cannot call setBitmap on a picture canvas");
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void drawPicture(Picture picture) {
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mPicture == picture) {
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new RuntimeException(
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            "Cannot draw a picture into its recording canvas");
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.drawPicture(picture);
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
196