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 "SkBBHFactory.h"
     15 #include "SkBitmapDevice.h"
     16 #include "SkCanvas.h"
     17 #include "SkChunkAlloc.h"
     18 #include "SkPaintPriv.h"
     19 #include "SkPicture.h"
     20 #include "SkRegion.h"
     21 #include "SkStream.h"
     22 #include "SkTDArray.h"
     23 #include "SkTSearch.h"
     24 #include "SkTime.h"
     25 
     26 #include "SkReader32.h"
     27 #include "SkWriter32.h"
     28 #include "SkRTree.h"
     29 #include "SkBBoxHierarchyRecord.h"
     30 
     31 #if SK_SUPPORT_GPU
     32 #include "GrContext.h"
     33 #endif
     34 
     35 template <typename T> int SafeCount(const T* obj) {
     36     return obj ? obj->count() : 0;
     37 }
     38 
     39 #define DUMP_BUFFER_SIZE 65536
     40 
     41 //#define ENABLE_TIME_DRAW    // dumps milliseconds for each draw
     42 
     43 
     44 #ifdef SK_DEBUG
     45 // enable SK_DEBUG_TRACE to trace DrawType elements when
     46 //     recorded and played back
     47 // #define SK_DEBUG_TRACE
     48 // enable SK_DEBUG_SIZE to see the size of picture components
     49 // #define SK_DEBUG_SIZE
     50 // enable SK_DEBUG_DUMP to see the contents of recorded elements
     51 // #define SK_DEBUG_DUMP
     52 // enable SK_DEBUG_VALIDATE to check internal structures for consistency
     53 // #define SK_DEBUG_VALIDATE
     54 #endif
     55 
     56 #if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP
     57 const char* DrawTypeToString(DrawType drawType) {
     58     switch (drawType) {
     59         case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break;
     60         case CLIP_PATH: return "CLIP_PATH";
     61         case CLIP_REGION: return "CLIP_REGION";
     62         case CLIP_RECT: return "CLIP_RECT";
     63         case CLIP_RRECT: return "CLIP_RRECT";
     64         case CONCAT: return "CONCAT";
     65         case DRAW_BITMAP: return "DRAW_BITMAP";
     66         case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX";
     67         case DRAW_BITMAP_NINE: return "DRAW_BITMAP_NINE";
     68         case DRAW_BITMAP_RECT_TO_RECT: return "DRAW_BITMAP_RECT_TO_RECT";
     69         case DRAW_CLEAR: return "DRAW_CLEAR";
     70         case DRAW_DATA: return "DRAW_DATA";
     71         case DRAW_OVAL: return "DRAW_OVAL";
     72         case DRAW_PAINT: return "DRAW_PAINT";
     73         case DRAW_PATH: return "DRAW_PATH";
     74         case DRAW_PICTURE: return "DRAW_PICTURE";
     75         case DRAW_POINTS: return "DRAW_POINTS";
     76         case DRAW_POS_TEXT: return "DRAW_POS_TEXT";
     77         case DRAW_POS_TEXT_TOP_BOTTOM: return "DRAW_POS_TEXT_TOP_BOTTOM";
     78         case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H";
     79         case DRAW_POS_TEXT_H_TOP_BOTTOM: return "DRAW_POS_TEXT_H_TOP_BOTTOM";
     80         case DRAW_RECT: return "DRAW_RECT";
     81         case DRAW_RRECT: return "DRAW_RRECT";
     82         case DRAW_SPRITE: return "DRAW_SPRITE";
     83         case DRAW_TEXT: return "DRAW_TEXT";
     84         case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH";
     85         case DRAW_TEXT_TOP_BOTTOM: return "DRAW_TEXT_TOP_BOTTOM";
     86         case DRAW_VERTICES: return "DRAW_VERTICES";
     87         case RESTORE: return "RESTORE";
     88         case ROTATE: return "ROTATE";
     89         case SAVE: return "SAVE";
     90         case SAVE_LAYER: return "SAVE_LAYER";
     91         case SCALE: return "SCALE";
     92         case SET_MATRIX: return "SET_MATRIX";
     93         case SKEW: return "SKEW";
     94         case TRANSLATE: return "TRANSLATE";
     95         case NOOP: return "NOOP";
     96         default:
     97             SkDebugf("DrawType error 0x%08x\n", drawType);
     98             SkASSERT(0);
     99             break;
    100     }
    101     SkASSERT(0);
    102     return NULL;
    103 }
    104 #endif
    105 
    106 #ifdef SK_DEBUG_VALIDATE
    107 static void validateMatrix(const SkMatrix* matrix) {
    108     SkScalar scaleX = matrix->getScaleX();
    109     SkScalar scaleY = matrix->getScaleY();
    110     SkScalar skewX = matrix->getSkewX();
    111     SkScalar skewY = matrix->getSkewY();
    112     SkScalar perspX = matrix->getPerspX();
    113     SkScalar perspY = matrix->getPerspY();
    114     if (scaleX != 0 && skewX != 0)
    115         SkDebugf("scaleX != 0 && skewX != 0\n");
    116     SkASSERT(scaleX == 0 || skewX == 0);
    117     SkASSERT(scaleY == 0 || skewY == 0);
    118     SkASSERT(perspX == 0);
    119     SkASSERT(perspY == 0);
    120 }
    121 #endif
    122 
    123 
    124 ///////////////////////////////////////////////////////////////////////////////
    125 
    126 SkPicture::SkPicture()
    127     : fAccelData(NULL) {
    128     this->needsNewGenID();
    129     fPlayback = NULL;
    130     fWidth = fHeight = 0;
    131 }
    132 
    133 SkPicture::SkPicture(int width, int height,
    134                      const SkPictureRecord& record,
    135                      bool deepCopyOps)
    136     : fWidth(width)
    137     , fHeight(height)
    138     , fAccelData(NULL) {
    139     this->needsNewGenID();
    140 
    141     SkPictInfo info;
    142     this->createHeader(&info);
    143     fPlayback = SkNEW_ARGS(SkPicturePlayback, (record, info, deepCopyOps));
    144 }
    145 
    146 SkPicture::SkPicture(const SkPicture& src)
    147     : INHERITED()
    148     , fAccelData(NULL) {
    149     this->needsNewGenID();
    150     fWidth = src.fWidth;
    151     fHeight = src.fHeight;
    152 
    153     if (src.fPlayback) {
    154         fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback));
    155         fUniqueID = src.uniqueID();     // need to call method to ensure != 0
    156     } else {
    157         fPlayback = NULL;
    158     }
    159 }
    160 
    161 SkPicture::~SkPicture() {
    162     SkDELETE(fPlayback);
    163     SkSafeUnref(fAccelData);
    164 }
    165 
    166 void SkPicture::swap(SkPicture& other) {
    167     SkTSwap(fUniqueID, other.fUniqueID);
    168     SkTSwap(fPlayback, other.fPlayback);
    169     SkTSwap(fAccelData, other.fAccelData);
    170     SkTSwap(fWidth, other.fWidth);
    171     SkTSwap(fHeight, other.fHeight);
    172 }
    173 
    174 SkPicture* SkPicture::clone() const {
    175     SkPicture* clonedPicture = SkNEW(SkPicture);
    176     this->clone(clonedPicture, 1);
    177     return clonedPicture;
    178 }
    179 
    180 void SkPicture::clone(SkPicture* pictures, int count) const {
    181     SkPictCopyInfo copyInfo;
    182 
    183     for (int i = 0; i < count; i++) {
    184         SkPicture* clone = &pictures[i];
    185 
    186         clone->needsNewGenID();
    187         clone->fWidth = fWidth;
    188         clone->fHeight = fHeight;
    189         SkDELETE(clone->fPlayback);
    190 
    191         /*  We want to copy the src's playback. However, if that hasn't been built
    192             yet, we need to fake a call to endRecording() without actually calling
    193             it (since it is destructive, and we don't want to change src).
    194          */
    195         if (fPlayback) {
    196             if (!copyInfo.initialized) {
    197                 int paintCount = SafeCount(fPlayback->fPaints);
    198 
    199                 /* The alternative to doing this is to have a clone method on the paint and have it
    200                  * make the deep copy of its internal structures as needed. The holdup to doing
    201                  * that is at this point we would need to pass the SkBitmapHeap so that we don't
    202                  * unnecessarily flatten the pixels in a bitmap shader.
    203                  */
    204                 copyInfo.paintData.setCount(paintCount);
    205 
    206                 /* Use an SkBitmapHeap to avoid flattening bitmaps in shaders. If there already is
    207                  * one, use it. If this SkPicturePlayback was created from a stream, fBitmapHeap
    208                  * will be NULL, so create a new one.
    209                  */
    210                 if (fPlayback->fBitmapHeap.get() == NULL) {
    211                     // FIXME: Put this on the stack inside SkPicture::clone.
    212                     SkBitmapHeap* heap = SkNEW(SkBitmapHeap);
    213                     copyInfo.controller.setBitmapStorage(heap);
    214                     heap->unref();
    215                 } else {
    216                     copyInfo.controller.setBitmapStorage(fPlayback->fBitmapHeap);
    217                 }
    218 
    219                 SkDEBUGCODE(int heapSize = SafeCount(fPlayback->fBitmapHeap.get());)
    220                 for (int i = 0; i < paintCount; i++) {
    221                     if (NeedsDeepCopy(fPlayback->fPaints->at(i))) {
    222                         copyInfo.paintData[i] =
    223                             SkFlatData::Create<SkPaint::FlatteningTraits>(&copyInfo.controller,
    224                                                               fPlayback->fPaints->at(i), 0);
    225 
    226                     } else {
    227                         // this is our sentinel, which we use in the unflatten loop
    228                         copyInfo.paintData[i] = NULL;
    229                     }
    230                 }
    231                 SkASSERT(SafeCount(fPlayback->fBitmapHeap.get()) == heapSize);
    232 
    233                 // needed to create typeface playback
    234                 copyInfo.controller.setupPlaybacks();
    235                 copyInfo.initialized = true;
    236             }
    237 
    238             clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fPlayback, &copyInfo));
    239             clone->fUniqueID = this->uniqueID(); // need to call method to ensure != 0
    240         } else {
    241             clone->fPlayback = NULL;
    242         }
    243     }
    244 }
    245 
    246 SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() {
    247     static int32_t gNextID = 0;
    248 
    249     int32_t id = sk_atomic_inc(&gNextID);
    250     if (id >= 1 << (8 * sizeof(Domain))) {
    251         SK_CRASH();
    252     }
    253 
    254     return static_cast<Domain>(id);
    255 }
    256 
    257 ///////////////////////////////////////////////////////////////////////////////
    258 
    259 const SkPicture::OperationList& SkPicture::OperationList::InvalidList() {
    260     static OperationList gInvalid;
    261     return gInvalid;
    262 }
    263 
    264 const SkPicture::OperationList& SkPicture::EXPERIMENTAL_getActiveOps(const SkIRect& queryRect) const {
    265     SkASSERT(NULL != fPlayback);
    266     if (NULL != fPlayback) {
    267         return fPlayback->getActiveOps(queryRect);
    268     }
    269     return OperationList::InvalidList();
    270 }
    271 
    272 size_t SkPicture::EXPERIMENTAL_curOpID() const {
    273     if (NULL != fPlayback) {
    274         return fPlayback->curOpID();
    275     }
    276     return 0;
    277 }
    278 
    279 void SkPicture::draw(SkCanvas* surface, SkDrawPictureCallback* callback) const {
    280     SkASSERT(NULL != fPlayback);
    281     if (NULL != fPlayback) {
    282         fPlayback->draw(*surface, callback);
    283     }
    284 }
    285 
    286 ///////////////////////////////////////////////////////////////////////////////
    287 
    288 #include "SkStream.h"
    289 
    290 static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
    291 
    292 bool SkPicture::IsValidPictInfo(const SkPictInfo& info) {
    293     if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) {
    294         return false;
    295     }
    296 
    297     if (info.fVersion < MIN_PICTURE_VERSION ||
    298         info.fVersion > CURRENT_PICTURE_VERSION) {
    299         return false;
    300     }
    301 
    302     return true;
    303 }
    304 
    305 bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
    306     if (NULL == stream) {
    307         return false;
    308     }
    309 
    310     // Check magic bytes.
    311     SkPictInfo info;
    312     SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
    313     if (!stream->read(&info, sizeof(info)) || !IsValidPictInfo(info)) {
    314         return false;
    315     }
    316 
    317     if (pInfo != NULL) {
    318         *pInfo = info;
    319     }
    320     return true;
    321 }
    322 
    323 bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer& buffer, SkPictInfo* pInfo) {
    324     // Check magic bytes.
    325     SkPictInfo info;
    326     SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
    327     if (!buffer.readByteArray(&info, sizeof(info)) || !IsValidPictInfo(info)) {
    328         return false;
    329     }
    330 
    331     if (pInfo != NULL) {
    332         *pInfo = info;
    333     }
    334     return true;
    335 }
    336 
    337 SkPicture::SkPicture(SkPicturePlayback* playback, int width, int height)
    338     : fPlayback(playback)
    339     , fWidth(width)
    340     , fHeight(height)
    341     , fAccelData(NULL) {
    342     this->needsNewGenID();
    343 }
    344 
    345 SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
    346     SkPictInfo info;
    347 
    348     if (!InternalOnly_StreamIsSKP(stream, &info)) {
    349         return NULL;
    350     }
    351 
    352     // Check to see if there is a playback to recreate.
    353     if (stream->readBool()) {
    354         SkPicturePlayback* playback = SkPicturePlayback::CreateFromStream(stream, info, proc);
    355         if (NULL == playback) {
    356             return NULL;
    357         }
    358 
    359         return SkNEW_ARGS(SkPicture, (playback, info.fWidth, info.fHeight));
    360     }
    361 
    362     return NULL;
    363 }
    364 
    365 SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) {
    366     SkPictInfo info;
    367 
    368     if (!InternalOnly_BufferIsSKP(buffer, &info)) {
    369         return NULL;
    370     }
    371 
    372     // Check to see if there is a playback to recreate.
    373     if (buffer.readBool()) {
    374         SkPicturePlayback* playback = SkPicturePlayback::CreateFromBuffer(buffer, info);
    375         if (NULL == playback) {
    376             return NULL;
    377         }
    378 
    379         return SkNEW_ARGS(SkPicture, (playback, info.fWidth, info.fHeight));
    380     }
    381 
    382     return NULL;
    383 }
    384 
    385 void SkPicture::createHeader(SkPictInfo* info) const {
    386     // Copy magic bytes at the beginning of the header
    387     SkASSERT(sizeof(kMagic) == 8);
    388     SkASSERT(sizeof(kMagic) == sizeof(info->fMagic));
    389     memcpy(info->fMagic, kMagic, sizeof(kMagic));
    390 
    391     // Set picture info after magic bytes in the header
    392     info->fVersion = CURRENT_PICTURE_VERSION;
    393     info->fWidth = fWidth;
    394     info->fHeight = fHeight;
    395     info->fFlags = SkPictInfo::kCrossProcess_Flag;
    396     // TODO: remove this flag, since we're always float (now)
    397     info->fFlags |= SkPictInfo::kScalarIsFloat_Flag;
    398 
    399     if (8 == sizeof(void*)) {
    400         info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
    401     }
    402 }
    403 
    404 void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const {
    405     SkPicturePlayback* playback = fPlayback;
    406 
    407     SkPictInfo info;
    408     this->createHeader(&info);
    409     stream->write(&info, sizeof(info));
    410     if (playback) {
    411         stream->writeBool(true);
    412         playback->serialize(stream, encoder);
    413         // delete playback if it is a local version (i.e. cons'd up just now)
    414         if (playback != fPlayback) {
    415             SkDELETE(playback);
    416         }
    417     } else {
    418         stream->writeBool(false);
    419     }
    420 }
    421 
    422 void SkPicture::WriteTagSize(SkWriteBuffer& buffer, uint32_t tag, size_t size) {
    423     buffer.writeUInt(tag);
    424     buffer.writeUInt(SkToU32(size));
    425 }
    426 
    427 void SkPicture::WriteTagSize(SkWStream* stream, uint32_t tag,  size_t size) {
    428     stream->write32(tag);
    429     stream->write32(SkToU32(size));
    430 }
    431 
    432 void SkPicture::flatten(SkWriteBuffer& buffer) const {
    433     SkPicturePlayback* playback = fPlayback;
    434 
    435     SkPictInfo info;
    436     this->createHeader(&info);
    437     buffer.writeByteArray(&info, sizeof(info));
    438     if (playback) {
    439         buffer.writeBool(true);
    440         playback->flatten(buffer);
    441         // delete playback if it is a local version (i.e. cons'd up just now)
    442         if (playback != fPlayback) {
    443             SkDELETE(playback);
    444         }
    445     } else {
    446         buffer.writeBool(false);
    447     }
    448 }
    449 
    450 #if SK_SUPPORT_GPU
    451 bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **reason) const {
    452     if (NULL == fPlayback) {
    453         if (NULL != reason) {
    454             *reason = "Missing playback object.";
    455         }
    456         return false;
    457     }
    458 
    459     return fPlayback->suitableForGpuRasterization(context, reason);
    460 }
    461 #endif
    462 
    463 bool SkPicture::willPlayBackBitmaps() const {
    464     if (!fPlayback) {
    465         return false;
    466     }
    467     return fPlayback->containsBitmaps();
    468 }
    469 
    470 #ifdef SK_BUILD_FOR_ANDROID
    471 void SkPicture::abortPlayback() {
    472     if (NULL == fPlayback) {
    473         return;
    474     }
    475     fPlayback->abort();
    476 }
    477 #endif
    478 
    479 static int32_t next_picture_generation_id() {
    480     static int32_t  gPictureGenerationID = 0;
    481     // do a loop in case our global wraps around, as we never want to
    482     // return a 0
    483     int32_t genID;
    484     do {
    485         genID = sk_atomic_inc(&gPictureGenerationID) + 1;
    486     } while (SK_InvalidGenID == genID);
    487     return genID;
    488 }
    489 
    490 uint32_t SkPicture::uniqueID() const {
    491     if (SK_InvalidGenID == fUniqueID) {
    492         fUniqueID = next_picture_generation_id();
    493     }
    494     return fUniqueID;
    495 }
    496