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