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 |