diff options
Diffstat (limited to 'src/core/SkPicture.cpp')
-rw-r--r-- | src/core/SkPicture.cpp | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp new file mode 100644 index 0000000..343ca2b --- /dev/null +++ b/src/core/SkPicture.cpp @@ -0,0 +1,247 @@ +/* +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include "SkPictureFlat.h" +#include "SkPicturePlayback.h" +#include "SkPictureRecord.h" + +#include "SkCanvas.h" +#include "SkChunkAlloc.h" +#include "SkPicture.h" +#include "SkRegion.h" +#include "SkStream.h" +#include "SkTDArray.h" +#include "SkTSearch.h" +#include "SkTime.h" + +#include "SkReader32.h" +#include "SkWriter32.h" + +#define DUMP_BUFFER_SIZE 65536 + +//#define ENABLE_TIME_DRAW // dumps milliseconds for each draw + + +#ifdef SK_DEBUG +// enable SK_DEBUG_TRACE to trace DrawType elements when +// recorded and played back +// #define SK_DEBUG_TRACE +// enable SK_DEBUG_SIZE to see the size of picture components +// #define SK_DEBUG_SIZE +// enable SK_DEBUG_DUMP to see the contents of recorded elements +// #define SK_DEBUG_DUMP +// enable SK_DEBUG_VALIDATE to check internal structures for consistency +// #define SK_DEBUG_VALIDATE +#endif + +#if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP +const char* DrawTypeToString(DrawType drawType) { + switch (drawType) { + case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break; + case CLIP_PATH: return "CLIP_PATH"; + case CLIP_REGION: return "CLIP_REGION"; + case CLIP_RECT: return "CLIP_RECT"; + case CONCAT: return "CONCAT"; + case DRAW_BITMAP: return "DRAW_BITMAP"; + case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX"; + case DRAW_BITMAP_RECT: return "DRAW_BITMAP_RECT"; + case DRAW_PAINT: return "DRAW_PAINT"; + case DRAW_PATH: return "DRAW_PATH"; + case DRAW_PICTURE: return "DRAW_PICTURE"; + case DRAW_POINTS: return "DRAW_POINTS"; + case DRAW_POS_TEXT: return "DRAW_POS_TEXT"; + case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H"; + case DRAW_RECT_GENERAL: return "DRAW_RECT_GENERAL"; + case DRAW_RECT_SIMPLE: return "DRAW_RECT_SIMPLE"; + case DRAW_SPRITE: return "DRAW_SPRITE"; + case DRAW_TEXT: return "DRAW_TEXT"; + case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH"; + case RESTORE: return "RESTORE"; + case ROTATE: return "ROTATE"; + case SAVE: return "SAVE"; + case SAVE_LAYER: return "SAVE_LAYER"; + case SCALE: return "SCALE"; + case SKEW: return "SKEW"; + case TRANSLATE: return "TRANSLATE"; + default: + SkDebugf("DrawType error 0x%08x\n", drawType); + SkASSERT(0); + break; + } + SkASSERT(0); + return NULL; +} +#endif + +#ifdef SK_DEBUG_VALIDATE +static void validateMatrix(const SkMatrix* matrix) { + SkScalar scaleX = matrix->getScaleX(); + SkScalar scaleY = matrix->getScaleY(); + SkScalar skewX = matrix->getSkewX(); + SkScalar skewY = matrix->getSkewY(); + SkScalar perspX = matrix->getPerspX(); + SkScalar perspY = matrix->getPerspY(); + if (scaleX != 0 && skewX != 0) + SkDebugf("scaleX != 0 && skewX != 0\n"); + SkASSERT(scaleX == 0 || skewX == 0); + SkASSERT(scaleY == 0 || skewY == 0); + SkASSERT(perspX == 0); + SkASSERT(perspY == 0); +} +#endif + + +/////////////////////////////////////////////////////////////////////////////// + +SkPicture::SkPicture() { + fRecord = NULL; + fPlayback = NULL; + fWidth = fHeight = 0; +} + +SkPicture::SkPicture(const SkPicture& src) : SkRefCnt() { + fWidth = src.fWidth; + fHeight = src.fHeight; + fRecord = NULL; + + /* We want to copy the src's playback. However, if that hasn't been built + yet, we need to fake a call to endRecording() without actually calling + it (since it is destructive, and we don't want to change src). + */ + if (src.fPlayback) { + fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback)); + } else if (src.fRecord) { + // here we do a fake src.endRecording() + fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fRecord)); + } else { + fPlayback = NULL; + } +} + +SkPicture::~SkPicture() { + fRecord->safeUnref(); + SkDELETE(fPlayback); +} + +void SkPicture::swap(SkPicture& other) { + SkTSwap(fRecord, other.fRecord); + SkTSwap(fPlayback, other.fPlayback); + SkTSwap(fWidth, other.fWidth); + SkTSwap(fHeight, other.fHeight); +} + +/////////////////////////////////////////////////////////////////////////////// + +SkCanvas* SkPicture::beginRecording(int width, int height, + uint32_t recordingFlags) { + if (fPlayback) { + SkDELETE(fPlayback); + fPlayback = NULL; + } + + if (NULL != fRecord) { + fRecord->unref(); + fRecord = NULL; + } + + fRecord = SkNEW_ARGS(SkPictureRecord, (recordingFlags)); + + fWidth = width; + fHeight = height; + + SkBitmap bm; + bm.setConfig(SkBitmap::kNo_Config, width, height); + fRecord->setBitmapDevice(bm); + + return fRecord; +} + +SkCanvas* SkPicture::getRecordingCanvas() const { + // will be null if we are not recording + return fRecord; +} + +void SkPicture::endRecording() { + if (NULL == fPlayback) { + if (NULL != fRecord) { + fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); + fRecord->unref(); + fRecord = NULL; + } + } + SkASSERT(NULL == fRecord); +} + +void SkPicture::draw(SkCanvas* surface) { + this->endRecording(); + if (fPlayback) { + fPlayback->draw(*surface); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +#include "SkStream.h" + +#define PICTURE_VERSION 1 + +SkPicture::SkPicture(SkStream* stream) : SkRefCnt() { + if (stream->readU32() != PICTURE_VERSION) { + sk_throw(); + } + + fWidth = stream->readU32(); + fHeight = stream->readU32(); + + fRecord = NULL; + fPlayback = NULL; + + if (stream->readBool()) { + fPlayback = SkNEW_ARGS(SkPicturePlayback, (stream)); + } +} + +void SkPicture::serialize(SkWStream* stream) const { + SkPicturePlayback* playback = fPlayback; + + if (NULL == playback && fRecord) { + playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); + } + + stream->write32(PICTURE_VERSION); + stream->write32(fWidth); + stream->write32(fHeight); + if (playback) { + stream->writeBool(true); + playback->serialize(stream); + // delete playback if it is a local version (i.e. cons'd up just now) + if (playback != fPlayback) { + SkDELETE(playback); + } + } else { + stream->writeBool(false); + } +} + +void SkPicture::abortPlayback() { + if (NULL == fPlayback) { + return; + } + fPlayback->abort(); +} + + |