| Index: src/core/SkPathRef.cpp
|
| diff --git a/src/core/SkPathRef.cpp b/src/core/SkPathRef.cpp
|
| index 2fc2de935c149031342cdcdc538535bf50dcb49b..d8f6501853dd926fae26880a87bb9a789d8f5c6d 100644
|
| --- a/src/core/SkPathRef.cpp
|
| +++ b/src/core/SkPathRef.cpp
|
| @@ -90,15 +90,15 @@ void SkPathRef::CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst,
|
| matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt);
|
|
|
| /*
|
| - * Here we optimize the bounds computation, by noting if the bounds are
|
| - * already known, and if so, we just transform those as well and mark
|
| - * them as "known", rather than force the transformed path to have to
|
| - * recompute them.
|
| - *
|
| - * Special gotchas if the path is effectively empty (<= 1 point) or
|
| - * if it is non-finite. In those cases bounds need to stay empty,
|
| - * regardless of the matrix.
|
| - */
|
| + * Here we optimize the bounds computation, by noting if the bounds are
|
| + * already known, and if so, we just transform those as well and mark
|
| + * them as "known", rather than force the transformed path to have to
|
| + * recompute them.
|
| + *
|
| + * Special gotchas if the path is effectively empty (<= 1 point) or
|
| + * if it is non-finite. In those cases bounds need to stay empty,
|
| + * regardless of the matrix.
|
| + */
|
| if (canXformBounds) {
|
| (*dst)->fBoundsIsDirty = false;
|
| if (src.fIsFinite) {
|
| @@ -120,6 +120,58 @@ void SkPathRef::CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst,
|
| bool rectStaysRect = matrix.rectStaysRect();
|
| (*dst)->fIsOval = src.fIsOval && rectStaysRect;
|
| (*dst)->fIsRRect = src.fIsRRect && rectStaysRect;
|
| + if ((*dst)->fIsOval || (*dst)->fIsRRect) {
|
| + int start = src.fRRectOrOvalStartIdx;
|
| + int rm = 0;
|
| + if ((*dst)->fIsRRect) {
|
| + rm = src.fRRectOrOvalStartIdx & 0b1;
|
| + start /= 2;
|
| + }
|
| + // Is the antidiagonal non-zero (otherwise the diagonal is zero)
|
| + int antiDiag;
|
| + // Is the non-zero value in the top row (either kMScaleX or kMSkewX) negative
|
| + int topNeg;
|
| + // Are the two non-zero diagonal or antidiagonal values the same sign.
|
| + int sameSign;
|
| + if (matrix.get(SkMatrix::kMScaleX) != 0) {
|
| + antiDiag = 0b00;
|
| + if (matrix.get(SkMatrix::kMScaleX) > 0) {
|
| + topNeg = 0b00;
|
| + sameSign = matrix.get(SkMatrix::kMScaleY) > 0 ? 0b01 : 0b00;
|
| + } else {
|
| + topNeg = 0b10;
|
| + sameSign = matrix.get(SkMatrix::kMScaleY) > 0 ? 0b00 : 0b01;
|
| + }
|
| + } else {
|
| + antiDiag = 0b01;
|
| + if (matrix.get(SkMatrix::kMSkewX) > 0) {
|
| + topNeg = 0b00;
|
| + sameSign = matrix.get(SkMatrix::kMSkewY) > 0 ? 0b01 : 0b00;
|
| + } else {
|
| + topNeg = 0b10;
|
| + sameSign = matrix.get(SkMatrix::kMSkewY) > 0 ? 0b00 : 0b01;
|
| + }
|
| + }
|
| + if (sameSign != antiDiag) {
|
| + // This is a rotation plus scale
|
| + (*dst)->fRRectOrOvalIsCCW = src.fRRectOrOvalIsCCW;
|
| + // Trust me (or create yourself a table)
|
| + (*dst)->fRRectOrOvalStartIdx = (start + 4 - (topNeg | antiDiag)) % 4;
|
| + SkASSERT((*dst)->fRRectOrOvalStartIdx < 4);
|
| + if ((*dst)->fIsRRect) {
|
| + (*dst)->fRRectOrOvalStartIdx = 2 * (*dst)->fRRectOrOvalStartIdx + rm;
|
| + }
|
| + } else {
|
| + // This is a mirror plus scale
|
| + (*dst)->fRRectOrOvalIsCCW = !src.fRRectOrOvalIsCCW;
|
| + // Trust me (or create yourself a table)
|
| + (*dst)->fRRectOrOvalStartIdx = (6 + (topNeg | antiDiag) - start) % 4;
|
| + SkASSERT((*dst)->fRRectOrOvalStartIdx < 4);
|
| + if ((*dst)->fIsRRect) {
|
| + (*dst)->fRRectOrOvalStartIdx = 2 * (*dst)->fRRectOrOvalStartIdx + (rm ? 0b0 : 0b1);
|
| + }
|
| + }
|
| + }
|
|
|
| SkDEBUGCODE((*dst)->validate();)
|
| }
|
| @@ -137,6 +189,8 @@ SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) {
|
| uint8_t segmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF;
|
| bool isOval = (packed >> kIsOval_SerializationShift) & 1;
|
| bool isRRect = (packed >> kIsRRect_SerializationShift) & 1;
|
| + bool rrectOrOvalIsCCW = (packed >> kRRectOrOvalIsCCW_SerializationShift) & 1;
|
| + unsigned rrectOrOvalStartIdx = (packed >> kRRectOrOvalStartIdx_SerializationShift) & 0x7;
|
|
|
| int32_t verbCount, pointCount, conicCount;
|
| ptrdiff_t maxPtrDiff = std::numeric_limits<ptrdiff_t>::max();
|
| @@ -173,6 +227,8 @@ SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) {
|
| ref->fSegmentMask = segmentMask;
|
| ref->fIsOval = isOval;
|
| ref->fIsRRect = isRRect;
|
| + ref->fRRectOrOvalIsCCW = rrectOrOvalIsCCW;
|
| + ref->fRRectOrOvalStartIdx = rrectOrOvalStartIdx;
|
| return ref;
|
| }
|
|
|
| @@ -253,7 +309,9 @@ void SkPathRef::writeToBuffer(SkWBuffer* buffer) const {
|
| // and fIsFinite are computed.
|
| const SkRect& bounds = this->getBounds();
|
|
|
| - int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift) |
|
| + int32_t packed = ((fRRectOrOvalStartIdx & 7) << kRRectOrOvalStartIdx_SerializationShift) |
|
| + ((fRRectOrOvalIsCCW & 1) << kRRectOrOvalIsCCW_SerializationShift) |
|
| + ((fIsFinite & 1) << kIsFinite_SerializationShift) |
|
| ((fIsOval & 1) << kIsOval_SerializationShift) |
|
| ((fIsRRect & 1) << kIsRRect_SerializationShift) |
|
| (fSegmentMask << kSegmentMask_SerializationShift);
|
| @@ -298,6 +356,8 @@ void SkPathRef::copy(const SkPathRef& ref,
|
| fSegmentMask = ref.fSegmentMask;
|
| fIsOval = ref.fIsOval;
|
| fIsRRect = ref.fIsRRect;
|
| + fRRectOrOvalIsCCW = ref.fRRectOrOvalIsCCW;
|
| + fRRectOrOvalStartIdx = ref.fRRectOrOvalStartIdx;
|
| SkDEBUGCODE(this->validate();)
|
| }
|
|
|
|
|