2015-06-10 21:23:15 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2015 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef SkPathPriv_DEFINED
|
|
|
|
#define SkPathPriv_DEFINED
|
|
|
|
|
|
|
|
#include "SkPath.h"
|
|
|
|
|
|
|
|
class SkPathPriv {
|
|
|
|
public:
|
2017-09-14 14:31:36 +00:00
|
|
|
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
|
|
|
|
static const int kPathRefGenIDBitCnt = 30; // leave room for the fill type (skbug.com/1762)
|
|
|
|
#else
|
|
|
|
static const int kPathRefGenIDBitCnt = 32;
|
|
|
|
#endif
|
|
|
|
|
2015-06-10 21:23:15 +00:00
|
|
|
enum FirstDirection {
|
|
|
|
kCW_FirstDirection, // == SkPath::kCW_Direction
|
|
|
|
kCCW_FirstDirection, // == SkPath::kCCW_Direction
|
|
|
|
kUnknown_FirstDirection,
|
|
|
|
};
|
|
|
|
|
|
|
|
static FirstDirection AsFirstDirection(SkPath::Direction dir) {
|
|
|
|
// since we agree numerically for the values in Direction, we can just cast.
|
|
|
|
return (FirstDirection)dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the opposite of the specified direction. kUnknown is its own
|
|
|
|
* opposite.
|
|
|
|
*/
|
|
|
|
static FirstDirection OppositeFirstDirection(FirstDirection dir) {
|
|
|
|
static const FirstDirection gOppositeDir[] = {
|
2016-03-29 16:03:52 +00:00
|
|
|
kCCW_FirstDirection, kCW_FirstDirection, kUnknown_FirstDirection,
|
2015-06-10 21:23:15 +00:00
|
|
|
};
|
|
|
|
return gOppositeDir[dir];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Tries to quickly compute the direction of the first non-degenerate
|
|
|
|
* contour. If it can be computed, return true and set dir to that
|
|
|
|
* direction. If it cannot be (quickly) determined, return false and ignore
|
|
|
|
* the dir parameter. If the direction was determined, it is cached to make
|
|
|
|
* subsequent calls return quickly.
|
|
|
|
*/
|
|
|
|
static bool CheapComputeFirstDirection(const SkPath&, FirstDirection* dir);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns true if the path's direction can be computed via
|
|
|
|
* cheapComputDirection() and if that computed direction matches the
|
|
|
|
* specified direction. If dir is kUnknown, returns true if the direction
|
|
|
|
* cannot be computed.
|
|
|
|
*/
|
|
|
|
static bool CheapIsFirstDirection(const SkPath& path, FirstDirection dir) {
|
|
|
|
FirstDirection computedDir = kUnknown_FirstDirection;
|
|
|
|
(void)CheapComputeFirstDirection(path, &computedDir);
|
|
|
|
return computedDir == dir;
|
|
|
|
}
|
|
|
|
|
2015-12-15 19:01:12 +00:00
|
|
|
static bool IsClosedSingleContour(const SkPath& path) {
|
|
|
|
int verbCount = path.countVerbs();
|
|
|
|
if (verbCount == 0)
|
|
|
|
return false;
|
|
|
|
int moveCount = 0;
|
|
|
|
auto verbs = path.fPathRef->verbs();
|
|
|
|
for (int i = 0; i < verbCount; i++) {
|
|
|
|
switch (verbs[~i]) { // verbs are stored backwards; we use [~i] to get the i'th verb
|
|
|
|
case SkPath::Verb::kMove_Verb:
|
|
|
|
moveCount += 1;
|
|
|
|
if (moveCount > 1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SkPath::Verb::kClose_Verb:
|
|
|
|
if (i == verbCount - 1) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2015-06-26 14:18:24 +00:00
|
|
|
}
|
2015-08-04 17:01:58 +00:00
|
|
|
|
|
|
|
static void AddGenIDChangeListener(const SkPath& path, SkPathRef::GenIDChangeListener* listener) {
|
|
|
|
path.fPathRef->addGenIDChangeListener(listener);
|
|
|
|
}
|
2016-06-01 16:42:31 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This returns true for a rect that begins and ends at the same corner and has either a move
|
|
|
|
* followed by four lines or a move followed by 3 lines and a close. None of the parameters are
|
|
|
|
* optional. This does not permit degenerate line or point rectangles.
|
|
|
|
*/
|
|
|
|
static bool IsSimpleClosedRect(const SkPath& path, SkRect* rect, SkPath::Direction* direction,
|
|
|
|
unsigned* start);
|
2016-08-25 19:29:23 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a path from arc params using the semantics of SkCanvas::drawArc. This function
|
|
|
|
* assumes empty ovals and zero sweeps have already been filtered out.
|
|
|
|
*/
|
|
|
|
static void CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar startAngle,
|
|
|
|
SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect);
|
2016-09-21 15:26:57 +00:00
|
|
|
|
2017-06-15 17:41:37 +00:00
|
|
|
/**
|
|
|
|
* Returns a C++11-iterable object that traverses a path's verbs in order. e.g:
|
|
|
|
*
|
|
|
|
* for (SkPath::Verb verb : SkPathPriv::Verbs(path)) {
|
|
|
|
* ...
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
struct Verbs {
|
|
|
|
public:
|
|
|
|
Verbs(const SkPath& path) : fPathRef(path.fPathRef.get()) {}
|
|
|
|
struct Iter {
|
|
|
|
void operator++() { --fVerb; } // verbs are laid out backwards in memory.
|
|
|
|
bool operator!=(const Iter& b) { return fVerb != b.fVerb; }
|
|
|
|
SkPath::Verb operator*() { return static_cast<SkPath::Verb>(*fVerb); }
|
|
|
|
const uint8_t* fVerb;
|
|
|
|
};
|
|
|
|
Iter begin() { return Iter{fPathRef->verbs() - 1}; }
|
|
|
|
Iter end() { return Iter{fPathRef->verbs() - fPathRef->countVerbs() - 1}; }
|
|
|
|
private:
|
|
|
|
Verbs(const Verbs&) = delete;
|
|
|
|
Verbs& operator=(const Verbs&) = delete;
|
|
|
|
SkPathRef* fPathRef;
|
|
|
|
};
|
|
|
|
|
2016-09-21 15:26:57 +00:00
|
|
|
/**
|
|
|
|
* Returns a pointer to the verb data. Note that the verbs are stored backwards in memory and
|
|
|
|
* thus the returned pointer is the last verb.
|
|
|
|
*/
|
|
|
|
static const uint8_t* VerbData(const SkPath& path) {
|
|
|
|
return path.fPathRef->verbsMemBegin();
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns a raw pointer to the path points */
|
|
|
|
static const SkPoint* PointData(const SkPath& path) {
|
|
|
|
return path.fPathRef->points();
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns the number of conic weights in the path */
|
|
|
|
static int ConicWeightCnt(const SkPath& path) {
|
|
|
|
return path.fPathRef->countWeights();
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns a raw pointer to the path conic weights. */
|
|
|
|
static const SkScalar* ConicWeightData(const SkPath& path) {
|
|
|
|
return path.fPathRef->conicWeights();
|
|
|
|
}
|
2017-11-04 21:22:22 +00:00
|
|
|
|
|
|
|
/** Returns true if the underlying SkPathRef has one single owner. */
|
|
|
|
static bool TestingOnly_unique(const SkPath& path) {
|
|
|
|
return path.fPathRef->unique();
|
|
|
|
}
|
|
|
|
|
2018-02-20 18:57:05 +00:00
|
|
|
/** Returns true if constructed by addCircle(), addOval(); and in some cases,
|
|
|
|
addRoundRect(), addRRect(). SkPath constructed with conicTo() or rConicTo() will not
|
|
|
|
return true though SkPath draws oval.
|
|
|
|
|
|
|
|
rect receives bounds of oval.
|
|
|
|
dir receives SkPath::Direction of oval: kCW_Direction if clockwise, kCCW_Direction if
|
|
|
|
counterclockwise.
|
|
|
|
start receives start of oval: 0 for top, 1 for right, 2 for bottom, 3 for left.
|
|
|
|
|
|
|
|
rect, dir, and start are unmodified if oval is not found.
|
|
|
|
|
|
|
|
Triggers performance optimizations on some GPU surface implementations.
|
|
|
|
|
|
|
|
@param rect storage for bounding SkRect of oval; may be nullptr
|
|
|
|
@param dir storage for SkPath::Direction; may be nullptr
|
|
|
|
@param start storage for start of oval; may be nullptr
|
|
|
|
@return true if SkPath was constructed by method that reduces to oval
|
|
|
|
*/
|
|
|
|
static bool IsOval(const SkPath& path, SkRect* rect, SkPath::Direction* dir, unsigned* start) {
|
|
|
|
bool isCCW = false;
|
|
|
|
bool result = path.fPathRef->isOval(rect, &isCCW, start);
|
|
|
|
if (dir && result) {
|
|
|
|
*dir = isCCW ? SkPath::kCCW_Direction : SkPath::kCW_Direction;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns true if constructed by addRoundRect(), addRRect(); and if construction
|
|
|
|
is not empty, not SkRect, and not oval. SkPath constructed with other calls
|
|
|
|
will not return true though SkPath draws SkRRect.
|
|
|
|
|
|
|
|
rrect receives bounds of SkRRect.
|
|
|
|
dir receives SkPath::Direction of oval: kCW_Direction if clockwise, kCCW_Direction if
|
|
|
|
counterclockwise.
|
|
|
|
start receives start of SkRRect: 0 for top, 1 for right, 2 for bottom, 3 for left.
|
|
|
|
|
|
|
|
rrect, dir, and start are unmodified if SkRRect is not found.
|
|
|
|
|
|
|
|
Triggers performance optimizations on some GPU surface implementations.
|
|
|
|
|
|
|
|
@param rrect storage for bounding SkRect of SkRRect; may be nullptr
|
|
|
|
@param dir storage for SkPath::Direction; may be nullptr
|
|
|
|
@param start storage for start of SkRRect; may be nullptr
|
|
|
|
@return true if SkPath contains only SkRRect
|
|
|
|
*/
|
|
|
|
static bool IsRRect(const SkPath& path, SkRRect* rrect, SkPath::Direction* dir,
|
|
|
|
unsigned* start) {
|
|
|
|
bool isCCW = false;
|
|
|
|
bool result = path.fPathRef->isRRect(rrect, &isCCW, start);
|
|
|
|
if (dir && result) {
|
|
|
|
*dir = isCCW ? SkPath::kCCW_Direction : SkPath::kCW_Direction;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2015-06-10 21:23:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|