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 "SkMiniRecorder.h"
     12 #include "SkPictureRecorder.h"
     13 #include "SkRecord.h"
     14 #include "SkRecordDraw.h"
     15 #include "SkRecordOpts.h"
     16 #include "SkRecordedDrawable.h"
     17 #include "SkRecorder.h"
     18 #include "SkTypes.h"
     19 
     20 SkPictureRecorder::SkPictureRecorder() {
     21     fActivelyRecording = false;
     22     fMiniRecorder.reset(new SkMiniRecorder);
     23     fRecorder.reset(new SkRecorder(nullptr, SkRect::MakeEmpty(), fMiniRecorder.get()));
     24 }
     25 
     26 SkPictureRecorder::~SkPictureRecorder() {}
     27 
     28 SkCanvas* SkPictureRecorder::beginRecording(const SkRect& userCullRect,
     29                                             SkBBHFactory* bbhFactory /* = nullptr */,
     30                                             uint32_t recordFlags /* = 0 */) {
     31     const SkRect cullRect = userCullRect.isEmpty() ? SkRect::MakeEmpty() : userCullRect;
     32 
     33     fCullRect = cullRect;
     34     fFlags = recordFlags;
     35 
     36     if (bbhFactory) {
     37         fBBH.reset((*bbhFactory)(cullRect));
     38         SkASSERT(fBBH.get());
     39     }
     40 
     41     if (!fRecord) {
     42         fRecord.reset(new SkRecord);
     43     }
     44     SkRecorder::DrawPictureMode dpm = (recordFlags & kPlaybackDrawPicture_RecordFlag)
     45         ? SkRecorder::Playback_DrawPictureMode
     46         : SkRecorder::Record_DrawPictureMode;
     47     fRecorder->reset(fRecord.get(), cullRect, dpm, fMiniRecorder.get());
     48     fActivelyRecording = true;
     49     return this->getRecordingCanvas();
     50 }
     51 
     52 SkCanvas* SkPictureRecorder::getRecordingCanvas() {
     53     return fActivelyRecording ? fRecorder.get() : nullptr;
     54 }
     55 
     56 sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPicture(uint32_t finishFlags) {
     57     fActivelyRecording = false;
     58     fRecorder->restoreToCount(1);  // If we were missing any restores, add them now.
     59 
     60     if (fRecord->count() == 0) {
     61         auto pic = fMiniRecorder->detachAsPicture(fBBH ? nullptr : &fCullRect);
     62         fBBH.reset(nullptr);
     63         return pic;
     64     }
     65 
     66     // TODO: delay as much of this work until just before first playback?
     67     SkRecordOptimize(fRecord.get());
     68 
     69     SkDrawableList* drawableList = fRecorder->getDrawableList();
     70     SkBigPicture::SnapshotArray* pictList =
     71         drawableList ? drawableList->newDrawableSnapshot() : nullptr;
     72 
     73     if (fBBH.get()) {
     74         SkAutoTMalloc<SkRect> bounds(fRecord->count());
     75         SkRecordFillBounds(fCullRect, *fRecord, bounds);
     76         fBBH->insert(bounds, fRecord->count());
     77 
     78         // Now that we've calculated content bounds, we can update fCullRect, often trimming it.
     79         // TODO: get updated fCullRect from bounds instead of forcing the BBH to return it?
     80         SkRect bbhBound = fBBH->getRootBound();
     81         SkASSERT((bbhBound.isEmpty() || fCullRect.contains(bbhBound))
     82             || (bbhBound.isEmpty() && fCullRect.isEmpty()));
     83         fCullRect = bbhBound;
     84     }
     85 
     86     size_t subPictureBytes = fRecorder->approxBytesUsedBySubPictures();
     87     for (int i = 0; pictList && i < pictList->count(); i++) {
     88         subPictureBytes += pictList->begin()[i]->approximateBytesUsed();
     89     }
     90     return sk_make_sp<SkBigPicture>(fCullRect, fRecord.release(), pictList, fBBH.release(),
     91                                     subPictureBytes);
     92 }
     93 
     94 sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPictureWithCull(const SkRect& cullRect,
     95                                                                      uint32_t finishFlags) {
     96     fCullRect = cullRect;
     97     return this->finishRecordingAsPicture(finishFlags);
     98 }
     99 
    100 
    101 void SkPictureRecorder::partialReplay(SkCanvas* canvas) const {
    102     if (nullptr == canvas) {
    103         return;
    104     }
    105 
    106     int drawableCount = 0;
    107     SkDrawable* const* drawables = nullptr;
    108     SkDrawableList* drawableList = fRecorder->getDrawableList();
    109     if (drawableList) {
    110         drawableCount = drawableList->count();
    111         drawables = drawableList->begin();
    112     }
    113     SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, nullptr/*bbh*/, nullptr/*callback*/);
    114 }
    115 
    116 sk_sp<SkDrawable> SkPictureRecorder::finishRecordingAsDrawable(uint32_t finishFlags) {
    117     fActivelyRecording = false;
    118     fRecorder->flushMiniRecorder();
    119     fRecorder->restoreToCount(1);  // If we were missing any restores, add them now.
    120 
    121     SkRecordOptimize(fRecord.get());
    122 
    123     if (fBBH.get()) {
    124         SkAutoTMalloc<SkRect> bounds(fRecord->count());
    125         SkRecordFillBounds(fCullRect, *fRecord, bounds);
    126         fBBH->insert(bounds, fRecord->count());
    127     }
    128 
    129     sk_sp<SkDrawable> drawable =
    130          sk_make_sp<SkRecordedDrawable>(std::move(fRecord), std::move(fBBH),
    131                                         fRecorder->detachDrawableList(), fCullRect);
    132 
    133     return drawable;
    134 }
    135