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 8506db0b7d2905c6bedba9fc5d4aeaf231a9a34eacommit-bot@chromium.org#include "SkRecordDraw.h" 9ab244f045a0740fa6106ed21a4e5824cd09f84f3Florin Malita#include "SkImage.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 24918e144408ba218df919528f8b48c544f4767883Mike Reed // is not necessarily in that same space. getLocalClipBounds() returns us 253e8232b6ef6b04290f0c280f88b38f8cd2c3f3ecmtklein // this canvas' clip bounds transformed back into identity space, which 263e8232b6ef6b04290f0c280f88b38f8cd2c3f3ecmtklein // lets us query the BBH. 27918e144408ba218df919528f8b48c544f4767883Mike Reed SkRect query = canvas->getLocalClipBounds(); 283e8232b6ef6b04290f0c280f88b38f8cd2c3f3ecmtklein 29c6ad06acefa096716f8dabed5342f9b89dc43dfemtklein SkTDArray<int> ops; 30a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein bbh->search(query, &ops); 315ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein 321bdfd3f4f09e47364f76d3f08177b1ce844ac786reed SkRecords::Draw draw(canvas, drawablePicts, drawables, drawableCount); 335ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein for (int i = 0; i < ops.count(); i++) { 34783fe16b8ed1cd1cff34eacc33296874a32f293brobertphillips if (callback && callback->abort()) { 355ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein return; 365ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein } 37d239d425148e5c1445b6a99d9bc33348c41197bcdanakj // This visit call uses the SkRecords::Draw::operator() to call 38d239d425148e5c1445b6a99d9bc33348c41197bcdanakj // methods on the |canvas|, wrapped by methods defined with the 39d239d425148e5c1445b6a99d9bc33348c41197bcdanakj // DRAW() macro. 40343a63d082bda969d7e8a4e09ba850e931185269mtklein record.visit(ops[i], draw); 415ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein } 425ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein } else { 435ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein // Draw all ops. 441bdfd3f4f09e47364f76d3f08177b1ce844ac786reed SkRecords::Draw draw(canvas, drawablePicts, drawables, drawableCount); 45c6ad06acefa096716f8dabed5342f9b89dc43dfemtklein for (int i = 0; i < record.count(); i++) { 46783fe16b8ed1cd1cff34eacc33296874a32f293brobertphillips if (callback && callback->abort()) { 475ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein return; 485ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein } 49d239d425148e5c1445b6a99d9bc33348c41197bcdanakj // This visit call uses the SkRecords::Draw::operator() to call 50d239d425148e5c1445b6a99d9bc33348c41197bcdanakj // methods on the |canvas|, wrapped by methods defined with the 51d239d425148e5c1445b6a99d9bc33348c41197bcdanakj // DRAW() macro. 52343a63d082bda969d7e8a4e09ba850e931185269mtklein record.visit(i, draw); 53c11530ea73b2a2fcb431df0f5c1887d08ac9113cMike Klein } 5473b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.org } 5527f6b0d013572184dc980462cce8d0f3caec1c8ecommit-bot@chromium.org} 56d9ce2be6b24b1c89d13c2edb63c3462b0f5c6aa3commit-bot@chromium.org 576be2aa9a251bf6022570a03140f956655b3ef1dareedvoid SkRecordPartialDraw(const SkRecord& record, SkCanvas* canvas, 586be2aa9a251bf6022570a03140f956655b3ef1dareed SkPicture const* const drawablePicts[], int drawableCount, 59c6ad06acefa096716f8dabed5342f9b89dc43dfemtklein int start, int stop, 604815fe5a0a497b676677fb4e4a0f05c511855490robertphillips const SkMatrix& initialCTM) { 6100f30bdc9e34b013da54b4406f36556c5be8d041mtklein SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/); 6200f30bdc9e34b013da54b4406f36556c5be8d041mtklein 6300f30bdc9e34b013da54b4406f36556c5be8d041mtklein stop = SkTMin(stop, record.count()); 6496fcdcc219d2a0d3579719b84b28bede76efba64halcanary SkRecords::Draw draw(canvas, drawablePicts, nullptr, drawableCount, &initialCTM); 65c6ad06acefa096716f8dabed5342f9b89dc43dfemtklein for (int i = start; i < stop; i++) { 66343a63d082bda969d7e8a4e09ba850e931185269mtklein record.visit(i, draw); 6700f30bdc9e34b013da54b4406f36556c5be8d041mtklein } 6800f30bdc9e34b013da54b4406f36556c5be8d041mtklein} 6900f30bdc9e34b013da54b4406f36556c5be8d041mtklein 7027f6b0d013572184dc980462cce8d0f3caec1c8ecommit-bot@chromium.orgnamespace SkRecords { 712e0c32af0508a1e544c9953ea2fe128dbae7d429commit-bot@chromium.org 722e0c32af0508a1e544c9953ea2fe128dbae7d429commit-bot@chromium.org// NoOps draw nothing. 7327f6b0d013572184dc980462cce8d0f3caec1c8ecommit-bot@chromium.orgtemplate <> void Draw::draw(const NoOp&) {} 7473b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.org 7527f6b0d013572184dc980462cce8d0f3caec1c8ecommit-bot@chromium.org#define DRAW(T, call) template <> void Draw::draw(const T& r) { fCanvas->call; } 767cc49d65fc5788f72458efc8fc4156cde4cca15aMike KleinDRAW(Flush, flush()); 7773b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(Restore, restore()); 785f6102d07982043542343ff0a6c67b1319ac9fc7Florin MalitaDRAW(Save, save()); 79da574d17f864ed70323a1c0fc6e4e969153a4c98mtkleinDRAW(SaveLayer, saveLayer(SkCanvas::SaveLayerRec(r.bounds, 80da574d17f864ed70323a1c0fc6e4e969153a4c98mtklein r.paint, 81da574d17f864ed70323a1c0fc6e4e969153a4c98mtklein r.backdrop.get(), 82b34ab04884f6219b93c1f143c83a1fc60fded40cMike Klein r.clipMask.get(), 8353f77bd4fdd76525b66b7f26d1c5c550858120dfFlorin Malita r.clipMatrix, 84da574d17f864ed70323a1c0fc6e4e969153a4c98mtklein r.saveLayerFlags))); 8599bd7d817471ec903a7fe364b4e1d4477b1372b5commit-bot@chromium.orgDRAW(SetMatrix, setMatrix(SkMatrix::Concat(fInitialCTM, r.matrix))); 86e9d2052e4931eeade49042a855b9c1f5ab7c84c5mtkleinDRAW(Concat, concat(r.matrix)); 87cbdf007bc2eb85056a1a5c75c088202becba2d16mtkleinDRAW(Translate, translate(r.dx, r.dy)); 8873b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.org 89ebfce6d9b42198e04288a15953f40c395a7b6139Mike ReedDRAW(ClipPath, clipPath(r.path, r.opAA.op(), r.opAA.aa())); 90ebfce6d9b42198e04288a15953f40c395a7b6139Mike ReedDRAW(ClipRRect, clipRRect(r.rrect, r.opAA.op(), r.opAA.aa())); 91ebfce6d9b42198e04288a15953f40c395a7b6139Mike ReedDRAW(ClipRect, clipRect(r.rect, r.opAA.op(), r.opAA.aa())); 9273b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(ClipRegion, clipRegion(r.region, r.op)); 9373b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.org 94ac3aa245acc7b469aa2f0d0078e53401d78ac8b9bsalomonDRAW(DrawArc, drawArc(r.oval, r.startAngle, r.sweepAngle, r.useCenter, r.paint)); 9573b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawDRRect, drawDRRect(r.outer, r.inner, r.paint)); 96da574d17f864ed70323a1c0fc6e4e969153a4c98mtkleinDRAW(DrawImage, drawImage(r.image.get(), r.left, r.top, r.paint)); 97c573a40ed5024b463e47088d307e3164a486dba5msarett 98c573a40ed5024b463e47088d307e3164a486dba5msaretttemplate <> void Draw::draw(const DrawImageLattice& r) { 99c573a40ed5024b463e47088d307e3164a486dba5msarett SkCanvas::Lattice lattice; 100c573a40ed5024b463e47088d307e3164a486dba5msarett lattice.fXCount = r.xCount; 101c573a40ed5024b463e47088d307e3164a486dba5msarett lattice.fXDivs = r.xDivs; 102c573a40ed5024b463e47088d307e3164a486dba5msarett lattice.fYCount = r.yCount; 103c573a40ed5024b463e47088d307e3164a486dba5msarett lattice.fYDivs = r.yDivs; 104ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev lattice.fRectTypes = (0 == r.flagCount) ? nullptr : r.flags; 105ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev lattice.fColors = (0 == r.flagCount) ? nullptr : r.colors; 10671df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett lattice.fBounds = &r.src; 107c573a40ed5024b463e47088d307e3164a486dba5msarett fCanvas->drawImageLattice(r.image.get(), lattice, r.dst, r.paint); 108c573a40ed5024b463e47088d307e3164a486dba5msarett} 109c573a40ed5024b463e47088d307e3164a486dba5msarett 110da574d17f864ed70323a1c0fc6e4e969153a4c98mtkleinDRAW(DrawImageRect, legacy_drawImageRect(r.image.get(), r.src, r.dst, r.paint, r.constraint)); 111da574d17f864ed70323a1c0fc6e4e969153a4c98mtkleinDRAW(DrawImageNine, drawImageNine(r.image.get(), r.center, r.dst, r.paint)); 11273b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawOval, drawOval(r.oval, r.paint)); 11373b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawPaint, drawPaint(r.paint)); 11473b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawPath, drawPath(r.path, r.paint)); 1157d954ad797176afedb9262fdea4507d0fc60eb9dMike ReedDRAW(DrawPatch, drawPatch(r.cubics, r.colors, r.texCoords, r.bmode, r.paint)); 116da574d17f864ed70323a1c0fc6e4e969153a4c98mtkleinDRAW(DrawPicture, drawPicture(r.picture.get(), &r.matrix, r.paint)); 11773b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawPoints, drawPoints(r.mode, r.count, r.pts, r.paint)); 11873b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawPosText, drawPosText(r.text, r.byteLength, r.pos, r.paint)); 11973b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawPosTextH, drawPosTextH(r.text, r.byteLength, r.xpos, r.y, r.paint)); 12073b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawRRect, drawRRect(r.rrect, r.paint)); 12173b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawRect, drawRect(r.rect, r.paint)); 12244df651ebefc284acc2f66425dff3ea0b0e14b36msarettDRAW(DrawRegion, drawRegion(r.region, r.paint)); 12373b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.orgDRAW(DrawText, drawText(r.text, r.byteLength, r.x, r.y, r.paint)); 124da574d17f864ed70323a1c0fc6e4e969153a4c98mtkleinDRAW(DrawTextBlob, drawTextBlob(r.blob.get(), r.x, r.y, r.paint)); 125af57903f330a0afd0c10244d4a66f64fdbef5d1emtkleinDRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, &r.matrix, r.paint)); 12645561a0b15fe045ba272c328684c3f7ae290785areedDRAW(DrawTextRSXform, drawTextRSXform(r.text, r.byteLength, r.xforms, r.cull, r.paint)); 127da574d17f864ed70323a1c0fc6e4e969153a4c98mtkleinDRAW(DrawAtlas, drawAtlas(r.atlas.get(), 128da574d17f864ed70323a1c0fc6e4e969153a4c98mtklein r.xforms, r.texs, r.colors, r.count, r.mode, r.cull, r.paint)); 129e88a1cb20e6b4c9f099070112225a88693a4630bMike ReedDRAW(DrawVertices, drawVertices(r.vertices, r.bmode, r.paint)); 1304204da25aa4c6e0b321314aa32fd9affb4865563Mike ReedDRAW(DrawShadowRec, private_draw_shadow_rec(r.path, r.rec)); 131da574d17f864ed70323a1c0fc6e4e969153a4c98mtkleinDRAW(DrawAnnotation, drawAnnotation(r.rect, r.key.c_str(), r.value.get())); 13273b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.org#undef DRAW 13373b55eb7d789549ee9d6602ed96d2d9b74f3c6e3commit-bot@chromium.org 1346be2aa9a251bf6022570a03140f956655b3ef1dareedtemplate <> void Draw::draw(const DrawDrawable& r) { 1356be2aa9a251bf6022570a03140f956655b3ef1dareed SkASSERT(r.index >= 0); 1366be2aa9a251bf6022570a03140f956655b3ef1dareed SkASSERT(r.index < fDrawableCount); 1371bdfd3f4f09e47364f76d3f08177b1ce844ac786reed if (fDrawables) { 13896fcdcc219d2a0d3579719b84b28bede76efba64halcanary SkASSERT(nullptr == fDrawablePicts); 139a8db72864a43ad1fbba3c2892cf5cd88060a43efreed fCanvas->drawDrawable(fDrawables[r.index], r.matrix); 1401bdfd3f4f09e47364f76d3f08177b1ce844ac786reed } else { 14196fcdcc219d2a0d3579719b84b28bede76efba64halcanary fCanvas->drawPicture(fDrawablePicts[r.index], r.matrix, nullptr); 1421bdfd3f4f09e47364f76d3f08177b1ce844ac786reed } 1436be2aa9a251bf6022570a03140f956655b3ef1dareed} 1446be2aa9a251bf6022570a03140f956655b3ef1dareed 1455ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein// This is an SkRecord visitor that fills an SkBBoxHierarchy. 146828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// 147828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// The interesting part here is how to calculate bounds for ops which don't 148828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// have intrinsic bounds. What is the bounds of a Save or a Translate? 149828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// 150828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// We answer this by thinking about a particular definition of bounds: if I 151828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// don't execute this op, pixels in this rectangle might draw incorrectly. So 152828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// the bounds of a Save, a Translate, a Restore, etc. are the union of the 153828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// bounds of Draw* ops that they might have an effect on. For any given 154828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// Save/Restore block, the bounds of the Save, the Restore, and any other 155828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// non-drawing ("control") ops inside are exactly the union of the bounds of 156828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// the drawing ops inside that block. 157828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// 158828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// To implement this, we keep a stack of active Save blocks. As we consume ops 159828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// inside the Save/Restore block, drawing ops are unioned with the bounds of 160828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// the block, and control ops are stashed away for later. When we finish the 161828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// block with a Restore, our bounds are complete, and we go back and fill them 162828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein// in for all the control ops we stashed away. 1635ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtkleinclass FillBounds : SkNoncopyable { 1645ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtkleinpublic: 16540732b34a1bf94eb44ee4b2327eece8d97735f11mtklein FillBounds(const SkRect& cullRect, const SkRecord& record, SkRect bounds[]) 1664e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips : fNumRecords(record.count()) 1674e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips , fCullRect(cullRect) 16840732b34a1bf94eb44ee4b2327eece8d97735f11mtklein , fBounds(bounds) { 169e9d2052e4931eeade49042a855b9c1f5ab7c84c5mtklein fCTM = SkMatrix::I(); 1704d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips fCurrentClipBounds = fCullRect; 1714e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips } 172828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein 17340732b34a1bf94eb44ee4b2327eece8d97735f11mtklein void cleanUp() { 174828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein // If we have any lingering unpaired Saves, simulate restores to make 175828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein // sure all ops in those Save blocks have their bounds calculated. 176828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein while (!fSaveStack.isEmpty()) { 177828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein this->popSaveBlock(); 178828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein } 179828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein 180828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein // Any control ops not part of any Save/Restore block draw everywhere. 181828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein while (!fControlIndices.isEmpty()) { 1824d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips this->popControl(fCullRect); 183828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein } 184828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein } 1855ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein 18640732b34a1bf94eb44ee4b2327eece8d97735f11mtklein void setCurrentOp(int currentOp) { fCurrentOp = currentOp; } 18740732b34a1bf94eb44ee4b2327eece8d97735f11mtklein 18840732b34a1bf94eb44ee4b2327eece8d97735f11mtklein 189a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein template <typename T> void operator()(const T& op) { 190a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein this->updateCTM(op); 191a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein this->updateClipBounds(op); 192a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein this->trackBounds(op); 1935ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein } 1945ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein 195533eb782edaa0b6fece6166d3001edf72ec39f11mtklein // In this file, SkRect are in local coordinates, Bounds are translated back to identity space. 196533eb782edaa0b6fece6166d3001edf72ec39f11mtklein typedef SkRect Bounds; 197533eb782edaa0b6fece6166d3001edf72ec39f11mtklein 198c6ad06acefa096716f8dabed5342f9b89dc43dfemtklein int currentOp() const { return fCurrentOp; } 199e9d2052e4931eeade49042a855b9c1f5ab7c84c5mtklein const SkMatrix& ctm() const { return fCTM; } 200c6ad06acefa096716f8dabed5342f9b89dc43dfemtklein const Bounds& getBounds(int index) const { return fBounds[index]; } 2014e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips 2024e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips // Adjust rect for all paints that may affect its geometry, then map it to identity space. 2034e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips Bounds adjustAndMap(SkRect rect, const SkPaint* paint) const { 2044e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips // Inverted rectangles really confuse our BBHs. 2054e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips rect.sort(); 2064e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips 2074e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips // Adjust the rect for its own paint. 2084e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips if (!AdjustForPaint(paint, &rect)) { 2094e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips // The paint could do anything to our bounds. The only safe answer is the current clip. 2104e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips return fCurrentClipBounds; 2114e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips } 2124e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips 2134e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips // Adjust rect for all the paints from the SaveLayers we're inside. 2144e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips if (!this->adjustForSaveLayerPaints(&rect)) { 2154e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips // Same deal as above. 2164e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips return fCurrentClipBounds; 2174e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips } 2184e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips 2194e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips // Map the rect back to identity space. 220e9d2052e4931eeade49042a855b9c1f5ab7c84c5mtklein fCTM.mapRect(&rect); 2214e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips 2224e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips // Nothing can draw outside the current clip. 223c187a3c8849ba5e409f79ead21cd5bc82173d9f8robertphillips if (!rect.intersect(fCurrentClipBounds)) { 224c187a3c8849ba5e409f79ead21cd5bc82173d9f8robertphillips return Bounds::MakeEmpty(); 225c187a3c8849ba5e409f79ead21cd5bc82173d9f8robertphillips } 226c187a3c8849ba5e409f79ead21cd5bc82173d9f8robertphillips 2274e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips return rect; 2284e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips } 2294e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips 2304e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillipsprivate: 231828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein struct SaveBounds { 232a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein int controlOps; // Number of control ops in this Save block, including the Save. 233533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds bounds; // Bounds of everything in the block. 234a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein const SkPaint* paint; // Unowned. If set, adjusts the bounds of all ops in this block. 235db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco SkMatrix ctm; 236828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein }; 237828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein 238cbdf007bc2eb85056a1a5c75c088202becba2d16mtklein // Only Restore, SetMatrix, Concat, and Translate change the CTM. 2398e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein template <typename T> void updateCTM(const T&) {} 240e9d2052e4931eeade49042a855b9c1f5ab7c84c5mtklein void updateCTM(const Restore& op) { fCTM = op.matrix; } 241e9d2052e4931eeade49042a855b9c1f5ab7c84c5mtklein void updateCTM(const SetMatrix& op) { fCTM = op.matrix; } 242e9d2052e4931eeade49042a855b9c1f5ab7c84c5mtklein void updateCTM(const Concat& op) { fCTM.preConcat(op.matrix); } 243cbdf007bc2eb85056a1a5c75c088202becba2d16mtklein void updateCTM(const Translate& op) { fCTM.preTranslate(op.dx, op.dy); } 244a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein 2458e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein // Most ops don't change the clip. 2468e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein template <typename T> void updateClipBounds(const T&) {} 247271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein 2488e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein // Clip{Path,RRect,Rect,Region} obviously change the clip. They all know their bounds already. 2498e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein void updateClipBounds(const ClipPath& op) { this->updateClipBoundsForClipOp(op.devBounds); } 2508e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein void updateClipBounds(const ClipRRect& op) { this->updateClipBoundsForClipOp(op.devBounds); } 2518e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein void updateClipBounds(const ClipRect& op) { this->updateClipBoundsForClipOp(op.devBounds); } 2528e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein void updateClipBounds(const ClipRegion& op) { this->updateClipBoundsForClipOp(op.devBounds); } 253271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein 2548e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein // The bounds of clip ops need to be adjusted for the paints of saveLayers they're inside. 2558e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein void updateClipBoundsForClipOp(const SkIRect& devBounds) { 2568e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein Bounds clip = SkRect::Make(devBounds); 257271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein // We don't call adjustAndMap() because as its last step it would intersect the adjusted 258271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein // clip bounds with the previous clip, exactly what we can't do when the clip grows. 25923d8593f8127411d9d687b4565b34b4ecd6b11d3schenney if (this->adjustForSaveLayerPaints(&clip)) { 26023d8593f8127411d9d687b4565b34b4ecd6b11d3schenney fCurrentClipBounds = clip.intersect(fCullRect) ? clip : Bounds::MakeEmpty(); 26123d8593f8127411d9d687b4565b34b4ecd6b11d3schenney } else { 26223d8593f8127411d9d687b4565b34b4ecd6b11d3schenney fCurrentClipBounds = fCullRect; 26323d8593f8127411d9d687b4565b34b4ecd6b11d3schenney } 264271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein } 265271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein 2668e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein // Restore holds the devBounds for the clip after the {save,saveLayer}/restore block completes. 2678e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein void updateClipBounds(const Restore& op) { 2688e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein // This is just like the clip ops above, but we need to skip the effects (if any) of our 2698e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein // paired saveLayer (if it is one); it has not yet been popped off the save stack. Our 2708e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein // devBounds reflect the state of the world after the saveLayer/restore block is done, 2718e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein // so they are not affected by the saveLayer's paint. 2728e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein const int kSavesToIgnore = 1; 2738e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein Bounds clip = SkRect::Make(op.devBounds); 27423d8593f8127411d9d687b4565b34b4ecd6b11d3schenney if (this->adjustForSaveLayerPaints(&clip, kSavesToIgnore)) { 27523d8593f8127411d9d687b4565b34b4ecd6b11d3schenney fCurrentClipBounds = clip.intersect(fCullRect) ? clip : Bounds::MakeEmpty(); 27623d8593f8127411d9d687b4565b34b4ecd6b11d3schenney } else { 27723d8593f8127411d9d687b4565b34b4ecd6b11d3schenney fCurrentClipBounds = fCullRect; 27823d8593f8127411d9d687b4565b34b4ecd6b11d3schenney } 2798e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein } 2808e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein 281271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein // We also take advantage of SaveLayer bounds when present to further cut the clip down. 282a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein void updateClipBounds(const SaveLayer& op) { 283a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein if (op.bounds) { 284271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein // adjustAndMap() intersects these layer bounds with the previous clip for us. 285271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein fCurrentClipBounds = this->adjustAndMap(*op.bounds, op.paint); 286a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein } 287a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein } 2886cfa73a29a26edf1d03bca224ad6860396308ffcmtklein 289828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein // The bounds of these ops must be calculated when we hit the Restore 290828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein // from the bounds of the ops in the same Save block. 29196fcdcc219d2a0d3579719b84b28bede76efba64halcanary void trackBounds(const Save&) { this->pushSaveBlock(nullptr); } 292a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein void trackBounds(const SaveLayer& op) { this->pushSaveBlock(op.paint); } 293a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein void trackBounds(const Restore&) { fBounds[fCurrentOp] = this->popSaveBlock(); } 294828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein 29568199a2d5f0cd0b9577b9695b9e095e720e96950mtklein void trackBounds(const SetMatrix&) { this->pushControl(); } 296e9d2052e4931eeade49042a855b9c1f5ab7c84c5mtklein void trackBounds(const Concat&) { this->pushControl(); } 297cbdf007bc2eb85056a1a5c75c088202becba2d16mtklein void trackBounds(const Translate&) { this->pushControl(); } 29868199a2d5f0cd0b9577b9695b9e095e720e96950mtklein void trackBounds(const ClipRect&) { this->pushControl(); } 29968199a2d5f0cd0b9577b9695b9e095e720e96950mtklein void trackBounds(const ClipRRect&) { this->pushControl(); } 30068199a2d5f0cd0b9577b9695b9e095e720e96950mtklein void trackBounds(const ClipPath&) { this->pushControl(); } 30168199a2d5f0cd0b9577b9695b9e095e720e96950mtklein void trackBounds(const ClipRegion&) { this->pushControl(); } 302828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein 303e5de130788c8637d2f7df9ddb0241b78e04d5882vjiaoblack 304828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein // For all other ops, we can calculate and store the bounds directly now. 305828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein template <typename T> void trackBounds(const T& op) { 306828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein fBounds[fCurrentOp] = this->bounds(op); 307828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein this->updateSaveBounds(fBounds[fCurrentOp]); 308828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein } 309828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein 310a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein void pushSaveBlock(const SkPaint* paint) { 311828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein // Starting a new Save block. Push a new entry to represent that. 3124d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips SaveBounds sb; 3134d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips sb.controlOps = 0; 3144d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips // If the paint affects transparent black, the bound shouldn't be smaller 3154d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips // than the current clip bounds. 3164d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips sb.bounds = 3174d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips PaintMayAffectTransparentBlack(paint) ? fCurrentClipBounds : Bounds::MakeEmpty(); 3184d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips sb.paint = paint; 319db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco sb.ctm = this->fCTM; 3204d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips 321828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein fSaveStack.push(sb); 322828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein this->pushControl(); 323828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein } 324828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein 325d910f544439fffa6c2bcc5181b79b2811a4c130amtklein static bool PaintMayAffectTransparentBlack(const SkPaint* paint) { 326327f905d2cb0d37c302d651d8f2b17ea56368467dneto if (paint) { 327327f905d2cb0d37c302d651d8f2b17ea56368467dneto // FIXME: this is very conservative 328327f905d2cb0d37c302d651d8f2b17ea56368467dneto if (paint->getImageFilter() || paint->getColorFilter()) { 329327f905d2cb0d37c302d651d8f2b17ea56368467dneto return true; 330327f905d2cb0d37c302d651d8f2b17ea56368467dneto } 331327f905d2cb0d37c302d651d8f2b17ea56368467dneto 332374772bd61951f01bf84fe17bf53d8867681c9aereed // Unusual blendmodes require us to process a saved layer 333327f905d2cb0d37c302d651d8f2b17ea56368467dneto // even with operations outisde the clip. 334327f905d2cb0d37c302d651d8f2b17ea56368467dneto // For example, DstIn is used by masking layers. 335327f905d2cb0d37c302d651d8f2b17ea56368467dneto // https://code.google.com/p/skia/issues/detail?id=1291 336327f905d2cb0d37c302d651d8f2b17ea56368467dneto // https://crbug.com/401593 337374772bd61951f01bf84fe17bf53d8867681c9aereed switch (paint->getBlendMode()) { 338374772bd61951f01bf84fe17bf53d8867681c9aereed // For each of the following transfer modes, if the source 339374772bd61951f01bf84fe17bf53d8867681c9aereed // alpha is zero (our transparent black), the resulting 340374772bd61951f01bf84fe17bf53d8867681c9aereed // blended alpha is not necessarily equal to the original 341374772bd61951f01bf84fe17bf53d8867681c9aereed // destination alpha. 342374772bd61951f01bf84fe17bf53d8867681c9aereed case SkBlendMode::kClear: 343374772bd61951f01bf84fe17bf53d8867681c9aereed case SkBlendMode::kSrc: 344374772bd61951f01bf84fe17bf53d8867681c9aereed case SkBlendMode::kSrcIn: 345374772bd61951f01bf84fe17bf53d8867681c9aereed case SkBlendMode::kDstIn: 346374772bd61951f01bf84fe17bf53d8867681c9aereed case SkBlendMode::kSrcOut: 347374772bd61951f01bf84fe17bf53d8867681c9aereed case SkBlendMode::kDstATop: 348374772bd61951f01bf84fe17bf53d8867681c9aereed case SkBlendMode::kModulate: 349374772bd61951f01bf84fe17bf53d8867681c9aereed return true; 350374772bd61951f01bf84fe17bf53d8867681c9aereed break; 351374772bd61951f01bf84fe17bf53d8867681c9aereed default: 352374772bd61951f01bf84fe17bf53d8867681c9aereed break; 353327f905d2cb0d37c302d651d8f2b17ea56368467dneto } 354327f905d2cb0d37c302d651d8f2b17ea56368467dneto } 355327f905d2cb0d37c302d651d8f2b17ea56368467dneto return false; 356d910f544439fffa6c2bcc5181b79b2811a4c130amtklein } 357d910f544439fffa6c2bcc5181b79b2811a4c130amtklein 358533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds popSaveBlock() { 359828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein // We're done the Save block. Apply the block's bounds to all control ops inside it. 360828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein SaveBounds sb; 361828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein fSaveStack.pop(&sb); 362d910f544439fffa6c2bcc5181b79b2811a4c130amtklein 363828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein while (sb.controlOps --> 0) { 3644d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips this->popControl(sb.bounds); 365828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein } 366828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein 367828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein // This whole Save block may be part another Save block. 3684d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips this->updateSaveBounds(sb.bounds); 369828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein 370828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein // If called from a real Restore (not a phony one for balance), it'll need the bounds. 3714d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips return sb.bounds; 372828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein } 373828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein 374828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein void pushControl() { 375828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein fControlIndices.push(fCurrentOp); 376828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein if (!fSaveStack.isEmpty()) { 377828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein fSaveStack.top().controlOps++; 378828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein } 3795ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein } 3805ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein 381533eb782edaa0b6fece6166d3001edf72ec39f11mtklein void popControl(const Bounds& bounds) { 382828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein fBounds[fControlIndices.top()] = bounds; 383828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein fControlIndices.pop(); 384828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein } 385828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein 386533eb782edaa0b6fece6166d3001edf72ec39f11mtklein void updateSaveBounds(const Bounds& bounds) { 387828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein // If we're in a Save block, expand its bounds to cover these bounds too. 388828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein if (!fSaveStack.isEmpty()) { 389828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein fSaveStack.top().bounds.join(bounds); 390828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein } 391828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein } 392828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein 3937cc49d65fc5788f72458efc8fc4156cde4cca15aMike Klein Bounds bounds(const Flush&) const { return fCurrentClipBounds; } 3947cc49d65fc5788f72458efc8fc4156cde4cca15aMike Klein 395131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein // FIXME: this method could use better bounds 396533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds bounds(const DrawText&) const { return fCurrentClipBounds; } 397131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein 398533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds bounds(const DrawPaint&) const { return fCurrentClipBounds; } 399533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds bounds(const NoOp&) const { return Bounds::MakeEmpty(); } // NoOps don't draw. 400a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein 401533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds bounds(const DrawRect& op) const { return this->adjustAndMap(op.rect, &op.paint); } 40244df651ebefc284acc2f66425dff3ea0b0e14b36msarett Bounds bounds(const DrawRegion& op) const { 40344df651ebefc284acc2f66425dff3ea0b0e14b36msarett SkRect rect = SkRect::Make(op.region.getBounds()); 40444df651ebefc284acc2f66425dff3ea0b0e14b36msarett return this->adjustAndMap(rect, &op.paint); 40544df651ebefc284acc2f66425dff3ea0b0e14b36msarett } 406533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds bounds(const DrawOval& op) const { return this->adjustAndMap(op.oval, &op.paint); } 407ac3aa245acc7b469aa2f0d0078e53401d78ac8b9bsalomon // Tighter arc bounds? 408ac3aa245acc7b469aa2f0d0078e53401d78ac8b9bsalomon Bounds bounds(const DrawArc& op) const { return this->adjustAndMap(op.oval, &op.paint); } 409533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds bounds(const DrawRRect& op) const { 41062b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein return this->adjustAndMap(op.rrect.rect(), &op.paint); 41162b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein } 412533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds bounds(const DrawDRRect& op) const { 41362b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein return this->adjustAndMap(op.outer.rect(), &op.paint); 41462b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein } 41565151754b9fdb6a968d7307764c20655d1b680a0piotaixr Bounds bounds(const DrawImage& op) const { 416da574d17f864ed70323a1c0fc6e4e969153a4c98mtklein const SkImage* image = op.image.get(); 41765151754b9fdb6a968d7307764c20655d1b680a0piotaixr SkRect rect = SkRect::MakeXYWH(op.left, op.top, image->width(), image->height()); 41862b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein 41965151754b9fdb6a968d7307764c20655d1b680a0piotaixr return this->adjustAndMap(rect, op.paint); 42065151754b9fdb6a968d7307764c20655d1b680a0piotaixr } 421c573a40ed5024b463e47088d307e3164a486dba5msarett Bounds bounds(const DrawImageLattice& op) const { 422c573a40ed5024b463e47088d307e3164a486dba5msarett return this->adjustAndMap(op.dst, op.paint); 423c573a40ed5024b463e47088d307e3164a486dba5msarett } 42465151754b9fdb6a968d7307764c20655d1b680a0piotaixr Bounds bounds(const DrawImageRect& op) const { 42565151754b9fdb6a968d7307764c20655d1b680a0piotaixr return this->adjustAndMap(op.dst, op.paint); 42665151754b9fdb6a968d7307764c20655d1b680a0piotaixr } 4274c21dc5ddf3b482293ed34eead876d8d61a662c3reed Bounds bounds(const DrawImageNine& op) const { 4284c21dc5ddf3b482293ed34eead876d8d61a662c3reed return this->adjustAndMap(op.dst, op.paint); 4294c21dc5ddf3b482293ed34eead876d8d61a662c3reed } 430533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds bounds(const DrawPath& op) const { 43162b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein return op.path.isInverseFillType() ? fCurrentClipBounds 43262b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein : this->adjustAndMap(op.path.getBounds(), &op.paint); 43362b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein } 434533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds bounds(const DrawPoints& op) const { 43562b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein SkRect dst; 43662b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein dst.set(op.pts, op.count); 43762b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein 43862b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein // Pad the bounding box a little to make sure hairline points' bounds aren't empty. 43962b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein SkScalar stroke = SkMaxScalar(op.paint.getStrokeWidth(), 0.01f); 44062b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein dst.outset(stroke/2, stroke/2); 44162b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein 44262b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein return this->adjustAndMap(dst, &op.paint); 44362b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein } 444533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds bounds(const DrawPatch& op) const { 445131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein SkRect dst; 446131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein dst.set(op.cubics, SkPatchUtils::kNumCtrlPts); 447131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein return this->adjustAndMap(dst, &op.paint); 448131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein } 449533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds bounds(const DrawVertices& op) const { 450e88a1cb20e6b4c9f099070112225a88693a4630bMike Reed return this->adjustAndMap(op.vertices->bounds(), &op.paint); 451131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein } 45264b4c789fd1721d6804ccb5a9ceae39df03a5711mtklein 45371c3c760a83123ee0b3127b8c65c6394ce541c50reed Bounds bounds(const DrawAtlas& op) const { 45471c3c760a83123ee0b3127b8c65c6394ce541c50reed if (op.cull) { 45545561a0b15fe045ba272c328684c3f7ae290785areed // TODO: <reed> can we pass nullptr for the paint? Isn't cull already "correct" 45645561a0b15fe045ba272c328684c3f7ae290785areed // for the paint (by the caller)? 45771c3c760a83123ee0b3127b8c65c6394ce541c50reed return this->adjustAndMap(*op.cull, op.paint); 45871c3c760a83123ee0b3127b8c65c6394ce541c50reed } else { 45971c3c760a83123ee0b3127b8c65c6394ce541c50reed return fCurrentClipBounds; 46071c3c760a83123ee0b3127b8c65c6394ce541c50reed } 46171c3c760a83123ee0b3127b8c65c6394ce541c50reed } 46264b4c789fd1721d6804ccb5a9ceae39df03a5711mtklein 4634204da25aa4c6e0b321314aa32fd9affb4865563Mike Reed Bounds bounds(const DrawShadowRec& op) const { 4641af03d4396a9567e3ca127830676eb4fd5a76266Jim Van Verth SkRect bounds; 4651af03d4396a9567e3ca127830676eb4fd5a76266Jim Van Verth SkDrawShadowMetrics::GetLocalBounds(op.path, op.rec, fCTM, &bounds); 4661af03d4396a9567e3ca127830676eb4fd5a76266Jim Van Verth return this->adjustAndMap(bounds, nullptr); 4674204da25aa4c6e0b321314aa32fd9affb4865563Mike Reed } 4684204da25aa4c6e0b321314aa32fd9affb4865563Mike Reed 469533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds bounds(const DrawPicture& op) const { 470a8d7f0b13cd4c6d773fcf055fe17db75d260fa05robertphillips SkRect dst = op.picture->cullRect(); 471af57903f330a0afd0c10244d4a66f64fdbef5d1emtklein op.matrix.mapRect(&dst); 472131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein return this->adjustAndMap(dst, op.paint); 473131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein } 47462b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein 475533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds bounds(const DrawPosText& op) const { 47662b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein const int N = op.paint.countText(op.text, op.byteLength); 47762b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein if (N == 0) { 478533eb782edaa0b6fece6166d3001edf72ec39f11mtklein return Bounds::MakeEmpty(); 47962b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein } 48062b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein 48162b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein SkRect dst; 482937c9c7eb4e06d4d3bc495e129c7b8103a5d6c0fmtklein dst.set(op.pos, N); 48362b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein AdjustTextForFontMetrics(&dst, op.paint); 48462b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein return this->adjustAndMap(dst, &op.paint); 48562b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein } 486533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds bounds(const DrawPosTextH& op) const { 48762b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein const int N = op.paint.countText(op.text, op.byteLength); 48862b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein if (N == 0) { 489533eb782edaa0b6fece6166d3001edf72ec39f11mtklein return Bounds::MakeEmpty(); 49062b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein } 49162b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein 49262b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein SkScalar left = op.xpos[0], right = op.xpos[0]; 49362b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein for (int i = 1; i < N; i++) { 49462b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein left = SkMinScalar(left, op.xpos[i]); 49562b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein right = SkMaxScalar(right, op.xpos[i]); 49662b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein } 49762b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein SkRect dst = { left, op.y, right, op.y }; 49862b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein AdjustTextForFontMetrics(&dst, op.paint); 49962b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein return this->adjustAndMap(dst, &op.paint); 50062b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein } 501533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds bounds(const DrawTextOnPath& op) const { 502131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein SkRect dst = op.path.getBounds(); 503131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein 5049a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein // Pad all sides by the maximum padding in any direction we'd normally apply. 505131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein SkRect pad = { 0, 0, 0, 0}; 506131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein AdjustTextForFontMetrics(&pad, op.paint); 5079a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein 5089a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein // That maximum padding happens to always be the right pad today. 5099a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein SkASSERT(pad.fLeft == -pad.fRight); 5109a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein SkASSERT(pad.fTop == -pad.fBottom); 5119a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein SkASSERT(pad.fRight > pad.fBottom); 5129a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein dst.outset(pad.fRight, pad.fRight); 5139a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein 514131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein return this->adjustAndMap(dst, &op.paint); 515131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein } 516131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein 51745561a0b15fe045ba272c328684c3f7ae290785areed Bounds bounds(const DrawTextRSXform& op) const { 51845561a0b15fe045ba272c328684c3f7ae290785areed if (op.cull) { 51945561a0b15fe045ba272c328684c3f7ae290785areed return this->adjustAndMap(*op.cull, nullptr); 52045561a0b15fe045ba272c328684c3f7ae290785areed } else { 52145561a0b15fe045ba272c328684c3f7ae290785areed return fCurrentClipBounds; 52245561a0b15fe045ba272c328684c3f7ae290785areed } 52345561a0b15fe045ba272c328684c3f7ae290785areed } 52445561a0b15fe045ba272c328684c3f7ae290785areed 525533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds bounds(const DrawTextBlob& op) const { 526131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein SkRect dst = op.blob->bounds(); 527131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein dst.offset(op.x, op.y); 528131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein return this->adjustAndMap(dst, &op.paint); 529131a22b2a22e4656f2351d42785fc3dee7a98fe2mtklein } 53062b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein 5316be2aa9a251bf6022570a03140f956655b3ef1dareed Bounds bounds(const DrawDrawable& op) const { 53296fcdcc219d2a0d3579719b84b28bede76efba64halcanary return this->adjustAndMap(op.worstCaseBounds, nullptr); 5336be2aa9a251bf6022570a03140f956655b3ef1dareed } 5346be2aa9a251bf6022570a03140f956655b3ef1dareed 535f70b531daaf47db1ee95c70da9843f1dd1f418d3reed Bounds bounds(const DrawAnnotation& op) const { 536f70b531daaf47db1ee95c70da9843f1dd1f418d3reed return this->adjustAndMap(op.rect, nullptr); 537f70b531daaf47db1ee95c70da9843f1dd1f418d3reed } 538343a63d082bda969d7e8a4e09ba850e931185269mtklein 53962b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein static void AdjustTextForFontMetrics(SkRect* rect, const SkPaint& paint) { 5409a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein#ifdef SK_DEBUG 5419a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein SkRect correct = *rect; 5429a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein#endif 5439a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein // crbug.com/373785 ~~> xPad = 4x yPad 5449a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein // crbug.com/424824 ~~> bump yPad from 2x text size to 2.5x 5459a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein const SkScalar yPad = 2.5f * paint.getTextSize(), 5469a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein xPad = 4.0f * yPad; 5479a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein rect->outset(xPad, yPad); 5489a657fa0b493ae43ed35ae04a686c5402d701420caryclark#ifdef SK_DEBUG 54962b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein SkPaint::FontMetrics metrics; 55062b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein paint.getFontMetrics(&metrics); 5519a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein correct.fLeft += metrics.fXMin; 5529a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein correct.fTop += metrics.fTop; 5539a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein correct.fRight += metrics.fXMax; 5549a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein correct.fBottom += metrics.fBottom; 555d13291a5a3d2a79b5348ecc4a8e38ab1b6da85f0mtklein // See skia:2862 for why we ignore small text sizes. 5569a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein SkASSERTF(paint.getTextSize() < 0.001f || rect->contains(correct), 557ed167acb7b494bf0aece05ac8a68b560782b027cmtklein "%f %f %f %f vs. %f %f %f %f\n", 5589a5380dd358a9c559a41beef7cb368cd7f0ca51fmtklein -xPad, -yPad, +xPad, +yPad, 559ed167acb7b494bf0aece05ac8a68b560782b027cmtklein metrics.fXMin, metrics.fTop, metrics.fXMax, metrics.fBottom); 560a19afb418027800c245ad19d651d8cf2071c9d70mtklein#endif 56162b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein } 56262b67ae96e94fd22569b058a3bc4625b9f52ed56mtklein 563479601b9a74b5b8e424ed3d68882e161617bdcebmtklein // Returns true if rect was meaningfully adjusted for the effects of paint, 564479601b9a74b5b8e424ed3d68882e161617bdcebmtklein // false if the paint could affect the rect in unknown ways. 565479601b9a74b5b8e424ed3d68882e161617bdcebmtklein static bool AdjustForPaint(const SkPaint* paint, SkRect* rect) { 566a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein if (paint) { 567a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein if (paint->canComputeFastBounds()) { 568479601b9a74b5b8e424ed3d68882e161617bdcebmtklein *rect = paint->computeFastBounds(*rect, rect); 569479601b9a74b5b8e424ed3d68882e161617bdcebmtklein return true; 570a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein } 571479601b9a74b5b8e424ed3d68882e161617bdcebmtklein return false; 572479601b9a74b5b8e424ed3d68882e161617bdcebmtklein } 573479601b9a74b5b8e424ed3d68882e161617bdcebmtklein return true; 574479601b9a74b5b8e424ed3d68882e161617bdcebmtklein } 575479601b9a74b5b8e424ed3d68882e161617bdcebmtklein 5768e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein bool adjustForSaveLayerPaints(SkRect* rect, int savesToIgnore = 0) const { 5778e393bf70ea2aab9ca31f52c15b518436c7b6055mtklein for (int i = fSaveStack.count() - 1 - savesToIgnore; i >= 0; i--) { 578db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco SkMatrix inverse; 579db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco if (!fSaveStack[i].ctm.invert(&inverse)) { 580db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco return false; 581db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco } 582db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco inverse.mapRect(rect); 583271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein if (!AdjustForPaint(fSaveStack[i].paint, rect)) { 584271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein return false; 585271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein } 586db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco fSaveStack[i].ctm.mapRect(rect); 587271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein } 588271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein return true; 589271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein } 590271a030f5d0d3c59715fbeffb31c761279f3f8caMike Klein 591c6ad06acefa096716f8dabed5342f9b89dc43dfemtklein const int fNumRecords; 592a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein 5934d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips // We do not guarantee anything for operations outside of the cull rect 5944d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips const SkRect fCullRect; 5954d52afef5cf90a2fed3bb69db71675c6450ab397robertphillips 596533eb782edaa0b6fece6166d3001edf72ec39f11mtklein // Conservative identity-space bounds for each op in the SkRecord. 59740732b34a1bf94eb44ee4b2327eece8d97735f11mtklein Bounds* fBounds; 598a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein 599a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein // We walk fCurrentOp through the SkRecord, as we go using updateCTM() 600a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein // and updateClipBounds() to maintain the exact CTM (fCTM) and conservative 601533eb782edaa0b6fece6166d3001edf72ec39f11mtklein // identity-space bounds of the current clip (fCurrentClipBounds). 602c6ad06acefa096716f8dabed5342f9b89dc43dfemtklein int fCurrentOp; 603e9d2052e4931eeade49042a855b9c1f5ab7c84c5mtklein SkMatrix fCTM; 604533eb782edaa0b6fece6166d3001edf72ec39f11mtklein Bounds fCurrentClipBounds; 605a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein 606a723b576aed31a6eb2bdda6388e6bd779d04c6b0mtklein // Used to track the bounds of Save/Restore blocks and the control ops inside them. 607828ce1f34b3471c108aee6ac2c39ddb90d0be11emtklein SkTDArray<SaveBounds> fSaveStack; 608c6ad06acefa096716f8dabed5342f9b89dc43dfemtklein SkTDArray<int> fControlIndices; 6095ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein}; 6105ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein 61127f6b0d013572184dc980462cce8d0f3caec1c8ecommit-bot@chromium.org} // namespace SkRecords 6125ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein 61340732b34a1bf94eb44ee4b2327eece8d97735f11mtkleinvoid SkRecordFillBounds(const SkRect& cullRect, const SkRecord& record, SkRect bounds[]) { 61440732b34a1bf94eb44ee4b2327eece8d97735f11mtklein SkRecords::FillBounds visitor(cullRect, record, bounds); 615c6ad06acefa096716f8dabed5342f9b89dc43dfemtklein for (int curOp = 0; curOp < record.count(); curOp++) { 6164e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips visitor.setCurrentOp(curOp); 617343a63d082bda969d7e8a4e09ba850e931185269mtklein record.visit(curOp, visitor); 6184e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips } 61940732b34a1bf94eb44ee4b2327eece8d97735f11mtklein visitor.cleanUp(); 6205ad6ee1b2ce54f8e59b9f5a337c688a98a4b0f2amtklein} 6214e8e3421aa919a82eb1dd287fecbd079f5a320b4robertphillips 622