| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkRecordDraw.h" | 8 #include "SkRecordDraw.h" |
| 9 | 9 |
| 10 namespace { | 10 namespace { |
| 11 | 11 |
| 12 // This is an SkRecord visitor that will draw that SkRecord to an SkCanvas. | 12 // This is an SkRecord visitor that will draw that SkRecord to an SkCanvas. |
| 13 class Draw : SkNoncopyable { | 13 class Draw : SkNoncopyable { |
| 14 public: | 14 public: |
| 15 explicit Draw(SkCanvas* canvas) : fCanvas(canvas), fIndex(0), fClipEmpty(fal
se) {} | 15 explicit Draw(SkCanvas* canvas) : fCanvas(canvas), fIndex(0), fClipEmpty(fal
se) {} |
| 16 | 16 |
| 17 unsigned index() const { return fIndex; } | 17 unsigned index() const { return fIndex; } |
| 18 void next() { ++fIndex; } | 18 void next() { ++fIndex; } |
| 19 | 19 |
| 20 template <typename T> void operator()(const T& r) { | 20 template <typename T> void operator()(const T& r) { |
| 21 if (!this->canSkip(r)) { | 21 if (!this->skip(r)) { |
| 22 this->draw(r); | 22 this->draw(r); |
| 23 this->updateClip<T>(); | 23 this->updateClip<T>(); |
| 24 } | 24 } |
| 25 } | 25 } |
| 26 | 26 |
| 27 private: | 27 private: |
| 28 // Can we skip this command right now? | 28 // Return true if we can skip this command, false if not. |
| 29 template <typename T> bool canSkip(const T&) const { | 29 // Update fIndex here directly to skip more than just this one command. |
| 30 template <typename T> bool skip(const T&) { |
| 30 // We can skip most commands if the clip is empty. Exceptions are speci
alized below. | 31 // We can skip most commands if the clip is empty. Exceptions are speci
alized below. |
| 31 return fClipEmpty; | 32 return fClipEmpty; |
| 32 } | 33 } |
| 33 | 34 |
| 34 // No base case, so we'll be compile-time checked that we implemented all po
ssibilities below. | 35 // No base case, so we'll be compile-time checked that we implemented all po
ssibilities below. |
| 35 template <typename T> void draw(const T&); | 36 template <typename T> void draw(const T&); |
| 36 | 37 |
| 37 // Update fClipEmpty if necessary. | 38 // Update fClipEmpty if necessary. |
| 38 template <typename T> void updateClip() { | 39 template <typename T> void updateClip() { |
| 39 // Most commands don't change the clip. Exceptions are specialized belo
w. | 40 // Most commands don't change the clip. Exceptions are specialized belo
w. |
| 40 } | 41 } |
| 41 | 42 |
| 42 SkCanvas* fCanvas; | 43 SkCanvas* fCanvas; |
| 43 unsigned fIndex; | 44 unsigned fIndex; |
| 44 bool fClipEmpty; | 45 bool fClipEmpty; |
| 45 }; | 46 }; |
| 46 | 47 |
| 48 // TODO(mtklein): do this specialization with template traits instead of macros |
| 49 |
| 47 // These commands may change the clip. | 50 // These commands may change the clip. |
| 48 #define UPDATE_CLIP(T) template <> void Draw::updateClip<SkRecords::T>() \ | 51 #define UPDATE_CLIP(T) template <> void Draw::updateClip<SkRecords::T>() \ |
| 49 { fClipEmpty = fCanvas->isClipEmpty(); } | 52 { fClipEmpty = fCanvas->isClipEmpty(); } |
| 50 UPDATE_CLIP(Restore); | 53 UPDATE_CLIP(Restore); |
| 51 UPDATE_CLIP(SaveLayer); | 54 UPDATE_CLIP(SaveLayer); |
| 52 UPDATE_CLIP(ClipPath); | 55 UPDATE_CLIP(ClipPath); |
| 53 UPDATE_CLIP(ClipRRect); | 56 UPDATE_CLIP(ClipRRect); |
| 54 UPDATE_CLIP(ClipRect); | 57 UPDATE_CLIP(ClipRect); |
| 55 UPDATE_CLIP(ClipRegion); | 58 UPDATE_CLIP(ClipRegion); |
| 56 #undef UPDATE_CLIP | 59 #undef UPDATE_CLIP |
| 57 | 60 |
| 58 // These commands must always run. | 61 // These commands must always run. |
| 59 #define CAN_SKIP(T) template <> bool Draw::canSkip(const SkRecords::T&) const {
return false; } | 62 #define SKIP(T) template <> bool Draw::skip(const SkRecords::T&) { return false;
} |
| 60 CAN_SKIP(Restore); | 63 SKIP(Restore); |
| 61 CAN_SKIP(Save); | 64 SKIP(Save); |
| 62 CAN_SKIP(SaveLayer); | 65 SKIP(SaveLayer); |
| 63 CAN_SKIP(Clear); | 66 SKIP(Clear); |
| 64 CAN_SKIP(PushCull); | 67 SKIP(PushCull); |
| 65 CAN_SKIP(PopCull); | 68 SKIP(PopCull); |
| 66 #undef CAN_SKIP | 69 #undef SKIP |
| 67 | 70 |
| 68 // We can skip these commands if they're intersecting with a clip that's already
empty. | 71 // We can skip these commands if they're intersecting with a clip that's already
empty. |
| 69 #define CAN_SKIP(T) template <> bool Draw::canSkip(const SkRecords::T& r) const
\ | 72 #define SKIP(T) template <> bool Draw::skip(const SkRecords::T& r) \ |
| 70 { return fClipEmpty && SkRegion::kIntersect_Op == r.op; } | 73 { return fClipEmpty && SkRegion::kIntersect_Op == r.op; } |
| 71 CAN_SKIP(ClipPath); | 74 SKIP(ClipPath); |
| 72 CAN_SKIP(ClipRRect); | 75 SKIP(ClipRRect); |
| 73 CAN_SKIP(ClipRect); | 76 SKIP(ClipRect); |
| 74 CAN_SKIP(ClipRegion); | 77 SKIP(ClipRegion); |
| 75 #undef CAN_SKIP | 78 #undef SKIP |
| 76 | 79 |
| 77 static bool can_skip_text(const SkCanvas& c, const SkPaint& p, SkScalar minY, Sk
Scalar maxY) { | 80 // NoOps can always be skipped and draw nothing. |
| 78 // If we're drawing vertical text, none of the checks we're about to do make
any sense. | 81 template <> bool Draw::skip(const SkRecords::NoOp&) { return true; } |
| 79 // We'll need to call SkPaint::computeFastBounds() later, so bail out if tha
t's not possible. | 82 template <> void Draw::draw(const SkRecords::NoOp&) {} |
| 80 if (p.isVerticalText() || !p.canComputeFastBounds()) { | |
| 81 return false; | |
| 82 } | |
| 83 | |
| 84 // Rather than checking the top and bottom font metrics, we guess. Actually
looking up the top | |
| 85 // and bottom metrics is slow, and this overapproximation should be good eno
ugh. | |
| 86 const SkScalar buffer = p.getTextSize() * 1.5f; | |
| 87 SkDEBUGCODE(SkPaint::FontMetrics metrics;) | |
| 88 SkDEBUGCODE(p.getFontMetrics(&metrics);) | |
| 89 SkASSERT(-buffer <= metrics.fTop); | |
| 90 SkASSERT(+buffer >= metrics.fBottom); | |
| 91 | |
| 92 // Let the paint adjust the text bounds. We don't care about left and right
here, so we use | |
| 93 // 0 and 1 respectively just so the bounds rectangle isn't empty. | |
| 94 SkRect bounds; | |
| 95 bounds.set(0, -buffer, SK_Scalar1, buffer); | |
| 96 SkRect adjusted = p.computeFastBounds(bounds, &bounds); | |
| 97 return c.quickRejectY(minY + adjusted.fTop, maxY + adjusted.fBottom); | |
| 98 } | |
| 99 | |
| 100 template <> bool Draw::canSkip(const SkRecords::DrawPosTextH& r) const { | |
| 101 return fClipEmpty || can_skip_text(*fCanvas, r.paint, r.y, r.y); | |
| 102 } | |
| 103 | |
| 104 template <> bool Draw::canSkip(const SkRecords::DrawPosText& r) const { | |
| 105 if (fClipEmpty) { | |
| 106 return true; | |
| 107 } | |
| 108 | |
| 109 // TODO(mtklein): may want to move this minY/maxY calculation into a one-tim
e pass | |
| 110 const unsigned points = r.paint.countText(r.text, r.byteLength); | |
| 111 if (points == 0) { | |
| 112 return true; | |
| 113 } | |
| 114 SkScalar minY = SK_ScalarInfinity, maxY = SK_ScalarNegativeInfinity; | |
| 115 for (unsigned i = 0; i < points; i++) { | |
| 116 minY = SkTMin(minY, r.pos[i].fY); | |
| 117 maxY = SkTMax(maxY, r.pos[i].fY); | |
| 118 } | |
| 119 | |
| 120 return can_skip_text(*fCanvas, r.paint, minY, maxY); | |
| 121 } | |
| 122 | 83 |
| 123 #define DRAW(T, call) template <> void Draw::draw(const SkRecords::T& r) { fCanv
as->call; } | 84 #define DRAW(T, call) template <> void Draw::draw(const SkRecords::T& r) { fCanv
as->call; } |
| 124 DRAW(Restore, restore()); | 85 DRAW(Restore, restore()); |
| 125 DRAW(Save, save(r.flags)); | 86 DRAW(Save, save(r.flags)); |
| 126 DRAW(SaveLayer, saveLayer(r.bounds, r.paint, r.flags)); | 87 DRAW(SaveLayer, saveLayer(r.bounds, r.paint, r.flags)); |
| 127 DRAW(PopCull, popCull()); | 88 DRAW(PopCull, popCull()); |
| 89 DRAW(PushCull, pushCull(r.rect)); |
| 128 DRAW(Clear, clear(r.color)); | 90 DRAW(Clear, clear(r.color)); |
| 129 DRAW(Concat, concat(r.matrix)); | 91 DRAW(Concat, concat(r.matrix)); |
| 130 DRAW(SetMatrix, setMatrix(r.matrix)); | 92 DRAW(SetMatrix, setMatrix(r.matrix)); |
| 131 | 93 |
| 132 DRAW(ClipPath, clipPath(r.path, r.op, r.doAA)); | 94 DRAW(ClipPath, clipPath(r.path, r.op, r.doAA)); |
| 133 DRAW(ClipRRect, clipRRect(r.rrect, r.op, r.doAA)); | 95 DRAW(ClipRRect, clipRRect(r.rrect, r.op, r.doAA)); |
| 134 DRAW(ClipRect, clipRect(r.rect, r.op, r.doAA)); | 96 DRAW(ClipRect, clipRect(r.rect, r.op, r.doAA)); |
| 135 DRAW(ClipRegion, clipRegion(r.region, r.op)); | 97 DRAW(ClipRegion, clipRegion(r.region, r.op)); |
| 136 | 98 |
| 137 DRAW(DrawBitmap, drawBitmap(r.bitmap, r.left, r.top, r.paint)); | 99 DRAW(DrawBitmap, drawBitmap(r.bitmap, r.left, r.top, r.paint)); |
| 138 DRAW(DrawBitmapMatrix, drawBitmapMatrix(r.bitmap, r.matrix, r.paint)); | 100 DRAW(DrawBitmapMatrix, drawBitmapMatrix(r.bitmap, r.matrix, r.paint)); |
| 139 DRAW(DrawBitmapNine, drawBitmapNine(r.bitmap, r.center, r.dst, r.paint)); | 101 DRAW(DrawBitmapNine, drawBitmapNine(r.bitmap, r.center, r.dst, r.paint)); |
| 140 DRAW(DrawBitmapRectToRect, drawBitmapRectToRect(r.bitmap, r.src, r.dst, r.paint,
r.flags)); | 102 DRAW(DrawBitmapRectToRect, drawBitmapRectToRect(r.bitmap, r.src, r.dst, r.paint,
r.flags)); |
| 141 DRAW(DrawDRRect, drawDRRect(r.outer, r.inner, r.paint)); | 103 DRAW(DrawDRRect, drawDRRect(r.outer, r.inner, r.paint)); |
| 142 DRAW(DrawOval, drawOval(r.oval, r.paint)); | 104 DRAW(DrawOval, drawOval(r.oval, r.paint)); |
| 143 DRAW(DrawPaint, drawPaint(r.paint)); | 105 DRAW(DrawPaint, drawPaint(r.paint)); |
| 144 DRAW(DrawPath, drawPath(r.path, r.paint)); | 106 DRAW(DrawPath, drawPath(r.path, r.paint)); |
| 145 DRAW(DrawPoints, drawPoints(r.mode, r.count, r.pts, r.paint)); | 107 DRAW(DrawPoints, drawPoints(r.mode, r.count, r.pts, r.paint)); |
| 146 DRAW(DrawPosText, drawPosText(r.text, r.byteLength, r.pos, r.paint)); | 108 DRAW(DrawPosText, drawPosText(r.text, r.byteLength, r.pos, r.paint)); |
| 147 DRAW(DrawPosTextH, drawPosTextH(r.text, r.byteLength, r.xpos, r.y, r.paint)); | 109 DRAW(DrawPosTextH, drawPosTextH(r.text, r.byteLength, r.xpos, r.y, r.paint)); |
| 148 DRAW(DrawRRect, drawRRect(r.rrect, r.paint)); | 110 DRAW(DrawRRect, drawRRect(r.rrect, r.paint)); |
| 149 DRAW(DrawRect, drawRect(r.rect, r.paint)); | 111 DRAW(DrawRect, drawRect(r.rect, r.paint)); |
| 150 DRAW(DrawSprite, drawSprite(r.bitmap, r.left, r.top, r.paint)); | 112 DRAW(DrawSprite, drawSprite(r.bitmap, r.left, r.top, r.paint)); |
| 151 DRAW(DrawText, drawText(r.text, r.byteLength, r.x, r.y, r.paint)); | 113 DRAW(DrawText, drawText(r.text, r.byteLength, r.x, r.y, r.paint)); |
| 152 DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, r.matrix, r.pa
int)); | 114 DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, r.matrix, r.pa
int)); |
| 153 DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.co
lors, | 115 DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.co
lors, |
| 154 r.xmode.get(), r.indices, r.indexCount, r.paint)
); | 116 r.xmode.get(), r.indices, r.indexCount, r.paint)
); |
| 155 #undef DRAW | 117 #undef DRAW |
| 156 | 118 |
| 157 // PushCull is a bit of a oddball. We might be able to just skip until just pas
t its popCull. | 119 // Added by SkRecordAnnotateCullingPairs. |
| 158 template <> void Draw::draw(const SkRecords::PushCull& r) { | 120 template <> bool Draw::skip(const SkRecords::PairedPushCull& r) { |
| 159 if (r.popOffset != SkRecords::kUnsetPopOffset && fCanvas->quickReject(r.rect
)) { | 121 if (fCanvas->quickReject(r.base->rect)) { |
| 160 fIndex += r.popOffset; | 122 fIndex += r.skip; |
| 161 } else { | 123 return true; |
| 162 fCanvas->pushCull(r.rect); | |
| 163 } | 124 } |
| 125 return false; |
| 164 } | 126 } |
| 165 | 127 |
| 128 // Added by SkRecordBoundDrawPosTextH |
| 129 template <> bool Draw::skip(const SkRecords::BoundedDrawPosTextH& r) { |
| 130 return fClipEmpty || fCanvas->quickRejectY(r.minY, r.maxY); |
| 131 } |
| 132 |
| 133 // These draw by proxying to the commands they wrap. (All the optimization is f
or skip().) |
| 134 #define DRAW(T) template <> void Draw::draw(const SkRecords::T& r) { this->draw(
*r.base); } |
| 135 DRAW(PairedPushCull); |
| 136 DRAW(BoundedDrawPosTextH); |
| 137 #undef DRAW |
| 138 |
| 166 } // namespace | 139 } // namespace |
| 167 | 140 |
| 168 void SkRecordDraw(const SkRecord& record, SkCanvas* canvas) { | 141 void SkRecordDraw(const SkRecord& record, SkCanvas* canvas) { |
| 169 for (Draw draw(canvas); draw.index() < record.count(); draw.next()) { | 142 for (Draw draw(canvas); draw.index() < record.count(); draw.next()) { |
| 170 record.visit(draw.index(), draw); | 143 record.visit(draw.index(), draw); |
| 171 } | 144 } |
| 172 } | 145 } |
| OLD | NEW |