| Index: src/record/SkRecordDraw.cpp
|
| diff --git a/src/record/SkRecordDraw.cpp b/src/record/SkRecordDraw.cpp
|
| index 21b2c7a82b33a630e4769554dfa444cc05c13890..74549db66f50ecbfbab1c0af41cf65db1d59aadd 100644
|
| --- a/src/record/SkRecordDraw.cpp
|
| +++ b/src/record/SkRecordDraw.cpp
|
| @@ -7,8 +7,16 @@
|
|
|
| #include "SkRecordDraw.h"
|
|
|
| +#include "SkRecordTraits.h"
|
| +
|
| namespace {
|
|
|
| +// All clip commands, Restore, and SaveLayer may change the clip.
|
| +template <typename T> struct ChangesClip { static const bool value = SkRecords::IsClip<T>::value; };
|
| +template <> struct ChangesClip<SkRecords::Restore> { static const bool value = true; };
|
| +template <> struct ChangesClip<SkRecords::SaveLayer> { static const bool value = true; };
|
| +
|
| +
|
| // This is an SkRecord visitor that will draw that SkRecord to an SkCanvas.
|
| class Draw : SkNoncopyable {
|
| public:
|
| @@ -25,60 +33,44 @@ public:
|
| }
|
|
|
| private:
|
| - // Return true if we can skip this command, false if not.
|
| - // Update fIndex here directly to skip more than just this one command.
|
| - template <typename T> bool skip(const T&) {
|
| - // We can skip most commands if the clip is empty. Exceptions are specialized below.
|
| - return fClipEmpty;
|
| - }
|
| -
|
| // No base case, so we'll be compile-time checked that we implemented all possibilities below.
|
| template <typename T> void draw(const T&);
|
|
|
| - // Update fClipEmpty if necessary.
|
| - template <typename T> void updateClip() {
|
| - // Most commands don't change the clip. Exceptions are specialized below.
|
| + // skip() returns true if we can skip this command, false if not.
|
| + // Update fIndex directly to skip more than just this one command.
|
| +
|
| + // If we're drawing into an empty clip, we can skip it. Otherwise, run the command.
|
| + template <typename T>
|
| + SK_WHEN(SkRecords::IsDraw<T>, bool) skip(const T&) { return fClipEmpty; }
|
| +
|
| + template <typename T>
|
| + SK_WHEN(!SkRecords::IsDraw<T>, bool) skip(const T&) { return false; }
|
| +
|
| + // Special versions for commands added by optimizations.
|
| + bool skip(const SkRecords::PairedPushCull& r) {
|
| + if (fCanvas->quickReject(r.base->rect)) {
|
| + fIndex += r.skip;
|
| + return true;
|
| + }
|
| + return this->skip(*r.base);
|
| + }
|
| +
|
| + bool skip(const SkRecords::BoundedDrawPosTextH& r) {
|
| + return this->skip(*r.base) || fCanvas->quickRejectY(r.minY, r.maxY);
|
| }
|
|
|
| + // If we might have changed the clip, update it, else do nothing.
|
| + template <typename T>
|
| + SK_WHEN(ChangesClip<T>, void) updateClip() { fClipEmpty = fCanvas->isClipEmpty(); }
|
| + template <typename T>
|
| + SK_WHEN(!ChangesClip<T>, void) updateClip() {}
|
| +
|
| SkCanvas* fCanvas;
|
| unsigned fIndex;
|
| bool fClipEmpty;
|
| };
|
|
|
| -// TODO(mtklein): do this specialization with template traits instead of macros
|
| -
|
| -// These commands may change the clip.
|
| -#define UPDATE_CLIP(T) template <> void Draw::updateClip<SkRecords::T>() \
|
| - { fClipEmpty = fCanvas->isClipEmpty(); }
|
| -UPDATE_CLIP(Restore);
|
| -UPDATE_CLIP(SaveLayer);
|
| -UPDATE_CLIP(ClipPath);
|
| -UPDATE_CLIP(ClipRRect);
|
| -UPDATE_CLIP(ClipRect);
|
| -UPDATE_CLIP(ClipRegion);
|
| -#undef UPDATE_CLIP
|
| -
|
| -// These commands must always run.
|
| -#define SKIP(T) template <> bool Draw::skip(const SkRecords::T&) { return false; }
|
| -SKIP(Restore);
|
| -SKIP(Save);
|
| -SKIP(SaveLayer);
|
| -SKIP(Clear);
|
| -SKIP(PushCull);
|
| -SKIP(PopCull);
|
| -#undef SKIP
|
| -
|
| -// We can skip these commands if they're intersecting with a clip that's already empty.
|
| -#define SKIP(T) template <> bool Draw::skip(const SkRecords::T& r) \
|
| - { return fClipEmpty && SkRegion::kIntersect_Op == r.op; }
|
| -SKIP(ClipPath);
|
| -SKIP(ClipRRect);
|
| -SKIP(ClipRect);
|
| -SKIP(ClipRegion);
|
| -#undef SKIP
|
| -
|
| -// NoOps can always be skipped and draw nothing.
|
| -template <> bool Draw::skip(const SkRecords::NoOp&) { return true; }
|
| +// NoOps draw nothing.
|
| template <> void Draw::draw(const SkRecords::NoOp&) {}
|
|
|
| #define DRAW(T, call) template <> void Draw::draw(const SkRecords::T& r) { fCanvas->call; }
|
| @@ -116,25 +108,8 @@ DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.co
|
| r.xmode.get(), r.indices, r.indexCount, r.paint));
|
| #undef DRAW
|
|
|
| -// Added by SkRecordAnnotateCullingPairs.
|
| -template <> bool Draw::skip(const SkRecords::PairedPushCull& r) {
|
| - if (fCanvas->quickReject(r.base->rect)) {
|
| - fIndex += r.skip;
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -// Added by SkRecordBoundDrawPosTextH
|
| -template <> bool Draw::skip(const SkRecords::BoundedDrawPosTextH& r) {
|
| - return fClipEmpty || fCanvas->quickRejectY(r.minY, r.maxY);
|
| -}
|
| -
|
| -// These draw by proxying to the commands they wrap. (All the optimization is for skip().)
|
| -#define DRAW(T) template <> void Draw::draw(const SkRecords::T& r) { this->draw(*r.base); }
|
| -DRAW(PairedPushCull);
|
| -DRAW(BoundedDrawPosTextH);
|
| -#undef DRAW
|
| +template <> void Draw::draw(const SkRecords::PairedPushCull& r) { this->draw(*r.base); }
|
| +template <> void Draw::draw(const SkRecords::BoundedDrawPosTextH& r) { this->draw(*r.base); }
|
|
|
| } // namespace
|
|
|
|
|