Index: src/record/SkRecordOpts.cpp |
diff --git a/src/record/SkRecordOpts.cpp b/src/record/SkRecordOpts.cpp |
index 4b35b33a3c20683ff1601879bf0504718c328a06..5b537de040120a7238ec2dbc95256eeabd51a027 100644 |
--- a/src/record/SkRecordOpts.cpp |
+++ b/src/record/SkRecordOpts.cpp |
@@ -7,6 +7,7 @@ |
#include "SkRecordOpts.h" |
+#include "SkRecordTraits.h" |
#include "SkRecords.h" |
#include "SkTDArray.h" |
@@ -40,9 +41,28 @@ public: |
explicit SaveRestoreNooper(SkRecord* record) |
: Common(record), fSave(kInactive), fChanged(false) {} |
- // Most drawing commands reset to inactive state without nooping anything. |
+ // Drawing commands reset state to inactive without nooping. |
template <typename T> |
- void operator()(T*) { fSave = kInactive; } |
+ SK_WHEN(SkRecords::IsDraw<T>, void) operator()(T*) { fSave = kInactive; } |
+ |
+ // Most non-drawing commands can be ignored. |
+ template <typename T> |
+ SK_WHEN(!SkRecords::IsDraw<T>, void) operator()(T*) {} |
+ |
+ void operator()(SkRecords::Save* r) { |
+ fSave = SkCanvas::kMatrixClip_SaveFlag == r->flags ? this->index() : kInactive; |
+ } |
+ |
+ void operator()(SkRecords::Restore* r) { |
+ if (fSave != kInactive) { |
+ // Remove everything between the save and restore, inclusive on both sides. |
+ fChanged = true; |
+ for (unsigned i = fSave; i <= this->index(); i++) { |
+ fRecord->replace<SkRecords::NoOp>(i); |
+ } |
+ fSave = kInactive; |
+ } |
+ } |
bool changed() const { return fChanged; } |
@@ -52,39 +72,6 @@ private: |
bool fChanged; |
}; |
-// If the command doesn't draw anything, that doesn't reset the state back to inactive. |
-// TODO(mtklein): do this with some sort of template-based trait mechanism instead of macros |
-#define DOESNT_DRAW(T) template <> void SaveRestoreNooper::operator()(SkRecords::T*) {} |
-DOESNT_DRAW(NoOp) |
-DOESNT_DRAW(Concat) |
-DOESNT_DRAW(SetMatrix) |
-DOESNT_DRAW(ClipRect) |
-DOESNT_DRAW(ClipRRect) |
-DOESNT_DRAW(ClipPath) |
-DOESNT_DRAW(ClipRegion) |
-DOESNT_DRAW(PairedPushCull) |
-DOESNT_DRAW(PushCull) |
-DOESNT_DRAW(PopCull) |
-#undef DOESNT_DRAW |
- |
-template <> |
-void SaveRestoreNooper::operator()(SkRecords::Save* r) { |
- fSave = SkCanvas::kMatrixClip_SaveFlag == r->flags ? this->index() : kInactive; |
-} |
- |
-template <> |
-void SaveRestoreNooper::operator()(SkRecords::Restore* r) { |
- if (fSave != kInactive) { |
- // Remove everything between the save and restore, inclusive on both sides. |
- fChanged = true; |
- for (unsigned i = fSave; i <= this->index(); i++) { |
- fRecord->replace<SkRecords::NoOp>(i); |
- } |
- fSave = kInactive; |
- } |
-} |
- |
- |
// Tries to replace PushCull with PairedPushCull, which lets us skip to the paired PopCull |
// when the canvas can quickReject the cull rect. |
class CullAnnotator : public Common { |
@@ -92,8 +79,24 @@ public: |
explicit CullAnnotator(SkRecord* record) : Common(record) {} |
// Do nothing to most ops. |
- template <typename T> |
- void operator()(T*) {} |
+ template <typename T> void operator()(T*) {} |
+ |
+ void operator()(SkRecords::PushCull* push) { |
+ Pair pair = { this->index(), push }; |
+ fPushStack.push(pair); |
+ } |
+ |
+ void operator()(SkRecords::PopCull* pop) { |
+ Pair push = fPushStack.top(); |
+ fPushStack.pop(); |
+ |
+ SkASSERT(this->index() > push.index); |
+ unsigned skip = this->index() - push.index; |
+ |
+ SkRecords::Adopted<SkRecords::PushCull> adopted(push.command); |
+ SkNEW_PLACEMENT_ARGS(fRecord->replace<SkRecords::PairedPushCull>(push.index, adopted), |
+ SkRecords::PairedPushCull, (&adopted, skip)); |
+ } |
private: |
struct Pair { |
@@ -104,68 +107,46 @@ private: |
SkTDArray<Pair> fPushStack; |
}; |
-template <> |
-void CullAnnotator::operator()(SkRecords::PushCull* push) { |
- Pair pair = { this->index(), push }; |
- fPushStack.push(pair); |
-} |
- |
-template <> |
-void CullAnnotator::operator()(SkRecords::PopCull* pop) { |
- Pair push = fPushStack.top(); |
- fPushStack.pop(); |
- |
- SkASSERT(this->index() > push.index); |
- unsigned skip = this->index() - push.index; |
- |
- SkRecords::Adopted<SkRecords::PushCull> adopted(push.command); |
- SkNEW_PLACEMENT_ARGS(fRecord->replace<SkRecords::PairedPushCull>(push.index, adopted), |
- SkRecords::PairedPushCull, (&adopted, skip)); |
-} |
- |
// Replaces DrawPosText with DrawPosTextH when all Y coordinates are equal. |
class StrengthReducer : public Common { |
public: |
explicit StrengthReducer(SkRecord* record) : Common(record) {} |
// Do nothing to most ops. |
- template <typename T> |
- void operator()(T*) {} |
-}; |
+ template <typename T> void operator()(T*) {} |
-template <> |
-void StrengthReducer::operator()(SkRecords::DrawPosText* r) { |
- const unsigned points = r->paint.countText(r->text, r->byteLength); |
- if (points == 0) { |
- // No point (ha!). |
- return; |
- } |
- |
- const SkScalar firstY = r->pos[0].fY; |
- for (unsigned i = 1; i < points; i++) { |
- if (r->pos[i].fY != firstY) { |
- // Needs the full strength of DrawPosText. |
+ void operator()(SkRecords::DrawPosText* r) { |
+ const unsigned points = r->paint.countText(r->text, r->byteLength); |
+ if (points == 0) { |
+ // No point (ha!). |
return; |
} |
- } |
- // All ys are the same. We can replace DrawPosText with DrawPosTextH. |
- |
- // r->pos is points SkPoints, [(x,y),(x,y),(x,y),(x,y), ... ]. |
- // We're going to squint and look at that as 2*points SkScalars, [x,y,x,y,x,y,x,y, ...]. |
- // Then we'll rearrange things so all the xs are in order up front, clobbering the ys. |
- SK_COMPILE_ASSERT(sizeof(SkPoint) == 2 * sizeof(SkScalar), SquintingIsNotSafe); |
- SkScalar* scalars = &r->pos[0].fX; |
- for (unsigned i = 0; i < 2*points; i += 2) { |
- scalars[i/2] = scalars[i]; |
- } |
- // Extend lifetime of r to the end of the method so we can copy its parts. |
- SkRecords::Adopted<SkRecords::DrawPosText> adopted(r); |
- SkNEW_PLACEMENT_ARGS(fRecord->replace<SkRecords::DrawPosTextH>(this->index(), adopted), |
- SkRecords::DrawPosTextH, |
- (r->text, r->byteLength, scalars, firstY, r->paint)); |
-} |
+ const SkScalar firstY = r->pos[0].fY; |
+ for (unsigned i = 1; i < points; i++) { |
+ if (r->pos[i].fY != firstY) { |
+ // Needs the full strength of DrawPosText. |
+ return; |
+ } |
+ } |
+ // All ys are the same. We can replace DrawPosText with DrawPosTextH. |
+ |
+ // r->pos is points SkPoints, [(x,y),(x,y),(x,y),(x,y), ... ]. |
+ // We're going to squint and look at that as 2*points SkScalars, [x,y,x,y,x,y,x,y, ...]. |
+ // Then we'll rearrange things so all the xs are in order up front, clobbering the ys. |
+ SK_COMPILE_ASSERT(sizeof(SkPoint) == 2 * sizeof(SkScalar), SquintingIsNotSafe); |
+ SkScalar* scalars = &r->pos[0].fX; |
+ for (unsigned i = 0; i < 2*points; i += 2) { |
+ scalars[i/2] = scalars[i]; |
+ } |
+ // Extend lifetime of r to the end of the method so we can copy its parts. |
+ SkRecords::Adopted<SkRecords::DrawPosText> adopted(r); |
+ SkNEW_PLACEMENT_ARGS(fRecord->replace<SkRecords::DrawPosTextH>(this->index(), adopted), |
+ SkRecords::DrawPosTextH, |
+ (r->text, r->byteLength, scalars, firstY, r->paint)); |
+ } |
+}; |
// Tries to replace DrawPosTextH with BoundedDrawPosTextH, which knows conservative upper and lower |
// bounds to use with SkCanvas::quickRejectY. |
@@ -174,37 +155,37 @@ public: |
explicit TextBounder(SkRecord* record) : Common(record) {} |
// Do nothing to most ops. |
- template <typename T> |
- void operator()(T*) {} |
-}; |
+ template <typename T> void operator()(T*) {} |
-template <> |
-void TextBounder::operator()(SkRecords::DrawPosTextH* r) { |
- // If we're drawing vertical text, none of the checks we're about to do make any sense. |
- // We'll need to call SkPaint::computeFastBounds() later, so bail if that's not possible. |
- if (r->paint.isVerticalText() || !r->paint.canComputeFastBounds()) { |
- return; |
+ void operator()(SkRecords::DrawPosTextH* r) { |
+ // If we're drawing vertical text, none of the checks we're about to do make any sense. |
+ // We'll need to call SkPaint::computeFastBounds() later, so bail if that's not possible. |
+ if (r->paint.isVerticalText() || !r->paint.canComputeFastBounds()) { |
+ return; |
+ } |
+ |
+ // Rather than checking the top and bottom font metrics, we guess. Actually looking up the |
+ // top and bottom metrics is slow, and this overapproximation should be good enough. |
+ const SkScalar buffer = r->paint.getTextSize() * 1.5f; |
+ SkDEBUGCODE(SkPaint::FontMetrics metrics;) |
+ SkDEBUGCODE(r->paint.getFontMetrics(&metrics);) |
+ SkASSERT(-buffer <= metrics.fTop); |
+ SkASSERT(+buffer >= metrics.fBottom); |
+ |
+ // Let the paint adjust the text bounds. We don't care about left and right here, so we use |
+ // 0 and 1 respectively just so the bounds rectangle isn't empty. |
+ SkRect bounds; |
+ bounds.set(0, r->y - buffer, SK_Scalar1, r->y + buffer); |
+ SkRect adjusted = r->paint.computeFastBounds(bounds, &bounds); |
+ |
+ SkRecords::Adopted<SkRecords::DrawPosTextH> adopted(r); |
+ SkNEW_PLACEMENT_ARGS( |
+ fRecord->replace<SkRecords::BoundedDrawPosTextH>(this->index(), adopted), |
+ SkRecords::BoundedDrawPosTextH, |
+ (&adopted, adjusted.fTop, adjusted.fBottom)); |
} |
+}; |
- // Rather than checking the top and bottom font metrics, we guess. Actually looking up the |
- // top and bottom metrics is slow, and this overapproximation should be good enough. |
- const SkScalar buffer = r->paint.getTextSize() * 1.5f; |
- SkDEBUGCODE(SkPaint::FontMetrics metrics;) |
- SkDEBUGCODE(r->paint.getFontMetrics(&metrics);) |
- SkASSERT(-buffer <= metrics.fTop); |
- SkASSERT(+buffer >= metrics.fBottom); |
- |
- // Let the paint adjust the text bounds. We don't care about left and right here, so we use |
- // 0 and 1 respectively just so the bounds rectangle isn't empty. |
- SkRect bounds; |
- bounds.set(0, r->y - buffer, SK_Scalar1, r->y + buffer); |
- SkRect adjusted = r->paint.computeFastBounds(bounds, &bounds); |
- |
- SkRecords::Adopted<SkRecords::DrawPosTextH> adopted(r); |
- SkNEW_PLACEMENT_ARGS(fRecord->replace<SkRecords::BoundedDrawPosTextH>(this->index(), adopted), |
- SkRecords::BoundedDrawPosTextH, |
- (&adopted, adjusted.fTop, adjusted.fBottom)); |
-} |
template <typename Pass> |
static void run_pass(Pass& pass, SkRecord* record) { |