1c4b21e6c03a6cdb03e116b9f510eb10cf8daedb1commit-bot@chromium.org/*
2c4b21e6c03a6cdb03e116b9f510eb10cf8daedb1commit-bot@chromium.org * Copyright 2014 Google Inc.
3c4b21e6c03a6cdb03e116b9f510eb10cf8daedb1commit-bot@chromium.org *
4c4b21e6c03a6cdb03e116b9f510eb10cf8daedb1commit-bot@chromium.org * Use of this source code is governed by a BSD-style license that can be
5c4b21e6c03a6cdb03e116b9f510eb10cf8daedb1commit-bot@chromium.org * found in the LICENSE file.
6c4b21e6c03a6cdb03e116b9f510eb10cf8daedb1commit-bot@chromium.org */
7c4b21e6c03a6cdb03e116b9f510eb10cf8daedb1commit-bot@chromium.org
882365915476caedc130d0e36012a1ce0c007c4aerobertphillips#include "SkLayerInfo.h"
9506db0b7d2905c6bedba9fc5d4aeaf231a9a34eacommit-bot@chromium.org#include "SkRecordDraw.h"
10131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein#include "SkPatchUtils.h"
11506db0b7d2905c6bedba9fc5d4aeaf231a9a34eacommit-bot@chromium.org
125ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtkleinvoid SkRecordDraw(const SkRecord& record,
135ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein                  SkCanvas* canvas,
141bdfd3f4f09e47364f76d3f08177b1ce844ac786reed                  SkPicture const* const drawablePicts[],
153cb3840c9af6f70896cf5565a38d4ee03c02d767reed                  SkDrawable* const drawables[],
161bdfd3f4f09e47364f76d3f08177b1ce844ac786reed                  int drawableCount,
175ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein                  const SkBBoxHierarchy* bbh,
18783fe16b8ed1cd1cff34eacc33296874a32f293brobertphillips                  SkPicture::AbortCallback* callback) {
19c11530ea73b2a2fcb431df0f5c1887d08ac9113cMike Klein    SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);
205ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein
2149f085dddff10473b6ebf832a974288300224e60bsalomon    if (bbh) {
225ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein        // Draw only ops that affect pixels in the canvas's current clip.
233e8232b6ef6b04290f0c280f88b38f8cd2c3f3ecmtklein        // The SkRecord and BBH were recorded in identity space.  This canvas
243e8232b6ef6b04290f0c280f88b38f8cd2c3f3ecmtklein        // is not necessarily in that same space.  getClipBounds() returns us
253e8232b6ef6b04290f0c280f88b38f8cd2c3f3ecmtklein        // this canvas' clip bounds transformed back into identity space, which
263e8232b6ef6b04290f0c280f88b38f8cd2c3f3ecmtklein        // lets us query the BBH.
277cc1a34fbf5506e3a9e6834f0dcd988aa7c94084mtklein        SkRect query;
287cc1a34fbf5506e3a9e6834f0dcd988aa7c94084mtklein        if (!canvas->getClipBounds(&query)) {
2949aabde6ef80e39f00a2d00487cf5a881987dd81mtklein            query.setEmpty();
307cc1a34fbf5506e3a9e6834f0dcd988aa7c94084mtklein        }
313e8232b6ef6b04290f0c280f88b38f8cd2c3f3ecmtklein
326bd41969a0f2283a7a7320bb0025551353c241ecmtklein        SkTDArray<unsigned> ops;
33a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein        bbh->search(query, &ops);
345ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein
351bdfd3f4f09e47364f76d3f08177b1ce844ac786reed        SkRecords::Draw draw(canvas, drawablePicts, drawables, drawableCount);
365ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein        for (int i = 0; i < ops.count(); i++) {
37783fe16b8ed1cd1cff34eacc33296874a32f293brobertphillips            if (callback && callback->abort()) {
385ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein                return;
395ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein            }
40d239d425148e5c1445b6a99d9bc33348c41197bcdanakj            // This visit call uses the SkRecords::Draw::operator() to call
41d239d425148e5c1445b6a99d9bc33348c41197bcdanakj            // methods on the |canvas|, wrapped by methods defined with the
42d239d425148e5c1445b6a99d9bc33348c41197bcdanakj            // DRAW() macro.
436bd41969a0f2283a7a7320bb0025551353c241ecmtklein            record.visit<void>(ops[i], draw);
445ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein        }
455ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein    } else {
465ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein        // Draw all ops.
471bdfd3f4f09e47364f76d3f08177b1ce844ac786reed        SkRecords::Draw draw(canvas, drawablePicts, drawables, drawableCount);
4800f30bdc9e34b013da54b4406f36556c5be8d041mtklein        for (unsigned i = 0; i < record.count(); i++) {
49783fe16b8ed1cd1cff34eacc33296874a32f293brobertphillips            if (callback && callback->abort()) {
505ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein                return;
515ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein            }
52d239d425148e5c1445b6a99d9bc33348c41197bcdanakj            // This visit call uses the SkRecords::Draw::operator() to call
53d239d425148e5c1445b6a99d9bc33348c41197bcdanakj            // methods on the |canvas|, wrapped by methods defined with the
54d239d425148e5c1445b6a99d9bc33348c41197bcdanakj            // DRAW() macro.
5500f30bdc9e34b013da54b4406f36556c5be8d041mtklein            record.visit<void>(i, draw);
56c11530ea73b2a2fcb431df0f5c1887d08ac9113cMike Klein        }
5773b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.org    }
5827f6b0d013572184dc980462cce8d0f3caec1c8ecommit-bot@chromium.org}
59d9ce2be6b24b1c89d13c2edb63c3462b0f5c6aa3commit-bot@chromium.org
606be2aa9a251bf6022570a03140f956655b3ef1dareedvoid SkRecordPartialDraw(const SkRecord& record, SkCanvas* canvas,
616be2aa9a251bf6022570a03140f956655b3ef1dareed                         SkPicture const* const drawablePicts[], int drawableCount,
624815fe5a0a497b676677fb4e4a0f05c511855490robertphillips                         unsigned start, unsigned stop,
634815fe5a0a497b676677fb4e4a0f05c511855490robertphillips                         const SkMatrix& initialCTM) {
6400f30bdc9e34b013da54b4406f36556c5be8d041mtklein    SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);
6500f30bdc9e34b013da54b4406f36556c5be8d041mtklein
6600f30bdc9e34b013da54b4406f36556c5be8d041mtklein    stop = SkTMin(stop, record.count());
678eddfb50c0c9e4bcba6384a2ce39852b5fb5becbreed    SkRecords::Draw draw(canvas, drawablePicts, NULL, drawableCount, &initialCTM);
6800f30bdc9e34b013da54b4406f36556c5be8d041mtklein    for (unsigned i = start; i < stop; i++) {
6900f30bdc9e34b013da54b4406f36556c5be8d041mtklein        record.visit<void>(i, draw);
7000f30bdc9e34b013da54b4406f36556c5be8d041mtklein    }
7100f30bdc9e34b013da54b4406f36556c5be8d041mtklein}
7200f30bdc9e34b013da54b4406f36556c5be8d041mtklein
7327f6b0d013572184dc980462cce8d0f3caec1c8ecommit-bot@chromium.orgnamespace SkRecords {
742e0c32af0508a1e544c9953ea2fe128dbae7d429commit-bot@chromium.org
752e0c32af0508a1e544c9953ea2fe128dbae7d429commit-bot@chromium.org// NoOps draw nothing.
7627f6b0d013572184dc980462cce8d0f3caec1c8ecommit-bot@chromium.orgtemplate <> void Draw::draw(const NoOp&) {}
7773b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.org
7827f6b0d013572184dc980462cce8d0f3caec1c8ecommit-bot@chromium.org#define DRAW(T, call) template <> void Draw::draw(const T& r) { fCanvas->call; }
7973b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(Restore, restore());
805f6102d07982043542343ff0a6c67b1319ac9fc7Florin MalitaDRAW(Save, save());
8173b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(SaveLayer, saveLayer(r.bounds, r.paint, r.flags));
8299bd7d817471ec903a7fe364b4e1d4477b1372b5commit-bot@chromium.orgDRAW(SetMatrix, setMatrix(SkMatrix::Concat(fInitialCTM, r.matrix)));
8373b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.org
84cdeeb095a629b0db9f0ddff09516f2b78255c047mtkleinDRAW(ClipPath, clipPath(r.path, r.opAA.op, r.opAA.aa));
85cdeeb095a629b0db9f0ddff09516f2b78255c047mtkleinDRAW(ClipRRect, clipRRect(r.rrect, r.opAA.op, r.opAA.aa));
86cdeeb095a629b0db9f0ddff09516f2b78255c047mtkleinDRAW(ClipRect, clipRect(r.rect, r.opAA.op, r.opAA.aa));
8773b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(ClipRegion, clipRegion(r.region, r.op));
8873b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.org
895f0e82204ecca0805a7689cdba5f802458e103f4mtkleinDRAW(BeginCommentGroup, beginCommentGroup(r.description));
905f0e82204ecca0805a7689cdba5f802458e103f4mtkleinDRAW(AddComment, addComment(r.key, r.value));
915f0e82204ecca0805a7689cdba5f802458e103f4mtkleinDRAW(EndCommentGroup, endCommentGroup());
925f0e82204ecca0805a7689cdba5f802458e103f4mtklein
93f55c314bfa6db980941f8d0ab485beb2e08589abmtkleinDRAW(DrawBitmap, drawBitmap(r.bitmap.shallowCopy(), r.left, r.top, r.paint));
94f55c314bfa6db980941f8d0ab485beb2e08589abmtkleinDRAW(DrawBitmapNine, drawBitmapNine(r.bitmap.shallowCopy(), r.center, r.dst, r.paint));
957cdc1ee11545a10708e857adf1d4a94a2f1e2a48mtkleinDRAW(DrawBitmapRectToRect,
96f55c314bfa6db980941f8d0ab485beb2e08589abmtklein        drawBitmapRectToRect(r.bitmap.shallowCopy(), r.src, r.dst, r.paint,
9742ddcd49060f64be57f00e651650154f9b4f3a08mtklein                             SkCanvas::kNone_DrawBitmapRectFlag));
9842ddcd49060f64be57f00e651650154f9b4f3a08mtkleinDRAW(DrawBitmapRectToRectBleed,
99f55c314bfa6db980941f8d0ab485beb2e08589abmtklein        drawBitmapRectToRect(r.bitmap.shallowCopy(), r.src, r.dst, r.paint,
10042ddcd49060f64be57f00e651650154f9b4f3a08mtklein                             SkCanvas::kBleed_DrawBitmapRectFlag));
10173b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawDRRect, drawDRRect(r.outer, r.inner, r.paint));
10265151754b9fdb6a968d7307764c20655d1b680a0piotaixrDRAW(DrawImage, drawImage(r.image, r.left, r.top, r.paint));
10365151754b9fdb6a968d7307764c20655d1b680a0piotaixrDRAW(DrawImageRect, drawImageRect(r.image, r.src, r.dst, r.paint));
10473b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawOval, drawOval(r.oval, r.paint));
10573b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawPaint, drawPaint(r.paint));
10673b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawPath, drawPath(r.path, r.paint));
1079b222a5ddd3b39ca191d8443bade6052cdcb713dmtkleinDRAW(DrawPatch, drawPatch(r.cubics, r.colors, r.texCoords, r.xmode, r.paint));
108af57903f330a0afd0c10244d4a66f64fdbef5d1emtkleinDRAW(DrawPicture, drawPicture(r.picture, &r.matrix, r.paint));
10973b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawPoints, drawPoints(r.mode, r.count, r.pts, r.paint));
11073b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawPosText, drawPosText(r.text, r.byteLength, r.pos, r.paint));
11173b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawPosTextH, drawPosTextH(r.text, r.byteLength, r.xpos, r.y, r.paint));
11273b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawRRect, drawRRect(r.rrect, r.paint));
11373b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawRect, drawRect(r.rect, r.paint));
114f55c314bfa6db980941f8d0ab485beb2e08589abmtkleinDRAW(DrawSprite, drawSprite(r.bitmap.shallowCopy(), r.left, r.top, r.paint));
11573b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawText, drawText(r.text, r.byteLength, r.x, r.y, r.paint));
11600d5c2c6523321d25b32905ff4822f083a4173eefmalitaDRAW(DrawTextBlob, drawTextBlob(r.blob, r.x, r.y, r.paint));
117af57903f330a0afd0c10244d4a66f64fdbef5d1emtkleinDRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, &r.matrix, r.paint));
11873b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.colors,
119d9ce2be6b24b1c89d13c2edb63c3462b0f5c6aa3commit-bot@chromium.org                                r.xmode.get(), r.indices, r.indexCount, r.paint));
12073b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.org#undef DRAW
12173b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.org
1226be2aa9a251bf6022570a03140f956655b3ef1dareedtemplate <> void Draw::draw(const DrawDrawable& r) {
1236be2aa9a251bf6022570a03140f956655b3ef1dareed    SkASSERT(r.index >= 0);
1246be2aa9a251bf6022570a03140f956655b3ef1dareed    SkASSERT(r.index < fDrawableCount);
1251bdfd3f4f09e47364f76d3f08177b1ce844ac786reed    if (fDrawables) {
1261bdfd3f4f09e47364f76d3f08177b1ce844ac786reed        SkASSERT(NULL == fDrawablePicts);
1273cb3840c9af6f70896cf5565a38d4ee03c02d767reed        fCanvas->drawDrawable(fDrawables[r.index]);
1281bdfd3f4f09e47364f76d3f08177b1ce844ac786reed    } else {
1291bdfd3f4f09e47364f76d3f08177b1ce844ac786reed        fCanvas->drawPicture(fDrawablePicts[r.index]);
1301bdfd3f4f09e47364f76d3f08177b1ce844ac786reed    }
1316be2aa9a251bf6022570a03140f956655b3ef1dareed}
1326be2aa9a251bf6022570a03140f956655b3ef1dareed
1335ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein// This is an SkRecord visitor that fills an SkBBoxHierarchy.
134828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein//
135828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// The interesting part here is how to calculate bounds for ops which don't
136828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// have intrinsic bounds.  What is the bounds of a Save or a Translate?
137828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein//
138828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// We answer this by thinking about a particular definition of bounds: if I
139828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// don't execute this op, pixels in this rectangle might draw incorrectly.  So
140828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// the bounds of a Save, a Translate, a Restore, etc. are the union of the
141828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// bounds of Draw* ops that they might have an effect on.  For any given
142828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// Save/Restore block, the bounds of the Save, the Restore, and any other
143828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// non-drawing ("control") ops inside are exactly the union of the bounds of
144828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// the drawing ops inside that block.
145828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein//
146828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// To implement this, we keep a stack of active Save blocks.  As we consume ops
147828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// inside the Save/Restore block, drawing ops are unioned with the bounds of
148828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// the block, and control ops are stashed away for later.  When we finish the
149828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// block with a Restore, our bounds are complete, and we go back and fill them
150828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// in for all the control ops we stashed away.
1515ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtkleinclass FillBounds : SkNoncopyable {
1525ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtkleinpublic:
1534e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    FillBounds(const SkRect& cullRect, const SkRecord& record)
1544e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        : fNumRecords(record.count())
1554e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        , fCullRect(cullRect)
1561bdfd3f4f09e47364f76d3f08177b1ce844ac786reed        , fBounds(record.count())
1571bdfd3f4f09e47364f76d3f08177b1ce844ac786reed    {
158828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        // Calculate bounds for all ops.  This won't go quite in order, so we'll need
159828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        // to store the bounds separately then feed them in to the BBH later in order.
1606332f1dd20d73a6d8b9564af7c27d09394eb6596mtklein        fCTM = &SkMatrix::I();
1614d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips        fCurrentClipBounds = fCullRect;
1624e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    }
163828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein
1644e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    void setCurrentOp(unsigned currentOp) { fCurrentOp = currentOp; }
1654e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
1664e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    void cleanUp(SkBBoxHierarchy* bbh) {
167828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        // If we have any lingering unpaired Saves, simulate restores to make
168828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        // sure all ops in those Save blocks have their bounds calculated.
169828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        while (!fSaveStack.isEmpty()) {
170828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein            this->popSaveBlock();
171828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        }
172828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein
173828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        // Any control ops not part of any Save/Restore block draw everywhere.
174828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        while (!fControlIndices.isEmpty()) {
1754d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips            this->popControl(fCullRect);
176828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        }
1775ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein
178828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        // Finally feed all stored bounds into the BBH.  They'll be returned in this order.
1798910879098694c61267e21789d933928c1b7995erobertphillips        if (bbh) {
180bfd5bff75c0ce27a70f02e4b5578d66aa9d6e306mtklein            bbh->insert(fBounds.get(), fNumRecords);
1818910879098694c61267e21789d933928c1b7995erobertphillips        }
182828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein    }
1835ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein
184a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein    template <typename T> void operator()(const T& op) {
185a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein        this->updateCTM(op);
186a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein        this->updateClipBounds(op);
187a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein        this->trackBounds(op);
1885ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein    }
1895ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein
190533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    // In this file, SkRect are in local coordinates, Bounds are translated back to identity space.
191533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    typedef SkRect Bounds;
192533eb782edaa0b6fece6166d3001edf72ec39f11mtklein
1934e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    unsigned currentOp() const { return fCurrentOp; }
1944e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    const SkMatrix& ctm() const { return *fCTM; }
1954e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    const Bounds& getBounds(unsigned index) const { return fBounds[index]; }
1964e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
1974e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    // Adjust rect for all paints that may affect its geometry, then map it to identity space.
1984e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    Bounds adjustAndMap(SkRect rect, const SkPaint* paint) const {
1994e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        // Inverted rectangles really confuse our BBHs.
2004e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        rect.sort();
2014e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
2024e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        // Adjust the rect for its own paint.
2034e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        if (!AdjustForPaint(paint, &rect)) {
2044e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            // The paint could do anything to our bounds.  The only safe answer is the current clip.
2054e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            return fCurrentClipBounds;
2064e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        }
2074e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
2084e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        // Adjust rect for all the paints from the SaveLayers we're inside.
2094e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        if (!this->adjustForSaveLayerPaints(&rect)) {
2104e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            // Same deal as above.
2114e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            return fCurrentClipBounds;
2124e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        }
2134e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
2144e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        // Map the rect back to identity space.
2154e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        fCTM->mapRect(&rect);
2164e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
2174e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        // Nothing can draw outside the current clip.
218c187a3c8849ba5e409f79ead21cd5bc82173d9f8robertphillips        if (!rect.intersect(fCurrentClipBounds)) {
219c187a3c8849ba5e409f79ead21cd5bc82173d9f8robertphillips            return Bounds::MakeEmpty();
220c187a3c8849ba5e409f79ead21cd5bc82173d9f8robertphillips        }
221c187a3c8849ba5e409f79ead21cd5bc82173d9f8robertphillips
2224e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        return rect;
2234e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    }
2244e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
2254e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillipsprivate:
226828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein    struct SaveBounds {
227a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein        int controlOps;        // Number of control ops in this Save block, including the Save.
228533eb782edaa0b6fece6166d3001edf72ec39f11mtklein        Bounds bounds;         // Bounds of everything in the block.
229a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein        const SkPaint* paint;  // Unowned.  If set, adjusts the bounds of all ops in this block.
230828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein    };
231828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein
2328e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein    // Only Restore and SetMatrix change the CTM.
2338e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein    template <typename T> void updateCTM(const T&) {}
2346332f1dd20d73a6d8b9564af7c27d09394eb6596mtklein    void updateCTM(const Restore& op)   { fCTM = &op.matrix; }
2356332f1dd20d73a6d8b9564af7c27d09394eb6596mtklein    void updateCTM(const SetMatrix& op) { fCTM = &op.matrix; }
236a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein
2378e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein    // Most ops don't change the clip.
2388e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein    template <typename T> void updateClipBounds(const T&) {}
239271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein
2408e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein    // Clip{Path,RRect,Rect,Region} obviously change the clip.  They all know their bounds already.
2418e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein    void updateClipBounds(const ClipPath&   op) { this->updateClipBoundsForClipOp(op.devBounds); }
2428e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein    void updateClipBounds(const ClipRRect&  op) { this->updateClipBoundsForClipOp(op.devBounds); }
2438e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein    void updateClipBounds(const ClipRect&   op) { this->updateClipBoundsForClipOp(op.devBounds); }
2448e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein    void updateClipBounds(const ClipRegion& op) { this->updateClipBoundsForClipOp(op.devBounds); }
245271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein
2468e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein    // The bounds of clip ops need to be adjusted for the paints of saveLayers they're inside.
2478e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein    void updateClipBoundsForClipOp(const SkIRect& devBounds) {
2488e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein        Bounds clip = SkRect::Make(devBounds);
249271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein        // We don't call adjustAndMap() because as its last step it would intersect the adjusted
250271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein        // clip bounds with the previous clip, exactly what we can't do when the clip grows.
25123d8593f8127411d9d687b4565b34b4ecd6b11d3schenney        if (this->adjustForSaveLayerPaints(&clip)) {
25223d8593f8127411d9d687b4565b34b4ecd6b11d3schenney            fCurrentClipBounds = clip.intersect(fCullRect) ? clip : Bounds::MakeEmpty();
25323d8593f8127411d9d687b4565b34b4ecd6b11d3schenney        } else {
25423d8593f8127411d9d687b4565b34b4ecd6b11d3schenney            fCurrentClipBounds = fCullRect;
25523d8593f8127411d9d687b4565b34b4ecd6b11d3schenney        }
256271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein    }
257271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein
2588e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein    // Restore holds the devBounds for the clip after the {save,saveLayer}/restore block completes.
2598e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein    void updateClipBounds(const Restore& op) {
2608e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein        // This is just like the clip ops above, but we need to skip the effects (if any) of our
2618e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein        // paired saveLayer (if it is one); it has not yet been popped off the save stack.  Our
2628e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein        // devBounds reflect the state of the world after the saveLayer/restore block is done,
2638e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein        // so they are not affected by the saveLayer's paint.
2648e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein        const int kSavesToIgnore = 1;
2658e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein        Bounds clip = SkRect::Make(op.devBounds);
26623d8593f8127411d9d687b4565b34b4ecd6b11d3schenney        if (this->adjustForSaveLayerPaints(&clip, kSavesToIgnore)) {
26723d8593f8127411d9d687b4565b34b4ecd6b11d3schenney            fCurrentClipBounds = clip.intersect(fCullRect) ? clip : Bounds::MakeEmpty();
26823d8593f8127411d9d687b4565b34b4ecd6b11d3schenney        } else {
26923d8593f8127411d9d687b4565b34b4ecd6b11d3schenney            fCurrentClipBounds = fCullRect;
27023d8593f8127411d9d687b4565b34b4ecd6b11d3schenney        }
2718e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein    }
2728e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein
273271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein    // We also take advantage of SaveLayer bounds when present to further cut the clip down.
274a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein    void updateClipBounds(const SaveLayer& op)  {
275a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein        if (op.bounds) {
276271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein            // adjustAndMap() intersects these layer bounds with the previous clip for us.
277271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein            fCurrentClipBounds = this->adjustAndMap(*op.bounds, op.paint);
278a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein        }
279a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein    }
2806cfa73a29a26edf1d03bca224ad6860396308ffcmtklein
281828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein    // The bounds of these ops must be calculated when we hit the Restore
282828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein    // from the bounds of the ops in the same Save block.
283a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein    void trackBounds(const Save&)          { this->pushSaveBlock(NULL); }
284a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein    void trackBounds(const SaveLayer& op)  { this->pushSaveBlock(op.paint); }
285a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein    void trackBounds(const Restore&) { fBounds[fCurrentOp] = this->popSaveBlock(); }
286828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein
28768199a2d5f0cd0b9577b9695b9e095e720e96950mtklein    void trackBounds(const SetMatrix&)         { this->pushControl(); }
28868199a2d5f0cd0b9577b9695b9e095e720e96950mtklein    void trackBounds(const ClipRect&)          { this->pushControl(); }
28968199a2d5f0cd0b9577b9695b9e095e720e96950mtklein    void trackBounds(const ClipRRect&)         { this->pushControl(); }
29068199a2d5f0cd0b9577b9695b9e095e720e96950mtklein    void trackBounds(const ClipPath&)          { this->pushControl(); }
29168199a2d5f0cd0b9577b9695b9e095e720e96950mtklein    void trackBounds(const ClipRegion&)        { this->pushControl(); }
29268199a2d5f0cd0b9577b9695b9e095e720e96950mtklein    void trackBounds(const BeginCommentGroup&) { this->pushControl(); }
29368199a2d5f0cd0b9577b9695b9e095e720e96950mtklein    void trackBounds(const AddComment&)        { this->pushControl(); }
29468199a2d5f0cd0b9577b9695b9e095e720e96950mtklein    void trackBounds(const EndCommentGroup&)   { this->pushControl(); }
295828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein
296828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein    // For all other ops, we can calculate and store the bounds directly now.
297828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein    template <typename T> void trackBounds(const T& op) {
298828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        fBounds[fCurrentOp] = this->bounds(op);
299828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        this->updateSaveBounds(fBounds[fCurrentOp]);
300828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein    }
301828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein
302a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein    void pushSaveBlock(const SkPaint* paint) {
303828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        // Starting a new Save block.  Push a new entry to represent that.
3044d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips        SaveBounds sb;
3054d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips        sb.controlOps = 0;
3064d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips        // If the paint affects transparent black, the bound shouldn't be smaller
3074d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips        // than the current clip bounds.
3084d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips        sb.bounds =
3094d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips            PaintMayAffectTransparentBlack(paint) ? fCurrentClipBounds : Bounds::MakeEmpty();
3104d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips        sb.paint = paint;
3114d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips
312828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        fSaveStack.push(sb);
313828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        this->pushControl();
314828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein    }
315828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein
316d910f544439fffa6c2bcc5181b79b2811a4c130amtklein    static bool PaintMayAffectTransparentBlack(const SkPaint* paint) {
317327f905d2cb0d37c302d651d8f2b17ea56368467dneto        if (paint) {
318327f905d2cb0d37c302d651d8f2b17ea56368467dneto            // FIXME: this is very conservative
319327f905d2cb0d37c302d651d8f2b17ea56368467dneto            if (paint->getImageFilter() || paint->getColorFilter()) {
320327f905d2cb0d37c302d651d8f2b17ea56368467dneto                return true;
321327f905d2cb0d37c302d651d8f2b17ea56368467dneto            }
322327f905d2cb0d37c302d651d8f2b17ea56368467dneto
323327f905d2cb0d37c302d651d8f2b17ea56368467dneto            // Unusual Xfermodes require us to process a saved layer
324327f905d2cb0d37c302d651d8f2b17ea56368467dneto            // even with operations outisde the clip.
325327f905d2cb0d37c302d651d8f2b17ea56368467dneto            // For example, DstIn is used by masking layers.
326327f905d2cb0d37c302d651d8f2b17ea56368467dneto            // https://code.google.com/p/skia/issues/detail?id=1291
327327f905d2cb0d37c302d651d8f2b17ea56368467dneto            // https://crbug.com/401593
328327f905d2cb0d37c302d651d8f2b17ea56368467dneto            SkXfermode* xfermode = paint->getXfermode();
329327f905d2cb0d37c302d651d8f2b17ea56368467dneto            SkXfermode::Mode mode;
330327f905d2cb0d37c302d651d8f2b17ea56368467dneto            // SrcOver is ok, and is also the common case with a NULL xfermode.
331327f905d2cb0d37c302d651d8f2b17ea56368467dneto            // So we should make that the fast path and bypass the mode extraction
332327f905d2cb0d37c302d651d8f2b17ea56368467dneto            // and test.
333327f905d2cb0d37c302d651d8f2b17ea56368467dneto            if (xfermode && xfermode->asMode(&mode)) {
334327f905d2cb0d37c302d651d8f2b17ea56368467dneto                switch (mode) {
335327f905d2cb0d37c302d651d8f2b17ea56368467dneto                    // For each of the following transfer modes, if the source
336327f905d2cb0d37c302d651d8f2b17ea56368467dneto                    // alpha is zero (our transparent black), the resulting
337327f905d2cb0d37c302d651d8f2b17ea56368467dneto                    // blended alpha is not necessarily equal to the original
338327f905d2cb0d37c302d651d8f2b17ea56368467dneto                    // destination alpha.
339327f905d2cb0d37c302d651d8f2b17ea56368467dneto                    case SkXfermode::kClear_Mode:
340327f905d2cb0d37c302d651d8f2b17ea56368467dneto                    case SkXfermode::kSrc_Mode:
341327f905d2cb0d37c302d651d8f2b17ea56368467dneto                    case SkXfermode::kSrcIn_Mode:
342327f905d2cb0d37c302d651d8f2b17ea56368467dneto                    case SkXfermode::kDstIn_Mode:
343327f905d2cb0d37c302d651d8f2b17ea56368467dneto                    case SkXfermode::kSrcOut_Mode:
344327f905d2cb0d37c302d651d8f2b17ea56368467dneto                    case SkXfermode::kDstATop_Mode:
345327f905d2cb0d37c302d651d8f2b17ea56368467dneto                    case SkXfermode::kModulate_Mode:
346327f905d2cb0d37c302d651d8f2b17ea56368467dneto                        return true;
347327f905d2cb0d37c302d651d8f2b17ea56368467dneto                        break;
348327f905d2cb0d37c302d651d8f2b17ea56368467dneto                    default:
349327f905d2cb0d37c302d651d8f2b17ea56368467dneto                        break;
350327f905d2cb0d37c302d651d8f2b17ea56368467dneto                }
351327f905d2cb0d37c302d651d8f2b17ea56368467dneto            }
352327f905d2cb0d37c302d651d8f2b17ea56368467dneto        }
353327f905d2cb0d37c302d651d8f2b17ea56368467dneto        return false;
354d910f544439fffa6c2bcc5181b79b2811a4c130amtklein    }
355d910f544439fffa6c2bcc5181b79b2811a4c130amtklein
356533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds popSaveBlock() {
357828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        // We're done the Save block.  Apply the block's bounds to all control ops inside it.
358828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        SaveBounds sb;
359828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        fSaveStack.pop(&sb);
360d910f544439fffa6c2bcc5181b79b2811a4c130amtklein
361828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        while (sb.controlOps --> 0) {
3624d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips            this->popControl(sb.bounds);
363828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        }
364828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein
365828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        // This whole Save block may be part another Save block.
3664d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips        this->updateSaveBounds(sb.bounds);
367828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein
368828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        // If called from a real Restore (not a phony one for balance), it'll need the bounds.
3694d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips        return sb.bounds;
370828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein    }
371828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein
372828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein    void pushControl() {
373828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        fControlIndices.push(fCurrentOp);
374828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        if (!fSaveStack.isEmpty()) {
375828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein            fSaveStack.top().controlOps++;
376828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        }
3775ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein    }
3785ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein
379533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    void popControl(const Bounds& bounds) {
380828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        fBounds[fControlIndices.top()] = bounds;
381828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        fControlIndices.pop();
382828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein    }
383828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein
384533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    void updateSaveBounds(const Bounds& bounds) {
385828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        // If we're in a Save block, expand its bounds to cover these bounds too.
386828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        if (!fSaveStack.isEmpty()) {
387828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein            fSaveStack.top().bounds.join(bounds);
388828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein        }
389828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein    }
390828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein
391131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein    // FIXME: this method could use better bounds
392533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawText&) const { return fCurrentClipBounds; }
393131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein
394533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawPaint&) const { return fCurrentClipBounds; }
395533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const NoOp&)  const { return Bounds::MakeEmpty(); }    // NoOps don't draw.
396a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein
39723d8593f8127411d9d687b4565b34b4ecd6b11d3schenney    Bounds bounds(const DrawSprite& op) const {  // Ignores the matrix, but respects the clip.
39823d8593f8127411d9d687b4565b34b4ecd6b11d3schenney        SkRect rect = Bounds::MakeXYWH(op.left, op.top, op.bitmap.width(), op.bitmap.height());
39923d8593f8127411d9d687b4565b34b4ecd6b11d3schenney        if (!rect.intersect(fCurrentClipBounds)) {
40023d8593f8127411d9d687b4565b34b4ecd6b11d3schenney            return Bounds::MakeEmpty();
40123d8593f8127411d9d687b4565b34b4ecd6b11d3schenney        }
40223d8593f8127411d9d687b4565b34b4ecd6b11d3schenney        return rect;
403131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein    }
404131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein
405533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawRect& op) const { return this->adjustAndMap(op.rect, &op.paint); }
406533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawOval& op) const { return this->adjustAndMap(op.oval, &op.paint); }
407533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawRRect& op) const {
40862b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        return this->adjustAndMap(op.rrect.rect(), &op.paint);
40962b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein    }
410533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawDRRect& op) const {
41162b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        return this->adjustAndMap(op.outer.rect(), &op.paint);
41262b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein    }
41365151754b9fdb6a968d7307764c20655d1b680a0piotaixr    Bounds bounds(const DrawImage& op) const {
41465151754b9fdb6a968d7307764c20655d1b680a0piotaixr        const SkImage* image = op.image;
41565151754b9fdb6a968d7307764c20655d1b680a0piotaixr        SkRect rect = SkRect::MakeXYWH(op.left, op.top, image->width(), image->height());
41662b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein
41765151754b9fdb6a968d7307764c20655d1b680a0piotaixr        return this->adjustAndMap(rect, op.paint);
41865151754b9fdb6a968d7307764c20655d1b680a0piotaixr    }
41965151754b9fdb6a968d7307764c20655d1b680a0piotaixr    Bounds bounds(const DrawImageRect& op) const {
42065151754b9fdb6a968d7307764c20655d1b680a0piotaixr        return this->adjustAndMap(op.dst, op.paint);
42165151754b9fdb6a968d7307764c20655d1b680a0piotaixr    }
422533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawBitmapRectToRect& op) const {
42362b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        return this->adjustAndMap(op.dst, op.paint);
42462b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein    }
42542ddcd49060f64be57f00e651650154f9b4f3a08mtklein    Bounds bounds(const DrawBitmapRectToRectBleed& op) const {
42642ddcd49060f64be57f00e651650154f9b4f3a08mtklein        return this->adjustAndMap(op.dst, op.paint);
42742ddcd49060f64be57f00e651650154f9b4f3a08mtklein    }
428533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawBitmapNine& op) const {
42962b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        return this->adjustAndMap(op.dst, op.paint);
43062b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein    }
431533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawBitmap& op) const {
432af57903f330a0afd0c10244d4a66f64fdbef5d1emtklein        return this->adjustAndMap(
433af57903f330a0afd0c10244d4a66f64fdbef5d1emtklein                SkRect::MakeXYWH(op.left, op.top, op.bitmap.width(), op.bitmap.height()),
434af57903f330a0afd0c10244d4a66f64fdbef5d1emtklein                op.paint);
43562b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein    }
43662b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein
437533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawPath& op) const {
43862b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        return op.path.isInverseFillType() ? fCurrentClipBounds
43962b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein                                           : this->adjustAndMap(op.path.getBounds(), &op.paint);
44062b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein    }
441533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawPoints& op) const {
44262b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        SkRect dst;
44362b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        dst.set(op.pts, op.count);
44462b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein
44562b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        // Pad the bounding box a little to make sure hairline points' bounds aren't empty.
44662b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        SkScalar stroke = SkMaxScalar(op.paint.getStrokeWidth(), 0.01f);
44762b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        dst.outset(stroke/2, stroke/2);
44862b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein
44962b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        return this->adjustAndMap(dst, &op.paint);
45062b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein    }
451533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawPatch& op) const {
452131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein        SkRect dst;
453131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein        dst.set(op.cubics, SkPatchUtils::kNumCtrlPts);
454131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein        return this->adjustAndMap(dst, &op.paint);
455131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein    }
456533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawVertices& op) const {
457131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein        SkRect dst;
458131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein        dst.set(op.vertices, op.vertexCount);
459131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein        return this->adjustAndMap(dst, &op.paint);
460131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein    }
461131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein
462533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawPicture& op) const {
463a8d7f0b13cd4c6d773fcf055fe17db75d260fa05robertphillips        SkRect dst = op.picture->cullRect();
464af57903f330a0afd0c10244d4a66f64fdbef5d1emtklein        op.matrix.mapRect(&dst);
465131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein        return this->adjustAndMap(dst, op.paint);
466131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein    }
46762b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein
468533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawPosText& op) const {
46962b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        const int N = op.paint.countText(op.text, op.byteLength);
47062b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        if (N == 0) {
471533eb782edaa0b6fece6166d3001edf72ec39f11mtklein            return Bounds::MakeEmpty();
47262b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        }
47362b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein
47462b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        SkRect dst;
475937c9c7eb4e06d4d3bc495e129c7b8103a5d6c0fmtklein        dst.set(op.pos, N);
47662b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        AdjustTextForFontMetrics(&dst, op.paint);
47762b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        return this->adjustAndMap(dst, &op.paint);
47862b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein    }
479533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawPosTextH& op) const {
48062b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        const int N = op.paint.countText(op.text, op.byteLength);
48162b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        if (N == 0) {
482533eb782edaa0b6fece6166d3001edf72ec39f11mtklein            return Bounds::MakeEmpty();
48362b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        }
48462b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein
48562b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        SkScalar left = op.xpos[0], right = op.xpos[0];
48662b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        for (int i = 1; i < N; i++) {
48762b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein            left  = SkMinScalar(left,  op.xpos[i]);
48862b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein            right = SkMaxScalar(right, op.xpos[i]);
48962b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        }
49062b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        SkRect dst = { left, op.y, right, op.y };
49162b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        AdjustTextForFontMetrics(&dst, op.paint);
49262b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        return this->adjustAndMap(dst, &op.paint);
49362b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein    }
494533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawTextOnPath& op) const {
495131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein        SkRect dst = op.path.getBounds();
496131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein
4979a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein        // Pad all sides by the maximum padding in any direction we'd normally apply.
498131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein        SkRect pad = { 0, 0, 0, 0};
499131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein        AdjustTextForFontMetrics(&pad, op.paint);
5009a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein
5019a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein        // That maximum padding happens to always be the right pad today.
5029a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein        SkASSERT(pad.fLeft == -pad.fRight);
5039a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein        SkASSERT(pad.fTop  == -pad.fBottom);
5049a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein        SkASSERT(pad.fRight > pad.fBottom);
5059a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein        dst.outset(pad.fRight, pad.fRight);
5069a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein
507131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein        return this->adjustAndMap(dst, &op.paint);
508131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein    }
509131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein
510533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds bounds(const DrawTextBlob& op) const {
511131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein        SkRect dst = op.blob->bounds();
512131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein        dst.offset(op.x, op.y);
513131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein        return this->adjustAndMap(dst, &op.paint);
514131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein    }
51562b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein
5166be2aa9a251bf6022570a03140f956655b3ef1dareed    Bounds bounds(const DrawDrawable& op) const {
5176be2aa9a251bf6022570a03140f956655b3ef1dareed        return this->adjustAndMap(op.worstCaseBounds, NULL);
5186be2aa9a251bf6022570a03140f956655b3ef1dareed    }
5196be2aa9a251bf6022570a03140f956655b3ef1dareed
52062b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein    static void AdjustTextForFontMetrics(SkRect* rect, const SkPaint& paint) {
5219a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein#ifdef SK_DEBUG
5229a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein        SkRect correct = *rect;
5239a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein#endif
5249a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein        // crbug.com/373785 ~~> xPad = 4x yPad
5259a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein        // crbug.com/424824 ~~> bump yPad from 2x text size to 2.5x
5269a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein        const SkScalar yPad = 2.5f * paint.getTextSize(),
5279a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein                       xPad = 4.0f * yPad;
5289a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein        rect->outset(xPad, yPad);
5299a657fa0b493ae43ed35ae04a686c5402d701420caryclark#ifdef SK_DEBUG
53062b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        SkPaint::FontMetrics metrics;
53162b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein        paint.getFontMetrics(&metrics);
5329a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein        correct.fLeft   += metrics.fXMin;
5339a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein        correct.fTop    += metrics.fTop;
5349a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein        correct.fRight  += metrics.fXMax;
5359a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein        correct.fBottom += metrics.fBottom;
536d13291a5a3d2a79b5348ecc4a8e38ab1b6da85f0mtklein        // See skia:2862 for why we ignore small text sizes.
5379a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein        SkASSERTF(paint.getTextSize() < 0.001f || rect->contains(correct),
538ed167acb7b494bf0aece05ac8a68b560782b027cmtklein                  "%f %f %f %f vs. %f %f %f %f\n",
5399a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein                  -xPad, -yPad, +xPad, +yPad,
540ed167acb7b494bf0aece05ac8a68b560782b027cmtklein                  metrics.fXMin, metrics.fTop, metrics.fXMax, metrics.fBottom);
541a19afb418027800c245ad19d651d8cf2071c9d70mtklein#endif
54262b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein    }
54362b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein
544479601b9a74b5b8e424ed3d68882e161617bdcebmtklein    // Returns true if rect was meaningfully adjusted for the effects of paint,
545479601b9a74b5b8e424ed3d68882e161617bdcebmtklein    // false if the paint could affect the rect in unknown ways.
546479601b9a74b5b8e424ed3d68882e161617bdcebmtklein    static bool AdjustForPaint(const SkPaint* paint, SkRect* rect) {
547a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein        if (paint) {
548a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein            if (paint->canComputeFastBounds()) {
549479601b9a74b5b8e424ed3d68882e161617bdcebmtklein                *rect = paint->computeFastBounds(*rect, rect);
550479601b9a74b5b8e424ed3d68882e161617bdcebmtklein                return true;
551a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein            }
552479601b9a74b5b8e424ed3d68882e161617bdcebmtklein            return false;
553479601b9a74b5b8e424ed3d68882e161617bdcebmtklein        }
554479601b9a74b5b8e424ed3d68882e161617bdcebmtklein        return true;
555479601b9a74b5b8e424ed3d68882e161617bdcebmtklein    }
556479601b9a74b5b8e424ed3d68882e161617bdcebmtklein
5578e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein    bool adjustForSaveLayerPaints(SkRect* rect, int savesToIgnore = 0) const {
5588e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein        for (int i = fSaveStack.count() - 1 - savesToIgnore; i >= 0; i--) {
559271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein            if (!AdjustForPaint(fSaveStack[i].paint, rect)) {
560271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein                return false;
561271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein            }
562271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein        }
563271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein        return true;
564271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein    }
565271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein
5664e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    const unsigned fNumRecords;
567a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein
5684d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips    // We do not guarantee anything for operations outside of the cull rect
5694d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips    const SkRect fCullRect;
5704d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips
571533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    // Conservative identity-space bounds for each op in the SkRecord.
572533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    SkAutoTMalloc<Bounds> fBounds;
573a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein
574a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein    // We walk fCurrentOp through the SkRecord, as we go using updateCTM()
575a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein    // and updateClipBounds() to maintain the exact CTM (fCTM) and conservative
576533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    // identity-space bounds of the current clip (fCurrentClipBounds).
577828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein    unsigned fCurrentOp;
5786332f1dd20d73a6d8b9564af7c27d09394eb6596mtklein    const SkMatrix* fCTM;
579533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    Bounds fCurrentClipBounds;
580a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein
581a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein    // Used to track the bounds of Save/Restore blocks and the control ops inside them.
582828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein    SkTDArray<SaveBounds> fSaveStack;
583828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein    SkTDArray<unsigned>   fControlIndices;
5845ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein};
5855ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein
5864e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips// SkRecord visitor to gather saveLayer/restore information.
5874e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillipsclass CollectLayers : SkNoncopyable {
5884e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillipspublic:
5891bdfd3f4f09e47364f76d3f08177b1ce844ac786reed    CollectLayers(const SkRect& cullRect, const SkRecord& record,
5901bdfd3f4f09e47364f76d3f08177b1ce844ac786reed                  const SkPicture::SnapshotArray* pictList, SkLayerInfo* accelData)
5914e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        : fSaveLayersInStack(0)
5924e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        , fAccelData(accelData)
5931bdfd3f4f09e47364f76d3f08177b1ce844ac786reed        , fPictList(pictList)
5941bdfd3f4f09e47364f76d3f08177b1ce844ac786reed        , fFillBounds(cullRect, record)
5951bdfd3f4f09e47364f76d3f08177b1ce844ac786reed    {}
5964e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
5974e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    void setCurrentOp(unsigned currentOp) { fFillBounds.setCurrentOp(currentOp); }
5984e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
5994e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    void cleanUp(SkBBoxHierarchy* bbh) {
6004e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        // fFillBounds must perform its cleanUp first so that all the bounding
6014e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        // boxes associated with unbalanced restores are updated (prior to
6024e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        // fetching their bound in popSaveLayerInfo).
6034e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        fFillBounds.cleanUp(bbh);
6044e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
6054e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        while (!fSaveLayerStack.isEmpty()) {
6064e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            this->popSaveLayerInfo();
6074e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        }
6084e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    }
6094e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
6104e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    template <typename T> void operator()(const T& op) {
6114e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        fFillBounds(op);
6124e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        this->trackSaveLayers(op);
6134e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    }
6144e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
6154e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillipsprivate:
6164e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    struct SaveLayerInfo {
6174e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        SaveLayerInfo() { }
618478dd723362fefc2023aee03e11216d913eeac03robertphillips        SaveLayerInfo(int opIndex, bool isSaveLayer, const SkRect* bounds, const SkPaint* paint)
6194e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            : fStartIndex(opIndex)
6204e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            , fIsSaveLayer(isSaveLayer)
6214e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            , fHasNestedSaveLayer(false)
622478dd723362fefc2023aee03e11216d913eeac03robertphillips            , fBounds(bounds ? *bounds : SkRect::MakeEmpty())
62374576eba1440c092025d6557e08da50678599d4erobertphillips            , fPaint(paint) {
6244e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        }
6254e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
6264e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        int                fStartIndex;
6274e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        bool               fIsSaveLayer;
6284e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        bool               fHasNestedSaveLayer;
629478dd723362fefc2023aee03e11216d913eeac03robertphillips        SkRect             fBounds;
6304e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        const SkPaint*     fPaint;
6314e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    };
6324e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
6334e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    template <typename T> void trackSaveLayers(const T& op) {
6344e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        /* most ops aren't involved in saveLayers */
6354e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    }
636478dd723362fefc2023aee03e11216d913eeac03robertphillips    void trackSaveLayers(const Save& s) { this->pushSaveLayerInfo(false, NULL, NULL); }
637478dd723362fefc2023aee03e11216d913eeac03robertphillips    void trackSaveLayers(const SaveLayer& sl) { this->pushSaveLayerInfo(true, sl.bounds, sl.paint); }
6384e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    void trackSaveLayers(const Restore& r) { this->popSaveLayerInfo(); }
6394e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
6401bdfd3f4f09e47364f76d3f08177b1ce844ac786reed    void trackSaveLayersForPicture(const SkPicture* picture, const SkPaint* paint) {
6414e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        // For sub-pictures, we wrap their layer information within the parent
6424e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        // picture's rendering hierarchy
64382365915476caedc130d0e36012a1ce0c007c4aerobertphillips        SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
6444e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
64582365915476caedc130d0e36012a1ce0c007c4aerobertphillips        const SkLayerInfo* childData =
6461bdfd3f4f09e47364f76d3f08177b1ce844ac786reed            static_cast<const SkLayerInfo*>(picture->EXPERIMENTAL_getAccelData(key));
6474e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        if (!childData) {
6484e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            // If the child layer hasn't been generated with saveLayer data we
6494e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            // assume the worst (i.e., that it does contain layers which nest
6504e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            // inside existing layers). Layers within sub-pictures that don't
6514e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            // have saveLayer data cannot be hoisted.
6524e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            // TODO: could the analysis data be use to fine tune this?
6534e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            this->updateStackForSaveLayer();
6544e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            return;
6554e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        }
6564e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
65782365915476caedc130d0e36012a1ce0c007c4aerobertphillips        for (int i = 0; i < childData->numBlocks(); ++i) {
65882365915476caedc130d0e36012a1ce0c007c4aerobertphillips            const SkLayerInfo::BlockInfo& src = childData->block(i);
6594e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
6601bdfd3f4f09e47364f76d3f08177b1ce844ac786reed            FillBounds::Bounds newBound = fFillBounds.adjustAndMap(src.fBounds, paint);
66174576eba1440c092025d6557e08da50678599d4erobertphillips            if (newBound.isEmpty()) {
6624e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips                continue;
6634e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            }
6644e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
6654e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            this->updateStackForSaveLayer();
6664e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
66782365915476caedc130d0e36012a1ce0c007c4aerobertphillips            SkLayerInfo::BlockInfo& dst = fAccelData->addBlock();
6684e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
6694e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            // If src.fPicture is NULL the layer is in dp.picture; otherwise
6704e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            // it belongs to a sub-picture.
6711bdfd3f4f09e47364f76d3f08177b1ce844ac786reed            dst.fPicture = src.fPicture ? src.fPicture : picture;
6724e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            dst.fPicture->ref();
67374576eba1440c092025d6557e08da50678599d4erobertphillips            dst.fBounds = newBound;
674478dd723362fefc2023aee03e11216d913eeac03robertphillips            dst.fSrcBounds = src.fSrcBounds;
6754e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            dst.fLocalMat = src.fLocalMat;
6764e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            dst.fPreMat = src.fPreMat;
6774e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            dst.fPreMat.postConcat(fFillBounds.ctm());
6784e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            if (src.fPaint) {
6794e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips                dst.fPaint = SkNEW_ARGS(SkPaint, (*src.fPaint));
6804e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            }
6814e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            dst.fSaveLayerOpID = src.fSaveLayerOpID;
6824e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            dst.fRestoreOpID = src.fRestoreOpID;
6834e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            dst.fHasNestedLayers = src.fHasNestedLayers;
6844e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            dst.fIsNested = fSaveLayersInStack > 0 || src.fIsNested;
68501d6e5f462d1d52203ee1a6660415877e4cf2dderobertphillips
68601d6e5f462d1d52203ee1a6660415877e4cf2dderobertphillips            // Store 'saveLayer ops from enclosing picture' + drawPict op + 'ops from sub-picture'
68701d6e5f462d1d52203ee1a6660415877e4cf2dderobertphillips            dst.fKeySize = fSaveLayerOpStack.count() + src.fKeySize + 1;
688e99d499caa7dbc80b58e0faf5ce137e7d30cc5d0robertphillips            dst.fKey = SkNEW_ARRAY(unsigned, dst.fKeySize);
689e99d499caa7dbc80b58e0faf5ce137e7d30cc5d0robertphillips            memcpy(dst.fKey, fSaveLayerOpStack.begin(), fSaveLayerOpStack.count() * sizeof(unsigned));
69001d6e5f462d1d52203ee1a6660415877e4cf2dderobertphillips            dst.fKey[fSaveLayerOpStack.count()] = fFillBounds.currentOp();
691e99d499caa7dbc80b58e0faf5ce137e7d30cc5d0robertphillips            memcpy(&dst.fKey[fSaveLayerOpStack.count()+1], src.fKey, src.fKeySize * sizeof(unsigned));
6924e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        }
6934e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    }
6944e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
6951bdfd3f4f09e47364f76d3f08177b1ce844ac786reed    void trackSaveLayers(const DrawPicture& dp) {
6961bdfd3f4f09e47364f76d3f08177b1ce844ac786reed        this->trackSaveLayersForPicture(dp.picture, dp.paint);
6971bdfd3f4f09e47364f76d3f08177b1ce844ac786reed    }
6981bdfd3f4f09e47364f76d3f08177b1ce844ac786reed
6991bdfd3f4f09e47364f76d3f08177b1ce844ac786reed    void trackSaveLayers(const DrawDrawable& dp) {
7001bdfd3f4f09e47364f76d3f08177b1ce844ac786reed        SkASSERT(fPictList);
7011bdfd3f4f09e47364f76d3f08177b1ce844ac786reed        SkASSERT(dp.index >= 0 && dp.index < fPictList->count());
7021bdfd3f4f09e47364f76d3f08177b1ce844ac786reed        const SkPaint* paint = NULL;    // drawables don't get a side-car paint
7031bdfd3f4f09e47364f76d3f08177b1ce844ac786reed        this->trackSaveLayersForPicture(fPictList->begin()[dp.index], paint);
7041bdfd3f4f09e47364f76d3f08177b1ce844ac786reed    }
7051bdfd3f4f09e47364f76d3f08177b1ce844ac786reed
7064e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    // Inform all the saveLayers already on the stack that they now have a
7074e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    // nested saveLayer inside them
7084e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    void updateStackForSaveLayer() {
7094e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        for (int index = fSaveLayerStack.count() - 1; index >= 0; --index) {
7104e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            if (fSaveLayerStack[index].fHasNestedSaveLayer) {
7114e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips                break;
7124e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            }
7134e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            fSaveLayerStack[index].fHasNestedSaveLayer = true;
7144e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            if (fSaveLayerStack[index].fIsSaveLayer) {
7154e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips                break;
7164e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            }
7174e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        }
7184e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    }
7194e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
720478dd723362fefc2023aee03e11216d913eeac03robertphillips    void pushSaveLayerInfo(bool isSaveLayer, const SkRect* bounds, const SkPaint* paint) {
7214e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        if (isSaveLayer) {
7224e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            this->updateStackForSaveLayer();
7234e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            ++fSaveLayersInStack;
72401d6e5f462d1d52203ee1a6660415877e4cf2dderobertphillips            fSaveLayerOpStack.push(fFillBounds.currentOp());
7254e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        }
7264e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
727478dd723362fefc2023aee03e11216d913eeac03robertphillips        fSaveLayerStack.push(SaveLayerInfo(fFillBounds.currentOp(), isSaveLayer, bounds, paint));
7284e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    }
7294e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
7304e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    void popSaveLayerInfo() {
7314e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        if (fSaveLayerStack.count() <= 0) {
7324e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            SkASSERT(false);
7334e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            return;
7344e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        }
7354e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
73601d6e5f462d1d52203ee1a6660415877e4cf2dderobertphillips        SkASSERT(fSaveLayersInStack == fSaveLayerOpStack.count());
73701d6e5f462d1d52203ee1a6660415877e4cf2dderobertphillips
7384e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        SaveLayerInfo sli;
7394e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        fSaveLayerStack.pop(&sli);
7404e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
7414e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        if (!sli.fIsSaveLayer) {
7424e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips            return;
7434e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        }
7444e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
7454e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        --fSaveLayersInStack;
7464e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
74782365915476caedc130d0e36012a1ce0c007c4aerobertphillips        SkLayerInfo::BlockInfo& block = fAccelData->addBlock();
7484e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
74982365915476caedc130d0e36012a1ce0c007c4aerobertphillips        SkASSERT(NULL == block.fPicture);  // This layer is in the top-most picture
7504e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
75182365915476caedc130d0e36012a1ce0c007c4aerobertphillips        block.fBounds = fFillBounds.getBounds(sli.fStartIndex);
75282365915476caedc130d0e36012a1ce0c007c4aerobertphillips        block.fLocalMat = fFillBounds.ctm();
75382365915476caedc130d0e36012a1ce0c007c4aerobertphillips        block.fPreMat = SkMatrix::I();
7544e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        if (sli.fPaint) {
75582365915476caedc130d0e36012a1ce0c007c4aerobertphillips            block.fPaint = SkNEW_ARGS(SkPaint, (*sli.fPaint));
7564e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        }
757478dd723362fefc2023aee03e11216d913eeac03robertphillips
758478dd723362fefc2023aee03e11216d913eeac03robertphillips        block.fSrcBounds = sli.fBounds;
75982365915476caedc130d0e36012a1ce0c007c4aerobertphillips        block.fSaveLayerOpID = sli.fStartIndex;
76082365915476caedc130d0e36012a1ce0c007c4aerobertphillips        block.fRestoreOpID = fFillBounds.currentOp();
76182365915476caedc130d0e36012a1ce0c007c4aerobertphillips        block.fHasNestedLayers = sli.fHasNestedSaveLayer;
76282365915476caedc130d0e36012a1ce0c007c4aerobertphillips        block.fIsNested = fSaveLayersInStack > 0;
76301d6e5f462d1d52203ee1a6660415877e4cf2dderobertphillips
76401d6e5f462d1d52203ee1a6660415877e4cf2dderobertphillips        block.fKeySize = fSaveLayerOpStack.count();
765e99d499caa7dbc80b58e0faf5ce137e7d30cc5d0robertphillips        block.fKey = SkNEW_ARRAY(unsigned, block.fKeySize);
766e99d499caa7dbc80b58e0faf5ce137e7d30cc5d0robertphillips        memcpy(block.fKey, fSaveLayerOpStack.begin(), block.fKeySize * sizeof(unsigned));
76701d6e5f462d1d52203ee1a6660415877e4cf2dderobertphillips
76801d6e5f462d1d52203ee1a6660415877e4cf2dderobertphillips        fSaveLayerOpStack.pop();
7694e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    }
7704e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
7714e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    // Used to collect saveLayer information for layer hoisting
77201d6e5f462d1d52203ee1a6660415877e4cf2dderobertphillips    int                      fSaveLayersInStack;
7734e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    SkTDArray<SaveLayerInfo> fSaveLayerStack;
77401d6e5f462d1d52203ee1a6660415877e4cf2dderobertphillips    // The op code indices of all the currently active saveLayers
775e99d499caa7dbc80b58e0faf5ce137e7d30cc5d0robertphillips    SkTDArray<unsigned>      fSaveLayerOpStack;
77601d6e5f462d1d52203ee1a6660415877e4cf2dderobertphillips    SkLayerInfo*             fAccelData;
7771bdfd3f4f09e47364f76d3f08177b1ce844ac786reed    const SkPicture::SnapshotArray* fPictList;
7784e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
7794e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    SkRecords::FillBounds fFillBounds;
7804e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips};
7814e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
78227f6b0d013572184dc980462cce8d0f3caec1c8ecommit-bot@chromium.org}  // namespace SkRecords
7835ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein
7844d52afef5cf90a2fed3bb69db71675c6450ab397robertphillipsvoid SkRecordFillBounds(const SkRect& cullRect, const SkRecord& record, SkBBoxHierarchy* bbh) {
7854e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    SkRecords::FillBounds visitor(cullRect, record);
7864e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
7874e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    for (unsigned curOp = 0; curOp < record.count(); curOp++) {
7884e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        visitor.setCurrentOp(curOp);
7894e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        record.visit<void>(curOp, visitor);
7904e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    }
7914e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
7924e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    visitor.cleanUp(bbh);
7935ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein}
7944e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
7954e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillipsvoid SkRecordComputeLayers(const SkRect& cullRect, const SkRecord& record,
7961bdfd3f4f09e47364f76d3f08177b1ce844ac786reed                           const SkPicture::SnapshotArray* pictList, SkBBoxHierarchy* bbh,
7971bdfd3f4f09e47364f76d3f08177b1ce844ac786reed                           SkLayerInfo* data) {
7981bdfd3f4f09e47364f76d3f08177b1ce844ac786reed    SkRecords::CollectLayers visitor(cullRect, record, pictList, data);
7994e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
8004e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    for (unsigned curOp = 0; curOp < record.count(); curOp++) {
8014e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        visitor.setCurrentOp(curOp);
8024e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips        record.visit<void>(curOp, visitor);
8034e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    }
8044e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
8054e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips    visitor.cleanUp(bbh);
8064e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips}
8074e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips
808