Cleanup: Turn GrReducedClip into a class with a static function.
Clean up namespace usage. Similar to what was done in https://skia.googlesource.com/skia/+/a5414c4a8efc3119ee20fcee96c0bf68a04909c7 BUG=None TEST=None R=bsalomon@google.com Review URL: https://codereview.chromium.org/653393003
This commit is contained in:
parent
11ed6b8140
commit
bf54e49e30
@ -28,8 +28,6 @@
|
|||||||
|
|
||||||
typedef SkClipStack::Element Element;
|
typedef SkClipStack::Element Element;
|
||||||
|
|
||||||
using namespace GrReducedClip;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
namespace {
|
namespace {
|
||||||
// set up the draw state to enable the aa clipping mask. Besides setting up the
|
// set up the draw state to enable the aa clipping mask. Besides setting up the
|
||||||
@ -85,14 +83,14 @@ bool path_needs_SW_renderer(GrContext* context,
|
|||||||
* will be used on any element. If so, it returns true to indicate that the
|
* will be used on any element. If so, it returns true to indicate that the
|
||||||
* entire clip should be rendered in SW and then uploaded en masse to the gpu.
|
* entire clip should be rendered in SW and then uploaded en masse to the gpu.
|
||||||
*/
|
*/
|
||||||
bool GrClipMaskManager::useSWOnlyPath(const ElementList& elements) {
|
bool GrClipMaskManager::useSWOnlyPath(const GrReducedClip::ElementList& elements) {
|
||||||
|
|
||||||
// TODO: generalize this function so that when
|
// TODO: generalize this function so that when
|
||||||
// a clip gets complex enough it can just be done in SW regardless
|
// a clip gets complex enough it can just be done in SW regardless
|
||||||
// of whether it would invoke the GrSoftwarePathRenderer.
|
// of whether it would invoke the GrSoftwarePathRenderer.
|
||||||
SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
|
SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
|
||||||
|
|
||||||
for (ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) {
|
for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) {
|
||||||
const Element* element = iter.get();
|
const Element* element = iter.get();
|
||||||
// rects can always be drawn directly w/o using the software path
|
// rects can always be drawn directly w/o using the software path
|
||||||
// Skip rrects once we're drawing them directly.
|
// Skip rrects once we're drawing them directly.
|
||||||
@ -107,7 +105,7 @@ bool GrClipMaskManager::useSWOnlyPath(const ElementList& elements) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GrClipMaskManager::installClipEffects(const ElementList& elements,
|
bool GrClipMaskManager::installClipEffects(const GrReducedClip::ElementList& elements,
|
||||||
GrDrawState::AutoRestoreEffects* are,
|
GrDrawState::AutoRestoreEffects* are,
|
||||||
const SkVector& clipToRTOffset,
|
const SkVector& clipToRTOffset,
|
||||||
const SkRect* drawBounds) {
|
const SkRect* drawBounds) {
|
||||||
@ -121,7 +119,7 @@ bool GrClipMaskManager::installClipEffects(const ElementList& elements,
|
|||||||
|
|
||||||
are->set(drawState);
|
are->set(drawState);
|
||||||
GrRenderTarget* rt = drawState->getRenderTarget();
|
GrRenderTarget* rt = drawState->getRenderTarget();
|
||||||
ElementList::Iter iter(elements);
|
GrReducedClip::ElementList::Iter iter(elements);
|
||||||
|
|
||||||
bool setARE = false;
|
bool setARE = false;
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
@ -217,9 +215,9 @@ bool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn,
|
|||||||
const SkRect* devBounds) {
|
const SkRect* devBounds) {
|
||||||
fCurrClipMaskType = kNone_ClipMaskType;
|
fCurrClipMaskType = kNone_ClipMaskType;
|
||||||
|
|
||||||
ElementList elements(16);
|
GrReducedClip::ElementList elements(16);
|
||||||
int32_t genID;
|
int32_t genID;
|
||||||
InitialState initialState;
|
GrReducedClip::InitialState initialState;
|
||||||
SkIRect clipSpaceIBounds;
|
SkIRect clipSpaceIBounds;
|
||||||
bool requiresAA;
|
bool requiresAA;
|
||||||
|
|
||||||
@ -234,15 +232,15 @@ bool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn,
|
|||||||
if (!ignoreClip) {
|
if (!ignoreClip) {
|
||||||
SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height());
|
SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height());
|
||||||
clipSpaceRTIBounds.offset(clipDataIn->fOrigin);
|
clipSpaceRTIBounds.offset(clipDataIn->fOrigin);
|
||||||
ReduceClipStack(*clipDataIn->fClipStack,
|
GrReducedClip::ReduceClipStack(*clipDataIn->fClipStack,
|
||||||
clipSpaceRTIBounds,
|
clipSpaceRTIBounds,
|
||||||
&elements,
|
&elements,
|
||||||
&genID,
|
&genID,
|
||||||
&initialState,
|
&initialState,
|
||||||
&clipSpaceIBounds,
|
&clipSpaceIBounds,
|
||||||
&requiresAA);
|
&requiresAA);
|
||||||
if (elements.isEmpty()) {
|
if (elements.isEmpty()) {
|
||||||
if (kAllIn_InitialState == initialState) {
|
if (GrReducedClip::kAllIn_InitialState == initialState) {
|
||||||
ignoreClip = clipSpaceIBounds == clipSpaceRTIBounds;
|
ignoreClip = clipSpaceIBounds == clipSpaceRTIBounds;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -534,8 +532,8 @@ GrTexture* GrClipMaskManager::allocMaskTexture(int32_t elementsGenID,
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Create a 8-bit clip mask in alpha
|
// Create a 8-bit clip mask in alpha
|
||||||
GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
|
GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
|
||||||
InitialState initialState,
|
GrReducedClip::InitialState initialState,
|
||||||
const ElementList& elements,
|
const GrReducedClip::ElementList& elements,
|
||||||
const SkIRect& clipSpaceIBounds) {
|
const SkIRect& clipSpaceIBounds) {
|
||||||
SkASSERT(kNone_ClipMaskType == fCurrClipMaskType);
|
SkASSERT(kNone_ClipMaskType == fCurrClipMaskType);
|
||||||
|
|
||||||
@ -575,7 +573,7 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
|
|||||||
// The scratch texture that we are drawing into can be substantially larger than the mask. Only
|
// The scratch texture that we are drawing into can be substantially larger than the mask. Only
|
||||||
// clear the part that we care about.
|
// clear the part that we care about.
|
||||||
fGpu->clear(&maskSpaceIBounds,
|
fGpu->clear(&maskSpaceIBounds,
|
||||||
kAllIn_InitialState == initialState ? 0xffffffff : 0x00000000,
|
GrReducedClip::kAllIn_InitialState == initialState ? 0xffffffff : 0x00000000,
|
||||||
true,
|
true,
|
||||||
result->asRenderTarget());
|
result->asRenderTarget());
|
||||||
|
|
||||||
@ -588,7 +586,7 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
|
|||||||
|
|
||||||
SkAutoTUnref<GrTexture> temp;
|
SkAutoTUnref<GrTexture> temp;
|
||||||
// walk through each clip element and perform its set op
|
// walk through each clip element and perform its set op
|
||||||
for (ElementList::Iter iter = elements.headIter(); iter.get(); iter.next()) {
|
for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get(); iter.next()) {
|
||||||
const Element* element = iter.get();
|
const Element* element = iter.get();
|
||||||
SkRegion::Op op = element->getOp();
|
SkRegion::Op op = element->getOp();
|
||||||
bool invert = element->isInverseFilled();
|
bool invert = element->isInverseFilled();
|
||||||
@ -688,8 +686,8 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
|
|||||||
// Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device
|
// Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device
|
||||||
// (as opposed to canvas) coordinates
|
// (as opposed to canvas) coordinates
|
||||||
bool GrClipMaskManager::createStencilClipMask(int32_t elementsGenID,
|
bool GrClipMaskManager::createStencilClipMask(int32_t elementsGenID,
|
||||||
InitialState initialState,
|
GrReducedClip::InitialState initialState,
|
||||||
const ElementList& elements,
|
const GrReducedClip::ElementList& elements,
|
||||||
const SkIRect& clipSpaceIBounds,
|
const SkIRect& clipSpaceIBounds,
|
||||||
const SkIPoint& clipSpaceToStencilOffset) {
|
const SkIPoint& clipSpaceToStencilOffset) {
|
||||||
|
|
||||||
@ -737,11 +735,12 @@ bool GrClipMaskManager::createStencilClipMask(int32_t elementsGenID,
|
|||||||
SkASSERT((clipBit <= 16) && "Ganesh only handles 16b or smaller stencil buffers");
|
SkASSERT((clipBit <= 16) && "Ganesh only handles 16b or smaller stencil buffers");
|
||||||
clipBit = (1 << (clipBit-1));
|
clipBit = (1 << (clipBit-1));
|
||||||
|
|
||||||
fGpu->clearStencilClip(rt, stencilSpaceIBounds, kAllIn_InitialState == initialState);
|
fGpu->clearStencilClip(rt, stencilSpaceIBounds,
|
||||||
|
GrReducedClip::kAllIn_InitialState == initialState);
|
||||||
|
|
||||||
// walk through each clip element and perform its set op
|
// walk through each clip element and perform its set op
|
||||||
// with the existing clip.
|
// with the existing clip.
|
||||||
for (ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) {
|
for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) {
|
||||||
const Element* element = iter.get();
|
const Element* element = iter.get();
|
||||||
bool fillInverted = false;
|
bool fillInverted = false;
|
||||||
// enabled at bottom of loop
|
// enabled at bottom of loop
|
||||||
@ -1058,11 +1057,11 @@ GrTexture* GrClipMaskManager::createSoftwareClipMask(int32_t elementsGenID,
|
|||||||
SkIntToScalar(-clipSpaceIBounds.fTop));
|
SkIntToScalar(-clipSpaceIBounds.fTop));
|
||||||
helper.init(maskSpaceIBounds, &matrix, false);
|
helper.init(maskSpaceIBounds, &matrix, false);
|
||||||
|
|
||||||
helper.clear(kAllIn_InitialState == initialState ? 0xFF : 0x00);
|
helper.clear(GrReducedClip::kAllIn_InitialState == initialState ? 0xFF : 0x00);
|
||||||
|
|
||||||
SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
|
SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
|
||||||
|
|
||||||
for (ElementList::Iter iter(elements.headIter()) ; iter.get(); iter.next()) {
|
for (GrReducedClip::ElementList::Iter iter(elements.headIter()) ; iter.get(); iter.next()) {
|
||||||
|
|
||||||
const Element* element = iter.get();
|
const Element* element = iter.get();
|
||||||
SkRegion::Op op = element->getOp();
|
SkRegion::Op op = element->getOp();
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2012 Google Inc.
|
* Copyright 2012 Google Inc.
|
||||||
*
|
*
|
||||||
@ -9,17 +8,314 @@
|
|||||||
#include "GrReducedClip.h"
|
#include "GrReducedClip.h"
|
||||||
|
|
||||||
typedef SkClipStack::Element Element;
|
typedef SkClipStack::Element Element;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
namespace GrReducedClip {
|
static void reduced_stack_walker(const SkClipStack& stack,
|
||||||
|
const SkRect& queryBounds,
|
||||||
|
GrReducedClip::ElementList* result,
|
||||||
|
int32_t* resultGenID,
|
||||||
|
GrReducedClip::InitialState* initialState,
|
||||||
|
bool* requiresAA) {
|
||||||
|
|
||||||
// helper function
|
// walk backwards until we get to:
|
||||||
void reduced_stack_walker(const SkClipStack& stack,
|
// a) the beginning
|
||||||
const SkRect& queryBounds,
|
// b) an operation that is known to make the bounds all inside/outside
|
||||||
ElementList* result,
|
// c) a replace operation
|
||||||
int32_t* resultGenID,
|
|
||||||
InitialState* initialState,
|
static const GrReducedClip::InitialState kUnknown_InitialState =
|
||||||
bool* requiresAA);
|
static_cast<GrReducedClip::InitialState>(-1);
|
||||||
|
*initialState = kUnknown_InitialState;
|
||||||
|
|
||||||
|
// During our backwards walk, track whether we've seen ops that either grow or shrink the clip.
|
||||||
|
// TODO: track these per saved clip so that we can consider them on the forward pass.
|
||||||
|
bool embiggens = false;
|
||||||
|
bool emsmallens = false;
|
||||||
|
|
||||||
|
SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
|
||||||
|
int numAAElements = 0;
|
||||||
|
while ((kUnknown_InitialState == *initialState)) {
|
||||||
|
const Element* element = iter.prev();
|
||||||
|
if (NULL == element) {
|
||||||
|
*initialState = GrReducedClip::kAllIn_InitialState;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (SkClipStack::kEmptyGenID == element->getGenID()) {
|
||||||
|
*initialState = GrReducedClip::kAllOut_InitialState;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (SkClipStack::kWideOpenGenID == element->getGenID()) {
|
||||||
|
*initialState = GrReducedClip::kAllIn_InitialState;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool skippable = false;
|
||||||
|
bool isFlip = false; // does this op just flip the in/out state of every point in the bounds
|
||||||
|
|
||||||
|
switch (element->getOp()) {
|
||||||
|
case SkRegion::kDifference_Op:
|
||||||
|
// check if the shape subtracted either contains the entire bounds (and makes
|
||||||
|
// the clip empty) or is outside the bounds and therefore can be skipped.
|
||||||
|
if (element->isInverseFilled()) {
|
||||||
|
if (element->contains(queryBounds)) {
|
||||||
|
skippable = true;
|
||||||
|
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
||||||
|
*initialState = GrReducedClip::kAllOut_InitialState;
|
||||||
|
skippable = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (element->contains(queryBounds)) {
|
||||||
|
*initialState = GrReducedClip::kAllOut_InitialState;
|
||||||
|
skippable = true;
|
||||||
|
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
||||||
|
skippable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!skippable) {
|
||||||
|
emsmallens = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SkRegion::kIntersect_Op:
|
||||||
|
// check if the shape intersected contains the entire bounds and therefore can
|
||||||
|
// be skipped or it is outside the entire bounds and therefore makes the clip
|
||||||
|
// empty.
|
||||||
|
if (element->isInverseFilled()) {
|
||||||
|
if (element->contains(queryBounds)) {
|
||||||
|
*initialState = GrReducedClip::kAllOut_InitialState;
|
||||||
|
skippable = true;
|
||||||
|
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
||||||
|
skippable = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (element->contains(queryBounds)) {
|
||||||
|
skippable = true;
|
||||||
|
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
||||||
|
*initialState = GrReducedClip::kAllOut_InitialState;
|
||||||
|
skippable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!skippable) {
|
||||||
|
emsmallens = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SkRegion::kUnion_Op:
|
||||||
|
// If the union-ed shape contains the entire bounds then after this element
|
||||||
|
// the bounds is entirely inside the clip. If the union-ed shape is outside the
|
||||||
|
// bounds then this op can be skipped.
|
||||||
|
if (element->isInverseFilled()) {
|
||||||
|
if (element->contains(queryBounds)) {
|
||||||
|
skippable = true;
|
||||||
|
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
||||||
|
*initialState = GrReducedClip::kAllIn_InitialState;
|
||||||
|
skippable = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (element->contains(queryBounds)) {
|
||||||
|
*initialState = GrReducedClip::kAllIn_InitialState;
|
||||||
|
skippable = true;
|
||||||
|
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
||||||
|
skippable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!skippable) {
|
||||||
|
embiggens = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SkRegion::kXOR_Op:
|
||||||
|
// If the bounds is entirely inside the shape being xor-ed then the effect is
|
||||||
|
// to flip the inside/outside state of every point in the bounds. We may be
|
||||||
|
// able to take advantage of this in the forward pass. If the xor-ed shape
|
||||||
|
// doesn't intersect the bounds then it can be skipped.
|
||||||
|
if (element->isInverseFilled()) {
|
||||||
|
if (element->contains(queryBounds)) {
|
||||||
|
skippable = true;
|
||||||
|
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
||||||
|
isFlip = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (element->contains(queryBounds)) {
|
||||||
|
isFlip = true;
|
||||||
|
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
||||||
|
skippable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!skippable) {
|
||||||
|
emsmallens = embiggens = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SkRegion::kReverseDifference_Op:
|
||||||
|
// When the bounds is entirely within the rev-diff shape then this behaves like xor
|
||||||
|
// and reverses every point inside the bounds. If the shape is completely outside
|
||||||
|
// the bounds then we know after this element is applied that the bounds will be
|
||||||
|
// all outside the current clip.B
|
||||||
|
if (element->isInverseFilled()) {
|
||||||
|
if (element->contains(queryBounds)) {
|
||||||
|
*initialState = GrReducedClip::kAllOut_InitialState;
|
||||||
|
skippable = true;
|
||||||
|
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
||||||
|
isFlip = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (element->contains(queryBounds)) {
|
||||||
|
isFlip = true;
|
||||||
|
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
||||||
|
*initialState = GrReducedClip::kAllOut_InitialState;
|
||||||
|
skippable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!skippable) {
|
||||||
|
emsmallens = embiggens = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SkRegion::kReplace_Op:
|
||||||
|
// Replace will always terminate our walk. We will either begin the forward walk
|
||||||
|
// at the replace op or detect here than the shape is either completely inside
|
||||||
|
// or completely outside the bounds. In this latter case it can be skipped by
|
||||||
|
// setting the correct value for initialState.
|
||||||
|
if (element->isInverseFilled()) {
|
||||||
|
if (element->contains(queryBounds)) {
|
||||||
|
*initialState = GrReducedClip::kAllOut_InitialState;
|
||||||
|
skippable = true;
|
||||||
|
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
||||||
|
*initialState = GrReducedClip::kAllIn_InitialState;
|
||||||
|
skippable = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (element->contains(queryBounds)) {
|
||||||
|
*initialState = GrReducedClip::kAllIn_InitialState;
|
||||||
|
skippable = true;
|
||||||
|
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
||||||
|
*initialState = GrReducedClip::kAllOut_InitialState;
|
||||||
|
skippable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!skippable) {
|
||||||
|
*initialState = GrReducedClip::kAllOut_InitialState;
|
||||||
|
embiggens = emsmallens = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SkDEBUGFAIL("Unexpected op.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!skippable) {
|
||||||
|
if (0 == result->count()) {
|
||||||
|
// This will be the last element. Record the stricter genID.
|
||||||
|
*resultGenID = element->getGenID();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it is a flip, change it to a bounds-filling rect
|
||||||
|
if (isFlip) {
|
||||||
|
SkASSERT(SkRegion::kXOR_Op == element->getOp() ||
|
||||||
|
SkRegion::kReverseDifference_Op == element->getOp());
|
||||||
|
SkNEW_INSERT_AT_LLIST_HEAD(result,
|
||||||
|
Element,
|
||||||
|
(queryBounds, SkRegion::kReverseDifference_Op, false));
|
||||||
|
} else {
|
||||||
|
Element* newElement = result->addToHead(*element);
|
||||||
|
if (newElement->isAA()) {
|
||||||
|
++numAAElements;
|
||||||
|
}
|
||||||
|
// Intersecting an inverse shape is the same as differencing the non-inverse shape.
|
||||||
|
// Replacing with an inverse shape is the same as setting initialState=kAllIn and
|
||||||
|
// differencing the non-inverse shape.
|
||||||
|
bool isReplace = SkRegion::kReplace_Op == newElement->getOp();
|
||||||
|
if (newElement->isInverseFilled() &&
|
||||||
|
(SkRegion::kIntersect_Op == newElement->getOp() || isReplace)) {
|
||||||
|
newElement->invertShapeFillType();
|
||||||
|
newElement->setOp(SkRegion::kDifference_Op);
|
||||||
|
if (isReplace) {
|
||||||
|
SkASSERT(GrReducedClip::kAllOut_InitialState == *initialState);
|
||||||
|
*initialState = GrReducedClip::kAllIn_InitialState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((GrReducedClip::kAllOut_InitialState == *initialState && !embiggens) ||
|
||||||
|
(GrReducedClip::kAllIn_InitialState == *initialState && !emsmallens)) {
|
||||||
|
result->reset();
|
||||||
|
} else {
|
||||||
|
Element* element = result->headIter().get();
|
||||||
|
while (element) {
|
||||||
|
bool skippable = false;
|
||||||
|
switch (element->getOp()) {
|
||||||
|
case SkRegion::kDifference_Op:
|
||||||
|
// subtracting from the empty set yields the empty set.
|
||||||
|
skippable = GrReducedClip::kAllOut_InitialState == *initialState;
|
||||||
|
break;
|
||||||
|
case SkRegion::kIntersect_Op:
|
||||||
|
// intersecting with the empty set yields the empty set
|
||||||
|
if (GrReducedClip::kAllOut_InitialState == *initialState) {
|
||||||
|
skippable = true;
|
||||||
|
} else {
|
||||||
|
// We can clear to zero and then simply draw the clip element.
|
||||||
|
*initialState = GrReducedClip::kAllOut_InitialState;
|
||||||
|
element->setOp(SkRegion::kReplace_Op);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SkRegion::kUnion_Op:
|
||||||
|
if (GrReducedClip::kAllIn_InitialState == *initialState) {
|
||||||
|
// unioning the infinite plane with anything is a no-op.
|
||||||
|
skippable = true;
|
||||||
|
} else {
|
||||||
|
// unioning the empty set with a shape is the shape.
|
||||||
|
element->setOp(SkRegion::kReplace_Op);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SkRegion::kXOR_Op:
|
||||||
|
if (GrReducedClip::kAllOut_InitialState == *initialState) {
|
||||||
|
// xor could be changed to diff in the kAllIn case, not sure it's a win.
|
||||||
|
element->setOp(SkRegion::kReplace_Op);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SkRegion::kReverseDifference_Op:
|
||||||
|
if (GrReducedClip::kAllIn_InitialState == *initialState) {
|
||||||
|
// subtracting the whole plane will yield the empty set.
|
||||||
|
skippable = true;
|
||||||
|
*initialState = GrReducedClip::kAllOut_InitialState;
|
||||||
|
} else {
|
||||||
|
// this picks up flips inserted in the backwards pass.
|
||||||
|
skippable = element->isInverseFilled() ?
|
||||||
|
!SkRect::Intersects(element->getBounds(), queryBounds) :
|
||||||
|
element->contains(queryBounds);
|
||||||
|
if (skippable) {
|
||||||
|
*initialState = GrReducedClip::kAllIn_InitialState;
|
||||||
|
} else {
|
||||||
|
element->setOp(SkRegion::kReplace_Op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SkRegion::kReplace_Op:
|
||||||
|
skippable = false; // we would have skipped it in the backwards walk if we
|
||||||
|
// could've.
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SkDEBUGFAIL("Unexpected op.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!skippable) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (element->isAA()) {
|
||||||
|
--numAAElements;
|
||||||
|
}
|
||||||
|
result->popHead();
|
||||||
|
element = result->headIter().get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (requiresAA) {
|
||||||
|
*requiresAA = numAAElements > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == result->count()) {
|
||||||
|
if (*initialState == GrReducedClip::kAllIn_InitialState) {
|
||||||
|
*resultGenID = SkClipStack::kWideOpenGenID;
|
||||||
|
} else {
|
||||||
|
*resultGenID = SkClipStack::kEmptyGenID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
There are plenty of optimizations that could be added here. Maybe flips could be folded into
|
There are plenty of optimizations that could be added here. Maybe flips could be folded into
|
||||||
@ -28,13 +324,13 @@ for the case where the bounds are kInsideOut_BoundsType. We could restrict earli
|
|||||||
based on later intersect operations, and perhaps remove intersect-rects. We could optionally
|
based on later intersect operations, and perhaps remove intersect-rects. We could optionally
|
||||||
take a rect in case the caller knows a bound on what is to be drawn through this clip.
|
take a rect in case the caller knows a bound on what is to be drawn through this clip.
|
||||||
*/
|
*/
|
||||||
void ReduceClipStack(const SkClipStack& stack,
|
void GrReducedClip::ReduceClipStack(const SkClipStack& stack,
|
||||||
const SkIRect& queryBounds,
|
const SkIRect& queryBounds,
|
||||||
ElementList* result,
|
ElementList* result,
|
||||||
int32_t* resultGenID,
|
int32_t* resultGenID,
|
||||||
InitialState* initialState,
|
InitialState* initialState,
|
||||||
SkIRect* tighterBounds,
|
SkIRect* tighterBounds,
|
||||||
bool* requiresAA) {
|
bool* requiresAA) {
|
||||||
result->reset();
|
result->reset();
|
||||||
|
|
||||||
// The clip established by the element list might be cached based on the last
|
// The clip established by the element list might be cached based on the last
|
||||||
@ -64,7 +360,7 @@ void ReduceClipStack(const SkClipStack& stack,
|
|||||||
SkASSERT(SkClipStack::kNormal_BoundsType == stackBoundsType);
|
SkASSERT(SkClipStack::kNormal_BoundsType == stackBoundsType);
|
||||||
SkRect isectRect;
|
SkRect isectRect;
|
||||||
if (stackBounds.contains(scalarQueryBounds)) {
|
if (stackBounds.contains(scalarQueryBounds)) {
|
||||||
*initialState = kAllIn_InitialState;
|
*initialState = GrReducedClip::kAllIn_InitialState;
|
||||||
if (tighterBounds) {
|
if (tighterBounds) {
|
||||||
*tighterBounds = queryBounds;
|
*tighterBounds = queryBounds;
|
||||||
}
|
}
|
||||||
@ -82,7 +378,7 @@ void ReduceClipStack(const SkClipStack& stack,
|
|||||||
if (requiresAA) {
|
if (requiresAA) {
|
||||||
*requiresAA = false;
|
*requiresAA = false;
|
||||||
}
|
}
|
||||||
*initialState = kAllIn_InitialState;
|
*initialState = GrReducedClip::kAllIn_InitialState;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,311 +436,3 @@ void ReduceClipStack(const SkClipStack& stack,
|
|||||||
// element.
|
// element.
|
||||||
SkASSERT(SkClipStack::kInvalidGenID != *resultGenID);
|
SkASSERT(SkClipStack::kInvalidGenID != *resultGenID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void reduced_stack_walker(const SkClipStack& stack,
|
|
||||||
const SkRect& queryBounds,
|
|
||||||
ElementList* result,
|
|
||||||
int32_t* resultGenID,
|
|
||||||
InitialState* initialState,
|
|
||||||
bool* requiresAA) {
|
|
||||||
|
|
||||||
// walk backwards until we get to:
|
|
||||||
// a) the beginning
|
|
||||||
// b) an operation that is known to make the bounds all inside/outside
|
|
||||||
// c) a replace operation
|
|
||||||
|
|
||||||
static const InitialState kUnknown_InitialState = static_cast<InitialState>(-1);
|
|
||||||
*initialState = kUnknown_InitialState;
|
|
||||||
|
|
||||||
// During our backwards walk, track whether we've seen ops that either grow or shrink the clip.
|
|
||||||
// TODO: track these per saved clip so that we can consider them on the forward pass.
|
|
||||||
bool embiggens = false;
|
|
||||||
bool emsmallens = false;
|
|
||||||
|
|
||||||
SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
|
|
||||||
int numAAElements = 0;
|
|
||||||
while ((kUnknown_InitialState == *initialState)) {
|
|
||||||
const Element* element = iter.prev();
|
|
||||||
if (NULL == element) {
|
|
||||||
*initialState = kAllIn_InitialState;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (SkClipStack::kEmptyGenID == element->getGenID()) {
|
|
||||||
*initialState = kAllOut_InitialState;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (SkClipStack::kWideOpenGenID == element->getGenID()) {
|
|
||||||
*initialState = kAllIn_InitialState;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool skippable = false;
|
|
||||||
bool isFlip = false; // does this op just flip the in/out state of every point in the bounds
|
|
||||||
|
|
||||||
switch (element->getOp()) {
|
|
||||||
case SkRegion::kDifference_Op:
|
|
||||||
// check if the shape subtracted either contains the entire bounds (and makes
|
|
||||||
// the clip empty) or is outside the bounds and therefore can be skipped.
|
|
||||||
if (element->isInverseFilled()) {
|
|
||||||
if (element->contains(queryBounds)) {
|
|
||||||
skippable = true;
|
|
||||||
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
|
||||||
*initialState = kAllOut_InitialState;
|
|
||||||
skippable = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (element->contains(queryBounds)) {
|
|
||||||
*initialState = kAllOut_InitialState;
|
|
||||||
skippable = true;
|
|
||||||
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
|
||||||
skippable = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!skippable) {
|
|
||||||
emsmallens = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SkRegion::kIntersect_Op:
|
|
||||||
// check if the shape intersected contains the entire bounds and therefore can
|
|
||||||
// be skipped or it is outside the entire bounds and therefore makes the clip
|
|
||||||
// empty.
|
|
||||||
if (element->isInverseFilled()) {
|
|
||||||
if (element->contains(queryBounds)) {
|
|
||||||
*initialState = kAllOut_InitialState;
|
|
||||||
skippable = true;
|
|
||||||
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
|
||||||
skippable = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (element->contains(queryBounds)) {
|
|
||||||
skippable = true;
|
|
||||||
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
|
||||||
*initialState = kAllOut_InitialState;
|
|
||||||
skippable = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!skippable) {
|
|
||||||
emsmallens = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SkRegion::kUnion_Op:
|
|
||||||
// If the union-ed shape contains the entire bounds then after this element
|
|
||||||
// the bounds is entirely inside the clip. If the union-ed shape is outside the
|
|
||||||
// bounds then this op can be skipped.
|
|
||||||
if (element->isInverseFilled()) {
|
|
||||||
if (element->contains(queryBounds)) {
|
|
||||||
skippable = true;
|
|
||||||
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
|
||||||
*initialState = kAllIn_InitialState;
|
|
||||||
skippable = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (element->contains(queryBounds)) {
|
|
||||||
*initialState = kAllIn_InitialState;
|
|
||||||
skippable = true;
|
|
||||||
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
|
||||||
skippable = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!skippable) {
|
|
||||||
embiggens = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SkRegion::kXOR_Op:
|
|
||||||
// If the bounds is entirely inside the shape being xor-ed then the effect is
|
|
||||||
// to flip the inside/outside state of every point in the bounds. We may be
|
|
||||||
// able to take advantage of this in the forward pass. If the xor-ed shape
|
|
||||||
// doesn't intersect the bounds then it can be skipped.
|
|
||||||
if (element->isInverseFilled()) {
|
|
||||||
if (element->contains(queryBounds)) {
|
|
||||||
skippable = true;
|
|
||||||
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
|
||||||
isFlip = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (element->contains(queryBounds)) {
|
|
||||||
isFlip = true;
|
|
||||||
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
|
||||||
skippable = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!skippable) {
|
|
||||||
emsmallens = embiggens = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SkRegion::kReverseDifference_Op:
|
|
||||||
// When the bounds is entirely within the rev-diff shape then this behaves like xor
|
|
||||||
// and reverses every point inside the bounds. If the shape is completely outside
|
|
||||||
// the bounds then we know after this element is applied that the bounds will be
|
|
||||||
// all outside the current clip.B
|
|
||||||
if (element->isInverseFilled()) {
|
|
||||||
if (element->contains(queryBounds)) {
|
|
||||||
*initialState = kAllOut_InitialState;
|
|
||||||
skippable = true;
|
|
||||||
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
|
||||||
isFlip = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (element->contains(queryBounds)) {
|
|
||||||
isFlip = true;
|
|
||||||
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
|
||||||
*initialState = kAllOut_InitialState;
|
|
||||||
skippable = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!skippable) {
|
|
||||||
emsmallens = embiggens = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SkRegion::kReplace_Op:
|
|
||||||
// Replace will always terminate our walk. We will either begin the forward walk
|
|
||||||
// at the replace op or detect here than the shape is either completely inside
|
|
||||||
// or completely outside the bounds. In this latter case it can be skipped by
|
|
||||||
// setting the correct value for initialState.
|
|
||||||
if (element->isInverseFilled()) {
|
|
||||||
if (element->contains(queryBounds)) {
|
|
||||||
*initialState = kAllOut_InitialState;
|
|
||||||
skippable = true;
|
|
||||||
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
|
||||||
*initialState = kAllIn_InitialState;
|
|
||||||
skippable = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (element->contains(queryBounds)) {
|
|
||||||
*initialState = kAllIn_InitialState;
|
|
||||||
skippable = true;
|
|
||||||
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
|
|
||||||
*initialState = kAllOut_InitialState;
|
|
||||||
skippable = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!skippable) {
|
|
||||||
*initialState = kAllOut_InitialState;
|
|
||||||
embiggens = emsmallens = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SkDEBUGFAIL("Unexpected op.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!skippable) {
|
|
||||||
if (0 == result->count()) {
|
|
||||||
// This will be the last element. Record the stricter genID.
|
|
||||||
*resultGenID = element->getGenID();
|
|
||||||
}
|
|
||||||
|
|
||||||
// if it is a flip, change it to a bounds-filling rect
|
|
||||||
if (isFlip) {
|
|
||||||
SkASSERT(SkRegion::kXOR_Op == element->getOp() ||
|
|
||||||
SkRegion::kReverseDifference_Op == element->getOp());
|
|
||||||
SkNEW_INSERT_AT_LLIST_HEAD(result,
|
|
||||||
Element,
|
|
||||||
(queryBounds, SkRegion::kReverseDifference_Op, false));
|
|
||||||
} else {
|
|
||||||
Element* newElement = result->addToHead(*element);
|
|
||||||
if (newElement->isAA()) {
|
|
||||||
++numAAElements;
|
|
||||||
}
|
|
||||||
// Intersecting an inverse shape is the same as differencing the non-inverse shape.
|
|
||||||
// Replacing with an inverse shape is the same as setting initialState=kAllIn and
|
|
||||||
// differencing the non-inverse shape.
|
|
||||||
bool isReplace = SkRegion::kReplace_Op == newElement->getOp();
|
|
||||||
if (newElement->isInverseFilled() &&
|
|
||||||
(SkRegion::kIntersect_Op == newElement->getOp() || isReplace)) {
|
|
||||||
newElement->invertShapeFillType();
|
|
||||||
newElement->setOp(SkRegion::kDifference_Op);
|
|
||||||
if (isReplace) {
|
|
||||||
SkASSERT(kAllOut_InitialState == *initialState);
|
|
||||||
*initialState = kAllIn_InitialState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((kAllOut_InitialState == *initialState && !embiggens) ||
|
|
||||||
(kAllIn_InitialState == *initialState && !emsmallens)) {
|
|
||||||
result->reset();
|
|
||||||
} else {
|
|
||||||
Element* element = result->headIter().get();
|
|
||||||
while (element) {
|
|
||||||
bool skippable = false;
|
|
||||||
switch (element->getOp()) {
|
|
||||||
case SkRegion::kDifference_Op:
|
|
||||||
// subtracting from the empty set yields the empty set.
|
|
||||||
skippable = kAllOut_InitialState == *initialState;
|
|
||||||
break;
|
|
||||||
case SkRegion::kIntersect_Op:
|
|
||||||
// intersecting with the empty set yields the empty set
|
|
||||||
if (kAllOut_InitialState == *initialState) {
|
|
||||||
skippable = true;
|
|
||||||
} else {
|
|
||||||
// We can clear to zero and then simply draw the clip element.
|
|
||||||
*initialState = kAllOut_InitialState;
|
|
||||||
element->setOp(SkRegion::kReplace_Op);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SkRegion::kUnion_Op:
|
|
||||||
if (kAllIn_InitialState == *initialState) {
|
|
||||||
// unioning the infinite plane with anything is a no-op.
|
|
||||||
skippable = true;
|
|
||||||
} else {
|
|
||||||
// unioning the empty set with a shape is the shape.
|
|
||||||
element->setOp(SkRegion::kReplace_Op);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SkRegion::kXOR_Op:
|
|
||||||
if (kAllOut_InitialState == *initialState) {
|
|
||||||
// xor could be changed to diff in the kAllIn case, not sure it's a win.
|
|
||||||
element->setOp(SkRegion::kReplace_Op);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SkRegion::kReverseDifference_Op:
|
|
||||||
if (kAllIn_InitialState == *initialState) {
|
|
||||||
// subtracting the whole plane will yield the empty set.
|
|
||||||
skippable = true;
|
|
||||||
*initialState = kAllOut_InitialState;
|
|
||||||
} else {
|
|
||||||
// this picks up flips inserted in the backwards pass.
|
|
||||||
skippable = element->isInverseFilled() ?
|
|
||||||
!SkRect::Intersects(element->getBounds(), queryBounds) :
|
|
||||||
element->contains(queryBounds);
|
|
||||||
if (skippable) {
|
|
||||||
*initialState = kAllIn_InitialState;
|
|
||||||
} else {
|
|
||||||
element->setOp(SkRegion::kReplace_Op);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SkRegion::kReplace_Op:
|
|
||||||
skippable = false; // we would have skipped it in the backwards walk if we
|
|
||||||
// could've.
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SkDEBUGFAIL("Unexpected op.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!skippable) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
if (element->isAA()) {
|
|
||||||
--numAAElements;
|
|
||||||
}
|
|
||||||
result->popHead();
|
|
||||||
element = result->headIter().get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (requiresAA) {
|
|
||||||
*requiresAA = numAAElements > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 == result->count()) {
|
|
||||||
if (*initialState == kAllIn_InitialState) {
|
|
||||||
*resultGenID = SkClipStack::kWideOpenGenID;
|
|
||||||
} else {
|
|
||||||
*resultGenID = SkClipStack::kEmptyGenID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace GrReducedClip
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2012 Google Inc.
|
* Copyright 2012 Google Inc.
|
||||||
*
|
*
|
||||||
@ -12,37 +11,39 @@
|
|||||||
#include "SkClipStack.h"
|
#include "SkClipStack.h"
|
||||||
#include "SkTLList.h"
|
#include "SkTLList.h"
|
||||||
|
|
||||||
namespace GrReducedClip {
|
class SK_API GrReducedClip {
|
||||||
|
public:
|
||||||
|
typedef SkTLList<SkClipStack::Element> ElementList;
|
||||||
|
|
||||||
typedef SkTLList<SkClipStack::Element> ElementList;
|
enum InitialState {
|
||||||
|
kAllIn_InitialState,
|
||||||
|
kAllOut_InitialState,
|
||||||
|
};
|
||||||
|
|
||||||
enum InitialState {
|
/**
|
||||||
kAllIn_InitialState,
|
* This function takes a clip stack and a query rectangle and it produces a
|
||||||
kAllOut_InitialState,
|
* reduced set of SkClipStack::Elements that are equivalent to applying the
|
||||||
|
* full stack to the rectangle. The clip stack generation id that represents
|
||||||
|
* the list of elements is returned in resultGenID. The initial state of the
|
||||||
|
* query rectangle before the first clip element is applied is returned via
|
||||||
|
* initialState. Optionally, the caller can request a tighter bounds on the
|
||||||
|
* clip be returned via tighterBounds. If not NULL, tighterBounds will
|
||||||
|
* always be contained by queryBounds after return. If tighterBounds is
|
||||||
|
* specified then it is assumed that the caller will implicitly clip against
|
||||||
|
* it. If the caller specifies non-NULL for requiresAA then it will indicate
|
||||||
|
* whether anti-aliasing is required to process any of the elements in the
|
||||||
|
* result.
|
||||||
|
*
|
||||||
|
* This may become a member function of SkClipStack when its interface is
|
||||||
|
* determined to be stable.
|
||||||
|
*/
|
||||||
|
static void ReduceClipStack(const SkClipStack& stack,
|
||||||
|
const SkIRect& queryBounds,
|
||||||
|
ElementList* result,
|
||||||
|
int32_t* resultGenID,
|
||||||
|
InitialState* initialState,
|
||||||
|
SkIRect* tighterBounds = NULL,
|
||||||
|
bool* requiresAA = NULL);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* This function takes a clip stack and a query rectangle and it produces a reduced set of
|
|
||||||
* SkClipStack::Elements that are equivalent to applying the full stack to the rectangle. The clip
|
|
||||||
* stack generation id that represents the list of elements is returned in resultGenID. The
|
|
||||||
* initial state of the query rectangle before the first clip element is applied is returned via
|
|
||||||
* initialState. Optionally, the caller can request a tighter bounds on the clip be returned via
|
|
||||||
* tighterBounds. If not NULL, tighterBounds will always be contained by queryBounds after return.
|
|
||||||
* If tighterBounds is specified then it is assumed that the caller will implicitly clip against it.
|
|
||||||
* If the caller specifies non-NULL for requiresAA then it will indicate whether anti-aliasing is
|
|
||||||
* required to process any of the elements in the result.
|
|
||||||
*
|
|
||||||
* This may become a member function of SkClipStack when its interface is determined to be stable.
|
|
||||||
* Marked SK_API so that SkLua can call this in a shared library build.
|
|
||||||
*/
|
|
||||||
SK_API void ReduceClipStack(const SkClipStack& stack,
|
|
||||||
const SkIRect& queryBounds,
|
|
||||||
ElementList* result,
|
|
||||||
int32_t* resultGenID,
|
|
||||||
InitialState* initialState,
|
|
||||||
SkIRect* tighterBounds = NULL,
|
|
||||||
bool* requiresAA = NULL);
|
|
||||||
|
|
||||||
} // namespace GrReducedClip
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user