clean up includes

Prepare SkRegion.h, SkShader.h, SkStream.h for documentation.
Name params, add trailing commas to enum member list,
move or remove some public SkRegion.h stuff.

SkRegion gets a minor overhaul to move some pieces
to private: or SkRegionPriv. The intent is to preserve the
current code so that the fixes for documentation do not impact
performance or code size.

R=djsollen@google.com,reed@google.com

Docs-Preview: https://skia.org/?cl=141284
Bug: skia:6818
Change-Id: I0d82794081b8739a9e8af0d1cd4a0e5d32d04f04
Reviewed-on: https://skia-review.googlesource.com/141284
Commit-Queue: Cary Clark <caryclark@skia.org>
Reviewed-by: Mike Reed <reed@google.com>
This commit is contained in:
Cary Clark 2018-07-28 10:14:27 -04:00 committed by Skia Commit-Bot
parent 98d3375b36
commit 6943689ab4
9 changed files with 178 additions and 261 deletions

View File

@ -8,7 +8,7 @@
#include "SkCanvas.h"
#include "SkPaint.h"
#include "SkRegion.h"
#include "SkRegionPriv.h"
#include "SkSurface.h"
bool FuzzRegionDeserialize(sk_sp<SkData> bytes) {
@ -30,7 +30,7 @@ bool FuzzRegionDeserialize(sk_sp<SkData> bytes) {
return false;
}
s->getCanvas()->drawRegion(region, SkPaint());
SkDEBUGCODE(region.validate());
SkDEBUGCODE(SkRegionPriv::Validate(region));
return true;
}

View File

