Picture.java revision 84fce187b0ae79adc5b4e64c26f72c8ed59e9703
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
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int WORKING_STREAM_STORAGE = 16 * 1024;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Picture() {
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(nativeConstructor(0));
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create a picture by making a copy of what has already been recorded in
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * src. The contents of src are unchanged, and if src changes later, those
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * changes will not be reflected in this picture.
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Picture(Picture src) {
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(nativeConstructor(src != null ? src.mNativePicture : 0));
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * To record a picture, call beginRecording() and then draw into the Canvas
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * that is returned. Nothing we appear on screen, but all of the draw
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * commands (e.g. drawRect(...)) will be recorded. To stop recording, call
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * endRecording(). At this point the Canvas that was returned must no longer
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * be referenced, and nothing should be drawn into it.
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Canvas beginRecording(int width, int height) {
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int ni = nativeBeginRecording(mNativePicture, width, height);
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mRecordingCanvas = new RecordingCanvas(this, ni);
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mRecordingCanvas;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Call endRecording when the picture is built. After this call, the picture
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * may be drawn, but the canvas that was returned by beginRecording must not
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * be referenced anymore. This is automatically called if Picture.draw() or
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Canvas.drawPicture() is called.
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void endRecording() {
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mRecordingCanvas != null) {
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mRecordingCanvas = null;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            nativeEndRecording(mNativePicture);
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the width of the picture as passed to beginRecording. This
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * does not reflect (per se) the content of the picture.
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public native int getWidth();
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the height of the picture as passed to beginRecording. This
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * does not reflect (per se) the content of the picture.
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public native int getHeight();
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Draw this picture on the canvas. The picture may have the side effect
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * of changing the matrix and clip of the canvas.
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param canvas  The picture is drawn to this canvas
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void draw(Canvas canvas) {
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mRecordingCanvas != null) {
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            endRecording();
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        nativeDraw(canvas.mNativeCanvas, mNativePicture);
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create a new picture (already recorded) from the data in the stream. This
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * data was generated by a previous call to writeToStream().
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static Picture createFromStream(InputStream stream) {
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return new Picture(
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            nativeCreateFromStream(stream, new byte[WORKING_STREAM_STORAGE]));
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Write the picture contents to a stream. The data can be used to recreate
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the picture in this or another process by calling createFromStream.
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void writeToStream(OutputStream stream) {
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // do explicit check before calling the native method
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (stream == null) {
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new NullPointerException();
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!nativeWriteToStream(mNativePicture, stream,
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                             new byte[WORKING_STREAM_STORAGE])) {
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new RuntimeException();
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() throws Throwable {
12684fce187b0ae79adc5b4e64c26f72c8ed59e9703Romain Guy        try {
12784fce187b0ae79adc5b4e64c26f72c8ed59e9703Romain Guy            nativeDestructor(mNativePicture);
12884fce187b0ae79adc5b4e64c26f72c8ed59e9703Romain Guy        } finally {
12984fce187b0ae79adc5b4e64c26f72c8ed59e9703Romain Guy            super.finalize();
13084fce187b0ae79adc5b4e64c26f72c8ed59e9703Romain Guy        }
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*package*/ final int ni() {
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mNativePicture;
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Picture(int nativePicture) {
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (nativePicture == 0) {
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new RuntimeException();
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mNativePicture = nativePicture;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // return empty picture if src is 0, or a copy of the native src
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native int nativeConstructor(int nativeSrcOr0);
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native int nativeCreateFromStream(InputStream stream,
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                byte[] storage);
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native int nativeBeginRecording(int nativeCanvas,
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                    int w, int h);
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native void nativeEndRecording(int nativeCanvas);
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native void nativeDraw(int nativeCanvas, int nativePicture);
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native boolean nativeWriteToStream(int nativePicture,
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                           OutputStream stream, byte[] storage);
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native void nativeDestructor(int nativePicture);
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static class RecordingCanvas extends Canvas {
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final Picture mPicture;
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public RecordingCanvas(Picture pict, int nativeCanvas) {
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(nativeCanvas);
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPicture = pict;
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void setBitmap(Bitmap bitmap) {
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new RuntimeException(
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                "Cannot call setBitmap on a picture canvas");
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void drawPicture(Picture picture) {
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mPicture == picture) {
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new RuntimeException(
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            "Cannot draw a picture into its recording canvas");
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.drawPicture(picture);
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
181