SkPicture.cpp revision 82065d667f64e232bcde2ad849756a6096fcbe6f
1/*
2**
3** Copyright 2007, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "SkPictureFlat.h"
19#include "SkPicturePlayback.h"
20#include "SkPictureRecord.h"
21
22#include "SkCanvas.h"
23#include "SkChunkAlloc.h"
24#include "SkPicture.h"
25#include "SkRegion.h"
26#include "SkStream.h"
27#include "SkTDArray.h"
28#include "SkTSearch.h"
29#include "SkTime.h"
30
31#include "SkReader32.h"
32#include "SkWriter32.h"
33
34#define DUMP_BUFFER_SIZE 65536
35
36//#define ENABLE_TIME_DRAW    // dumps milliseconds for each draw
37
38
39#ifdef SK_DEBUG
40// enable SK_DEBUG_TRACE to trace DrawType elements when
41//     recorded and played back
42// #define SK_DEBUG_TRACE
43// enable SK_DEBUG_SIZE to see the size of picture components
44// #define SK_DEBUG_SIZE
45// enable SK_DEBUG_DUMP to see the contents of recorded elements
46// #define SK_DEBUG_DUMP
47// enable SK_DEBUG_VALIDATE to check internal structures for consistency
48// #define SK_DEBUG_VALIDATE
49#endif
50
51#if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP
52const char* DrawTypeToString(DrawType drawType) {
53    switch (drawType) {
54        case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break;
55        case CLIP_PATH: return "CLIP_PATH";
56        case CLIP_REGION: return "CLIP_REGION";
57        case CLIP_RECT: return "CLIP_RECT";
58        case CONCAT: return "CONCAT";
59        case DRAW_BITMAP: return "DRAW_BITMAP";
60        case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX";
61        case DRAW_BITMAP_RECT: return "DRAW_BITMAP_RECT";
62        case DRAW_PAINT: return "DRAW_PAINT";
63        case DRAW_PATH: return "DRAW_PATH";
64        case DRAW_PICTURE: return "DRAW_PICTURE";
65        case DRAW_POINTS: return "DRAW_POINTS";
66        case DRAW_POS_TEXT: return "DRAW_POS_TEXT";
67        case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H";
68        case DRAW_RECT_GENERAL: return "DRAW_RECT_GENERAL";
69        case DRAW_RECT_SIMPLE: return "DRAW_RECT_SIMPLE";
70        case DRAW_SPRITE: return "DRAW_SPRITE";
71        case DRAW_TEXT: return "DRAW_TEXT";
72        case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH";
73        case RESTORE: return "RESTORE";
74        case ROTATE: return "ROTATE";
75        case SAVE: return "SAVE";
76        case SAVE_LAYER: return "SAVE_LAYER";
77        case SCALE: return "SCALE";
78        case SKEW: return "SKEW";
79        case TRANSLATE: return "TRANSLATE";
80        default:
81            SkDebugf("DrawType error 0x%08x\n", drawType);
82            SkASSERT(0);
83            break;
84    }
85    SkASSERT(0);
86    return NULL;
87}
88#endif
89
90#ifdef SK_DEBUG_VALIDATE
91static void validateMatrix(const SkMatrix* matrix) {
92    SkScalar scaleX = matrix->getScaleX();
93    SkScalar scaleY = matrix->getScaleY();
94    SkScalar skewX = matrix->getSkewX();
95    SkScalar skewY = matrix->getSkewY();
96    SkScalar perspX = matrix->getPerspX();
97    SkScalar perspY = matrix->getPerspY();
98    if (scaleX != 0 && skewX != 0)
99        SkDebugf("scaleX != 0 && skewX != 0\n");
100    SkASSERT(scaleX == 0 || skewX == 0);
101    SkASSERT(scaleY == 0 || skewY == 0);
102    SkASSERT(perspX == 0);
103    SkASSERT(perspY == 0);
104}
105#endif
106
107
108///////////////////////////////////////////////////////////////////////////////
109
110SkPicture::SkPicture() {
111    fRecord = NULL;
112    fPlayback = NULL;
113    fWidth = fHeight = 0;
114}
115
116SkPicture::SkPicture(const SkPicture& src) : SkRefCnt() {
117    fWidth = src.fWidth;
118    fHeight = src.fHeight;
119    fRecord = NULL;
120
121    /*  We want to copy the src's playback. However, if that hasn't been built
122        yet, we need to fake a call to endRecording() without actually calling
123        it (since it is destructive, and we don't want to change src).
124     */
125    if (src.fPlayback) {
126        fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback));
127    } else if (src.fRecord) {
128        // here we do a fake src.endRecording()
129        fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fRecord));
130    } else {
131        fPlayback = NULL;
132    }
133}
134
135SkPicture::~SkPicture() {
136    SkSafeUnref(fRecord);
137    SkDELETE(fPlayback);
138}
139
140void SkPicture::swap(SkPicture& other) {
141    SkTSwap(fRecord, other.fRecord);
142    SkTSwap(fPlayback, other.fPlayback);
143    SkTSwap(fWidth, other.fWidth);
144    SkTSwap(fHeight, other.fHeight);
145}
146
147///////////////////////////////////////////////////////////////////////////////
148
149SkCanvas* SkPicture::beginRecording(int width, int height,
150                                    uint32_t recordingFlags) {
151    if (fPlayback) {
152        SkDELETE(fPlayback);
153        fPlayback = NULL;
154    }
155
156    if (NULL != fRecord) {
157        fRecord->unref();
158        fRecord = NULL;
159    }
160
161    fRecord = SkNEW_ARGS(SkPictureRecord, (recordingFlags));
162
163    fWidth = width;
164    fHeight = height;
165
166    SkBitmap bm;
167    bm.setConfig(SkBitmap::kNo_Config, width, height);
168    fRecord->setBitmapDevice(bm);
169
170    return fRecord;
171}
172
173SkCanvas* SkPicture::getRecordingCanvas() const {
174    // will be null if we are not recording
175    return fRecord;
176}
177
178void SkPicture::endRecording() {
179    if (NULL == fPlayback) {
180        if (NULL != fRecord) {
181            fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
182            fRecord->unref();
183            fRecord = NULL;
184        }
185    }
186    SkASSERT(NULL == fRecord);
187}
188
189void SkPicture::draw(SkCanvas* surface) {
190    this->endRecording();
191    if (fPlayback) {
192        fPlayback->draw(*surface);
193    }
194}
195
196///////////////////////////////////////////////////////////////////////////////
197
198#include "SkStream.h"
199
200#define PICTURE_VERSION     1
201
202SkPicture::SkPicture(SkStream* stream) : SkRefCnt() {
203    if (stream->readU32() != PICTURE_VERSION) {
204        sk_throw();
205    }
206
207    fWidth = stream->readU32();
208    fHeight = stream->readU32();
209
210    fRecord = NULL;
211    fPlayback = NULL;
212
213    if (stream->readBool()) {
214        fPlayback = SkNEW_ARGS(SkPicturePlayback, (stream));
215    }
216}
217
218void SkPicture::serialize(SkWStream* stream) const {
219    SkPicturePlayback* playback = fPlayback;
220
221    if (NULL == playback && fRecord) {
222        playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
223    }
224
225    stream->write32(PICTURE_VERSION);
226    stream->write32(fWidth);
227    stream->write32(fHeight);
228    if (playback) {
229        stream->writeBool(true);
230        playback->serialize(stream);
231        // delete playback if it is a local version (i.e. cons'd up just now)
232        if (playback != fPlayback) {
233            SkDELETE(playback);
234        }
235    } else {
236        stream->writeBool(false);
237    }
238}
239
240void SkPicture::abortPlayback() {
241    if (NULL == fPlayback) {
242        return;
243    }
244    fPlayback->abort();
245}
246
247
248