@ -15,29 +15,20 @@
class SkPath;
class SkRgnBuilder;
namespace android {
class Region;
}
#define SkRegion_gEmptyRunHeadPtr ((SkRegion::RunHead*)-1)
#define SkRegion_gRectRunHeadPtr nullptr
/** \class SkRegion
The SkRegion class encapsulates the geometric region used to specify
clipping areas for drawing.
*/
class SK_API SkRegion {
public:
typedef int32_t RunType;
static constexpr int kRunTypeSentinel = 0x7FFFFFFF;
public:
SkRegion();
SkRegion(const SkRegion&);
explicit SkRegion(const SkIRect&);
SkRegion(const SkRegion& region);
explicit SkRegion(const SkIRect& region);
~SkRegion();
SkRegion& operator=(const SkRegion&);
SkRegion& operator=(const SkRegion& region);
/**
* Return true if the two regions are equal. i.e. The enclose exactly
@ -65,13 +56,13 @@ public:
* Swap the contents of this and the specified region. This operation
* is gauarenteed to never fail.
*/
void swap(SkRegion&);
void swap(SkRegion& other);
/** Return true if this region is empty */
bool isEmpty() const { return fRunHead == SkRegion_gEmptyRunHeadPtr; }
bool isEmpty() const { return fRunHead == emptyRunHeadPtr(); }
/** Return true if this region is a single, non-empty rectangle */
bool isRect() const { return fRunHead == SkRegion_gRectRunHeadPtr; }
bool isRect() const { return fRunHead == kRectRunHeadPtr; }
/** Return true if this region consists of more than 1 rectangular area */
bool isComplex() const { return !this->isEmpty() && !this->isRect(); }
@ -109,7 +100,7 @@ public:
* If rect is non-empty, set this region to that rectangle and return true,
* otherwise set this region to empty and return false.
*/
bool setRect(const SkIRect&);
bool setRect(const SkIRect& rect);
/**
* If left < right and top < bottom, set this region to that rectangle and
@ -131,7 +122,7 @@ public:
* Set this region to the specified region, and return true if it is
* non-empty.
*/
bool setRegion(const SkRegion&);
bool setRegion(const SkRegion& region);
/**
* Set this region to the area described by the path, clipped.
@ -139,19 +130,19 @@ public:
* This produces a region that is identical to the pixels that would be
* drawn by the path (with no antialiasing) with the specified clip.
*/
bool setPath(const SkPath&, const SkRegion& clip);
bool setPath(const SkPath& path, const SkRegion& clip);
/**
* Returns true if the specified rectangle has a non-empty intersection
* with this region.
*/
bool intersects(const SkIRect&) const;
bool intersects(const SkIRect& rect) const;
/**
* Returns true if the specified region has a non-empty intersection
* with this region.
*/
bool intersects(const SkRegion&) const;
bool intersects(const SkRegion& other) const;
/**
* Return true if the specified x,y coordinate is inside the region.
@ -164,7 +155,7 @@ public:
* returns the correct result. Note: if either this region or the rectangle
* is empty, contains() returns false.
*/
bool contains(const SkIRect&) const;
bool contains(const SkIRect& other) const;
/**
* Return true if the specified region is completely inside the region.
@ -172,7 +163,7 @@ public:
* returns the correct result. Note: if either region is empty, contains()
* returns false.
*/
bool contains(const SkRegion&) const;
bool contains(const SkRegion& other) const;
/**
* Return true if this region is a single rectangle (not complex) and the
@ -196,7 +187,7 @@ public:
SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region
return left < right && top < bottom &&
fRunHead == SkRegion_gRectRunHeadPtr && // this->isRect()
fRunHead == kRectRunHeadPtr && // this->isRect()
/* fBounds.contains(left, top, right, bottom); */
fBounds.fLeft <= left && fBounds.fTop <= top &&
fBounds.fRight >= right && fBounds.fBottom >= bottom;
@ -245,7 +236,7 @@ public:
kReverseDifference_Op,
kReplace_Op, //!< replace the dst region with the op region
kLastOp = kReplace_Op
kLastOp = kReplace_Op,
};
static const int kOpCnt = kLastOp + 1;
@ -317,11 +308,11 @@ public:
class SK_API Iterator {
public:
Iterator() : fRgn(nullptr), fDone(true) {}
Iterator(const SkRegion&);
Iterator(const SkRegion& region);
// if we have a region, reset to it and return true, else return false
bool rewind();
// reset the iterator, using the new region
void reset(const SkRegion&);
void reset(const SkRegion& region);
bool done() const { return fDone; }
void next();
const SkIRect& rect() const { return fRect; }
@ -330,7 +321,7 @@ public:
private:
const SkRegion* fRgn;
const RunType* fRuns;
const SkRegion::RunType* fRuns;
SkIRect fRect;
bool fDone;
};
@ -341,7 +332,7 @@ public:
*/
class SK_API Cliperator {
public:
Cliperator(const SkRegion&, const SkIRect& clip);
Cliperator(const SkRegion& region, const SkIRect& clip);
bool done() { return fDone; }
void next();
const SkIRect& rect() const { return fRect; }
@ -359,7 +350,7 @@ public:
*/
class Spanerator {
public:
Spanerator(const SkRegion&, int y, int left, int right);
Spanerator(const SkRegion& region, int y, int left, int right);
bool next(int* left, int* right);
private:
@ -383,19 +374,6 @@ public:
*/
size_t readFromMemory(const void* buffer, size_t length);
/**
* Returns a reference to a global empty region. Just a convenience for
* callers that need a const empty region.
*/
static const SkRegion& GetEmptyRegion();
SkDEBUGCODE(void dump() const;)
SkDEBUGCODE(void validate() const;)
SkDEBUGCODE(static void UnitTest();)
// expose this to allow for regression test on complex regions
SkDEBUGCODE(bool debugSetRuns(const RunType runs[], int count);)
private:
static constexpr int kOpCount = kReplace_Op + 1;
@ -404,15 +382,18 @@ private:
// S
static constexpr int kRectRegionRuns = 7;
friend class android::Region; // needed for marshalling efficiently
struct RunHead;
static RunHead* emptyRunHeadPtr() { return (SkRegion::RunHead*) -1; }
static constexpr RunHead* kRectRunHeadPtr = nullptr;
// allocate space for count runs
void allocateRuns(int count);
void allocateRuns(int count, int ySpanCount, int intervalCount);
void allocateRuns(const RunHead& src);
SkDEBUGCODE(void dump() const;)
SkIRect fBounds;
RunHead* fRunHead;

View File

@ -59,7 +59,7 @@ public:
*/
kDecal_TileMode,
kLast_TileMode = kDecal_TileMode
kLast_TileMode = kDecal_TileMode,
};
static constexpr int kTileModeCount = kLast_TileMode + 1;
@ -139,7 +139,7 @@ public:
kRadial_GradientType,
kSweep_GradientType,
kConical_GradientType,
kLast_GradientType = kConical_GradientType
kLast_GradientType = kConical_GradientType,
};
struct GradientInfo {

View File

@ -288,7 +288,7 @@ class SK_API SkNullWStream : public SkWStream {
public:
SkNullWStream() : fBytesWritten(0) {}
bool write(const void*, size_t n) override { fBytesWritten += n; return true; }
bool write(const void* , size_t n) override { fBytesWritten += n; return true; }
void flush() override {}
size_t bytesWritten() const override { return fBytesWritten; }
@ -373,7 +373,7 @@ public:
SkMemoryStream(const void* data, size_t length, bool copyData = false);
/** Creates the stream to read from the specified data */
SkMemoryStream(sk_sp<SkData>);
SkMemoryStream(sk_sp<SkData> data);
/** Returns a stream with a copy of the input data. */
static std::unique_ptr<SkMemoryStream> MakeCopy(const void* data, size_t length);
@ -397,7 +397,7 @@ public:
void setMemoryOwned(const void* data, size_t length);
sk_sp<SkData> asData() const { return fData; }
void setData(sk_sp<SkData>);
void setData(sk_sp<SkData> data);
void skipToAlign4();
const void* getAtPos();

View File

@ -114,46 +114,6 @@ static void test_text(SkCanvas* canvas) {
drawFadingText(canvas, str, len, x, y, paint);
}
#ifdef SK_DEBUG
static void make_rgn(SkRegion* rgn, int left, int top, int right, int bottom,
int count, int32_t runs[]) {
SkIRect r;
r.set(left, top, right, bottom);
rgn->debugSetRuns(runs, count);
SkASSERT(rgn->getBounds() == r);
}
static void test_union_bug_1505668(SkRegion* ra, SkRegion* rb, SkRegion* rc) {
static int32_t dataA[] = {
0x00000001,
0x000001dd, 2, 0x00000001, 0x0000000c, 0x0000000d, 0x00000025, 0x7fffffff,
0x000001de, 1, 0x00000001, 0x00000025, 0x7fffffff,
0x000004b3, 1, 0x00000001, 0x00000026, 0x7fffffff,
0x000004b4, 1, 0x0000000c, 0x00000026, 0x7fffffff,
0x00000579, 1, 0x00000000, 0x0000013a, 0x7fffffff,
0x000005d8, 1, 0x00000000, 0x0000013b, 0x7fffffff,
0x7fffffff
};
make_rgn(ra, 0, 1, 315, 1496, SK_ARRAY_COUNT(dataA), dataA);
static int32_t dataB[] = {
0x000000b6,
0x000000c4, 1, 0x000000a1, 0x000000f0, 0x7fffffff,
0x000000d6, 0, 0x7fffffff,
0x000000e4, 2, 0x00000070, 0x00000079, 0x000000a1, 0x000000b0, 0x7fffffff,
0x000000e6, 0, 0x7fffffff,
0x000000f4, 2, 0x00000070, 0x00000079, 0x000000a1, 0x000000b0, 0x7fffffff,
0x000000f6, 0, 0x7fffffff,
0x00000104, 1, 0x000000a1, 0x000000b0, 0x7fffffff,
0x7fffffff
};
make_rgn(rb, 112, 182, 240, 260, SK_ARRAY_COUNT(dataB), dataB);
rc->op(*ra, *rb, SkRegion::kUnion_Op);
}
#endif
static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
dst->fLeft = (int)::roundf(src.fLeft * scale);
dst->fTop = (int)::roundf(src.fTop * scale);
@ -324,26 +284,7 @@ protected:
test_text(canvas);
return;
}
#ifdef SK_DEBUG
if (true) {
SkRegion a, b, c;
test_union_bug_1505668(&a, &b, &c);
if (false) { // draw the result of the test
SkPaint paint;
canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
paint.setColor(SK_ColorRED);
paint_rgn(canvas, a, paint);
paint.setColor(0x800000FF);
paint_rgn(canvas, b, paint);
paint.setColor(SK_ColorBLACK);
paint.setStyle(SkPaint::kStroke_Style);
// paint_rgn(canvas, c, paint);
return;
}
}
#endif
const SkPoint origins[] = {
{ 30*SK_Scalar1, 50*SK_Scalar1 },
{ 150*SK_Scalar1, 50*SK_Scalar1 },

View File

@ -7,6 +7,7 @@
#include "SkRasterClip.h"
#include "SkPath.h"
#include "SkRegionPriv.h"
enum MutateResult {
kDoNothing_MutateResult,
@ -459,7 +460,7 @@ void SkRasterClip::validate() const {
SkASSERT(fAA.isEmpty());
}
fBW.validate();
SkRegionPriv::Validate(fBW);
fAA.validate();
SkASSERT(this->computeIsEmpty() == fIsEmpty);

View File

@ -31,7 +31,11 @@ SkDEBUGCODE(int32_t gRgnAllocCounter;)
/////////////////////////////////////////////////////////////////////////////////////////////////
#define SkRegion_gEmptyRunHeadPtr ((SkRegionPriv::RunHead*)-1)
#define SkRegion_gRectRunHeadPtr nullptr
constexpr int kRunArrayStackCount = 256;
// This is a simple data structure which is like a SkSTArray<N,T,true>, except that:
// - It does not initialize memory.
// - It does not distinguish between reserved space and initialized space.
@ -45,7 +49,7 @@ public:
#ifdef SK_DEBUG
int count() const { return fCount; }
#endif
SkRegion::RunType& operator[](int i) {
SkRegionPriv::RunType& operator[](int i) {
SkASSERT((unsigned)i < (unsigned)fCount);
return fPtr[i];
}
@ -56,36 +60,36 @@ public:
count += count >> 1;
fMalloc.realloc(count);
if (fPtr == fStack) {
memcpy(fMalloc.get(), fStack, fCount * sizeof(SkRegion::RunType));
memcpy(fMalloc.get(), fStack, fCount * sizeof(SkRegionPriv::RunType));
}
fPtr = fMalloc.get();
fCount = count;
}
}
private:
SkRegion::RunType fStack[kRunArrayStackCount];
SkAutoTMalloc<SkRegion::RunType> fMalloc;
SkRegionPriv::RunType fStack[kRunArrayStackCount];
SkAutoTMalloc<SkRegionPriv::RunType> fMalloc;
int fCount = kRunArrayStackCount;
SkRegion::RunType* fPtr; // non-owning pointer
SkRegionPriv::RunType* fPtr; // non-owning pointer
};
/* Pass in the beginning with the intervals.
* We back up 1 to read the interval-count.
* Return the beginning of the next scanline (i.e. the next Y-value)
*/
static SkRegion::RunType* skip_intervals(const SkRegion::RunType runs[]) {
static SkRegionPriv::RunType* skip_intervals(const SkRegionPriv::RunType runs[]) {
int intervals = runs[-1];
#ifdef SK_DEBUG
if (intervals > 0) {
SkASSERT(runs[0] < runs[1]);
SkASSERT(runs[1] < SkRegion::kRunTypeSentinel);
SkASSERT(runs[1] < SkRegion_kRunTypeSentinel);
} else {
SkASSERT(0 == intervals);
SkASSERT(SkRegion::kRunTypeSentinel == runs[0]);
SkASSERT(SkRegion_kRunTypeSentinel == runs[0]);
}
#endif
runs += intervals * 2 + 1;
return const_cast<SkRegion::RunType*>(runs);
return const_cast<SkRegionPriv::RunType*>(runs);
}
bool SkRegion::RunsAreARect(const SkRegion::RunType runs[], int count,
@ -189,10 +193,10 @@ bool SkRegion::setRect(const SkIRect& r) {
return this->setEmpty();
}
this->freeRuns();
SkASSERT(r.left() != SkRegion::kRunTypeSentinel);
SkASSERT(r.top() != SkRegion::kRunTypeSentinel);
SkASSERT(r.right() != SkRegion::kRunTypeSentinel);
SkASSERT(r.bottom() != SkRegion::kRunTypeSentinel);
SkASSERT(r.left() != SkRegion_kRunTypeSentinel);
SkASSERT(r.top() != SkRegion_kRunTypeSentinel);
SkASSERT(r.right() != SkRegion_kRunTypeSentinel);
SkASSERT(r.bottom() != SkRegion_kRunTypeSentinel);
fBounds = r;
fRunHead = SkRegion_gRectRunHeadPtr;
return true;
@ -274,7 +278,7 @@ static bool isRunCountEmpty(int count) {
}
bool SkRegion::setRuns(RunType runs[], int count) {
SkDEBUGCODE(this->validate();)
SkDEBUGCODE(SkRegionPriv::Validate(*this));
SkASSERT(count > 0);
if (isRunCountEmpty(count)) {
@ -291,7 +295,7 @@ bool SkRegion::setRuns(RunType runs[], int count) {
assert_sentinel(runs[1], false); // bottom
// runs[2] is uncomputed intervalCount
if (runs[3] == SkRegion::kRunTypeSentinel) { // should be first left...
if (runs[3] == SkRegion_kRunTypeSentinel) { // should be first left...
runs += 3; // skip empty initial span
runs[0] = runs[-2]; // set new top to prev bottom
assert_sentinel(runs[1], false); // bot: a sentinal would mean two in a row
@ -304,8 +308,8 @@ bool SkRegion::setRuns(RunType runs[], int count) {
assert_sentinel(stop[-2], true);
// now check for a trailing empty span
if (stop[-5] == SkRegion::kRunTypeSentinel) { // eek, stop[-4] was a bottom with no x-runs
stop[-4] = SkRegion::kRunTypeSentinel; // kill empty last span
if (stop[-5] == SkRegion_kRunTypeSentinel) { // eek, stop[-4] was a bottom with no x-runs
stop[-4] = SkRegion_kRunTypeSentinel; // kill empty last span
stop -= 3;
assert_sentinel(stop[-1], true); // last y-sentinel
assert_sentinel(stop[-2], true); // last x-sentinel
@ -342,7 +346,7 @@ bool SkRegion::setRuns(RunType runs[], int count) {
return this->setEmpty();
}
SkDEBUGCODE(this->validate();)
SkDEBUGCODE(SkRegionPriv::Validate(*this));
return true;
}
@ -354,12 +358,12 @@ void SkRegion::BuildRectRuns(const SkIRect& bounds,
runs[2] = 1; // 1 interval for this scanline
runs[3] = bounds.fLeft;
runs[4] = bounds.fRight;
runs[5] = kRunTypeSentinel;
runs[6] = kRunTypeSentinel;
runs[5] = SkRegion_kRunTypeSentinel;
runs[6] = SkRegion_kRunTypeSentinel;
}
bool SkRegion::contains(int32_t x, int32_t y) const {
SkDEBUGCODE(this->validate();)
SkDEBUGCODE(SkRegionPriv::Validate(*this));
if (!fBounds.contains(x, y)) {
return false;
@ -392,17 +396,17 @@ bool SkRegion::contains(int32_t x, int32_t y) const {
return false;
}
static SkRegion::RunType scanline_bottom(const SkRegion::RunType runs[]) {
static SkRegionPriv::RunType scanline_bottom(const SkRegionPriv::RunType runs[]) {
return runs[0];
}
static const SkRegion::RunType* scanline_next(const SkRegion::RunType runs[]) {
static const SkRegionPriv::RunType* scanline_next(const SkRegionPriv::RunType runs[]) {
// skip [B N [L R]... S]
return runs + 2 + runs[1] * 2 + 1;
}
static bool scanline_contains(const SkRegion::RunType runs[],
SkRegion::RunType L, SkRegion::RunType R) {
static bool scanline_contains(const SkRegionPriv::RunType runs[],
SkRegionPriv::RunType L, SkRegionPriv::RunType R) {
runs += 2; // skip Bottom and IntervalCount
for (;;) {
if (L < runs[0]) {
@ -417,7 +421,7 @@ static bool scanline_contains(const SkRegion::RunType runs[],
}
bool SkRegion::contains(const SkIRect& r) const {
SkDEBUGCODE(this->validate();)
SkDEBUGCODE(SkRegionPriv::Validate(*this));
if (!fBounds.contains(r)) {
return false;
@ -441,8 +445,8 @@ bool SkRegion::contains(const SkIRect& r) const {
}
bool SkRegion::contains(const SkRegion& rgn) const {
SkDEBUGCODE(this->validate();)
SkDEBUGCODE(rgn.validate();)
SkDEBUGCODE(SkRegionPriv::Validate(*this));
SkDEBUGCODE(SkRegionPriv::Validate(rgn));
if (this->isEmpty() || rgn.isEmpty() || !fBounds.contains(rgn.fBounds)) {
return false;
@ -467,7 +471,7 @@ const SkRegion::RunType* SkRegion::getRuns(RunType tmpStorage[],
const RunType* runs = tmpStorage;
if (this->isEmpty()) {
tmpStorage[0] = kRunTypeSentinel;
tmpStorage[0] = SkRegion_kRunTypeSentinel;
*intervals = 0;
} else if (this->isRect()) {
BuildRectRuns(fBounds, tmpStorage);
@ -481,8 +485,8 @@ const SkRegion::RunType* SkRegion::getRuns(RunType tmpStorage[],
///////////////////////////////////////////////////////////////////////////////
static bool scanline_intersects(const SkRegion::RunType runs[],
SkRegion::RunType L, SkRegion::RunType R) {
static bool scanline_intersects(const SkRegionPriv::RunType runs[],
SkRegionPriv::RunType L, SkRegionPriv::RunType R) {
runs += 2; // skip Bottom and IntervalCount
for (;;) {
if (R <= runs[0]) {
@ -497,7 +501,7 @@ static bool scanline_intersects(const SkRegion::RunType runs[],
}
bool SkRegion::intersects(const SkIRect& r) const {
SkDEBUGCODE(this->validate();)
SkDEBUGCODE(SkRegionPriv::Validate(*this));
if (this->isEmpty() || r.isEmpty()) {
return false;
@ -554,8 +558,8 @@ bool SkRegion::intersects(const SkRegion& rgn) const {
///////////////////////////////////////////////////////////////////////////////
bool SkRegion::operator==(const SkRegion& b) const {
SkDEBUGCODE(validate();)
SkDEBUGCODE(b.validate();)
SkDEBUGCODE(SkRegionPriv::Validate(*this));
SkDEBUGCODE(SkRegionPriv::Validate(b));
if (this == &b) {
return true;
@ -591,7 +595,7 @@ static int32_t pin_offset_s32(int32_t min, int32_t max, int32_t offset) {
}
void SkRegion::translate(int dx, int dy, SkRegion* dst) const {
SkDEBUGCODE(this->validate();)
SkDEBUGCODE(SkRegionPriv::Validate(*this));
if (nullptr == dst) {
return;
@ -625,28 +629,28 @@ void SkRegion::translate(int dx, int dy, SkRegion* dst) const {
*druns++ = (SkRegion::RunType)(*sruns++ + dy); // top
for (;;) {
int bottom = *sruns++;
if (bottom == kRunTypeSentinel) {
if (bottom == SkRegion_kRunTypeSentinel) {
break;
}
*druns++ = (SkRegion::RunType)(bottom + dy); // bottom;
*druns++ = *sruns++; // copy intervalCount;
for (;;) {
int x = *sruns++;
if (x == kRunTypeSentinel) {
if (x == SkRegion_kRunTypeSentinel) {
break;
}
*druns++ = (SkRegion::RunType)(x + dx);
*druns++ = (SkRegion::RunType)(*sruns++ + dx);
}
*druns++ = kRunTypeSentinel; // x sentinel
*druns++ = SkRegion_kRunTypeSentinel; // x sentinel
}
*druns++ = kRunTypeSentinel; // y sentinel
*druns++ = SkRegion_kRunTypeSentinel; // y sentinel
SkASSERT(sruns - fRunHead->readonly_runs() == fRunHead->fRunCount);
SkASSERT(druns - dst->fRunHead->readonly_runs() == dst->fRunHead->fRunCount);
}
SkDEBUGCODE(this->validate();)
SkDEBUGCODE(SkRegionPriv::Validate(*this));
}
///////////////////////////////////////////////////////////////////////////////
@ -673,20 +677,20 @@ bool SkRegion::setRects(const SkIRect rects[], int count) {
#ifdef SK_DEBUG
static void assert_valid_pair(int left, int rite)
{
SkASSERT(left == SkRegion::kRunTypeSentinel || left < rite);
SkASSERT(left == SkRegion_kRunTypeSentinel || left < rite);
}
#else
#define assert_valid_pair(left, rite)
#endif
struct spanRec {
const SkRegion::RunType* fA_runs;
const SkRegion::RunType* fB_runs;
const SkRegionPriv::RunType* fA_runs;
const SkRegionPriv::RunType* fB_runs;
int fA_left, fA_rite, fB_left, fB_rite;
int fLeft, fRite, fInside;
void init(const SkRegion::RunType a_runs[],
const SkRegion::RunType b_runs[]) {
void init(const SkRegionPriv::RunType a_runs[],
const SkRegionPriv::RunType b_runs[]) {
fA_left = *a_runs++;
fA_rite = *a_runs++;
fB_left = *b_runs++;
@ -697,10 +701,10 @@ struct spanRec {
}
bool done() const {
SkASSERT(fA_left <= SkRegion::kRunTypeSentinel);
SkASSERT(fB_left <= SkRegion::kRunTypeSentinel);
return fA_left == SkRegion::kRunTypeSentinel &&
fB_left == SkRegion::kRunTypeSentinel;
SkASSERT(fA_left <= SkRegion_kRunTypeSentinel);
SkASSERT(fB_left <= SkRegion_kRunTypeSentinel);
return fA_left == SkRegion_kRunTypeSentinel &&
fB_left == SkRegion_kRunTypeSentinel;
}
void next() {
@ -770,20 +774,20 @@ struct spanRec {
}
};
static int distance_to_sentinel(const SkRegion::RunType* runs) {
const SkRegion::RunType* ptr = runs;
while (*ptr != SkRegion::kRunTypeSentinel) { ptr += 2; }
static int distance_to_sentinel(const SkRegionPriv::RunType* runs) {
const SkRegionPriv::RunType* ptr = runs;
while (*ptr != SkRegion_kRunTypeSentinel) { ptr += 2; }
return ptr - runs;
}
static int operate_on_span(const SkRegion::RunType a_runs[],
const SkRegion::RunType b_runs[],
static int operate_on_span(const SkRegionPriv::RunType a_runs[],
const SkRegionPriv::RunType b_runs[],
RunArray* array, int dstOffset,
int min, int max) {
// This is a worst-case for this span plus two for TWO terminating sentinels.
array->resizeToAtLeast(
dstOffset + distance_to_sentinel(a_runs) + distance_to_sentinel(b_runs) + 2);
SkRegion::RunType* dst = &(*array)[dstOffset]; // get pointer AFTER resizing.
SkRegionPriv::RunType* dst = &(*array)[dstOffset]; // get pointer AFTER resizing.
spanRec rec;
bool firstInterval = true;
@ -800,17 +804,17 @@ static int operate_on_span(const SkRegion::RunType a_runs[],
if ((unsigned)(rec.fInside - min) <= (unsigned)(max - min) &&
left < rite) { // skip if equal
if (firstInterval || *(dst - 1) < left) {
*dst++ = (SkRegion::RunType)(left);
*dst++ = (SkRegion::RunType)(rite);
*dst++ = (SkRegionPriv::RunType)(left);
*dst++ = (SkRegionPriv::RunType)(rite);
firstInterval = false;
} else {
// update the right edge
*(dst - 1) = (SkRegion::RunType)(rite);
*(dst - 1) = (SkRegionPriv::RunType)(rite);
}
}
}
SkASSERT(dst < &(*array)[array->count() - 1]);
*dst++ = SkRegion::kRunTypeSentinel;
*dst++ = SkRegion_kRunTypeSentinel;
return dst - &(*array)[0];
}
@ -839,32 +843,32 @@ public:
: fMin(gOpMinMax[op].fMin)
, fMax(gOpMinMax[op].fMax)
, fArray(array)
, fTop((SkRegion::RunType)top) // just a first guess, we might update this
, fTop((SkRegionPriv::RunType)top) // just a first guess, we might update this
{ SkASSERT((unsigned)op <= 3); }
void addSpan(int bottom, const SkRegion::RunType a_runs[],
const SkRegion::RunType b_runs[]) {
void addSpan(int bottom, const SkRegionPriv::RunType a_runs[],
const SkRegionPriv::RunType b_runs[]) {
// skip X values and slots for the next Y+intervalCount
int start = fPrevDst + fPrevLen + 2;
// start points to beginning of dst interval
int stop = operate_on_span(a_runs, b_runs, fArray, start, fMin, fMax);
size_t len = SkToSizeT(stop - start);
SkASSERT(len >= 1 && (len & 1) == 1);
SkASSERT(SkRegion::kRunTypeSentinel == (*fArray)[stop - 1]);
SkASSERT(SkRegion_kRunTypeSentinel == (*fArray)[stop - 1]);
// Assert memcmp won't exceed fArray->count().
SkASSERT(fArray->count() >= SkToInt(start + len - 1));
if (fPrevLen == len &&
(1 == len || !memcmp(&(*fArray)[fPrevDst],
&(*fArray)[start],
(len - 1) * sizeof(SkRegion::RunType)))) {
(len - 1) * sizeof(SkRegionPriv::RunType)))) {
// update Y value
(*fArray)[fPrevDst - 2] = (SkRegion::RunType)bottom;
(*fArray)[fPrevDst - 2] = (SkRegionPriv::RunType)bottom;
} else { // accept the new span
if (len == 1 && fPrevLen == 0) {
fTop = (SkRegion::RunType)bottom; // just update our bottom
fTop = (SkRegionPriv::RunType)bottom; // just update our bottom
} else {
(*fArray)[start - 2] = (SkRegion::RunType)bottom;
(*fArray)[start - 2] = (SkRegionPriv::RunType)bottom;
(*fArray)[start - 1] = SkToS32(len >> 1);
fPrevDst = start;
fPrevLen = len;
@ -876,7 +880,7 @@ public:
(*fArray)[fStartDst] = fTop;
// Previously reserved enough for TWO sentinals.
SkASSERT(fArray->count() > SkToInt(fPrevDst + fPrevLen));
(*fArray)[fPrevDst + fPrevLen] = SkRegion::kRunTypeSentinel;
(*fArray)[fPrevDst + fPrevLen] = SkRegion_kRunTypeSentinel;
return (int)(fPrevDst - fStartDst + fPrevLen + 1);
}
@ -889,21 +893,21 @@ private:
int fStartDst = 0;
int fPrevDst = 1;
size_t fPrevLen = 0; // will never match a length from operate_on_span
SkRegion::RunType fTop;
SkRegionPriv::RunType fTop;
};
// want a unique value to signal that we exited due to quickExit
#define QUICK_EXIT_TRUE_COUNT (-1)
static int operate(const SkRegion::RunType a_runs[],
const SkRegion::RunType b_runs[],
static int operate(const SkRegionPriv::RunType a_runs[],
const SkRegionPriv::RunType b_runs[],
RunArray* dst,
SkRegion::Op op,
bool quickExit) {
const SkRegion::RunType gEmptyScanline[] = {
const SkRegionPriv::RunType gEmptyScanline[] = {
0, // dummy bottom value
0, // zero intervals
SkRegion::kRunTypeSentinel,
SkRegion_kRunTypeSentinel,
// just need a 2nd value, since spanRec.init() reads 2 values, even
// though if the first value is the sentinel, it ignores the 2nd value.
// w/o the 2nd value here, we might read uninitialized memory.
@ -911,7 +915,7 @@ static int operate(const SkRegion::RunType a_runs[],
// our sentinel value.
0
};
const SkRegion::RunType* const gSentinel = &gEmptyScanline[2];
const SkRegionPriv::RunType* const gSentinel = &gEmptyScanline[2];
int a_top = *a_runs++;
int a_bot = *a_runs++;
@ -930,13 +934,13 @@ static int operate(const SkRegion::RunType a_runs[],
RgnOper oper(SkMin32(a_top, b_top), dst, op);
int prevBot = SkRegion::kRunTypeSentinel; // so we fail the first test
int prevBot = SkRegion_kRunTypeSentinel; // so we fail the first test
while (a_bot < SkRegion::kRunTypeSentinel ||
b_bot < SkRegion::kRunTypeSentinel) {
while (a_bot < SkRegion_kRunTypeSentinel ||
b_bot < SkRegion_kRunTypeSentinel) {
int top, bot SK_INIT_TO_AVOID_WARNING;
const SkRegion::RunType* run0 = gSentinel;
const SkRegion::RunType* run1 = gSentinel;
const SkRegionPriv::RunType* run0 = gSentinel;
const SkRegionPriv::RunType* run1 = gSentinel;
bool a_flush = false;
bool b_flush = false;
@ -986,7 +990,7 @@ static int operate(const SkRegion::RunType a_runs[],
a_top = a_bot;
a_bot = *a_runs++;
a_runs += 1; // skip uninitialized intervalCount
if (a_bot == SkRegion::kRunTypeSentinel) {
if (a_bot == SkRegion_kRunTypeSentinel) {
a_top = a_bot;
}
}
@ -995,7 +999,7 @@ static int operate(const SkRegion::RunType a_runs[],
b_top = b_bot;
b_bot = *b_runs++;
b_runs += 1; // skip uninitialized intervalCount
if (b_bot == SkRegion::kRunTypeSentinel) {
if (b_bot == SkRegion_kRunTypeSentinel) {
b_top = b_bot;
}
}
@ -1138,7 +1142,7 @@ bool SkRegion::Oper(const SkRegion& rgnaOrig, const SkRegion& rgnbOrig, Op op,
}
bool SkRegion::op(const SkRegion& rgna, const SkRegion& rgnb, Op op) {
SkDEBUGCODE(this->validate();)
SkDEBUGCODE(SkRegionPriv::Validate(*this));
return SkRegion::Oper(rgna, rgnb, op, this);
}
@ -1209,16 +1213,16 @@ static bool validate_run(const int32_t* runs,
}
SkASSERT(runCount >= 7); // 7==SkRegion::kRectRegionRuns
// quick sanity check:
if (runs[runCount - 1] != SkRegion::kRunTypeSentinel ||
runs[runCount - 2] != SkRegion::kRunTypeSentinel) {
if (runs[runCount - 1] != SkRegion_kRunTypeSentinel ||
runs[runCount - 2] != SkRegion_kRunTypeSentinel) {
return false;
}
const int32_t* const end = runs + runCount;
SkIRect bounds = {0, 0, 0 ,0}; // calulated bounds
SkIRect rect = {0, 0, 0, 0}; // current rect
rect.fTop = *runs++;
if (rect.fTop == SkRegion::kRunTypeSentinel) {
return false; // no rect can contain SkRegion::kRunTypeSentinel
if (rect.fTop == SkRegion_kRunTypeSentinel) {
return false; // no rect can contain SkRegion_kRunTypeSentinel
}
if (rect.fTop != givenBounds.fTop) {
return false; // Must not begin with empty span that does not contribute to bounds.
@ -1229,7 +1233,7 @@ static bool validate_run(const int32_t* runs,
return false; // too many yspans
}
rect.fBottom = *runs++;
if (rect.fBottom == SkRegion::kRunTypeSentinel) {
if (rect.fBottom == SkRegion_kRunTypeSentinel) {
return false;
}
if (rect.fBottom > givenBounds.fBottom) {
@ -1250,8 +1254,8 @@ static bool validate_run(const int32_t* runs,
while (xIntervals-- > 0) {
rect.fLeft = *runs++;
rect.fRight = *runs++;
if (rect.fLeft == SkRegion::kRunTypeSentinel ||
rect.fRight == SkRegion::kRunTypeSentinel ||
if (rect.fLeft == SkRegion_kRunTypeSentinel ||
rect.fRight == SkRegion_kRunTypeSentinel ||
rect.fLeft >= rect.fRight || // check non-empty rect
(!firstInterval && rect.fLeft <= lastRight)) {
return false;
@ -1260,12 +1264,12 @@ static bool validate_run(const int32_t* runs,
firstInterval = false;
bounds.join(rect);
}
if (*runs++ != SkRegion::kRunTypeSentinel) {
if (*runs++ != SkRegion_kRunTypeSentinel) {
return false; // required check sentinal.
}
rect.fTop = rect.fBottom;
SkASSERT(runs < end);
} while (*runs != SkRegion::kRunTypeSentinel);
} while (*runs != SkRegion_kRunTypeSentinel);
++runs;
if (ySpanCount != 0 || intervalCount != 0 || givenBounds != bounds) {
return false;
@ -1318,13 +1322,6 @@ size_t SkRegion::readFromMemory(const void* storage, size_t length) {
///////////////////////////////////////////////////////////////////////////////
const SkRegion& SkRegion::GetEmptyRegion() {
static SkRegion gEmpty;
return gEmpty;
}
///////////////////////////////////////////////////////////////////////////////
bool SkRegion::isValid() const {
if (this->isEmpty()) {
return fBounds == SkIRect{0, 0, 0, 0};
@ -1341,7 +1338,7 @@ bool SkRegion::isValid() const {
}
#ifdef SK_DEBUG
void SkRegion::validate() const { SkASSERT(this->isValid()); }
void SkRegionPriv::Validate(const SkRegion& rgn) { SkASSERT(rgn.isValid()); }
void SkRegion::dump() const {
if (this->isEmpty()) {
@ -1403,13 +1400,13 @@ void SkRegion::Iterator::next() {
const RunType* runs = fRuns;
if (runs[0] < kRunTypeSentinel) { // valid X value
if (runs[0] < SkRegion_kRunTypeSentinel) { // valid X value
fRect.fLeft = runs[0];
fRect.fRight = runs[1];
runs += 2;
} else { // we're at the end of a line
runs += 1;
if (runs[0] < kRunTypeSentinel) { // valid Y value
if (runs[0] < SkRegion_kRunTypeSentinel) { // valid Y value
int intervals = runs[1];
if (0 == intervals) { // empty line
fRect.fTop = runs[0];
@ -1472,7 +1469,7 @@ void SkRegion::Cliperator::next() {
SkRegion::Spanerator::Spanerator(const SkRegion& rgn, int y, int left,
int right) {
SkDEBUGCODE(rgn.validate();)
SkDEBUGCODE(SkRegionPriv::Validate(rgn));
const SkIRect& r = rgn.getBounds();
@ -1592,17 +1589,3 @@ void SkRegionPriv::VisitSpans(const SkRegion& rgn,
}
}
///////////////////////////////////////////////////////////////////////////////
#ifdef SK_DEBUG
bool SkRegion::debugSetRuns(const RunType runs[], int count) {
// we need to make a copy, since the real method may modify the array, and
// so it cannot be const.
SkAutoTArray<RunType> storage(count);
memcpy(storage.get(), runs, count * sizeof(RunType));
return this->setRuns(storage.get(), count);
}
#endif

View File

@ -14,8 +14,29 @@
#include "SkMalloc.h"
#include "SkTo.h"
#include <functional>
class SkRegionPriv {
public:
static constexpr int kRunTypeSentinel = 0x7FFFFFFF;
typedef SkRegion::RunType RunType;
typedef SkRegion::RunHead RunHead;
// Call the function with each span, in Y -> X ascending order.
// We pass a rect, but we will still ensure the span Y->X ordering, so often the height
// of the rect may be 1. It should never be empty.
static void VisitSpans(const SkRegion& rgn, const std::function<void(const SkIRect&)>&);
#ifdef SK_DEBUG
static void Validate(const SkRegion& rgn);
#endif
};
static constexpr int SkRegion_kRunTypeSentinel = 0x7FFFFFFF;
inline bool SkRegionValueIsSentinel(int32_t value) {
return value == (int32_t)SkRegion::kRunTypeSentinel;
return value == (int32_t)SkRegion_kRunTypeSentinel;
}
#define assert_sentinel(value, isSentinel) \
@ -27,11 +48,11 @@ inline bool SkRegionValueIsSentinel(int32_t value) {
// Given the first interval (just past the interval-count), compute the
// interval count, by search for the x-sentinel
//
static int compute_intervalcount(const SkRegion::RunType runs[]) {
const SkRegion::RunType* curr = runs;
while (*curr < SkRegion::kRunTypeSentinel) {
static int compute_intervalcount(const SkRegionPriv::RunType runs[]) {
const SkRegionPriv::RunType* curr = runs;
while (*curr < SkRegion_kRunTypeSentinel) {
SkASSERT(curr[0] < curr[1]);
SkASSERT(curr[1] < SkRegion::kRunTypeSentinel);
SkASSERT(curr[1] < SkRegion_kRunTypeSentinel);
curr += 2;
}
return SkToInt((curr - runs) >> 1);
@ -133,10 +154,10 @@ public:
*/
static SkRegion::RunType* SkipEntireScanline(const SkRegion::RunType runs[]) {
// we are not the Y Sentinel
SkASSERT(runs[0] < SkRegion::kRunTypeSentinel);
SkASSERT(runs[0] < SkRegion_kRunTypeSentinel);
const int intervals = runs[1];
SkASSERT(runs[2 + intervals * 2] == SkRegion::kRunTypeSentinel);
SkASSERT(runs[2 + intervals * 2] == SkRegion_kRunTypeSentinel);
#ifdef SK_DEBUG
{
int n = compute_intervalcount(&runs[2]);
@ -168,7 +189,7 @@ public:
int bottom = runs[0];
// If we hit this, we've walked off the region, and our bounds check
// failed.
SkASSERT(bottom < SkRegion::kRunTypeSentinel);
SkASSERT(bottom < SkRegion_kRunTypeSentinel);
if (y < bottom) {
break;
}
@ -190,12 +211,12 @@ public:
do {
bot = *runs++;
SkASSERT(bot < SkRegion::kRunTypeSentinel);
SkASSERT(bot < SkRegion_kRunTypeSentinel);
ySpanCount += 1;
const int intervals = *runs++;
SkASSERT(intervals >= 0);
SkASSERT(intervals < SkRegion::kRunTypeSentinel);
SkASSERT(intervals < SkRegion_kRunTypeSentinel);
if (intervals > 0) {
#ifdef SK_DEBUG
@ -205,25 +226,25 @@ public:
}
#endif
RunType L = runs[0];
SkASSERT(L < SkRegion::kRunTypeSentinel);
SkASSERT(L < SkRegion_kRunTypeSentinel);
if (left > L) {
left = L;
}
runs += intervals * 2;
RunType R = runs[-1];
SkASSERT(R < SkRegion::kRunTypeSentinel);
SkASSERT(R < SkRegion_kRunTypeSentinel);
if (rite < R) {
rite = R;
}
intervalCount += intervals;
}
SkASSERT(SkRegion::kRunTypeSentinel == *runs);
SkASSERT(SkRegion_kRunTypeSentinel == *runs);
runs += 1; // skip x-sentinel
// test Y-sentinel
} while (SkRegion::kRunTypeSentinel > *runs);
} while (SkRegion_kRunTypeSentinel > *runs);
#ifdef SK_DEBUG
// +1 to skip the last Y-sentinel
@ -244,14 +265,4 @@ private:
int32_t fIntervalCount;
};
#include <functional>
class SkRegionPriv {
public:
// Call the function with each span, in Y -> X ascending order.
// We pass a rect, but we will still ensure the span Y->X ordering, so often the height
// of the rect may be 1. It should never be empty.
static void VisitSpans(const SkRegion& rgn, const std::function<void(const SkIRect&)>&);
};
#endif

View File

@ -236,11 +236,11 @@ void SkRgnBuilder::copyToRgn(SkRegion::RunType runs[]) const {
memcpy(runs, line->firstX(), count * sizeof(SkRegion::RunType));
runs += count;
}
*runs++ = SkRegion::kRunTypeSentinel;
*runs++ = SkRegion_kRunTypeSentinel;
line = line->nextScanline();
} while (line < stop);
SkASSERT(line == stop);
*runs = SkRegion::kRunTypeSentinel;
*runs = SkRegion_kRunTypeSentinel;
}
static unsigned verb_to_initial_last_index(unsigned verb) {
@ -320,7 +320,7 @@ static bool check_inverse_on_empty_return(SkRegion* dst, const SkPath& path, con
}
bool SkRegion::setPath(const SkPath& path, const SkRegion& clip) {
SkDEBUGCODE(this->validate();)
SkDEBUGCODE(SkRegionPriv::Validate(*this));
if (clip.isEmpty() || !path.isFinite()) {
return this->setEmpty();
@ -382,7 +382,7 @@ bool SkRegion::setPath(const SkPath& path, const SkRegion& clip) {
tmp.fRunHead->computeRunBounds(&tmp.fBounds);
this->swap(tmp);
}
SkDEBUGCODE(this->validate();)
SkDEBUGCODE(SkRegionPriv::Validate(*this));
return true;
}
@ -397,17 +397,17 @@ struct Edge {
kCompleteLink = (kY0Link | kY1Link)
};
SkRegion::RunType fX;
SkRegion::RunType fY0, fY1;
SkRegionPriv::RunType fX;
SkRegionPriv::RunType fY0, fY1;
uint8_t fFlags;
Edge* fNext;
void set(int x, int y0, int y1) {
SkASSERT(y0 != y1);
fX = (SkRegion::RunType)(x);
fY0 = (SkRegion::RunType)(y0);
fY1 = (SkRegion::RunType)(y1);
fX = (SkRegionPriv::RunType)(x);
fY0 = (SkRegionPriv::RunType)(y0);
fY1 = (SkRegionPriv::RunType)(y1);
fFlags = 0;
SkDEBUGCODE(fNext = nullptr;)
}