19f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com
29f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com/*
39f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com * Copyright 2012 Google Inc.
49f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com *
59f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com * Use of this source code is governed by a BSD-style license that can be
69f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com * found in the LICENSE file.
79f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com */
89f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com
99f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com#include "SkBBoxHierarchyRecord.h"
109f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com#include "SkPictureStateTree.h"
119f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com
120bdbea75ff1a6f3c313c18cab0139728967cb93erobertphillipsSkBBoxHierarchyRecord::SkBBoxHierarchyRecord(const SkISize& size,
1319fafef9784fe7c644540ffd0ee9f6da1914a038commit-bot@chromium.org                                             uint32_t recordFlags,
1419fafef9784fe7c644540ffd0ee9f6da1914a038commit-bot@chromium.org                                             SkBBoxHierarchy* h)
150bdbea75ff1a6f3c313c18cab0139728967cb93erobertphillips    : INHERITED(size, recordFlags) {
169f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com    fStateTree = SkNEW(SkPictureStateTree);
179f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com    fBoundingHierarchy = h;
189f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com    fBoundingHierarchy->ref();
194b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org    fBoundingHierarchy->setClient(this);
209f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com}
219f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com
229f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.comvoid SkBBoxHierarchyRecord::handleBBox(const SkRect& bounds) {
234469938e92d779dff05e745559e67907bbf21e78reed@google.com    SkPictureStateTree::Draw* draw = fStateTree->appendDraw(this->writeStream().bytesWritten());
24533eb782edaa0b6fece6166d3001edf72ec39f11mtklein    fBoundingHierarchy->insert(draw, bounds, true);
259f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com}
269f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com
275f6102d07982043542343ff0a6c67b1319ac9fc7Florin Malitavoid SkBBoxHierarchyRecord::willSave() {
289f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com    fStateTree->appendSave();
295f6102d07982043542343ff0a6c67b1319ac9fc7Florin Malita    this->INHERITED::willSave();
309f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com}
319f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com
32e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.orgSkCanvas::SaveLayerStrategy SkBBoxHierarchyRecord::willSaveLayer(const SkRect* bounds,
33e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org                                                                 const SkPaint* paint,
34e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org                                                                 SaveFlags flags) {
3568250c8e7c2bf5d669397c849259c3bcad40237esenorblanco@chromium.org    // For now, assume all filters affect transparent black.
3668250c8e7c2bf5d669397c849259c3bcad40237esenorblanco@chromium.org    // FIXME: This could be made less conservative as an optimization.
3749f085dddff10473b6ebf832a974288300224e60bsalomon    bool paintAffectsTransparentBlack = paint &&
3849f085dddff10473b6ebf832a974288300224e60bsalomon        ((paint->getImageFilter()) ||
3949f085dddff10473b6ebf832a974288300224e60bsalomon         (paint->getColorFilter()));
40327f905d2cb0d37c302d651d8f2b17ea56368467dneto    bool needToHandleBBox = paintAffectsTransparentBlack;
41327f905d2cb0d37c302d651d8f2b17ea56368467dneto    if (!needToHandleBBox && paint) {
42327f905d2cb0d37c302d651d8f2b17ea56368467dneto      // Unusual Xfermodes require us to process a saved layer
43327f905d2cb0d37c302d651d8f2b17ea56368467dneto      // even with operations outisde the clip.
44327f905d2cb0d37c302d651d8f2b17ea56368467dneto      // For example, DstIn is used by masking layers.
45327f905d2cb0d37c302d651d8f2b17ea56368467dneto      // https://code.google.com/p/skia/issues/detail?id=1291
46327f905d2cb0d37c302d651d8f2b17ea56368467dneto      SkXfermode* xfermode = paint->getXfermode();
47327f905d2cb0d37c302d651d8f2b17ea56368467dneto      SkXfermode::Mode mode;
48327f905d2cb0d37c302d651d8f2b17ea56368467dneto      // SrcOver is the common case with a NULL xfermode, so we should
49327f905d2cb0d37c302d651d8f2b17ea56368467dneto      // make that the fast path and bypass the mode extraction and test.
50327f905d2cb0d37c302d651d8f2b17ea56368467dneto      if (xfermode && xfermode->asMode(&mode)) {
51327f905d2cb0d37c302d651d8f2b17ea56368467dneto        switch (mode) {
52327f905d2cb0d37c302d651d8f2b17ea56368467dneto          case SkXfermode::kClear_Mode:
53327f905d2cb0d37c302d651d8f2b17ea56368467dneto          case SkXfermode::kSrc_Mode:
54327f905d2cb0d37c302d651d8f2b17ea56368467dneto          case SkXfermode::kSrcIn_Mode:
55327f905d2cb0d37c302d651d8f2b17ea56368467dneto          case SkXfermode::kDstIn_Mode:
56327f905d2cb0d37c302d651d8f2b17ea56368467dneto          case SkXfermode::kSrcOut_Mode:
57327f905d2cb0d37c302d651d8f2b17ea56368467dneto          case SkXfermode::kDstATop_Mode:
58327f905d2cb0d37c302d651d8f2b17ea56368467dneto          case SkXfermode::kModulate_Mode:
59327f905d2cb0d37c302d651d8f2b17ea56368467dneto            needToHandleBBox = true;
60327f905d2cb0d37c302d651d8f2b17ea56368467dneto            break;
61327f905d2cb0d37c302d651d8f2b17ea56368467dneto          default:
62327f905d2cb0d37c302d651d8f2b17ea56368467dneto            break;
63327f905d2cb0d37c302d651d8f2b17ea56368467dneto        }
64327f905d2cb0d37c302d651d8f2b17ea56368467dneto      }
65327f905d2cb0d37c302d651d8f2b17ea56368467dneto    }
66327f905d2cb0d37c302d651d8f2b17ea56368467dneto
6768250c8e7c2bf5d669397c849259c3bcad40237esenorblanco@chromium.org    SkRect drawBounds;
68327f905d2cb0d37c302d651d8f2b17ea56368467dneto    if (needToHandleBBox) {
69d910f544439fffa6c2bcc5181b79b2811a4c130amtklein        SkIRect deviceBounds;
70d910f544439fffa6c2bcc5181b79b2811a4c130amtklein        this->getClipDeviceBounds(&deviceBounds);
71d910f544439fffa6c2bcc5181b79b2811a4c130amtklein        drawBounds.set(deviceBounds);
7268250c8e7c2bf5d669397c849259c3bcad40237esenorblanco@chromium.org    }
734469938e92d779dff05e745559e67907bbf21e78reed@google.com    fStateTree->appendSaveLayer(this->writeStream().bytesWritten());
7468250c8e7c2bf5d669397c849259c3bcad40237esenorblanco@chromium.org    SkCanvas::SaveLayerStrategy strategy = this->INHERITED::willSaveLayer(bounds, paint, flags);
75327f905d2cb0d37c302d651d8f2b17ea56368467dneto    if (needToHandleBBox) {
7668250c8e7c2bf5d669397c849259c3bcad40237esenorblanco@chromium.org        this->handleBBox(drawBounds);
7768250c8e7c2bf5d669397c849259c3bcad40237esenorblanco@chromium.org        this->addNoOp();
7868250c8e7c2bf5d669397c849259c3bcad40237esenorblanco@chromium.org    }
7968250c8e7c2bf5d669397c849259c3bcad40237esenorblanco@chromium.org    return strategy;
809f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com}
819f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com
82e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.orgvoid SkBBoxHierarchyRecord::willRestore() {
839f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com    fStateTree->appendRestore();
84e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org    this->INHERITED::willRestore();
859f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com}
869f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com
8744c48d062f7996b5b46917e1b312a32ad101f326commit-bot@chromium.orgvoid SkBBoxHierarchyRecord::didConcat(const SkMatrix& matrix) {
889f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com    fStateTree->appendTransform(getTotalMatrix());
8944c48d062f7996b5b46917e1b312a32ad101f326commit-bot@chromium.org    INHERITED::didConcat(matrix);
909f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com}
919f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com
9244c48d062f7996b5b46917e1b312a32ad101f326commit-bot@chromium.orgvoid SkBBoxHierarchyRecord::didSetMatrix(const SkMatrix& matrix) {
939f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com    fStateTree->appendTransform(getTotalMatrix());
9444c48d062f7996b5b46917e1b312a32ad101f326commit-bot@chromium.org    INHERITED::didSetMatrix(matrix);
959f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com}
969f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com
978f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.comvoid SkBBoxHierarchyRecord::onClipRect(const SkRect& rect,
988f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com                                       SkRegion::Op op,
998f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com                                       ClipEdgeStyle edgeStyle) {
1004469938e92d779dff05e745559e67907bbf21e78reed@google.com    fStateTree->appendClip(this->writeStream().bytesWritten());
1018f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com    this->INHERITED::onClipRect(rect, op, edgeStyle);
1029f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com}
1039f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com
1048f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.comvoid SkBBoxHierarchyRecord::onClipRegion(const SkRegion& region,
1058f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com                                         SkRegion::Op op) {
1064469938e92d779dff05e745559e67907bbf21e78reed@google.com    fStateTree->appendClip(this->writeStream().bytesWritten());
1078f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com    this->INHERITED::onClipRegion(region, op);
1089f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com}
1099f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com
1108f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.comvoid SkBBoxHierarchyRecord::onClipPath(const SkPath& path,
1118f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com                                       SkRegion::Op op,
1128f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com                                       ClipEdgeStyle edgeStyle) {
1134469938e92d779dff05e745559e67907bbf21e78reed@google.com    fStateTree->appendClip(this->writeStream().bytesWritten());
1148f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com    this->INHERITED::onClipPath(path, op, edgeStyle);
1159f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com}
1169f5898d31b91500e09a70c7f70265a2d813b2534rileya@google.com
1178f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.comvoid SkBBoxHierarchyRecord::onClipRRect(const SkRRect& rrect,
1188f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com                                        SkRegion::Op op,
1198f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com                                        ClipEdgeStyle edgeStyle) {
1204469938e92d779dff05e745559e67907bbf21e78reed@google.com    fStateTree->appendClip(this->writeStream().bytesWritten());
1218f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com    this->INHERITED::onClipRRect(rrect, op, edgeStyle);
122675de168d8ec37958a40a3593bd86c631d810fecjunov@chromium.org}
1234b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org
1244b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.orgbool SkBBoxHierarchyRecord::shouldRewind(void* data) {
1254b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org    // SkBBoxHierarchy::rewindInserts is called by SkPicture after the
1264b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org    // SkPicture has rewound its command stream.  To match that rewind in the
1274b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org    // BBH, we rewind all draws that reference commands that were recorded
1284b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org    // past the point to which the SkPicture has rewound, which is given by
1294469938e92d779dff05e745559e67907bbf21e78reed@google.com    // writeStream().bytesWritten().
1304b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org    SkPictureStateTree::Draw* draw = static_cast<SkPictureStateTree::Draw*>(data);
1314469938e92d779dff05e745559e67907bbf21e78reed@google.com    return draw->fOffset >= writeStream().bytesWritten();
1324b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org}
133