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