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 SkIRect r; 24 bounds.roundOut(&r); 25 SkPictureStateTree::Draw* draw = fStateTree->appendDraw(this->writeStream().bytesWritten()); 26 fBoundingHierarchy->insert(draw, r, true); 27 } 28 29 void SkBBoxHierarchyRecord::willSave(SaveFlags flags) { 30 fStateTree->appendSave(); 31 this->INHERITED::willSave(flags); 32 } 33 34 SkCanvas::SaveLayerStrategy SkBBoxHierarchyRecord::willSaveLayer(const SkRect* bounds, 35 const SkPaint* paint, 36 SaveFlags flags) { 37 // For now, assume all filters affect transparent black. 38 // FIXME: This could be made less conservative as an optimization. 39 bool paintAffectsTransparentBlack = NULL != paint && 40 ((NULL != paint->getImageFilter()) || 41 (NULL != paint->getColorFilter())); 42 SkRect drawBounds; 43 if (paintAffectsTransparentBlack) { 44 if (bounds) { 45 drawBounds = *bounds; 46 this->getTotalMatrix().mapRect(&drawBounds); 47 } else { 48 SkIRect deviceBounds; 49 this->getClipDeviceBounds(&deviceBounds); 50 drawBounds.set(deviceBounds); 51 } 52 } 53 fStateTree->appendSaveLayer(this->writeStream().bytesWritten()); 54 SkCanvas::SaveLayerStrategy strategy = this->INHERITED::willSaveLayer(bounds, paint, flags); 55 if (paintAffectsTransparentBlack) { 56 this->handleBBox(drawBounds); 57 this->addNoOp(); 58 } 59 return strategy; 60 } 61 62 void SkBBoxHierarchyRecord::willRestore() { 63 fStateTree->appendRestore(); 64 this->INHERITED::willRestore(); 65 } 66 67 void SkBBoxHierarchyRecord::didConcat(const SkMatrix& matrix) { 68 fStateTree->appendTransform(getTotalMatrix()); 69 INHERITED::didConcat(matrix); 70 } 71 72 void SkBBoxHierarchyRecord::didSetMatrix(const SkMatrix& matrix) { 73 fStateTree->appendTransform(getTotalMatrix()); 74 INHERITED::didSetMatrix(matrix); 75 } 76 77 void SkBBoxHierarchyRecord::onClipRect(const SkRect& rect, 78 SkRegion::Op op, 79 ClipEdgeStyle edgeStyle) { 80 fStateTree->appendClip(this->writeStream().bytesWritten()); 81 this->INHERITED::onClipRect(rect, op, edgeStyle); 82 } 83 84 void SkBBoxHierarchyRecord::onClipRegion(const SkRegion& region, 85 SkRegion::Op op) { 86 fStateTree->appendClip(this->writeStream().bytesWritten()); 87 this->INHERITED::onClipRegion(region, op); 88 } 89 90 void SkBBoxHierarchyRecord::onClipPath(const SkPath& path, 91 SkRegion::Op op, 92 ClipEdgeStyle edgeStyle) { 93 fStateTree->appendClip(this->writeStream().bytesWritten()); 94 this->INHERITED::onClipPath(path, op, edgeStyle); 95 } 96 97 void SkBBoxHierarchyRecord::onClipRRect(const SkRRect& rrect, 98 SkRegion::Op op, 99 ClipEdgeStyle edgeStyle) { 100 fStateTree->appendClip(this->writeStream().bytesWritten()); 101 this->INHERITED::onClipRRect(rrect, op, edgeStyle); 102 } 103 104 bool SkBBoxHierarchyRecord::shouldRewind(void* data) { 105 // SkBBoxHierarchy::rewindInserts is called by SkPicture after the 106 // SkPicture has rewound its command stream. To match that rewind in the 107 // BBH, we rewind all draws that reference commands that were recorded 108 // past the point to which the SkPicture has rewound, which is given by 109 // writeStream().bytesWritten(). 110 SkPictureStateTree::Draw* draw = static_cast<SkPictureStateTree::Draw*>(data); 111 return draw->fOffset >= writeStream().bytesWritten(); 112 } 113