Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2014 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkBigPicture.h"
      9 #include "SkData.h"
     10 #include "SkDrawable.h"
     11 #include "SkLayerInfo.h"
     12 #include "SkPictureRecorder.h"
     13 #include "SkPictureUtils.h"
     14 #include "SkRecord.h"
     15 #include "SkRecordDraw.h"
     16 #include "SkRecordOpts.h"
     17 #include "SkRecorder.h"
     18 #include "SkTypes.h"
     19 
     20 SkPictureRecorder::SkPictureRecorder() {
     21     fActivelyRecording = false;
     22     fRecorder.reset(new SkRecorder(nullptr, SkRect::MakeWH(0, 0), &fMiniRecorder));
     23 }
     24 
     25 SkPictureRecorder::~SkPictureRecorder() {}
     26 
     27 SkCanvas* SkPictureRecorder::beginRecording(const SkRect& cullRect,
     28                                             SkBBHFactory* bbhFactory /* = nullptr */,
     29                                             uint32_t recordFlags /* = 0 */) {
     30     fCullRect = cullRect;
     31     fFlags = recordFlags;
     32 
     33     if (bbhFactory) {
     34         fBBH.reset((*bbhFactory)(cullRect));
     35         SkASSERT(fBBH.get());
     36     }
     37 
     38     if (!fRecord) {
     39         fRecord.reset(new SkRecord);
     40     }
     41     SkRecorder::DrawPictureMode dpm = (recordFlags & kPlaybackDrawPicture_RecordFlag)
     42         ? SkRecorder::Playback_DrawPictureMode
     43         : SkRecorder::Record_DrawPictureMode;
     44     fRecorder->reset(fRecord.get(), cullRect, dpm, &fMiniRecorder);
     45     fActivelyRecording = true;
     46     return this->getRecordingCanvas();
     47 }
     48 
     49 SkCanvas* SkPictureRecorder::getRecordingCanvas() {
     50     return fActivelyRecording ? fRecorder.get() : nullptr;
     51 }
     52 
     53 SkPicture* SkPictureRecorder::endRecordingAsPicture() {
     54     fActivelyRecording = false;
     55     fRecorder->restoreToCount(1);  // If we were missing any restores, add them now.
     56 
     57     if (fRecord->count() == 0) {
     58         return fMiniRecorder.detachAsPicture(fCullRect);
     59     }
     60 
     61     // TODO: delay as much of this work until just before first playback?
     62     SkRecordOptimize(fRecord);
     63 
     64     SkAutoTUnref<SkLayerInfo> saveLayerData;
     65 
     66     if (fBBH && (fFlags & kComputeSaveLayerInfo_RecordFlag)) {
     67         saveLayerData.reset(new SkLayerInfo);
     68     }
     69 
     70     SkDrawableList* drawableList = fRecorder->getDrawableList();
     71     SkBigPicture::SnapshotArray* pictList =
     72         drawableList ? drawableList->newDrawableSnapshot() : nullptr;
     73 
     74     if (fBBH.get()) {
     75         SkAutoTMalloc<SkRect> bounds(fRecord->count());
     76         if (saveLayerData) {
     77             SkRecordComputeLayers(fCullRect, *fRecord, bounds, pictList, saveLayerData);
     78         } else {
     79             SkRecordFillBounds(fCullRect, *fRecord, bounds);
     80         }
     81         fBBH->insert(bounds, fRecord->count());
     82 
     83         // Now that we've calculated content bounds, we can update fCullRect, often trimming it.
     84         // TODO: get updated fCullRect from bounds instead of forcing the BBH to return it?
     85         SkRect bbhBound = fBBH->getRootBound();
     86         SkASSERT((bbhBound.isEmpty() || fCullRect.contains(bbhBound))
     87             || (bbhBound.isEmpty() && fCullRect.isEmpty()));
     88         fCullRect = bbhBound;
     89     }
     90 
     91     size_t subPictureBytes = fRecorder->approxBytesUsedBySubPictures();
     92     for (int i = 0; pictList && i < pictList->count(); i++) {
     93         subPictureBytes += SkPictureUtils::ApproximateBytesUsed(pictList->begin()[i]);
     94     }
     95     return new SkBigPicture(fCullRect, fRecord.detach(), pictList, fBBH.detach(),
     96                             saveLayerData.detach(), subPictureBytes);
     97 }
     98 
     99 SkPicture* SkPictureRecorder::endRecordingAsPicture(const SkRect& cullRect) {
    100     fCullRect = cullRect;
    101     return this->endRecordingAsPicture();
    102 }
    103 
    104 
    105 void SkPictureRecorder::partialReplay(SkCanvas* canvas) const {
    106     if (nullptr == canvas) {
    107         return;
    108     }
    109 
    110     int drawableCount = 0;
    111     SkDrawable* const* drawables = nullptr;
    112     SkDrawableList* drawableList = fRecorder->getDrawableList();
    113     if (drawableList) {
    114         drawableCount = drawableList->count();
    115         drawables = drawableList->begin();
    116     }
    117     SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, nullptr/*bbh*/, nullptr/*callback*/);
    118 }
    119 
    120 ///////////////////////////////////////////////////////////////////////////////////////////////////
    121 
    122 class SkRecordedDrawable : public SkDrawable {
    123     SkAutoTUnref<SkRecord>          fRecord;
    124     SkAutoTUnref<SkBBoxHierarchy>   fBBH;
    125     SkAutoTDelete<SkDrawableList>   fDrawableList;
    126     const SkRect                    fBounds;
    127     const bool                      fDoSaveLayerInfo;
    128 
    129 public:
    130     SkRecordedDrawable(SkRecord* record, SkBBoxHierarchy* bbh, SkDrawableList* drawableList,
    131                        const SkRect& bounds, bool doSaveLayerInfo)
    132         : fRecord(SkRef(record))
    133         , fBBH(SkSafeRef(bbh))
    134         , fDrawableList(drawableList)   // we take ownership
    135         , fBounds(bounds)
    136         , fDoSaveLayerInfo(doSaveLayerInfo)
    137     {}
    138 
    139 protected:
    140     SkRect onGetBounds() override { return fBounds; }
    141 
    142     void onDraw(SkCanvas* canvas) override {
    143         SkDrawable* const* drawables = nullptr;
    144         int drawableCount = 0;
    145         if (fDrawableList) {
    146             drawables = fDrawableList->begin();
    147             drawableCount = fDrawableList->count();
    148         }
    149         SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, fBBH, nullptr/*callback*/);
    150     }
    151 
    152     SkPicture* onNewPictureSnapshot() override {
    153         SkBigPicture::SnapshotArray* pictList = nullptr;
    154         if (fDrawableList) {
    155             // TODO: should we plumb-down the BBHFactory and recordFlags from our host
    156             //       PictureRecorder?
    157             pictList = fDrawableList->newDrawableSnapshot();
    158         }
    159 
    160         SkAutoTUnref<SkLayerInfo> saveLayerData;
    161         if (fBBH && fDoSaveLayerInfo) {
    162             // TODO: can we avoid work by not allocating / filling these bounds?
    163             SkAutoTMalloc<SkRect> scratchBounds(fRecord->count());
    164             saveLayerData.reset(new SkLayerInfo);
    165 
    166             SkRecordComputeLayers(fBounds, *fRecord, scratchBounds, pictList, saveLayerData);
    167         }
    168 
    169         size_t subPictureBytes = 0;
    170         for (int i = 0; pictList && i < pictList->count(); i++) {
    171             subPictureBytes += SkPictureUtils::ApproximateBytesUsed(pictList->begin()[i]);
    172         }
    173         // SkBigPicture will take ownership of a ref on both fRecord and fBBH.
    174         // We're not willing to give up our ownership, so we must ref them for SkPicture.
    175         return new SkBigPicture(fBounds, SkRef(fRecord.get()), pictList, SkSafeRef(fBBH.get()),
    176                                 saveLayerData.detach(), subPictureBytes);
    177     }
    178 };
    179 
    180 SkDrawable* SkPictureRecorder::endRecordingAsDrawable() {
    181     fActivelyRecording = false;
    182     fRecorder->flushMiniRecorder();
    183     fRecorder->restoreToCount(1);  // If we were missing any restores, add them now.
    184 
    185     // TODO: delay as much of this work until just before first playback?
    186     SkRecordOptimize(fRecord);
    187 
    188     if (fBBH.get()) {
    189         SkAutoTMalloc<SkRect> bounds(fRecord->count());
    190         SkRecordFillBounds(fCullRect, *fRecord, bounds);
    191         fBBH->insert(bounds, fRecord->count());
    192     }
    193 
    194     SkDrawable* drawable =
    195             new SkRecordedDrawable(fRecord, fBBH, fRecorder->detachDrawableList(), fCullRect,
    196                                    SkToBool(fFlags & kComputeSaveLayerInfo_RecordFlag));
    197 
    198     // release our refs now, so only the drawable will be the owner.
    199     fRecord.reset(nullptr);
    200     fBBH.reset(nullptr);
    201 
    202     return drawable;
    203 }
    204