1 2 /* 3 * Copyright 2012 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 #include "SkBBoxHierarchyRecord.h" 10 #include "SkPictureStateTree.h" 11 12 SkBBoxHierarchyRecord::SkBBoxHierarchyRecord(const SkISize& size, 13 uint32_t recordFlags, 14 SkBBoxHierarchy* h) 15 : INHERITED(size, recordFlags) { 16 fStateTree = SkNEW(SkPictureStateTree); 17 fBoundingHierarchy = h; 18 fBoundingHierarchy->ref(); 19 fBoundingHierarchy->setClient(this); 20 } 21 22 void SkBBoxHierarchyRecord::handleBBox(const SkRect& bounds) { 23 SkPictureStateTree::Draw* draw = fStateTree->appendDraw(this->writeStream().bytesWritten()); 24 fBoundingHierarchy->insert(draw, bounds, true); 25 } 26 27 void SkBBoxHierarchyRecord::willSave() { 28 fStateTree->appendSave(); 29 this->INHERITED::willSave(); 30 } 31 32 SkCanvas::SaveLayerStrategy SkBBoxHierarchyRecord::willSaveLayer(const SkRect* bounds, 33 const SkPaint* paint, 34 SaveFlags flags) { 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)) { 51 switch (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; 60 break; 61 default: 62 break; 63 } 64 } 65 } 66 67 SkRect drawBounds; 68 if (needToHandleBBox) { 69 SkIRect deviceBounds; 70 this->getClipDeviceBounds(&deviceBounds); 71 drawBounds.set(deviceBounds); 72 } 73 fStateTree->appendSaveLayer(this->writeStream().bytesWritten()); 74 SkCanvas::SaveLayerStrategy strategy = this->INHERITED::willSaveLayer(bounds, paint, flags); 75 if (needToHandleBBox) { 76 this->handleBBox(drawBounds); 77 this->addNoOp(); 78 } 79 return strategy; 80 } 81 82 void SkBBoxHierarchyRecord::willRestore() { 83 fStateTree->appendRestore(); 84 this->INHERITED::willRestore(); 85 } 86 87 void SkBBoxHierarchyRecord::didConcat(const SkMatrix& matrix) { 88 fStateTree->appendTransform(getTotalMatrix()); 89 INHERITED::didConcat(matrix); 90 } 91 92 void SkBBoxHierarchyRecord::didSetMatrix(const SkMatrix& matrix) { 93 fStateTree->appendTransform(getTotalMatrix()); 94 INHERITED::didSetMatrix(matrix); 95 } 96 97 void SkBBoxHierarchyRecord::onClipRect(const SkRect& rect, 98 SkRegion::Op op, 99 ClipEdgeStyle edgeStyle) { 100 fStateTree->appendClip(this->writeStream().bytesWritten()); 101 this->INHERITED::onClipRect(rect, op, edgeStyle); 102 } 103 104 void SkBBoxHierarchyRecord::onClipRegion(const SkRegion& region, 105 SkRegion::Op op) { 106 fStateTree->appendClip(this->writeStream().bytesWritten()); 107 this->INHERITED::onClipRegion(region, op); 108 } 109 110 void SkBBoxHierarchyRecord::onClipPath(const SkPath& path, 111 SkRegion::Op op, 112 ClipEdgeStyle edgeStyle) { 113 fStateTree->appendClip(this->writeStream().bytesWritten()); 114 this->INHERITED::onClipPath(path, op, edgeStyle); 115 } 116 117 void SkBBoxHierarchyRecord::onClipRRect(const SkRRect& rrect, 118 SkRegion::Op op, 119 ClipEdgeStyle edgeStyle) { 120 fStateTree->appendClip(this->writeStream().bytesWritten()); 121 this->INHERITED::onClipRRect(rrect, op, edgeStyle); 122 } 123 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(); 132 } 133