1/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkLayerInfo.h"
9#include "SkRecordDraw.h"
10#include "SkPatchUtils.h"
11
12void SkRecordDraw(const SkRecord& record,
13                  SkCanvas* canvas,
14                  SkPicture const* const drawablePicts[],
15                  SkDrawable* const drawables[],
16                  int drawableCount,
17                  const SkBBoxHierarchy* bbh,
18                  SkPicture::AbortCallback* callback) {
19    SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);
20
21    if (bbh) {
22        // Draw only ops that affect pixels in the canvas's current clip.
23        // The SkRecord and BBH were recorded in identity space.  This canvas
24        // is not necessarily in that same space.  getClipBounds() returns us
25        // this canvas' clip bounds transformed back into identity space, which
26        // lets us query the BBH.
27        SkRect query;
28        if (!canvas->getClipBounds(&query)) {
29            query.setEmpty();
30        }
31
32        SkTDArray<unsigned> ops;
33        bbh->search(query, &ops);
34
35        SkRecords::Draw draw(canvas, drawablePicts, drawables, drawableCount);
36        for (int i = 0; i < ops.count(); i++) {
37            if (callback && callback->abort()) {
38                return;
39            }
40            // This visit call uses the SkRecords::Draw::operator() to call
41            // methods on the |canvas|, wrapped by methods defined with the
42            // DRAW() macro.
43            record.visit<void>(ops[i], draw);
44        }
45    } else {
46        // Draw all ops.
47        SkRecords::Draw draw(canvas, drawablePicts, drawables, drawableCount);
48        for (unsigned i = 0; i < record.count(); i++) {
49            if (callback && callback->abort()) {
50                return;
51            }
52            // This visit call uses the SkRecords::Draw::operator() to call
53            // methods on the |canvas|, wrapped by methods defined with the
54            // DRAW() macro.
55            record.visit<void>(i, draw);
56        }
57    }
58}
59
60void SkRecordPartialDraw(const SkRecord& record, SkCanvas* canvas,
61                         SkPicture const* const drawablePicts[], int drawableCount,
62                         unsigned start, unsigned stop,
63                         const SkMatrix& initialCTM) {
64    SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);
65
66    stop = SkTMin(stop, record.count());
67    SkRecords::Draw draw(canvas, drawablePicts, NULL, drawableCount, &initialCTM);
68    for (unsigned i = start; i < stop; i++) {
69        record.visit<void>(i, draw);
70    }
71}
72
73namespace SkRecords {
74
75// NoOps draw nothing.
76template <> void Draw::draw(const NoOp&) {}
77
78#define DRAW(T, call) template <> void Draw::draw(const T& r) { fCanvas->call; }
79DRAW(Restore, restore());
80DRAW(Save, save());
81DRAW(SaveLayer, saveLayer(r.bounds, r.paint, r.flags));
82DRAW(SetMatrix, setMatrix(SkMatrix::Concat(fInitialCTM, r.matrix)));
83
84DRAW(ClipPath, clipPath(r.path, r.opAA.op, r.opAA.aa));
85DRAW(ClipRRect, clipRRect(r.rrect, r.opAA.op, r.opAA.aa));
86DRAW(ClipRect, clipRect(r.rect, r.opAA.op, r.opAA.aa));
87DRAW(ClipRegion, clipRegion(r.region, r.op));
88
89DRAW(BeginCommentGroup, beginCommentGroup(r.description));
90DRAW(AddComment, addComment(r.key, r.value));
91DRAW(EndCommentGroup, endCommentGroup());
92
93DRAW(DrawBitmap, drawBitmap(r.bitmap.shallowCopy(), r.left, r.top, r.paint));
94DRAW(DrawBitmapNine, drawBitmapNine(r.bitmap.shallowCopy(), r.center, r.dst, r.paint));
95DRAW(DrawBitmapRectToRect,
96        drawBitmapRectToRect(r.bitmap.shallowCopy(), r.src, r.dst, r.paint,
97                             SkCanvas::kNone_DrawBitmapRectFlag));
98DRAW(DrawBitmapRectToRectBleed,
99        drawBitmapRectToRect(r.bitmap.shallowCopy(), r.src, r.dst, r.paint,
100                             SkCanvas::kBleed_DrawBitmapRectFlag));
101DRAW(DrawDRRect, drawDRRect(r.outer, r.inner, r.paint));
102DRAW(DrawImage, drawImage(r.image, r.left, r.top, r.paint));
103DRAW(DrawImageRect, drawImageRect(r.image, r.src, r.dst, r.paint));
104DRAW(DrawOval, drawOval(r.oval, r.paint));
105DRAW(DrawPaint, drawPaint(r.paint));
106DRAW(DrawPath, drawPath(r.path, r.paint));
107DRAW(DrawPatch, drawPatch(r.cubics, r.colors, r.texCoords, r.xmode, r.paint));
108DRAW(DrawPicture, drawPicture(r.picture, &r.matrix, r.paint));
109DRAW(DrawPoints, drawPoints(r.mode, r.count, r.pts, r.paint));
110DRAW(DrawPosText, drawPosText(r.text, r.byteLength, r.pos, r.paint));
111DRAW(DrawPosTextH, drawPosTextH(r.text, r.byteLength, r.xpos, r.y, r.paint));
112DRAW(DrawRRect, drawRRect(r.rrect, r.paint));
113DRAW(DrawRect, drawRect(r.rect, r.paint));
114DRAW(DrawSprite, drawSprite(r.bitmap.shallowCopy(), r.left, r.top, r.paint));
115DRAW(DrawText, drawText(r.text, r.byteLength, r.x, r.y, r.paint));
116DRAW(DrawTextBlob, drawTextBlob(r.blob, r.x, r.y, r.paint));
117DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, &r.matrix, r.paint));
118DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.colors,
119                                r.xmode.get(), r.indices, r.indexCount, r.paint));
120#undef DRAW
121
122template <> void Draw::draw(const DrawDrawable& r) {
123    SkASSERT(r.index >= 0);
124    SkASSERT(r.index < fDrawableCount);
125    if (fDrawables) {
126        SkASSERT(NULL == fDrawablePicts);
127        fCanvas->drawDrawable(fDrawables[r.index]);
128    } else {
129        fCanvas->drawPicture(fDrawablePicts[r.index]);
130    }
131}
132
133// This is an SkRecord visitor that fills an SkBBoxHierarchy.
134//
135// The interesting part here is how to calculate bounds for ops which don't
136// have intrinsic bounds.  What is the bounds of a Save or a Translate?
137//
138// We answer this by thinking about a particular definition of bounds: if I
139// don't execute this op, pixels in this rectangle might draw incorrectly.  So
140// the bounds of a Save, a Translate, a Restore, etc. are the union of the
141// bounds of Draw* ops that they might have an effect on.  For any given
142// Save/Restore block, the bounds of the Save, the Restore, and any other
143// non-drawing ("control") ops inside are exactly the union of the bounds of
144// the drawing ops inside that block.
145//
146// To implement this, we keep a stack of active Save blocks.  As we consume ops
147// inside the Save/Restore block, drawing ops are unioned with the bounds of
148// the block, and control ops are stashed away for later.  When we finish the
149// block with a Restore, our bounds are complete, and we go back and fill them
150// in for all the control ops we stashed away.
151class FillBounds : SkNoncopyable {
152public:
153    FillBounds(const SkRect& cullRect, const SkRecord& record)
154        : fNumRecords(record.count())
155        , fCullRect(cullRect)
156        , fBounds(record.count())
157    {
158        // Calculate bounds for all ops.  This won't go quite in order, so we'll need
159        // to store the bounds separately then feed them in to the BBH later in order.
160        fCTM = &SkMatrix::I();
161        fCurrentClipBounds = fCullRect;
162    }
163
164    void setCurrentOp(unsigned currentOp) { fCurrentOp = currentOp; }
165
166    void cleanUp(SkBBoxHierarchy* bbh) {
167        // If we have any lingering unpaired Saves, simulate restores to make
168        // sure all ops in those Save blocks have their bounds calculated.
169        while (!fSaveStack.isEmpty()) {
170            this->popSaveBlock();
171        }
172
173        // Any control ops not part of any Save/Restore block draw everywhere.
174        while (!fControlIndices.isEmpty()) {
175            this->popControl(fCullRect);
176        }
177
178        // Finally feed all stored bounds into the BBH.  They'll be returned in this order.
179        if (bbh) {
180            bbh->insert(fBounds.get(), fNumRecords);
181        }
182    }
183
184    template <typename T> void operator()(const T& op) {
185        this->updateCTM(op);
186        this->updateClipBounds(op);
187        this->trackBounds(op);
188    }
189
190    // In this file, SkRect are in local coordinates, Bounds are translated back to identity space.
191    typedef SkRect Bounds;
192
193    unsigned currentOp() const { return fCurrentOp; }
194    const SkMatrix& ctm() const { return *fCTM; }
195    const Bounds& getBounds(unsigned index) const { return fBounds[index]; }
196
197    // Adjust rect for all paints that may affect its geometry, then map it to identity space.
198    Bounds adjustAndMap(SkRect rect, const SkPaint* paint) const {
199        // Inverted rectangles really confuse our BBHs.
200        rect.sort();
201
202        // Adjust the rect for its own paint.
203        if (!AdjustForPaint(paint, &rect)) {
204            // The paint could do anything to our bounds.  The only safe answer is the current clip.
205            return fCurrentClipBounds;
206        }
207
208        // Adjust rect for all the paints from the SaveLayers we're inside.
209        if (!this->adjustForSaveLayerPaints(&rect)) {
210            // Same deal as above.
211            return fCurrentClipBounds;
212        }
213
214        // Map the rect back to identity space.
215        fCTM->mapRect(&rect);
216
217        // Nothing can draw outside the current clip.
218        if (!rect.intersect(fCurrentClipBounds)) {
219            return Bounds::MakeEmpty();
220        }
221
222        return rect;
223    }
224
225private:
226    struct SaveBounds {
227        int controlOps;        // Number of control ops in this Save block, including the Save.
228        Bounds bounds;         // Bounds of everything in the block.
229        const SkPaint* paint;  // Unowned.  If set, adjusts the bounds of all ops in this block.
230    };
231
232    // Only Restore and SetMatrix change the CTM.
233    template <typename T> void updateCTM(const T&) {}
234    void updateCTM(const Restore& op)   { fCTM = &op.matrix; }
235    void updateCTM(const SetMatrix& op) { fCTM = &op.matrix; }
236
237    // Most ops don't change the clip.
238    template <typename T> void updateClipBounds(const T&) {}
239
240    // Clip{Path,RRect,Rect,Region} obviously change the clip.  They all know their bounds already.
241    void updateClipBounds(const ClipPath&   op) { this->updateClipBoundsForClipOp(op.devBounds); }
242    void updateClipBounds(const ClipRRect&  op) { this->updateClipBoundsForClipOp(op.devBounds); }
243    void updateClipBounds(const ClipRect&   op) { this->updateClipBoundsForClipOp(op.devBounds); }
244    void updateClipBounds(const ClipRegion& op) { this->updateClipBoundsForClipOp(op.devBounds); }
245
246    // The bounds of clip ops need to be adjusted for the paints of saveLayers they're inside.
247    void updateClipBoundsForClipOp(const SkIRect& devBounds) {
248        Bounds clip = SkRect::Make(devBounds);
249        // We don't call adjustAndMap() because as its last step it would intersect the adjusted
250        // clip bounds with the previous clip, exactly what we can't do when the clip grows.
251        if (this->adjustForSaveLayerPaints(&clip)) {
252            fCurrentClipBounds = clip.intersect(fCullRect) ? clip : Bounds::MakeEmpty();
253        } else {
254            fCurrentClipBounds = fCullRect;
255        }
256    }
257
258    // Restore holds the devBounds for the clip after the {save,saveLayer}/restore block completes.
259    void updateClipBounds(const Restore& op) {
260        // This is just like the clip ops above, but we need to skip the effects (if any) of our
261        // paired saveLayer (if it is one); it has not yet been popped off the save stack.  Our
262        // devBounds reflect the state of the world after the saveLayer/restore block is done,
263        // so they are not affected by the saveLayer's paint.
264        const int kSavesToIgnore = 1;
265        Bounds clip = SkRect::Make(op.devBounds);
266        if (this->adjustForSaveLayerPaints(&clip, kSavesToIgnore)) {
267            fCurrentClipBounds = clip.intersect(fCullRect) ? clip : Bounds::MakeEmpty();
268        } else {
269            fCurrentClipBounds = fCullRect;
270        }
271    }
272
273    // We also take advantage of SaveLayer bounds when present to further cut the clip down.
274    void updateClipBounds(const SaveLayer& op)  {
275        if (op.bounds) {
276            // adjustAndMap() intersects these layer bounds with the previous clip for us.
277            fCurrentClipBounds = this->adjustAndMap(*op.bounds, op.paint);
278        }
279    }
280
281    // The bounds of these ops must be calculated when we hit the Restore
282    // from the bounds of the ops in the same Save block.
283    void trackBounds(const Save&)          { this->pushSaveBlock(NULL); }
284    void trackBounds(const SaveLayer& op)  { this->pushSaveBlock(op.paint); }
285    void trackBounds(const Restore&) { fBounds[fCurrentOp] = this->popSaveBlock(); }
286
287    void trackBounds(const SetMatrix&)         { this->pushControl(); }
288    void trackBounds(const ClipRect&)          { this->pushControl(); }
289    void trackBounds(const ClipRRect&)         { this->pushControl(); }
290    void trackBounds(const ClipPath&)          { this->pushControl(); }
291    void trackBounds(const ClipRegion&)        { this->pushControl(); }
292    void trackBounds(const BeginCommentGroup&) { this->pushControl(); }
293    void trackBounds(const AddComment&)        { this->pushControl(); }
294    void trackBounds(const EndCommentGroup&)   { this->pushControl(); }
295
296    // For all other ops, we can calculate and store the bounds directly now.
297    template <typename T> void trackBounds(const T& op) {
298        fBounds[fCurrentOp] = this->bounds(op);
299        this->updateSaveBounds(fBounds[fCurrentOp]);
300    }
301
302    void pushSaveBlock(const SkPaint* paint) {
303        // Starting a new Save block.  Push a new entry to represent that.
304        SaveBounds sb;
305        sb.controlOps = 0;
306        // If the paint affects transparent black, the bound shouldn't be smaller
307        // than the current clip bounds.
308        sb.bounds =
309            PaintMayAffectTransparentBlack(paint) ? fCurrentClipBounds : Bounds::MakeEmpty();
310        sb.paint = paint;
311
312        fSaveStack.push(sb);
313        this->pushControl();
314    }
315
316    static bool PaintMayAffectTransparentBlack(const SkPaint* paint) {
317        if (paint) {
318            // FIXME: this is very conservative
319            if (paint->getImageFilter() || paint->getColorFilter()) {
320                return true;
321            }
322
323            // Unusual Xfermodes require us to process a saved layer
324            // even with operations outisde the clip.
325            // For example, DstIn is used by masking layers.
326            // https://code.google.com/p/skia/issues/detail?id=1291
327            // https://crbug.com/401593
328            SkXfermode* xfermode = paint->getXfermode();
329            SkXfermode::Mode mode;
330            // SrcOver is ok, and is also the common case with a NULL xfermode.
331            // So we should make that the fast path and bypass the mode extraction
332            // and test.
333            if (xfermode && xfermode->asMode(&mode)) {
334                switch (mode) {
335                    // For each of the following transfer modes, if the source
336                    // alpha is zero (our transparent black), the resulting
337                    // blended alpha is not necessarily equal to the original
338                    // destination alpha.
339                    case SkXfermode::kClear_Mode:
340                    case SkXfermode::kSrc_Mode:
341                    case SkXfermode::kSrcIn_Mode:
342                    case SkXfermode::kDstIn_Mode:
343                    case SkXfermode::kSrcOut_Mode:
344                    case SkXfermode::kDstATop_Mode:
345                    case SkXfermode::kModulate_Mode:
346                        return true;
347                        break;
348                    default:
349                        break;
350                }
351            }
352        }
353        return false;
354    }
355
356    Bounds popSaveBlock() {
357        // We're done the Save block.  Apply the block's bounds to all control ops inside it.
358        SaveBounds sb;
359        fSaveStack.pop(&sb);
360
361        while (sb.controlOps --> 0) {
362            this->popControl(sb.bounds);
363        }
364
365        // This whole Save block may be part another Save block.
366        this->updateSaveBounds(sb.bounds);
367
368        // If called from a real Restore (not a phony one for balance), it'll need the bounds.
369        return sb.bounds;
370    }
371
372    void pushControl() {
373        fControlIndices.push(fCurrentOp);
374        if (!fSaveStack.isEmpty()) {
375            fSaveStack.top().controlOps++;
376        }
377    }
378
379    void popControl(const Bounds& bounds) {
380        fBounds[fControlIndices.top()] = bounds;
381        fControlIndices.pop();
382    }
383
384    void updateSaveBounds(const Bounds& bounds) {
385        // If we're in a Save block, expand its bounds to cover these bounds too.
386        if (!fSaveStack.isEmpty()) {
387            fSaveStack.top().bounds.join(bounds);
388        }
389    }
390
391    // FIXME: this method could use better bounds
392    Bounds bounds(const DrawText&) const { return fCurrentClipBounds; }
393
394    Bounds bounds(const DrawPaint&) const { return fCurrentClipBounds; }
395    Bounds bounds(const NoOp&)  const { return Bounds::MakeEmpty(); }    // NoOps don't draw.
396
397    Bounds bounds(const DrawSprite& op) const {  // Ignores the matrix, but respects the clip.
398        SkRect rect = Bounds::MakeXYWH(op.left, op.top, op.bitmap.width(), op.bitmap.height());
399        if (!rect.intersect(fCurrentClipBounds)) {
400            return Bounds::MakeEmpty();
401        }
402        return rect;
403    }
404
405    Bounds bounds(const DrawRect& op) const { return this->adjustAndMap(op.rect, &op.paint); }
406    Bounds bounds(const DrawOval& op) const { return this->adjustAndMap(op.oval, &op.paint); }
407    Bounds bounds(const DrawRRect& op) const {
408        return this->adjustAndMap(op.rrect.rect(), &op.paint);
409    }
410    Bounds bounds(const DrawDRRect& op) const {
411        return this->adjustAndMap(op.outer.rect(), &op.paint);
412    }
413    Bounds bounds(const DrawImage& op) const {
414        const SkImage* image = op.image;
415        SkRect rect = SkRect::MakeXYWH(op.left, op.top, image->width(), image->height());
416
417        return this->adjustAndMap(rect, op.paint);
418    }
419    Bounds bounds(const DrawImageRect& op) const {
420        return this->adjustAndMap(op.dst, op.paint);
421    }
422    Bounds bounds(const DrawBitmapRectToRect& op) const {
423        return this->adjustAndMap(op.dst, op.paint);
424    }
425    Bounds bounds(const DrawBitmapRectToRectBleed& op) const {
426        return this->adjustAndMap(op.dst, op.paint);
427    }
428    Bounds bounds(const DrawBitmapNine& op) const {
429        return this->adjustAndMap(op.dst, op.paint);
430    }
431    Bounds bounds(const DrawBitmap& op) const {
432        return this->adjustAndMap(
433                SkRect::MakeXYWH(op.left, op.top, op.bitmap.width(), op.bitmap.height()),
434                op.paint);
435    }
436
437    Bounds bounds(const DrawPath& op) const {
438        return op.path.isInverseFillType() ? fCurrentClipBounds
439                                           : this->adjustAndMap(op.path.getBounds(), &op.paint);
440    }
441    Bounds bounds(const DrawPoints& op) const {
442        SkRect dst;
443        dst.set(op.pts, op.count);
444
445        // Pad the bounding box a little to make sure hairline points' bounds aren't empty.
446        SkScalar stroke = SkMaxScalar(op.paint.getStrokeWidth(), 0.01f);
447        dst.outset(stroke/2, stroke/2);
448
449        return this->adjustAndMap(dst, &op.paint);
450    }
451    Bounds bounds(const DrawPatch& op) const {
452        SkRect dst;
453        dst.set(op.cubics, SkPatchUtils::kNumCtrlPts);
454        return this->adjustAndMap(dst, &op.paint);
455    }
456    Bounds bounds(const DrawVertices& op) const {
457        SkRect dst;
458        dst.set(op.vertices, op.vertexCount);
459        return this->adjustAndMap(dst, &op.paint);
460    }
461
462    Bounds bounds(const DrawPicture& op) const {
463        SkRect dst = op.picture->cullRect();
464        op.matrix.mapRect(&dst);
465        return this->adjustAndMap(dst, op.paint);
466    }
467
468    Bounds bounds(const DrawPosText& op) const {
469        const int N = op.paint.countText(op.text, op.byteLength);
470        if (N == 0) {
471            return Bounds::MakeEmpty();
472        }
473
474        SkRect dst;
475        dst.set(op.pos, N);
476        AdjustTextForFontMetrics(&dst, op.paint);
477        return this->adjustAndMap(dst, &op.paint);
478    }
479    Bounds bounds(const DrawPosTextH& op) const {
480        const int N = op.paint.countText(op.text, op.byteLength);
481        if (N == 0) {
482            return Bounds::MakeEmpty();
483        }
484
485        SkScalar left = op.xpos[0], right = op.xpos[0];
486        for (int i = 1; i < N; i++) {
487            left  = SkMinScalar(left,  op.xpos[i]);
488            right = SkMaxScalar(right, op.xpos[i]);
489        }
490        SkRect dst = { left, op.y, right, op.y };
491        AdjustTextForFontMetrics(&dst, op.paint);
492        return this->adjustAndMap(dst, &op.paint);
493    }
494    Bounds bounds(const DrawTextOnPath& op) const {
495        SkRect dst = op.path.getBounds();
496
497        // Pad all sides by the maximum padding in any direction we'd normally apply.
498        SkRect pad = { 0, 0, 0, 0};
499        AdjustTextForFontMetrics(&pad, op.paint);
500
501        // That maximum padding happens to always be the right pad today.
502        SkASSERT(pad.fLeft == -pad.fRight);
503        SkASSERT(pad.fTop  == -pad.fBottom);
504        SkASSERT(pad.fRight > pad.fBottom);
505        dst.outset(pad.fRight, pad.fRight);
506
507        return this->adjustAndMap(dst, &op.paint);
508    }
509
510    Bounds bounds(const DrawTextBlob& op) const {
511        SkRect dst = op.blob->bounds();
512        dst.offset(op.x, op.y);
513        return this->adjustAndMap(dst, &op.paint);
514    }
515
516    Bounds bounds(const DrawDrawable& op) const {
517        return this->adjustAndMap(op.worstCaseBounds, NULL);
518    }
519
520    static void AdjustTextForFontMetrics(SkRect* rect, const SkPaint& paint) {
521#ifdef SK_DEBUG
522        SkRect correct = *rect;
523#endif
524        // crbug.com/373785 ~~> xPad = 4x yPad
525        // crbug.com/424824 ~~> bump yPad from 2x text size to 2.5x
526        const SkScalar yPad = 2.5f * paint.getTextSize(),
527                       xPad = 4.0f * yPad;
528        rect->outset(xPad, yPad);
529#ifdef SK_DEBUG
530        SkPaint::FontMetrics metrics;
531        paint.getFontMetrics(&metrics);
532        correct.fLeft   += metrics.fXMin;
533        correct.fTop    += metrics.fTop;
534        correct.fRight  += metrics.fXMax;
535        correct.fBottom += metrics.fBottom;
536        // See skia:2862 for why we ignore small text sizes.
537        SkASSERTF(paint.getTextSize() < 0.001f || rect->contains(correct),
538                  "%f %f %f %f vs. %f %f %f %f\n",
539                  -xPad, -yPad, +xPad, +yPad,
540                  metrics.fXMin, metrics.fTop, metrics.fXMax, metrics.fBottom);
541#endif
542    }
543
544    // Returns true if rect was meaningfully adjusted for the effects of paint,
545    // false if the paint could affect the rect in unknown ways.
546    static bool AdjustForPaint(const SkPaint* paint, SkRect* rect) {
547        if (paint) {
548            if (paint->canComputeFastBounds()) {
549                *rect = paint->computeFastBounds(*rect, rect);
550                return true;
551            }
552            return false;
553        }
554        return true;
555    }
556
557    bool adjustForSaveLayerPaints(SkRect* rect, int savesToIgnore = 0) const {
558        for (int i = fSaveStack.count() - 1 - savesToIgnore; i >= 0; i--) {
559            if (!AdjustForPaint(fSaveStack[i].paint, rect)) {
560                return false;
561            }
562        }
563        return true;
564    }
565
566    const unsigned fNumRecords;
567
568    // We do not guarantee anything for operations outside of the cull rect
569    const SkRect fCullRect;
570
571    // Conservative identity-space bounds for each op in the SkRecord.
572    SkAutoTMalloc<Bounds> fBounds;
573
574    // We walk fCurrentOp through the SkRecord, as we go using updateCTM()
575    // and updateClipBounds() to maintain the exact CTM (fCTM) and conservative
576    // identity-space bounds of the current clip (fCurrentClipBounds).
577    unsigned fCurrentOp;
578    const SkMatrix* fCTM;
579    Bounds fCurrentClipBounds;
580
581    // Used to track the bounds of Save/Restore blocks and the control ops inside them.
582    SkTDArray<SaveBounds> fSaveStack;
583    SkTDArray<unsigned>   fControlIndices;
584};
585
586// SkRecord visitor to gather saveLayer/restore information.
587class CollectLayers : SkNoncopyable {
588public:
589    CollectLayers(const SkRect& cullRect, const SkRecord& record,
590                  const SkPicture::SnapshotArray* pictList, SkLayerInfo* accelData)
591        : fSaveLayersInStack(0)
592        , fAccelData(accelData)
593        , fPictList(pictList)
594        , fFillBounds(cullRect, record)
595    {}
596
597    void setCurrentOp(unsigned currentOp) { fFillBounds.setCurrentOp(currentOp); }
598
599    void cleanUp(SkBBoxHierarchy* bbh) {
600        // fFillBounds must perform its cleanUp first so that all the bounding
601        // boxes associated with unbalanced restores are updated (prior to
602        // fetching their bound in popSaveLayerInfo).
603        fFillBounds.cleanUp(bbh);
604
605        while (!fSaveLayerStack.isEmpty()) {
606            this->popSaveLayerInfo();
607        }
608    }
609
610    template <typename T> void operator()(const T& op) {
611        fFillBounds(op);
612        this->trackSaveLayers(op);
613    }
614
615private:
616    struct SaveLayerInfo {
617        SaveLayerInfo() { }
618        SaveLayerInfo(int opIndex, bool isSaveLayer, const SkRect* bounds, const SkPaint* paint)
619            : fStartIndex(opIndex)
620            , fIsSaveLayer(isSaveLayer)
621            , fHasNestedSaveLayer(false)
622            , fBounds(bounds ? *bounds : SkRect::MakeEmpty())
623            , fPaint(paint) {
624        }
625
626        int                fStartIndex;
627        bool               fIsSaveLayer;
628        bool               fHasNestedSaveLayer;
629        SkRect             fBounds;
630        const SkPaint*     fPaint;
631    };
632
633    template <typename T> void trackSaveLayers(const T& op) {
634        /* most ops aren't involved in saveLayers */
635    }
636    void trackSaveLayers(const Save& s) { this->pushSaveLayerInfo(false, NULL, NULL); }
637    void trackSaveLayers(const SaveLayer& sl) { this->pushSaveLayerInfo(true, sl.bounds, sl.paint); }
638    void trackSaveLayers(const Restore& r) { this->popSaveLayerInfo(); }
639
640    void trackSaveLayersForPicture(const SkPicture* picture, const SkPaint* paint) {
641        // For sub-pictures, we wrap their layer information within the parent
642        // picture's rendering hierarchy
643        SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
644
645        const SkLayerInfo* childData =
646            static_cast<const SkLayerInfo*>(picture->EXPERIMENTAL_getAccelData(key));
647        if (!childData) {
648            // If the child layer hasn't been generated with saveLayer data we
649            // assume the worst (i.e., that it does contain layers which nest
650            // inside existing layers). Layers within sub-pictures that don't
651            // have saveLayer data cannot be hoisted.
652            // TODO: could the analysis data be use to fine tune this?
653            this->updateStackForSaveLayer();
654            return;
655        }
656
657        for (int i = 0; i < childData->numBlocks(); ++i) {
658            const SkLayerInfo::BlockInfo& src = childData->block(i);
659
660            FillBounds::Bounds newBound = fFillBounds.adjustAndMap(src.fBounds, paint);
661            if (newBound.isEmpty()) {
662                continue;
663            }
664
665            this->updateStackForSaveLayer();
666
667            SkLayerInfo::BlockInfo& dst = fAccelData->addBlock();
668
669            // If src.fPicture is NULL the layer is in dp.picture; otherwise
670            // it belongs to a sub-picture.
671            dst.fPicture = src.fPicture ? src.fPicture : picture;
672            dst.fPicture->ref();
673            dst.fBounds = newBound;
674            dst.fSrcBounds = src.fSrcBounds;
675            dst.fLocalMat = src.fLocalMat;
676            dst.fPreMat = src.fPreMat;
677            dst.fPreMat.postConcat(fFillBounds.ctm());
678            if (src.fPaint) {
679                dst.fPaint = SkNEW_ARGS(SkPaint, (*src.fPaint));
680            }
681            dst.fSaveLayerOpID = src.fSaveLayerOpID;
682            dst.fRestoreOpID = src.fRestoreOpID;
683            dst.fHasNestedLayers = src.fHasNestedLayers;
684            dst.fIsNested = fSaveLayersInStack > 0 || src.fIsNested;
685
686            // Store 'saveLayer ops from enclosing picture' + drawPict op + 'ops from sub-picture'
687            dst.fKeySize = fSaveLayerOpStack.count() + src.fKeySize + 1;
688            dst.fKey = SkNEW_ARRAY(unsigned, dst.fKeySize);
689            memcpy(dst.fKey, fSaveLayerOpStack.begin(), fSaveLayerOpStack.count() * sizeof(unsigned));
690            dst.fKey[fSaveLayerOpStack.count()] = fFillBounds.currentOp();
691            memcpy(&dst.fKey[fSaveLayerOpStack.count()+1], src.fKey, src.fKeySize * sizeof(unsigned));
692        }
693    }
694
695    void trackSaveLayers(const DrawPicture& dp) {
696        this->trackSaveLayersForPicture(dp.picture, dp.paint);
697    }
698
699    void trackSaveLayers(const DrawDrawable& dp) {
700        SkASSERT(fPictList);
701        SkASSERT(dp.index >= 0 && dp.index < fPictList->count());
702        const SkPaint* paint = NULL;    // drawables don't get a side-car paint
703        this->trackSaveLayersForPicture(fPictList->begin()[dp.index], paint);
704    }
705
706    // Inform all the saveLayers already on the stack that they now have a
707    // nested saveLayer inside them
708    void updateStackForSaveLayer() {
709        for (int index = fSaveLayerStack.count() - 1; index >= 0; --index) {
710            if (fSaveLayerStack[index].fHasNestedSaveLayer) {
711                break;
712            }
713            fSaveLayerStack[index].fHasNestedSaveLayer = true;
714            if (fSaveLayerStack[index].fIsSaveLayer) {
715                break;
716            }
717        }
718    }
719
720    void pushSaveLayerInfo(bool isSaveLayer, const SkRect* bounds, const SkPaint* paint) {
721        if (isSaveLayer) {
722            this->updateStackForSaveLayer();
723            ++fSaveLayersInStack;
724            fSaveLayerOpStack.push(fFillBounds.currentOp());
725        }
726
727        fSaveLayerStack.push(SaveLayerInfo(fFillBounds.currentOp(), isSaveLayer, bounds, paint));
728    }
729
730    void popSaveLayerInfo() {
731        if (fSaveLayerStack.count() <= 0) {
732            SkASSERT(false);
733            return;
734        }
735
736        SkASSERT(fSaveLayersInStack == fSaveLayerOpStack.count());
737
738        SaveLayerInfo sli;
739        fSaveLayerStack.pop(&sli);
740
741        if (!sli.fIsSaveLayer) {
742            return;
743        }
744
745        --fSaveLayersInStack;
746
747        SkLayerInfo::BlockInfo& block = fAccelData->addBlock();
748
749        SkASSERT(NULL == block.fPicture);  // This layer is in the top-most picture
750
751        block.fBounds = fFillBounds.getBounds(sli.fStartIndex);
752        block.fLocalMat = fFillBounds.ctm();
753        block.fPreMat = SkMatrix::I();
754        if (sli.fPaint) {
755            block.fPaint = SkNEW_ARGS(SkPaint, (*sli.fPaint));
756        }
757
758        block.fSrcBounds = sli.fBounds;
759        block.fSaveLayerOpID = sli.fStartIndex;
760        block.fRestoreOpID = fFillBounds.currentOp();
761        block.fHasNestedLayers = sli.fHasNestedSaveLayer;
762        block.fIsNested = fSaveLayersInStack > 0;
763
764        block.fKeySize = fSaveLayerOpStack.count();
765        block.fKey = SkNEW_ARRAY(unsigned, block.fKeySize);
766        memcpy(block.fKey, fSaveLayerOpStack.begin(), block.fKeySize * sizeof(unsigned));
767
768        fSaveLayerOpStack.pop();
769    }
770
771    // Used to collect saveLayer information for layer hoisting
772    int                      fSaveLayersInStack;
773    SkTDArray<SaveLayerInfo> fSaveLayerStack;
774    // The op code indices of all the currently active saveLayers
775    SkTDArray<unsigned>      fSaveLayerOpStack;
776    SkLayerInfo*             fAccelData;
777    const SkPicture::SnapshotArray* fPictList;
778
779    SkRecords::FillBounds fFillBounds;
780};
781
782}  // namespace SkRecords
783
784void SkRecordFillBounds(const SkRect& cullRect, const SkRecord& record, SkBBoxHierarchy* bbh) {
785    SkRecords::FillBounds visitor(cullRect, record);
786
787    for (unsigned curOp = 0; curOp < record.count(); curOp++) {
788        visitor.setCurrentOp(curOp);
789        record.visit<void>(curOp, visitor);
790    }
791
792    visitor.cleanUp(bbh);
793}
794
795void SkRecordComputeLayers(const SkRect& cullRect, const SkRecord& record,
796                           const SkPicture::SnapshotArray* pictList, SkBBoxHierarchy* bbh,
797                           SkLayerInfo* data) {
798    SkRecords::CollectLayers visitor(cullRect, record, pictList, data);
799
800    for (unsigned curOp = 0; curOp < record.count(); curOp++) {
801        visitor.setCurrentOp(curOp);
802        record.visit<void>(curOp, visitor);
803    }
804
805    visitor.cleanUp(bbh);
806}
807
808