3 * Copyright 2012 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
9 #include "SkBBoxHierarchyRecord.h"
10 #include "SkPictureStateTree.h"
12 SkBBoxHierarchyRecord::SkBBoxHierarchyRecord(const SkISize& size,
15 : INHERITED(size, recordFlags) {
16 fStateTree = SkNEW(SkPictureStateTree);
17 fBoundingHierarchy = h;
18 fBoundingHierarchy->ref();
19 fBoundingHierarchy->setClient(this);
22 void SkBBoxHierarchyRecord::handleBBox(const SkRect& bounds) {
23 SkPictureStateTree::Draw* draw = fStateTree->appendDraw(this->writeStream().bytesWritten());
24 fBoundingHierarchy->insert(draw, bounds, true);
27 void SkBBoxHierarchyRecord::willSave() {
28 fStateTree->appendSave();
29 this->INHERITED::willSave();
32 SkCanvas::SaveLayerStrategy SkBBoxHierarchyRecord::willSaveLayer(const SkRect* bounds,
35 // For now, assume all filters affect transparent black.
36 // FIXME: This could be made less conservative as an optimization.
37 bool paintAffectsTransparentBlack = paint &&
38 ((paint->getImageFilter()) ||
39 (paint->getColorFilter()));
40 bool needToHandleBBox = paintAffectsTransparentBlack;
41 if (!needToHandleBBox && paint) {
42 // Unusual Xfermodes require us to process a saved layer
43 // even with operations outisde the clip.
44 // For example, DstIn is used by masking layers.
45 // https://code.google.com/p/skia/issues/detail?id=1291
46 SkXfermode* xfermode = paint->getXfermode();
47 SkXfermode::Mode mode;
48 // SrcOver is the common case with a NULL xfermode, so we should
49 // make that the fast path and bypass the mode extraction and test.
50 if (xfermode && xfermode->asMode(&mode)) {
52 case SkXfermode::kClear_Mode:
53 case SkXfermode::kSrc_Mode:
54 case SkXfermode::kSrcIn_Mode:
55 case SkXfermode::kDstIn_Mode:
56 case SkXfermode::kSrcOut_Mode:
57 case SkXfermode::kDstATop_Mode:
58 case SkXfermode::kModulate_Mode:
59 needToHandleBBox = true;
68 if (needToHandleBBox) {
70 this->getClipDeviceBounds(&deviceBounds);
71 drawBounds.set(deviceBounds);
73 fStateTree->appendSaveLayer(this->writeStream().bytesWritten());
74 SkCanvas::SaveLayerStrategy strategy = this->INHERITED::willSaveLayer(bounds, paint, flags);
75 if (needToHandleBBox) {
76 this->handleBBox(drawBounds);
82 void SkBBoxHierarchyRecord::willRestore() {
83 fStateTree->appendRestore();
84 this->INHERITED::willRestore();
87 void SkBBoxHierarchyRecord::didConcat(const SkMatrix& matrix) {
88 fStateTree->appendTransform(getTotalMatrix());
89 INHERITED::didConcat(matrix);
92 void SkBBoxHierarchyRecord::didSetMatrix(const SkMatrix& matrix) {
93 fStateTree->appendTransform(getTotalMatrix());
94 INHERITED::didSetMatrix(matrix);
97 void SkBBoxHierarchyRecord::onClipRect(const SkRect& rect,
99 ClipEdgeStyle edgeStyle) {
100 fStateTree->appendClip(this->writeStream().bytesWritten());
101 this->INHERITED::onClipRect(rect, op, edgeStyle);
104 void SkBBoxHierarchyRecord::onClipRegion(const SkRegion& region,
106 fStateTree->appendClip(this->writeStream().bytesWritten());
107 this->INHERITED::onClipRegion(region, op);
110 void SkBBoxHierarchyRecord::onClipPath(const SkPath& path,
112 ClipEdgeStyle edgeStyle) {
113 fStateTree->appendClip(this->writeStream().bytesWritten());
114 this->INHERITED::onClipPath(path, op, edgeStyle);
117 void SkBBoxHierarchyRecord::onClipRRect(const SkRRect& rrect,
119 ClipEdgeStyle edgeStyle) {
120 fStateTree->appendClip(this->writeStream().bytesWritten());
121 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
124 bool SkBBoxHierarchyRecord::shouldRewind(void* data) {
125 // SkBBoxHierarchy::rewindInserts is called by SkPicture after the
126 // SkPicture has rewound its command stream. To match that rewind in the
127 // BBH, we rewind all draws that reference commands that were recorded
128 // past the point to which the SkPicture has rewound, which is given by
129 // writeStream().bytesWritten().
130 SkPictureStateTree::Draw* draw = static_cast<SkPictureStateTree::Draw*>(data);
131 return draw->fOffset >= writeStream().bytesWritten();