SkPicture.cpp revision 01ec2eb42e9c64f8d06afd51f80c055710147141
1
2/*
3 * Copyright 2007 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkPictureFlat.h"
11#include "SkPicturePlayback.h"
12#include "SkPictureRecord.h"
13
14#include "SkCanvas.h"
15#include "SkChunkAlloc.h"
16#include "SkPicture.h"
17#include "SkRegion.h"
18#include "SkStream.h"
19#include "SkTDArray.h"
20#include "SkTSearch.h"
21#include "SkTime.h"
22
23#include "SkReader32.h"
24#include "SkWriter32.h"
25
26SK_DEFINE_INST_COUNT(SkPicture)
27
28#define DUMP_BUFFER_SIZE 65536
29
30//#define ENABLE_TIME_DRAW    // dumps milliseconds for each draw
31
32
33#ifdef SK_DEBUG
34// enable SK_DEBUG_TRACE to trace DrawType elements when
35//     recorded and played back
36// #define SK_DEBUG_TRACE
37// enable SK_DEBUG_SIZE to see the size of picture components
38// #define SK_DEBUG_SIZE
39// enable SK_DEBUG_DUMP to see the contents of recorded elements
40// #define SK_DEBUG_DUMP
41// enable SK_DEBUG_VALIDATE to check internal structures for consistency
42// #define SK_DEBUG_VALIDATE
43#endif
44
45#if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP
46const char* DrawTypeToString(DrawType drawType) {
47    switch (drawType) {
48        case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break;
49        case CLIP_PATH: return "CLIP_PATH";
50        case CLIP_REGION: return "CLIP_REGION";
51        case CLIP_RECT: return "CLIP_RECT";
52        case CONCAT: return "CONCAT";
53        case DRAW_BITMAP: return "DRAW_BITMAP";
54        case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX";
55        case DRAW_BITMAP_RECT: return "DRAW_BITMAP_RECT";
56        case DRAW_PAINT: return "DRAW_PAINT";
57        case DRAW_PATH: return "DRAW_PATH";
58        case DRAW_PICTURE: return "DRAW_PICTURE";
59        case DRAW_POINTS: return "DRAW_POINTS";
60        case DRAW_POS_TEXT: return "DRAW_POS_TEXT";
61        case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H";
62        case DRAW_RECT_GENERAL: return "DRAW_RECT_GENERAL";
63        case DRAW_RECT_SIMPLE: return "DRAW_RECT_SIMPLE";
64        case DRAW_SPRITE: return "DRAW_SPRITE";
65        case DRAW_TEXT: return "DRAW_TEXT";
66        case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH";
67        case RESTORE: return "RESTORE";
68        case ROTATE: return "ROTATE";
69        case SAVE: return "SAVE";
70        case SAVE_LAYER: return "SAVE_LAYER";
71        case SCALE: return "SCALE";
72        case SKEW: return "SKEW";
73        case TRANSLATE: return "TRANSLATE";
74        default:
75            SkDebugf("DrawType error 0x%08x\n", drawType);
76            SkASSERT(0);
77            break;
78    }
79    SkASSERT(0);
80    return NULL;
81}
82#endif
83
84#ifdef SK_DEBUG_VALIDATE
85static void validateMatrix(const SkMatrix* matrix) {
86    SkScalar scaleX = matrix->getScaleX();
87    SkScalar scaleY = matrix->getScaleY();
88    SkScalar skewX = matrix->getSkewX();
89    SkScalar skewY = matrix->getSkewY();
90    SkScalar perspX = matrix->getPerspX();
91    SkScalar perspY = matrix->getPerspY();
92    if (scaleX != 0 && skewX != 0)
93        SkDebugf("scaleX != 0 && skewX != 0\n");
94    SkASSERT(scaleX == 0 || skewX == 0);
95    SkASSERT(scaleY == 0 || skewY == 0);
96    SkASSERT(perspX == 0);
97    SkASSERT(perspY == 0);
98}
99#endif
100
101
102///////////////////////////////////////////////////////////////////////////////
103
104SkPicture::SkPicture() {
105    fRecord = NULL;
106    fPlayback = NULL;
107    fWidth = fHeight = 0;
108}
109
110SkPicture::SkPicture(const SkPicture& src) : SkRefCnt() {
111    fWidth = src.fWidth;
112    fHeight = src.fHeight;
113    fRecord = NULL;
114
115    /*  We want to copy the src's playback. However, if that hasn't been built
116        yet, we need to fake a call to endRecording() without actually calling
117        it (since it is destructive, and we don't want to change src).
118     */
119    if (src.fPlayback) {
120        fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback));
121    } else if (src.fRecord) {
122        // here we do a fake src.endRecording()
123        fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fRecord));
124    } else {
125        fPlayback = NULL;
126    }
127}
128
129SkPicture::~SkPicture() {
130    SkSafeUnref(fRecord);
131    SkDELETE(fPlayback);
132}
133
134void SkPicture::swap(SkPicture& other) {
135    SkTSwap(fRecord, other.fRecord);
136    SkTSwap(fPlayback, other.fPlayback);
137    SkTSwap(fWidth, other.fWidth);
138    SkTSwap(fHeight, other.fHeight);
139}
140
141///////////////////////////////////////////////////////////////////////////////
142
143SkCanvas* SkPicture::beginRecording(int width, int height,
144                                    uint32_t recordingFlags) {
145    if (fPlayback) {
146        SkDELETE(fPlayback);
147        fPlayback = NULL;
148    }
149
150    if (NULL != fRecord) {
151        fRecord->unref();
152        fRecord = NULL;
153    }
154
155    fRecord = SkNEW_ARGS(SkPictureRecord, (recordingFlags));
156
157    fWidth = width;
158    fHeight = height;
159
160    SkBitmap bm;
161    bm.setConfig(SkBitmap::kNo_Config, width, height);
162    fRecord->setBitmapDevice(bm);
163
164    return fRecord;
165}
166
167bool SkPicture::hasRecorded() const {
168    return NULL != fRecord && fRecord->writeStream().size() > 0;
169}
170
171SkCanvas* SkPicture::getRecordingCanvas() const {
172    // will be null if we are not recording
173    return fRecord;
174}
175
176void SkPicture::endRecording() {
177    if (NULL == fPlayback) {
178        if (NULL != fRecord) {
179            fRecord->endRecording();
180            fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
181            fRecord->unref();
182            fRecord = NULL;
183        }
184    }
185    SkASSERT(NULL == fRecord);
186}
187
188void SkPicture::draw(SkCanvas* surface) {
189    this->endRecording();
190    if (fPlayback) {
191        fPlayback->draw(*surface);
192    }
193}
194
195///////////////////////////////////////////////////////////////////////////////
196
197#include "SkStream.h"
198
199// V2 : adds SkPixelRef's generation ID.
200// V3 : PictInfo tag at beginning, and EOF tag at the end
201// V4 : move SkPictInfo to be the header
202// V5 : don't read/write FunctionPtr on cross-process (we can detect that)
203// V6 : added serialization of SkPath's bounds (and packed its flags tighter)
204#define PICTURE_VERSION     6
205
206SkPicture::SkPicture(SkStream* stream) : SkRefCnt() {
207    fRecord = NULL;
208    fPlayback = NULL;
209    fWidth = fHeight = 0;
210
211    SkPictInfo info;
212
213    if (!stream->read(&info, sizeof(info))) {
214        return;
215    }
216    if (PICTURE_VERSION != info.fVersion) {
217        return;
218    }
219
220    if (stream->readBool()) {
221        bool isValid = false;
222        fPlayback = SkNEW_ARGS(SkPicturePlayback, (stream, info, &isValid));
223        if (!isValid) {
224            SkDELETE(fPlayback);
225            fPlayback = NULL;
226            return;
227        }
228    }
229
230    // do this at the end, so that they will be zero if we hit an error.
231    fWidth = info.fWidth;
232    fHeight = info.fHeight;
233}
234
235void SkPicture::serialize(SkWStream* stream) const {
236    SkPicturePlayback* playback = fPlayback;
237
238    if (NULL == playback && fRecord) {
239        playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
240    }
241
242    SkPictInfo info;
243
244    info.fVersion = PICTURE_VERSION;
245    info.fWidth = fWidth;
246    info.fHeight = fHeight;
247    info.fFlags = SkPictInfo::kCrossProcess_Flag;
248#ifdef SK_SCALAR_IS_FLOAT
249    info.fFlags |= SkPictInfo::kScalarIsFloat_Flag;
250#endif
251    if (8 == sizeof(void*)) {
252        info.fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
253    }
254
255    stream->write(&info, sizeof(info));
256    if (playback) {
257        stream->writeBool(true);
258        playback->serialize(stream);
259        // delete playback if it is a local version (i.e. cons'd up just now)
260        if (playback != fPlayback) {
261            SkDELETE(playback);
262        }
263    } else {
264        stream->writeBool(false);
265    }
266}
267
268void SkPicture::abortPlayback() {
269    if (NULL == fPlayback) {
270        return;
271    }
272    fPlayback->abort();
273}
274
275
276