1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2013 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkShader.h" 9cb93a386Sopenharmony_ci#include "src/utils/SkCanvasStack.h" 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ciSkCanvasStack::SkCanvasStack(int width, int height) 12cb93a386Sopenharmony_ci : INHERITED(width, height) {} 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_ciSkCanvasStack::~SkCanvasStack() { 15cb93a386Sopenharmony_ci this->removeAll(); 16cb93a386Sopenharmony_ci} 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_civoid SkCanvasStack::pushCanvas(std::unique_ptr<SkCanvas> canvas, const SkIPoint& origin) { 19cb93a386Sopenharmony_ci if (canvas) { 20cb93a386Sopenharmony_ci // compute the bounds of this canvas 21cb93a386Sopenharmony_ci const SkIRect canvasBounds = SkIRect::MakeSize(canvas->getBaseLayerSize()); 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci // push the canvas onto the stack 24cb93a386Sopenharmony_ci this->INHERITED::addCanvas(canvas.get()); 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci // push the canvas data onto the stack 27cb93a386Sopenharmony_ci CanvasData* data = &fCanvasData.push_back(); 28cb93a386Sopenharmony_ci data->origin = origin; 29cb93a386Sopenharmony_ci data->requiredClip.setRect(canvasBounds); 30cb93a386Sopenharmony_ci data->ownedCanvas = std::move(canvas); 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_ci // subtract this region from the canvas objects already on the stack. 33cb93a386Sopenharmony_ci // This ensures they do not draw into the space occupied by the layers 34cb93a386Sopenharmony_ci // above them. 35cb93a386Sopenharmony_ci for (int i = fList.count() - 1; i > 0; --i) { 36cb93a386Sopenharmony_ci SkIRect localBounds = canvasBounds; 37cb93a386Sopenharmony_ci localBounds.offset(origin - fCanvasData[i-1].origin); 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci fCanvasData[i-1].requiredClip.op(localBounds, SkRegion::kDifference_Op); 40cb93a386Sopenharmony_ci fList[i-1]->clipRegion(fCanvasData[i-1].requiredClip); 41cb93a386Sopenharmony_ci } 42cb93a386Sopenharmony_ci } 43cb93a386Sopenharmony_ci SkASSERT(fList.count() == fCanvasData.count()); 44cb93a386Sopenharmony_ci} 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_civoid SkCanvasStack::removeAll() { 47cb93a386Sopenharmony_ci this->INHERITED::removeAll(); // call the baseclass *before* we actually delete the canvases 48cb93a386Sopenharmony_ci fCanvasData.reset(); 49cb93a386Sopenharmony_ci} 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci/** 52cb93a386Sopenharmony_ci * Traverse all canvases (e.g. layers) the stack and ensure that they are clipped 53cb93a386Sopenharmony_ci * to their bounds and that the area covered by any canvas higher in the stack is 54cb93a386Sopenharmony_ci * also clipped out. 55cb93a386Sopenharmony_ci */ 56cb93a386Sopenharmony_civoid SkCanvasStack::clipToZOrderedBounds() { 57cb93a386Sopenharmony_ci SkASSERT(fList.count() == fCanvasData.count()); 58cb93a386Sopenharmony_ci for (int i = 0; i < fList.count(); ++i) { 59cb93a386Sopenharmony_ci fList[i]->clipRegion(fCanvasData[i].requiredClip); 60cb93a386Sopenharmony_ci } 61cb93a386Sopenharmony_ci} 62cb93a386Sopenharmony_ci 63cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////// 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci/** 66cb93a386Sopenharmony_ci * We need to handle setMatrix specially as it overwrites the matrix in each 67cb93a386Sopenharmony_ci * canvas unlike all other matrix operations (i.e. translate, scale, etc) which 68cb93a386Sopenharmony_ci * just pre-concatenate with the existing matrix. 69cb93a386Sopenharmony_ci */ 70cb93a386Sopenharmony_civoid SkCanvasStack::didSetM44(const SkM44& mx) { 71cb93a386Sopenharmony_ci SkASSERT(fList.count() == fCanvasData.count()); 72cb93a386Sopenharmony_ci for (int i = 0; i < fList.count(); ++i) { 73cb93a386Sopenharmony_ci fList[i]->setMatrix(SkM44::Translate(SkIntToScalar(-fCanvasData[i].origin.x()), 74cb93a386Sopenharmony_ci SkIntToScalar(-fCanvasData[i].origin.y())) * mx); 75cb93a386Sopenharmony_ci } 76cb93a386Sopenharmony_ci this->SkCanvas::didSetM44(mx); 77cb93a386Sopenharmony_ci} 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_civoid SkCanvasStack::onClipRect(const SkRect& r, SkClipOp op, ClipEdgeStyle edgeStyle) { 80cb93a386Sopenharmony_ci this->INHERITED::onClipRect(r, op, edgeStyle); 81cb93a386Sopenharmony_ci this->clipToZOrderedBounds(); 82cb93a386Sopenharmony_ci} 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_civoid SkCanvasStack::onClipRRect(const SkRRect& rr, SkClipOp op, ClipEdgeStyle edgeStyle) { 85cb93a386Sopenharmony_ci this->INHERITED::onClipRRect(rr, op, edgeStyle); 86cb93a386Sopenharmony_ci this->clipToZOrderedBounds(); 87cb93a386Sopenharmony_ci} 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_civoid SkCanvasStack::onClipPath(const SkPath& p, SkClipOp op, ClipEdgeStyle edgeStyle) { 90cb93a386Sopenharmony_ci this->INHERITED::onClipPath(p, op, edgeStyle); 91cb93a386Sopenharmony_ci this->clipToZOrderedBounds(); 92cb93a386Sopenharmony_ci} 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_civoid SkCanvasStack::onClipShader(sk_sp<SkShader> cs, SkClipOp op) { 95cb93a386Sopenharmony_ci this->INHERITED::onClipShader(std::move(cs), op); 96cb93a386Sopenharmony_ci // we don't change the "bounds" of the clip, so we don't need to update zorder 97cb93a386Sopenharmony_ci} 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_civoid SkCanvasStack::onClipRegion(const SkRegion& deviceRgn, SkClipOp op) { 100cb93a386Sopenharmony_ci SkASSERT(fList.count() == fCanvasData.count()); 101cb93a386Sopenharmony_ci for (int i = 0; i < fList.count(); ++i) { 102cb93a386Sopenharmony_ci SkRegion tempRegion; 103cb93a386Sopenharmony_ci deviceRgn.translate(-fCanvasData[i].origin.x(), 104cb93a386Sopenharmony_ci -fCanvasData[i].origin.y(), &tempRegion); 105cb93a386Sopenharmony_ci tempRegion.op(fCanvasData[i].requiredClip, SkRegion::kIntersect_Op); 106cb93a386Sopenharmony_ci fList[i]->clipRegion(tempRegion, op); 107cb93a386Sopenharmony_ci } 108cb93a386Sopenharmony_ci this->SkCanvas::onClipRegion(deviceRgn, op); 109cb93a386Sopenharmony_ci} 110