Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkBuffer.h" | 8 #include "SkBuffer.h" |
| 9 #include "SkErrorInternals.h" | 9 #include "SkErrorInternals.h" |
| 10 #include "SkGeometry.h" | 10 #include "SkGeometry.h" |
| 11 #include "SkMath.h" | 11 #include "SkMath.h" |
| 12 #include "SkPath.h" | 12 #include "SkPathPriv.h" |
| 13 #include "SkPathRef.h" | 13 #include "SkPathRef.h" |
| 14 #include "SkRRect.h" | 14 #include "SkRRect.h" |
| 15 #include "SkThread.h" | 15 #include "SkThread.h" |
| 16 | 16 |
| 17 //////////////////////////////////////////////////////////////////////////// | 17 //////////////////////////////////////////////////////////////////////////// |
| 18 | 18 |
| 19 /** | 19 /** |
| 20 * Path.bounds is defined to be the bounds of all the control points. | 20 * Path.bounds is defined to be the bounds of all the control points. |
| 21 * If we called bounds.join(r) we would skip r if r was empty, which breaks | 21 * If we called bounds.join(r) we would skip r if r was empty, which breaks |
| 22 * our promise. Hence we have a custom joiner that doesn't look at emptiness | 22 * our promise. Hence we have a custom joiner that doesn't look at emptiness |
| 23 */ | 23 */ |
| 24 static void joinNoEmptyChecks(SkRect* dst, const SkRect& src) { | 24 static void joinNoEmptyChecks(SkRect* dst, const SkRect& src) { |
| 25 dst->fLeft = SkMinScalar(dst->fLeft, src.fLeft); | 25 dst->fLeft = SkMinScalar(dst->fLeft, src.fLeft); |
| 26 dst->fTop = SkMinScalar(dst->fTop, src.fTop); | 26 dst->fTop = SkMinScalar(dst->fTop, src.fTop); |
| 27 dst->fRight = SkMaxScalar(dst->fRight, src.fRight); | 27 dst->fRight = SkMaxScalar(dst->fRight, src.fRight); |
| 28 dst->fBottom = SkMaxScalar(dst->fBottom, src.fBottom); | 28 dst->fBottom = SkMaxScalar(dst->fBottom, src.fBottom); |
| 29 } | 29 } |
| 30 | 30 |
| 31 static bool is_degenerate(const SkPath& path) { | 31 static bool is_degenerate(const SkPath& path) { |
| 32 SkPath::Iter iter(path, false); | 32 SkPath::Iter iter(path, false); |
| 33 SkPoint pts[4]; | 33 SkPoint pts[4]; |
| 34 return SkPath::kDone_Verb == iter.next(pts); | 34 return SkPath::kDone_Verb == iter.next(pts); |
| 35 } | 35 } |
| 36 | 36 |
| 37 class SkAutoDisableDirectionCheck { | 37 class SkAutoDisableDirectionCheck { |
| 38 public: | 38 public: |
| 39 SkAutoDisableDirectionCheck(SkPath* path) : fPath(path) { | 39 SkAutoDisableDirectionCheck(SkPath* path) : fPath(path) { |
| 40 fSaved = static_cast<SkPath::Direction>(fPath->fDirection); | 40 fSaved = static_cast<SkPathPriv::FirstDirection>(fPath->fFirstDirection) ; |
| 41 } | 41 } |
| 42 | 42 |
| 43 ~SkAutoDisableDirectionCheck() { | 43 ~SkAutoDisableDirectionCheck() { |
| 44 fPath->fDirection = fSaved; | 44 fPath->fFirstDirection = fSaved; |
| 45 } | 45 } |
| 46 | 46 |
| 47 private: | 47 private: |
| 48 SkPath* fPath; | 48 SkPath* fPath; |
| 49 SkPath::Direction fSaved; | 49 SkPathPriv::FirstDirection fSaved; |
| 50 }; | 50 }; |
| 51 #define SkAutoDisableDirectionCheck(...) SK_REQUIRE_LOCAL_VAR(SkAutoDisableDirec tionCheck) | 51 #define SkAutoDisableDirectionCheck(...) SK_REQUIRE_LOCAL_VAR(SkAutoDisableDirec tionCheck) |
| 52 | 52 |
| 53 /* This guy's constructor/destructor bracket a path editing operation. It is | 53 /* This guy's constructor/destructor bracket a path editing operation. It is |
| 54 used when we know the bounds of the amount we are going to add to the path | 54 used when we know the bounds of the amount we are going to add to the path |
| 55 (usually a new contour, but not required). | 55 (usually a new contour, but not required). |
| 56 | 56 |
| 57 It captures some state about the path up front (i.e. if it already has a | 57 It captures some state about the path up front (i.e. if it already has a |
| 58 cached bounds), and then if it can, it updates the cache bounds explicitly, | 58 cached bounds), and then if it can, it updates the cache bounds explicitly, |
| 59 avoiding the need to revisit all of the points in getBounds(). | 59 avoiding the need to revisit all of the points in getBounds(). |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 128 : fPathRef(SkPathRef::CreateEmpty()) { | 128 : fPathRef(SkPathRef::CreateEmpty()) { |
| 129 this->resetFields(); | 129 this->resetFields(); |
| 130 fIsVolatile = false; | 130 fIsVolatile = false; |
| 131 } | 131 } |
| 132 | 132 |
| 133 void SkPath::resetFields() { | 133 void SkPath::resetFields() { |
| 134 //fPathRef is assumed to have been emptied by the caller. | 134 //fPathRef is assumed to have been emptied by the caller. |
| 135 fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE; | 135 fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE; |
| 136 fFillType = kWinding_FillType; | 136 fFillType = kWinding_FillType; |
| 137 fConvexity = kUnknown_Convexity; | 137 fConvexity = kUnknown_Convexity; |
| 138 fDirection = kUnknown_Direction; | 138 fFirstDirection = SkPathPriv::kUnknown_FirstDirection; |
| 139 | 139 |
| 140 // We don't touch Android's fSourcePath. It's used to track texture garbage collection, so we | 140 // We don't touch Android's fSourcePath. It's used to track texture garbage collection, so we |
| 141 // don't want to muck with it if it's been set to something non-NULL. | 141 // don't want to muck with it if it's been set to something non-NULL. |
| 142 } | 142 } |
| 143 | 143 |
| 144 SkPath::SkPath(const SkPath& that) | 144 SkPath::SkPath(const SkPath& that) |
| 145 : fPathRef(SkRef(that.fPathRef.get())) { | 145 : fPathRef(SkRef(that.fPathRef.get())) { |
| 146 this->copyFields(that); | 146 this->copyFields(that); |
| 147 SkDEBUGCODE(that.validate();) | 147 SkDEBUGCODE(that.validate();) |
| 148 } | 148 } |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 160 } | 160 } |
| 161 SkDEBUGCODE(this->validate();) | 161 SkDEBUGCODE(this->validate();) |
| 162 return *this; | 162 return *this; |
| 163 } | 163 } |
| 164 | 164 |
| 165 void SkPath::copyFields(const SkPath& that) { | 165 void SkPath::copyFields(const SkPath& that) { |
| 166 //fPathRef is assumed to have been set by the caller. | 166 //fPathRef is assumed to have been set by the caller. |
| 167 fLastMoveToIndex = that.fLastMoveToIndex; | 167 fLastMoveToIndex = that.fLastMoveToIndex; |
| 168 fFillType = that.fFillType; | 168 fFillType = that.fFillType; |
| 169 fConvexity = that.fConvexity; | 169 fConvexity = that.fConvexity; |
| 170 fDirection = that.fDirection; | 170 fFirstDirection = that.fFirstDirection; |
| 171 fIsVolatile = that.fIsVolatile; | 171 fIsVolatile = that.fIsVolatile; |
| 172 } | 172 } |
| 173 | 173 |
| 174 bool operator==(const SkPath& a, const SkPath& b) { | 174 bool operator==(const SkPath& a, const SkPath& b) { |
| 175 // note: don't need to look at isConvex or bounds, since just comparing the | 175 // note: don't need to look at isConvex or bounds, since just comparing the |
| 176 // raw data is sufficient. | 176 // raw data is sufficient. |
| 177 return &a == &b || | 177 return &a == &b || |
| 178 (a.fFillType == b.fFillType && *a.fPathRef.get() == *b.fPathRef.get()); | 178 (a.fFillType == b.fFillType && *a.fPathRef.get() == *b.fPathRef.get()); |
| 179 } | 179 } |
| 180 | 180 |
| 181 void SkPath::swap(SkPath& that) { | 181 void SkPath::swap(SkPath& that) { |
| 182 if (this != &that) { | 182 if (this != &that) { |
| 183 fPathRef.swap(&that.fPathRef); | 183 fPathRef.swap(&that.fPathRef); |
| 184 SkTSwap<int>(fLastMoveToIndex, that.fLastMoveToIndex); | 184 SkTSwap<int>(fLastMoveToIndex, that.fLastMoveToIndex); |
| 185 SkTSwap<uint8_t>(fFillType, that.fFillType); | 185 SkTSwap<uint8_t>(fFillType, that.fFillType); |
| 186 SkTSwap<uint8_t>(fConvexity, that.fConvexity); | 186 SkTSwap<uint8_t>(fConvexity, that.fConvexity); |
| 187 SkTSwap<uint8_t>(fDirection, that.fDirection); | 187 SkTSwap<uint8_t>(fFirstDirection, that.fFirstDirection); |
| 188 SkTSwap<SkBool8>(fIsVolatile, that.fIsVolatile); | 188 SkTSwap<SkBool8>(fIsVolatile, that.fIsVolatile); |
| 189 } | 189 } |
| 190 } | 190 } |
| 191 | 191 |
| 192 static inline bool check_edge_against_rect(const SkPoint& p0, | 192 static inline bool check_edge_against_rect(const SkPoint& p0, |
| 193 const SkPoint& p1, | 193 const SkPoint& p1, |
| 194 const SkRect& rect, | 194 const SkRect& rect, |
| 195 SkPath::Direction dir) { | 195 SkPathPriv::FirstDirection dir) { |
| 196 const SkPoint* edgeBegin; | 196 const SkPoint* edgeBegin; |
| 197 SkVector v; | 197 SkVector v; |
| 198 if (SkPath::kCW_Direction == dir) { | 198 if (SkPathPriv::kCW_FirstDirection == dir) { |
| 199 v = p1 - p0; | 199 v = p1 - p0; |
| 200 edgeBegin = &p0; | 200 edgeBegin = &p0; |
| 201 } else { | 201 } else { |
| 202 v = p0 - p1; | 202 v = p0 - p1; |
| 203 edgeBegin = &p1; | 203 edgeBegin = &p1; |
| 204 } | 204 } |
| 205 if (v.fX || v.fY) { | 205 if (v.fX || v.fY) { |
| 206 // check the cross product of v with the vec from edgeBegin to each rect corner | 206 // check the cross product of v with the vec from edgeBegin to each rect corner |
| 207 SkScalar yL = SkScalarMul(v.fY, rect.fLeft - edgeBegin->fX); | 207 SkScalar yL = SkScalarMul(v.fY, rect.fLeft - edgeBegin->fX); |
| 208 SkScalar xT = SkScalarMul(v.fX, rect.fTop - edgeBegin->fY); | 208 SkScalar xT = SkScalarMul(v.fX, rect.fTop - edgeBegin->fY); |
| 209 SkScalar yR = SkScalarMul(v.fY, rect.fRight - edgeBegin->fX); | 209 SkScalar yR = SkScalarMul(v.fY, rect.fRight - edgeBegin->fX); |
| 210 SkScalar xB = SkScalarMul(v.fX, rect.fBottom - edgeBegin->fY); | 210 SkScalar xB = SkScalarMul(v.fX, rect.fBottom - edgeBegin->fY); |
| 211 if ((xT < yL) || (xT < yR) || (xB < yL) || (xB < yR)) { | 211 if ((xT < yL) || (xT < yR) || (xB < yL) || (xB < yR)) { |
| 212 return false; | 212 return false; |
| 213 } | 213 } |
| 214 } | 214 } |
| 215 return true; | 215 return true; |
| 216 } | 216 } |
| 217 | 217 |
| 218 bool SkPath::conservativelyContainsRect(const SkRect& rect) const { | 218 bool SkPath::conservativelyContainsRect(const SkRect& rect) const { |
| 219 // This only handles non-degenerate convex paths currently. | 219 // This only handles non-degenerate convex paths currently. |
| 220 if (kConvex_Convexity != this->getConvexity()) { | 220 if (kConvex_Convexity != this->getConvexity()) { |
| 221 return false; | 221 return false; |
| 222 } | 222 } |
| 223 | 223 |
| 224 Direction direction; | 224 SkPathPriv::FirstDirection direction; |
| 225 if (!this->cheapComputeDirection(&direction)) { | 225 if (!SkPathPriv::CheapComputeFirstDirection(*this, &direction)) { |
| 226 return false; | 226 return false; |
| 227 } | 227 } |
| 228 | 228 |
| 229 SkPoint firstPt; | 229 SkPoint firstPt; |
| 230 SkPoint prevPt; | 230 SkPoint prevPt; |
| 231 RawIter iter(*this); | 231 RawIter iter(*this); |
| 232 SkPath::Verb verb; | 232 SkPath::Verb verb; |
| 233 SkPoint pts[4]; | 233 SkPoint pts[4]; |
| 234 SkDEBUGCODE(int moveCnt = 0;) | 234 SkDEBUGCODE(int moveCnt = 0;) |
| 235 SkDEBUGCODE(int segmentCount = 0;) | 235 SkDEBUGCODE(int segmentCount = 0;) |
| (...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 655 | 655 |
| 656 void SkPath::setConvexity(Convexity c) { | 656 void SkPath::setConvexity(Convexity c) { |
| 657 if (fConvexity != c) { | 657 if (fConvexity != c) { |
| 658 fConvexity = c; | 658 fConvexity = c; |
| 659 } | 659 } |
| 660 } | 660 } |
| 661 | 661 |
| 662 ////////////////////////////////////////////////////////////////////////////// | 662 ////////////////////////////////////////////////////////////////////////////// |
| 663 // Construction methods | 663 // Construction methods |
| 664 | 664 |
| 665 #define DIRTY_AFTER_EDIT \ | 665 #define DIRTY_AFTER_EDIT \ |
| 666 do { \ | 666 do { \ |
| 667 fConvexity = kUnknown_Convexity; \ | 667 fConvexity = kUnknown_Convexity; \ |
| 668 fDirection = kUnknown_Direction; \ | 668 fFirstDirection = SkPathPriv::kUnknown_FirstDirection; \ |
| 669 } while (0) | 669 } while (0) |
| 670 | 670 |
| 671 void SkPath::incReserve(U16CPU inc) { | 671 void SkPath::incReserve(U16CPU inc) { |
| 672 SkDEBUGCODE(this->validate();) | 672 SkDEBUGCODE(this->validate();) |
| 673 SkPathRef::Editor(&fPathRef, inc, inc); | 673 SkPathRef::Editor(&fPathRef, inc, inc); |
| 674 SkDEBUGCODE(this->validate();) | 674 SkDEBUGCODE(this->validate();) |
| 675 } | 675 } |
| 676 | 676 |
| 677 void SkPath::moveTo(SkScalar x, SkScalar y) { | 677 void SkPath::moveTo(SkScalar x, SkScalar y) { |
| 678 SkDEBUGCODE(this->validate();) | 678 SkDEBUGCODE(this->validate();) |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 841 SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir); | 841 SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir); |
| 842 } | 842 } |
| 843 | 843 |
| 844 void SkPath::addRect(const SkRect& rect, Direction dir) { | 844 void SkPath::addRect(const SkRect& rect, Direction dir) { |
| 845 this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir); | 845 this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir); |
| 846 } | 846 } |
| 847 | 847 |
| 848 void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right, | 848 void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right, |
| 849 SkScalar bottom, Direction dir) { | 849 SkScalar bottom, Direction dir) { |
| 850 assert_known_direction(dir); | 850 assert_known_direction(dir); |
| 851 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; | 851 fFirstDirection = this->hasOnlyMoveTos() ? |
| 852 (SkPathPriv::FirstDirection)dir : SkPathPriv::kUnknown_F irstDirection; | |
| 852 SkAutoDisableDirectionCheck addc(this); | 853 SkAutoDisableDirectionCheck addc(this); |
| 853 | 854 |
| 854 SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom); | 855 SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom); |
| 855 | 856 |
| 856 this->incReserve(5); | 857 this->incReserve(5); |
| 857 | 858 |
| 858 this->moveTo(left, top); | 859 this->moveTo(left, top); |
| 859 if (dir == kCCW_Direction) { | 860 if (dir == kCCW_Direction) { |
| 860 this->lineTo(left, bottom); | 861 this->lineTo(left, bottom); |
| 861 this->lineTo(right, bottom); | 862 this->lineTo(right, bottom); |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 981 return; | 982 return; |
| 982 } | 983 } |
| 983 | 984 |
| 984 const SkRect& bounds = rrect.getBounds(); | 985 const SkRect& bounds = rrect.getBounds(); |
| 985 | 986 |
| 986 if (rrect.isRect()) { | 987 if (rrect.isRect()) { |
| 987 this->addRect(bounds, dir); | 988 this->addRect(bounds, dir); |
| 988 } else if (rrect.isOval()) { | 989 } else if (rrect.isOval()) { |
| 989 this->addOval(bounds, dir); | 990 this->addOval(bounds, dir); |
| 990 } else { | 991 } else { |
| 991 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; | 992 fFirstDirection = this->hasOnlyMoveTos() ? |
| 993 (SkPathPriv::FirstDirection)dir : SkPathPriv::kUnkno wn_FirstDirection; | |
| 992 | 994 |
| 993 SkAutoPathBoundsUpdate apbu(this, bounds); | 995 SkAutoPathBoundsUpdate apbu(this, bounds); |
| 994 SkAutoDisableDirectionCheck addc(this); | 996 SkAutoDisableDirectionCheck addc(this); |
| 995 | 997 |
| 996 const SkScalar L = bounds.fLeft; | 998 const SkScalar L = bounds.fLeft; |
| 997 const SkScalar T = bounds.fTop; | 999 const SkScalar T = bounds.fTop; |
| 998 const SkScalar R = bounds.fRight; | 1000 const SkScalar R = bounds.fRight; |
| 999 const SkScalar B = bounds.fBottom; | 1001 const SkScalar B = bounds.fBottom; |
| 1000 const SkScalar W = SK_ScalarRoot2Over2; | 1002 const SkScalar W = SK_ScalarRoot2Over2; |
| 1001 | 1003 |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1070 assert_known_direction(dir); | 1072 assert_known_direction(dir); |
| 1071 | 1073 |
| 1072 /* If addOval() is called after previous moveTo(), | 1074 /* If addOval() is called after previous moveTo(), |
| 1073 this path is still marked as an oval. This is used to | 1075 this path is still marked as an oval. This is used to |
| 1074 fit into WebKit's calling sequences. | 1076 fit into WebKit's calling sequences. |
| 1075 We can't simply check isEmpty() in this case, as additional | 1077 We can't simply check isEmpty() in this case, as additional |
| 1076 moveTo() would mark the path non empty. | 1078 moveTo() would mark the path non empty. |
| 1077 */ | 1079 */ |
| 1078 bool isOval = hasOnlyMoveTos(); | 1080 bool isOval = hasOnlyMoveTos(); |
| 1079 if (isOval) { | 1081 if (isOval) { |
| 1080 fDirection = dir; | 1082 fFirstDirection = (SkPathPriv::FirstDirection)dir; |
| 1081 } else { | 1083 } else { |
| 1082 fDirection = kUnknown_Direction; | 1084 fFirstDirection = SkPathPriv::kUnknown_FirstDirection; |
| 1083 } | 1085 } |
| 1084 | 1086 |
| 1085 SkAutoDisableDirectionCheck addc(this); | 1087 SkAutoDisableDirectionCheck addc(this); |
| 1086 | 1088 |
| 1087 SkAutoPathBoundsUpdate apbu(this, oval); | 1089 SkAutoPathBoundsUpdate apbu(this, oval); |
| 1088 | 1090 |
| 1089 const SkScalar L = oval.fLeft; | 1091 const SkScalar L = oval.fLeft; |
| 1090 const SkScalar T = oval.fTop; | 1092 const SkScalar T = oval.fTop; |
| 1091 const SkScalar R = oval.fRight; | 1093 const SkScalar R = oval.fRight; |
| 1092 const SkScalar B = oval.fBottom; | 1094 const SkScalar B = oval.fBottom; |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1470 break; | 1472 break; |
| 1471 default: | 1473 default: |
| 1472 SkDEBUGFAIL("unknown verb"); | 1474 SkDEBUGFAIL("unknown verb"); |
| 1473 break; | 1475 break; |
| 1474 } | 1476 } |
| 1475 } | 1477 } |
| 1476 | 1478 |
| 1477 dst->swap(tmp); | 1479 dst->swap(tmp); |
| 1478 SkPathRef::Editor ed(&dst->fPathRef); | 1480 SkPathRef::Editor ed(&dst->fPathRef); |
| 1479 matrix.mapPoints(ed.points(), ed.pathRef()->countPoints()); | 1481 matrix.mapPoints(ed.points(), ed.pathRef()->countPoints()); |
| 1480 dst->fDirection = kUnknown_Direction; | 1482 dst->fFirstDirection = SkPathPriv::kUnknown_FirstDirection; |
| 1481 } else { | 1483 } else { |
| 1482 SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix ); | 1484 SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix ); |
| 1483 | 1485 |
| 1484 if (this != dst) { | 1486 if (this != dst) { |
| 1485 dst->fFillType = fFillType; | 1487 dst->fFillType = fFillType; |
| 1486 dst->fConvexity = fConvexity; | 1488 dst->fConvexity = fConvexity; |
| 1487 dst->fIsVolatile = fIsVolatile; | 1489 dst->fIsVolatile = fIsVolatile; |
| 1488 } | 1490 } |
| 1489 | 1491 |
| 1490 if (kUnknown_Direction == fDirection) { | 1492 if (SkPathPriv::kUnknown_FirstDirection == fFirstDirection) { |
| 1491 dst->fDirection = kUnknown_Direction; | 1493 dst->fFirstDirection = SkPathPriv::kUnknown_FirstDirection; |
| 1492 } else { | 1494 } else { |
| 1493 SkScalar det2x2 = | 1495 SkScalar det2x2 = |
| 1494 SkScalarMul(matrix.get(SkMatrix::kMScaleX), matrix.get(SkMatrix: :kMScaleY)) - | 1496 SkScalarMul(matrix.get(SkMatrix::kMScaleX), matrix.get(SkMatrix: :kMScaleY)) - |
| 1495 SkScalarMul(matrix.get(SkMatrix::kMSkewX), matrix.get(SkMatrix:: kMSkewY)); | 1497 SkScalarMul(matrix.get(SkMatrix::kMSkewX), matrix.get(SkMatrix:: kMSkewY)); |
| 1496 if (det2x2 < 0) { | 1498 if (det2x2 < 0) { |
| 1497 dst->fDirection = SkPath::OppositeDirection(static_cast<Directio n>(fDirection)); | 1499 dst->fFirstDirection = SkPathPriv::OppositeFirstDirection((SkPat hPriv::FirstDirection)fFirstDirection); |
| 1498 } else if (det2x2 > 0) { | 1500 } else if (det2x2 > 0) { |
| 1499 dst->fDirection = fDirection; | 1501 dst->fFirstDirection = fFirstDirection; |
| 1500 } else { | 1502 } else { |
| 1501 dst->fConvexity = kUnknown_Convexity; | 1503 dst->fConvexity = kUnknown_Convexity; |
| 1502 dst->fDirection = kUnknown_Direction; | 1504 dst->fFirstDirection = SkPathPriv::kUnknown_FirstDirection; |
| 1503 } | 1505 } |
| 1504 } | 1506 } |
| 1505 | 1507 |
| 1506 SkDEBUGCODE(dst->validate();) | 1508 SkDEBUGCODE(dst->validate();) |
| 1507 } | 1509 } |
| 1508 } | 1510 } |
| 1509 | 1511 |
| 1510 /////////////////////////////////////////////////////////////////////////////// | 1512 /////////////////////////////////////////////////////////////////////////////// |
| 1511 /////////////////////////////////////////////////////////////////////////////// | 1513 /////////////////////////////////////////////////////////////////////////////// |
| 1512 | 1514 |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1851 | 1853 |
| 1852 if (NULL == storage) { | 1854 if (NULL == storage) { |
| 1853 const int byteCount = sizeof(int32_t) + fPathRef->writeSize(); | 1855 const int byteCount = sizeof(int32_t) + fPathRef->writeSize(); |
| 1854 return SkAlign4(byteCount); | 1856 return SkAlign4(byteCount); |
| 1855 } | 1857 } |
| 1856 | 1858 |
| 1857 SkWBuffer buffer(storage); | 1859 SkWBuffer buffer(storage); |
| 1858 | 1860 |
| 1859 int32_t packed = (fConvexity << kConvexity_SerializationShift) | | 1861 int32_t packed = (fConvexity << kConvexity_SerializationShift) | |
| 1860 (fFillType << kFillType_SerializationShift) | | 1862 (fFillType << kFillType_SerializationShift) | |
| 1861 (fDirection << kDirection_SerializationShift) | | 1863 (fFirstDirection << kDirection_SerializationShift) | |
| 1862 (fIsVolatile << kIsVolatile_SerializationShift); | 1864 (fIsVolatile << kIsVolatile_SerializationShift); |
| 1863 | 1865 |
| 1864 buffer.write32(packed); | 1866 buffer.write32(packed); |
| 1865 | 1867 |
| 1866 fPathRef->writeToBuffer(&buffer); | 1868 fPathRef->writeToBuffer(&buffer); |
| 1867 | 1869 |
| 1868 buffer.padToAlign4(); | 1870 buffer.padToAlign4(); |
| 1869 return buffer.pos(); | 1871 return buffer.pos(); |
| 1870 } | 1872 } |
| 1871 | 1873 |
| 1872 size_t SkPath::readFromMemory(const void* storage, size_t length) { | 1874 size_t SkPath::readFromMemory(const void* storage, size_t length) { |
| 1873 SkRBufferWithSizeCheck buffer(storage, length); | 1875 SkRBufferWithSizeCheck buffer(storage, length); |
| 1874 | 1876 |
| 1875 int32_t packed; | 1877 int32_t packed; |
| 1876 if (!buffer.readS32(&packed)) { | 1878 if (!buffer.readS32(&packed)) { |
| 1877 return 0; | 1879 return 0; |
| 1878 } | 1880 } |
| 1879 | 1881 |
| 1880 fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF; | 1882 fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF; |
| 1881 fFillType = (packed >> kFillType_SerializationShift) & 0xFF; | 1883 fFillType = (packed >> kFillType_SerializationShift) & 0xFF; |
| 1882 fDirection = (packed >> kDirection_SerializationShift) & 0x3; | 1884 fFirstDirection = (packed >> kDirection_SerializationShift) & 0x3; |
| 1883 fIsVolatile = (packed >> kIsVolatile_SerializationShift) & 0x1; | 1885 fIsVolatile = (packed >> kIsVolatile_SerializationShift) & 0x1; |
| 1884 SkPathRef* pathRef = SkPathRef::CreateFromBuffer(&buffer); | 1886 SkPathRef* pathRef = SkPathRef::CreateFromBuffer(&buffer); |
| 1885 | 1887 |
| 1886 size_t sizeRead = 0; | 1888 size_t sizeRead = 0; |
| 1887 if (buffer.isValid()) { | 1889 if (buffer.isValid()) { |
| 1888 fPathRef.reset(pathRef); | 1890 fPathRef.reset(pathRef); |
| 1889 SkDEBUGCODE(this->validate();) | 1891 SkDEBUGCODE(this->validate();) |
| 1890 buffer.skipToAlign4(); | 1892 buffer.skipToAlign4(); |
| 1891 sizeRead = buffer.pos(); | 1893 sizeRead = buffer.pos(); |
| 1892 } else if (pathRef) { | 1894 } else if (pathRef) { |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2054 static bool approximately_zero_when_compared_to(double x, double y) { | 2056 static bool approximately_zero_when_compared_to(double x, double y) { |
| 2055 return x == 0 || fabs(x) < fabs(y * FLT_EPSILON); | 2057 return x == 0 || fabs(x) < fabs(y * FLT_EPSILON); |
| 2056 } | 2058 } |
| 2057 | 2059 |
| 2058 | 2060 |
| 2059 // only valid for a single contour | 2061 // only valid for a single contour |
| 2060 struct Convexicator { | 2062 struct Convexicator { |
| 2061 Convexicator() | 2063 Convexicator() |
| 2062 : fPtCount(0) | 2064 : fPtCount(0) |
| 2063 , fConvexity(SkPath::kConvex_Convexity) | 2065 , fConvexity(SkPath::kConvex_Convexity) |
| 2064 , fDirection(SkPath::kUnknown_Direction) | 2066 , fFirstDirection(SkPathPriv::kUnknown_FirstDirection) |
| 2065 , fIsFinite(true) | 2067 , fIsFinite(true) |
| 2066 , fIsCurve(false) { | 2068 , fIsCurve(false) { |
| 2067 fExpectedDir = kInvalid_DirChange; | 2069 fExpectedDir = kInvalid_DirChange; |
| 2068 // warnings | 2070 // warnings |
| 2069 fLastPt.set(0, 0); | 2071 fLastPt.set(0, 0); |
| 2070 fCurrPt.set(0, 0); | 2072 fCurrPt.set(0, 0); |
| 2071 fLastVec.set(0, 0); | 2073 fLastVec.set(0, 0); |
| 2072 fFirstVec.set(0, 0); | 2074 fFirstVec.set(0, 0); |
| 2073 | 2075 |
| 2074 fDx = fDy = 0; | 2076 fDx = fDy = 0; |
| 2075 fSx = fSy = kValueNeverReturnedBySign; | 2077 fSx = fSy = kValueNeverReturnedBySign; |
| 2076 } | 2078 } |
| 2077 | 2079 |
| 2078 SkPath::Convexity getConvexity() const { return fConvexity; } | 2080 SkPath::Convexity getConvexity() const { return fConvexity; } |
| 2079 | 2081 |
| 2080 /** The direction returned is only valid if the path is determined convex */ | 2082 /** The direction returned is only valid if the path is determined convex */ |
| 2081 SkPath::Direction getDirection() const { return fDirection; } | 2083 SkPathPriv::FirstDirection getFirstDirection() const { return fFirstDirectio n; } |
| 2082 | 2084 |
| 2083 void addPt(const SkPoint& pt) { | 2085 void addPt(const SkPoint& pt) { |
| 2084 if (SkPath::kConcave_Convexity == fConvexity || !fIsFinite) { | 2086 if (SkPath::kConcave_Convexity == fConvexity || !fIsFinite) { |
| 2085 return; | 2087 return; |
| 2086 } | 2088 } |
| 2087 | 2089 |
| 2088 if (0 == fPtCount) { | 2090 if (0 == fPtCount) { |
| 2089 fCurrPt = pt; | 2091 fCurrPt = pt; |
| 2090 ++fPtCount; | 2092 ++fPtCount; |
| 2091 } else { | 2093 } else { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2172 | 2174 |
| 2173 private: | 2175 private: |
| 2174 void addVec(const SkVector& vec) { | 2176 void addVec(const SkVector& vec) { |
| 2175 SkASSERT(vec.fX || vec.fY); | 2177 SkASSERT(vec.fX || vec.fY); |
| 2176 DirChange dir = this->directionChange(vec); | 2178 DirChange dir = this->directionChange(vec); |
| 2177 switch (dir) { | 2179 switch (dir) { |
| 2178 case kLeft_DirChange: // fall through | 2180 case kLeft_DirChange: // fall through |
| 2179 case kRight_DirChange: | 2181 case kRight_DirChange: |
| 2180 if (kInvalid_DirChange == fExpectedDir) { | 2182 if (kInvalid_DirChange == fExpectedDir) { |
| 2181 fExpectedDir = dir; | 2183 fExpectedDir = dir; |
| 2182 fDirection = (kRight_DirChange == dir) ? SkPath::kCW_Directi on | 2184 fFirstDirection = (kRight_DirChange == dir) ? SkPathPriv::kC W_FirstDirection |
| 2183 : SkPath::kCCW_Direct ion; | 2185 : SkPathPriv::kC CW_FirstDirection; |
| 2184 } else if (dir != fExpectedDir) { | 2186 } else if (dir != fExpectedDir) { |
| 2185 fConvexity = SkPath::kConcave_Convexity; | 2187 fConvexity = SkPath::kConcave_Convexity; |
| 2186 fDirection = SkPath::kUnknown_Direction; | 2188 fFirstDirection = SkPathPriv::kUnknown_FirstDirection; |
| 2187 } | 2189 } |
| 2188 fLastVec = vec; | 2190 fLastVec = vec; |
| 2189 break; | 2191 break; |
| 2190 case kStraight_DirChange: | 2192 case kStraight_DirChange: |
| 2191 break; | 2193 break; |
| 2192 case kBackwards_DirChange: | 2194 case kBackwards_DirChange: |
| 2193 if (fIsCurve) { | 2195 if (fIsCurve) { |
| 2194 fConvexity = SkPath::kConcave_Convexity; | 2196 fConvexity = SkPath::kConcave_Convexity; |
| 2195 fDirection = SkPath::kUnknown_Direction; | 2197 fFirstDirection = SkPathPriv::kUnknown_FirstDirection; |
| 2196 } | 2198 } |
| 2197 fLastVec = vec; | 2199 fLastVec = vec; |
| 2198 break; | 2200 break; |
| 2199 case kInvalid_DirChange: | 2201 case kInvalid_DirChange: |
| 2200 SkFAIL("Use of invalid direction change flag"); | 2202 SkFAIL("Use of invalid direction change flag"); |
| 2201 break; | 2203 break; |
| 2202 } | 2204 } |
| 2203 } | 2205 } |
| 2204 | 2206 |
| 2205 SkPoint fPriorPt; | 2207 SkPoint fPriorPt; |
| 2206 SkPoint fLastPt; | 2208 SkPoint fLastPt; |
| 2207 SkPoint fCurrPt; | 2209 SkPoint fCurrPt; |
| 2208 // fLastVec does not necessarily start at fLastPt. We only advance it when t he cross product | 2210 // fLastVec does not necessarily start at fLastPt. We only advance it when t he cross product |
| 2209 // value with the current vec is deemed to be of a significant value. | 2211 // value with the current vec is deemed to be of a significant value. |
| 2210 SkVector fLastVec, fFirstVec; | 2212 SkVector fLastVec, fFirstVec; |
| 2211 int fPtCount; // non-degenerate points | 2213 int fPtCount; // non-degenerate points |
| 2212 DirChange fExpectedDir; | 2214 DirChange fExpectedDir; |
| 2213 SkPath::Convexity fConvexity; | 2215 SkPath::Convexity fConvexity; |
| 2214 SkPath::Direction fDirection; | 2216 SkPathPriv::FirstDirection fFirstDirection; |
| 2215 int fDx, fDy, fSx, fSy; | 2217 int fDx, fDy, fSx, fSy; |
| 2216 bool fIsFinite; | 2218 bool fIsFinite; |
| 2217 bool fIsCurve; | 2219 bool fIsCurve; |
| 2218 }; | 2220 }; |
| 2219 | 2221 |
| 2220 SkPath::Convexity SkPath::internalGetConvexity() const { | 2222 SkPath::Convexity SkPath::internalGetConvexity() const { |
| 2221 SkASSERT(kUnknown_Convexity == fConvexity); | 2223 SkASSERT(kUnknown_Convexity == fConvexity); |
| 2222 SkPoint pts[4]; | 2224 SkPoint pts[4]; |
| 2223 SkPath::Verb verb; | 2225 SkPath::Verb verb; |
| 2224 SkPath::Iter iter(*this, true); | 2226 SkPath::Iter iter(*this, true); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2270 // early exit | 2272 // early exit |
| 2271 if (!state.isFinite()) { | 2273 if (!state.isFinite()) { |
| 2272 return kUnknown_Convexity; | 2274 return kUnknown_Convexity; |
| 2273 } | 2275 } |
| 2274 if (kConcave_Convexity == state.getConvexity()) { | 2276 if (kConcave_Convexity == state.getConvexity()) { |
| 2275 fConvexity = kConcave_Convexity; | 2277 fConvexity = kConcave_Convexity; |
| 2276 return kConcave_Convexity; | 2278 return kConcave_Convexity; |
| 2277 } | 2279 } |
| 2278 } | 2280 } |
| 2279 fConvexity = state.getConvexity(); | 2281 fConvexity = state.getConvexity(); |
| 2280 if (kConvex_Convexity == fConvexity && kUnknown_Direction == fDirection) { | 2282 if (kConvex_Convexity == fConvexity && SkPathPriv::kUnknown_FirstDirection = = fFirstDirection) { |
| 2281 fDirection = state.getDirection(); | 2283 fFirstDirection = state.getFirstDirection(); |
| 2282 } | 2284 } |
| 2283 return static_cast<Convexity>(fConvexity); | 2285 return static_cast<Convexity>(fConvexity); |
| 2284 } | 2286 } |
| 2285 | 2287 |
| 2286 /////////////////////////////////////////////////////////////////////////////// | 2288 /////////////////////////////////////////////////////////////////////////////// |
| 2287 | 2289 |
| 2288 class ContourIter { | 2290 class ContourIter { |
| 2289 public: | 2291 public: |
| 2290 ContourIter(const SkPathRef& pathRef); | 2292 ContourIter(const SkPathRef& pathRef); |
| 2291 | 2293 |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2431 min = x; | 2433 min = x; |
| 2432 minIndex = i; | 2434 minIndex = i; |
| 2433 } else if (x > max) { | 2435 } else if (x > max) { |
| 2434 max = x; | 2436 max = x; |
| 2435 maxIndex = i; | 2437 maxIndex = i; |
| 2436 } | 2438 } |
| 2437 } | 2439 } |
| 2438 *maxIndexPtr = maxIndex; | 2440 *maxIndexPtr = maxIndex; |
| 2439 return minIndex; | 2441 return minIndex; |
| 2440 } | 2442 } |
| 2441 | 2443 |
|
robertphillips
2015/06/15 15:22:35
cross_to_dir ?
| |
| 2442 static void crossToDir(SkScalar cross, SkPath::Direction* dir) { | 2444 static void crossToDir(SkScalar cross, SkPathPriv::FirstDirection* dir) { |
| 2443 *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction; | 2445 *dir = cross > 0 ? SkPathPriv::kCW_FirstDirection : SkPathPriv::kCCW_FirstDi rection; |
| 2444 } | 2446 } |
| 2445 | 2447 |
| 2446 /* | 2448 /* |
| 2447 * We loop through all contours, and keep the computed cross-product of the | 2449 * We loop through all contours, and keep the computed cross-product of the |
| 2448 * contour that contained the global y-max. If we just look at the first | 2450 * contour that contained the global y-max. If we just look at the first |
| 2449 * contour, we may find one that is wound the opposite way (correctly) since | 2451 * contour, we may find one that is wound the opposite way (correctly) since |
| 2450 * it is the interior of a hole (e.g. 'o'). Thus we must find the contour | 2452 * it is the interior of a hole (e.g. 'o'). Thus we must find the contour |
| 2451 * that is outer most (or at least has the global y-max) before we can consider | 2453 * that is outer most (or at least has the global y-max) before we can consider |
| 2452 * its cross product. | 2454 * its cross product. |
| 2453 */ | 2455 */ |
| 2454 bool SkPath::cheapComputeDirection(Direction* dir) const { | 2456 bool SkPathPriv::CheapComputeFirstDirection(const SkPath& path, FirstDirection* dir) { |
| 2455 if (kUnknown_Direction != fDirection) { | 2457 if (kUnknown_FirstDirection != path.fFirstDirection) { |
| 2456 *dir = static_cast<Direction>(fDirection); | 2458 *dir = static_cast<FirstDirection>(path.fFirstDirection); |
| 2457 return true; | 2459 return true; |
| 2458 } | 2460 } |
| 2459 | 2461 |
| 2460 // don't want to pay the cost for computing this if it | 2462 // don't want to pay the cost for computing this if it |
| 2461 // is unknown, so we don't call isConvex() | 2463 // is unknown, so we don't call isConvex() |
| 2462 if (kConvex_Convexity == this->getConvexityOrUnknown()) { | 2464 if (SkPath::kConvex_Convexity == path.getConvexityOrUnknown()) { |
| 2463 SkASSERT(kUnknown_Direction == fDirection); | 2465 SkASSERT(kUnknown_FirstDirection == path.fFirstDirection); |
| 2464 *dir = static_cast<Direction>(fDirection); | 2466 *dir = static_cast<FirstDirection>(path.fFirstDirection); |
| 2465 return false; | 2467 return false; |
| 2466 } | 2468 } |
| 2467 | 2469 |
| 2468 ContourIter iter(*fPathRef.get()); | 2470 ContourIter iter(*path.fPathRef.get()); |
| 2469 | 2471 |
| 2470 // initialize with our logical y-min | 2472 // initialize with our logical y-min |
| 2471 SkScalar ymax = this->getBounds().fTop; | 2473 SkScalar ymax = path.getBounds().fTop; |
| 2472 SkScalar ymaxCross = 0; | 2474 SkScalar ymaxCross = 0; |
| 2473 | 2475 |
| 2474 for (; !iter.done(); iter.next()) { | 2476 for (; !iter.done(); iter.next()) { |
| 2475 int n = iter.count(); | 2477 int n = iter.count(); |
| 2476 if (n < 3) { | 2478 if (n < 3) { |
| 2477 continue; | 2479 continue; |
| 2478 } | 2480 } |
| 2479 | 2481 |
| 2480 const SkPoint* pts = iter.pts(); | 2482 const SkPoint* pts = iter.pts(); |
| 2481 SkScalar cross = 0; | 2483 SkScalar cross = 0; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2527 } | 2529 } |
| 2528 | 2530 |
| 2529 if (cross) { | 2531 if (cross) { |
| 2530 // record our best guess so far | 2532 // record our best guess so far |
| 2531 ymax = pts[index].fY; | 2533 ymax = pts[index].fY; |
| 2532 ymaxCross = cross; | 2534 ymaxCross = cross; |
| 2533 } | 2535 } |
| 2534 } | 2536 } |
| 2535 if (ymaxCross) { | 2537 if (ymaxCross) { |
| 2536 crossToDir(ymaxCross, dir); | 2538 crossToDir(ymaxCross, dir); |
| 2537 fDirection = *dir; | 2539 path.fFirstDirection = *dir; |
| 2538 return true; | 2540 return true; |
| 2539 } else { | 2541 } else { |
| 2540 return false; | 2542 return false; |
| 2541 } | 2543 } |
| 2542 } | 2544 } |
| 2543 | 2545 |
| 2544 /////////////////////////////////////////////////////////////////////////////// | 2546 /////////////////////////////////////////////////////////////////////////////// |
| 2545 | 2547 |
| 2546 static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C, | 2548 static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C, |
| 2547 SkScalar D, SkScalar t) { | 2549 SkScalar D, SkScalar t) { |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2785 switch (this->getFillType()) { | 2787 switch (this->getFillType()) { |
| 2786 case SkPath::kEvenOdd_FillType: | 2788 case SkPath::kEvenOdd_FillType: |
| 2787 case SkPath::kInverseEvenOdd_FillType: | 2789 case SkPath::kInverseEvenOdd_FillType: |
| 2788 w &= 1; | 2790 w &= 1; |
| 2789 break; | 2791 break; |
| 2790 default: | 2792 default: |
| 2791 break; | 2793 break; |
| 2792 } | 2794 } |
| 2793 return SkToBool(w); | 2795 return SkToBool(w); |
| 2794 } | 2796 } |
| OLD | NEW |