| 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) {
|
|
|