Home | History | Annotate | Download | only in core
      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 "SkDevice.h"
     17 #include "SkPicture.h"
     18 #include "SkRegion.h"
     19 #include "SkStream.h"
     20 #include "SkTDArray.h"
     21 #include "SkTSearch.h"
     22 #include "SkTime.h"
     23 
     24 #include "SkReader32.h"
     25 #include "SkWriter32.h"
     26 #include "SkRTree.h"
     27 #include "SkBBoxHierarchyRecord.h"
     28 
     29 SK_DEFINE_INST_COUNT(SkPicture)
     30 
     31 #define DUMP_BUFFER_SIZE 65536
     32 
     33 //#define ENABLE_TIME_DRAW    // dumps milliseconds for each draw
     34 
     35 
     36 #ifdef SK_DEBUG
     37 // enable SK_DEBUG_TRACE to trace DrawType elements when
     38 //     recorded and played back
     39 // #define SK_DEBUG_TRACE
     40 // enable SK_DEBUG_SIZE to see the size of picture components
     41 // #define SK_DEBUG_SIZE
     42 // enable SK_DEBUG_DUMP to see the contents of recorded elements
     43 // #define SK_DEBUG_DUMP
     44 // enable SK_DEBUG_VALIDATE to check internal structures for consistency
     45 // #define SK_DEBUG_VALIDATE
     46 #endif
     47 
     48 #if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP
     49 const char* DrawTypeToString(DrawType drawType) {
     50     switch (drawType) {
     51         case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break;
     52         case CLIP_PATH: return "CLIP_PATH";
     53         case CLIP_REGION: return "CLIP_REGION";
     54         case CLIP_RECT: return "CLIP_RECT";
     55         case CLIP_RRECT: return "CLIP_RRECT";
     56         case CONCAT: return "CONCAT";
     57         case DRAW_BITMAP: return "DRAW_BITMAP";
     58         case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX";
     59         case DRAW_BITMAP_NINE: return "DRAW_BITMAP_NINE";
     60         case DRAW_BITMAP_RECT_TO_RECT: return "DRAW_BITMAP_RECT_TO_RECT";
     61         case DRAW_CLEAR: return "DRAW_CLEAR";
     62         case DRAW_DATA: return "DRAW_DATA";
     63         case DRAW_OVAL: return "DRAW_OVAL";
     64         case DRAW_PAINT: return "DRAW_PAINT";
     65         case DRAW_PATH: return "DRAW_PATH";
     66         case DRAW_PICTURE: return "DRAW_PICTURE";
     67         case DRAW_POINTS: return "DRAW_POINTS";
     68         case DRAW_POS_TEXT: return "DRAW_POS_TEXT";
     69         case DRAW_POS_TEXT_TOP_BOTTOM: return "DRAW_POS_TEXT_TOP_BOTTOM";
     70         case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H";
     71         case DRAW_POS_TEXT_H_TOP_BOTTOM: return "DRAW_POS_TEXT_H_TOP_BOTTOM";
     72         case DRAW_RECT: return "DRAW_RECT";
     73         case DRAW_RRECT: return "DRAW_RRECT";
     74         case DRAW_SPRITE: return "DRAW_SPRITE";
     75         case DRAW_TEXT: return "DRAW_TEXT";
     76         case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH";
     77         case DRAW_TEXT_TOP_BOTTOM: return "DRAW_TEXT_TOP_BOTTOM";
     78         case DRAW_VERTICES: return "DRAW_VERTICES";
     79         case RESTORE: return "RESTORE";
     80         case ROTATE: return "ROTATE";
     81         case SAVE: return "SAVE";
     82         case SAVE_LAYER: return "SAVE_LAYER";
     83         case SCALE: return "SCALE";
     84         case SET_MATRIX: return "SET_MATRIX";
     85         case SKEW: return "SKEW";
     86         case TRANSLATE: return "TRANSLATE";
     87         case NOOP: return "NOOP";
     88         default:
     89             SkDebugf("DrawType error 0x%08x\n", drawType);
     90             SkASSERT(0);
     91             break;
     92     }
     93     SkASSERT(0);
     94     return NULL;
     95 }
     96 #endif
     97 
     98 #ifdef SK_DEBUG_VALIDATE
     99 static void validateMatrix(const SkMatrix* matrix) {
    100     SkScalar scaleX = matrix->getScaleX();
    101     SkScalar scaleY = matrix->getScaleY();
    102     SkScalar skewX = matrix->getSkewX();
    103     SkScalar skewY = matrix->getSkewY();
    104     SkScalar perspX = matrix->getPerspX();
    105     SkScalar perspY = matrix->getPerspY();
    106     if (scaleX != 0 && skewX != 0)
    107         SkDebugf("scaleX != 0 && skewX != 0\n");
    108     SkASSERT(scaleX == 0 || skewX == 0);
    109     SkASSERT(scaleY == 0 || skewY == 0);
    110     SkASSERT(perspX == 0);
    111     SkASSERT(perspY == 0);
    112 }
    113 #endif
    114 
    115 
    116 ///////////////////////////////////////////////////////////////////////////////
    117 
    118 SkPicture::SkPicture() {
    119     fRecord = NULL;
    120     fPlayback = NULL;
    121     fWidth = fHeight = 0;
    122 }
    123 
    124 SkPicture::SkPicture(const SkPicture& src) : INHERITED() {
    125     fWidth = src.fWidth;
    126     fHeight = src.fHeight;
    127     fRecord = NULL;
    128 
    129     /*  We want to copy the src's playback. However, if that hasn't been built
    130         yet, we need to fake a call to endRecording() without actually calling
    131         it (since it is destructive, and we don't want to change src).
    132      */
    133     if (src.fPlayback) {
    134         fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback));
    135     } else if (src.fRecord) {
    136         // here we do a fake src.endRecording()
    137         fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fRecord));
    138     } else {
    139         fPlayback = NULL;
    140     }
    141 }
    142 
    143 SkPicture::~SkPicture() {
    144     SkSafeUnref(fRecord);
    145     SkDELETE(fPlayback);
    146 }
    147 
    148 void SkPicture::swap(SkPicture& other) {
    149     SkTSwap(fRecord, other.fRecord);
    150     SkTSwap(fPlayback, other.fPlayback);
    151     SkTSwap(fWidth, other.fWidth);
    152     SkTSwap(fHeight, other.fHeight);
    153 }
    154 
    155 SkPicture* SkPicture::clone() const {
    156     SkPicture* clonedPicture = SkNEW(SkPicture);
    157     clone(clonedPicture, 1);
    158     return clonedPicture;
    159 }
    160 
    161 void SkPicture::clone(SkPicture* pictures, int count) const {
    162     SkPictCopyInfo copyInfo;
    163 
    164     for (int i = 0; i < count; i++) {
    165         SkPicture* clone = &pictures[i];
    166 
    167         clone->fWidth = fWidth;
    168         clone->fHeight = fHeight;
    169         clone->fRecord = NULL;
    170 
    171         if (NULL != clone->fRecord) {
    172             clone->fRecord->unref();
    173             clone->fRecord = NULL;
    174         }
    175         SkDELETE(clone->fPlayback);
    176 
    177         /*  We want to copy the src's playback. However, if that hasn't been built
    178             yet, we need to fake a call to endRecording() without actually calling
    179             it (since it is destructive, and we don't want to change src).
    180          */
    181         if (fPlayback) {
    182             clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fPlayback, &copyInfo));
    183         } else if (fRecord) {
    184             // here we do a fake src.endRecording()
    185             clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord, true));
    186         } else {
    187             clone->fPlayback = NULL;
    188         }
    189     }
    190 }
    191 
    192 ///////////////////////////////////////////////////////////////////////////////
    193 
    194 SkCanvas* SkPicture::beginRecording(int width, int height,
    195                                     uint32_t recordingFlags) {
    196     if (fPlayback) {
    197         SkDELETE(fPlayback);
    198         fPlayback = NULL;
    199     }
    200 
    201     if (NULL != fRecord) {
    202         fRecord->unref();
    203         fRecord = NULL;
    204     }
    205 
    206     SkBitmap bm;
    207     bm.setConfig(SkBitmap::kNo_Config, width, height);
    208     SkAutoTUnref<SkDevice> dev(SkNEW_ARGS(SkDevice, (bm)));
    209 
    210     // Must be set before calling createBBoxHierarchy
    211     fWidth = width;
    212     fHeight = height;
    213 
    214     if (recordingFlags & kOptimizeForClippedPlayback_RecordingFlag) {
    215         SkBBoxHierarchy* tree = this->createBBoxHierarchy();
    216         SkASSERT(NULL != tree);
    217         fRecord = SkNEW_ARGS(SkBBoxHierarchyRecord, (recordingFlags, tree, dev));
    218         tree->unref();
    219     } else {
    220         fRecord = SkNEW_ARGS(SkPictureRecord, (recordingFlags, dev));
    221     }
    222     fRecord->beginRecording();
    223 
    224     return fRecord;
    225 }
    226 
    227 SkBBoxHierarchy* SkPicture::createBBoxHierarchy() const {
    228     // These values were empirically determined to produce reasonable
    229     // performance in most cases.
    230     static const int kRTreeMinChildren = 6;
    231     static const int kRTreeMaxChildren = 11;
    232 
    233     SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(fWidth),
    234                                        SkIntToScalar(fHeight));
    235     return SkRTree::Create(kRTreeMinChildren, kRTreeMaxChildren,
    236                            aspectRatio);
    237 }
    238 
    239 SkCanvas* SkPicture::getRecordingCanvas() const {
    240     // will be null if we are not recording
    241     return fRecord;
    242 }
    243 
    244 void SkPicture::endRecording() {
    245     if (NULL == fPlayback) {
    246         if (NULL != fRecord) {
    247             fRecord->endRecording();
    248             fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
    249             fRecord->unref();
    250             fRecord = NULL;
    251         }
    252     }
    253     SkASSERT(NULL == fRecord);
    254 }
    255 
    256 void SkPicture::draw(SkCanvas* surface, SkDrawPictureCallback* callback) {
    257     this->endRecording();
    258     if (fPlayback) {
    259         fPlayback->draw(*surface, callback);
    260     }
    261 }
    262 
    263 ///////////////////////////////////////////////////////////////////////////////
    264 
    265 #include "SkStream.h"
    266 
    267 bool SkPicture::StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
    268     if (NULL == stream) {
    269         return false;
    270     }
    271 
    272     SkPictInfo info;
    273     if (!stream->read(&info, sizeof(SkPictInfo))) {
    274         return false;
    275     }
    276     if (PICTURE_VERSION != info.fVersion) {
    277         return false;
    278     }
    279 
    280     if (pInfo != NULL) {
    281         *pInfo = info;
    282     }
    283     return true;
    284 }
    285 
    286 SkPicture::SkPicture(SkPicturePlayback* playback, int width, int height)
    287     : fPlayback(playback)
    288     , fRecord(NULL)
    289     , fWidth(width)
    290     , fHeight(height) {}
    291 
    292 SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
    293     SkPictInfo info;
    294 
    295     if (!StreamIsSKP(stream, &info)) {
    296         return NULL;
    297     }
    298 
    299     SkPicturePlayback* playback;
    300     // Check to see if there is a playback to recreate.
    301     if (stream->readBool()) {
    302         playback = SkNEW_ARGS(SkPicturePlayback, (stream, info, proc));
    303     } else {
    304         playback = NULL;
    305     }
    306 
    307     return SkNEW_ARGS(SkPicture, (playback, info.fWidth, info.fHeight));
    308 }
    309 
    310 void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const {
    311     SkPicturePlayback* playback = fPlayback;
    312 
    313     if (NULL == playback && fRecord) {
    314         playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
    315     }
    316 
    317     SkPictInfo info;
    318 
    319     info.fVersion = PICTURE_VERSION;
    320     info.fWidth = fWidth;
    321     info.fHeight = fHeight;
    322     info.fFlags = SkPictInfo::kCrossProcess_Flag;
    323 #ifdef SK_SCALAR_IS_FLOAT
    324     info.fFlags |= SkPictInfo::kScalarIsFloat_Flag;
    325 #endif
    326     if (8 == sizeof(void*)) {
    327         info.fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
    328     }
    329 
    330     stream->write(&info, sizeof(info));
    331     if (playback) {
    332         stream->writeBool(true);
    333         playback->serialize(stream, encoder);
    334         // delete playback if it is a local version (i.e. cons'd up just now)
    335         if (playback != fPlayback) {
    336             SkDELETE(playback);
    337         }
    338     } else {
    339         stream->writeBool(false);
    340     }
    341 }
    342 
    343 #ifdef SK_BUILD_FOR_ANDROID
    344 void SkPicture::abortPlayback() {
    345     if (NULL == fPlayback) {
    346         return;
    347     }
    348     fPlayback->abort();
    349 }
    350 #endif
    351