Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(704)

Side by Side Diff: src/core/SkPath.cpp

Issue 597963002: Fix convexicator bug (Closed) Base URL: https://skia.googlesource.com/skia.git@m38_2125
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tests/PathTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2006 The Android Open Source Project 3 * Copyright 2006 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 9
10 #include "SkBuffer.h" 10 #include "SkBuffer.h"
(...skipping 2114 matching lines...) Expand 10 before | Expand all | Expand 10 after
2125 } 2125 }
2126 #endif // SK_DEBUG_PATH 2126 #endif // SK_DEBUG_PATH
2127 } 2127 }
2128 #endif // SK_DEBUG 2128 #endif // SK_DEBUG
2129 2129
2130 /////////////////////////////////////////////////////////////////////////////// 2130 ///////////////////////////////////////////////////////////////////////////////
2131 2131
2132 static int sign(SkScalar x) { return x < 0; } 2132 static int sign(SkScalar x) { return x < 0; }
2133 #define kValueNeverReturnedBySign 2 2133 #define kValueNeverReturnedBySign 2
2134 2134
2135 enum DirChange {
2136 kLeft_DirChange,
2137 kRight_DirChange,
2138 kStraight_DirChange,
2139 kBackwards_DirChange,
2140
2141 kInvalid_DirChange
2142 };
2143
2144
2135 static bool almost_equal(SkScalar compA, SkScalar compB) { 2145 static bool almost_equal(SkScalar compA, SkScalar compB) {
2136 // The error epsilon was empirically derived; worse case round rects 2146 // The error epsilon was empirically derived; worse case round rects
2137 // with a mid point outset by 2x float epsilon in tests had an error 2147 // with a mid point outset by 2x float epsilon in tests had an error
2138 // of 12. 2148 // of 12.
2139 const int epsilon = 16; 2149 const int epsilon = 16;
2140 if (!SkScalarIsFinite(compA) || !SkScalarIsFinite(compB)) { 2150 if (!SkScalarIsFinite(compA) || !SkScalarIsFinite(compB)) {
2141 return false; 2151 return false;
2142 } 2152 }
2143 // no need to check for small numbers because SkPath::Iter has removed degen erate values 2153 // no need to check for small numbers because SkPath::Iter has removed degen erate values
2144 int aBits = SkFloatAs2sCompliment(compA); 2154 int aBits = SkFloatAs2sCompliment(compA);
2145 int bBits = SkFloatAs2sCompliment(compB); 2155 int bBits = SkFloatAs2sCompliment(compB);
2146 return aBits < bBits + epsilon && bBits < aBits + epsilon; 2156 return aBits < bBits + epsilon && bBits < aBits + epsilon;
2147 } 2157 }
2148 2158
2159 static DirChange direction_change(const SkPoint& lastPt, const SkVector& curPt,
2160 const SkVector& lastVec, const SkVector& curVe c) {
2161 SkScalar cross = SkPoint::CrossProduct(lastVec, curVec);
2162
2163 SkScalar smallest = SkTMin(curPt.fX, SkTMin(curPt.fY, SkTMin(lastPt.fX, last Pt.fY)));
2164 SkScalar largest = SkTMax(curPt.fX, SkTMax(curPt.fY, SkTMax(lastPt.fX, lastP t.fY)));
2165 largest = SkTMax(largest, -smallest);
2166
2167 if (!almost_equal(largest, largest + cross)) {
2168 int sign = SkScalarSignAsInt(cross);
2169 if (sign) {
2170 return (1 == sign) ? kRight_DirChange : kLeft_DirChange;
2171 }
2172 }
2173
2174 if (!SkScalarNearlyZero(lastVec.lengthSqd(), SK_ScalarNearlyZero*SK_ScalarNe arlyZero) &&
2175 !SkScalarNearlyZero(curVec.lengthSqd(), SK_ScalarNearlyZero*SK_ScalarNea rlyZero) &&
2176 lastVec.dot(curVec) < 0.0f) {
2177 return kBackwards_DirChange;
2178 }
2179
2180 return kStraight_DirChange;
2181 }
2182
2149 // only valid for a single contour 2183 // only valid for a single contour
2150 struct Convexicator { 2184 struct Convexicator {
2151 Convexicator() 2185 Convexicator()
2152 : fPtCount(0) 2186 : fPtCount(0)
2153 , fConvexity(SkPath::kConvex_Convexity) 2187 , fConvexity(SkPath::kConvex_Convexity)
2154 , fDirection(SkPath::kUnknown_Direction) { 2188 , fDirection(SkPath::kUnknown_Direction) {
2155 fSign = 0; 2189 fExpectedDir = kInvalid_DirChange;
2156 // warnings 2190 // warnings
2157 fLastPt.set(0, 0); 2191 fLastPt.set(0, 0);
2158 fCurrPt.set(0, 0); 2192 fCurrPt.set(0, 0);
2159 fLastVec.set(0, 0); 2193 fLastVec.set(0, 0);
2160 fFirstVec.set(0, 0); 2194 fFirstVec.set(0, 0);
2161 2195
2162 fDx = fDy = 0; 2196 fDx = fDy = 0;
2163 fSx = fSy = kValueNeverReturnedBySign; 2197 fSx = fSy = kValueNeverReturnedBySign;
2164 } 2198 }
2165 2199
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
2204 2238
2205 void close() { 2239 void close() {
2206 if (fPtCount > 2) { 2240 if (fPtCount > 2) {
2207 this->addVec(fFirstVec); 2241 this->addVec(fFirstVec);
2208 } 2242 }
2209 } 2243 }
2210 2244
2211 private: 2245 private:
2212 void addVec(const SkVector& vec) { 2246 void addVec(const SkVector& vec) {
2213 SkASSERT(vec.fX || vec.fY); 2247 SkASSERT(vec.fX || vec.fY);
2214 SkScalar cross = SkPoint::CrossProduct(fLastVec, vec); 2248 DirChange dir = direction_change(fLastPt, fCurrPt, fLastVec, vec);
2215 SkScalar smallest = SkTMin(fCurrPt.fX, SkTMin(fCurrPt.fY, SkTMin(fLastPt .fX, fLastPt.fY))); 2249 switch (dir) {
2216 SkScalar largest = SkTMax(fCurrPt.fX, SkTMax(fCurrPt.fY, SkTMax(fLastPt. fX, fLastPt.fY))); 2250 case kLeft_DirChange: // fall through
2217 largest = SkTMax(largest, -smallest); 2251 case kRight_DirChange:
2218 if (!almost_equal(largest, largest + cross)) { 2252 if (kInvalid_DirChange == fExpectedDir) {
2219 int sign = SkScalarSignAsInt(cross); 2253 fExpectedDir = dir;
2220 if (0 == fSign) { 2254 fDirection = (kRight_DirChange == dir) ? SkPath::kCW_Directi on
2221 fSign = sign; 2255 : SkPath::kCCW_Direct ion;
2222 fDirection = (1 == sign) ? SkPath::kCW_Direction : SkPath::kCCW_ Direction; 2256 } else if (dir != fExpectedDir) {
2223 } else if (sign && fSign != sign) { 2257 fConvexity = SkPath::kConcave_Convexity;
2224 fConvexity = SkPath::kConcave_Convexity; 2258 fDirection = SkPath::kUnknown_Direction;
2225 fDirection = SkPath::kUnknown_Direction; 2259 }
2226 } 2260 fLastVec = vec;
2227 fLastVec = vec; 2261 break;
2262 case kStraight_DirChange:
2263 break;
2264 case kBackwards_DirChange:
2265 fLastVec = vec;
2266 break;
2267 case kInvalid_DirChange:
2268 SkFAIL("Use of invalid direction change flag");
2269 break;
2228 } 2270 }
2229 } 2271 }
2230 2272
2231 SkPoint fLastPt; 2273 SkPoint fLastPt;
2232 SkPoint fCurrPt; 2274 SkPoint fCurrPt;
2233 // fLastVec does not necessarily start at fLastPt. We only advance it when t he cross product 2275 // fLastVec does not necessarily start at fLastPt. We only advance it when t he cross product
2234 // value with the current vec is deemed to be of a significant value. 2276 // value with the current vec is deemed to be of a significant value.
2235 SkVector fLastVec, fFirstVec; 2277 SkVector fLastVec, fFirstVec;
2236 int fPtCount; // non-degenerate points 2278 int fPtCount; // non-degenerate points
2237 int fSign; 2279 DirChange fExpectedDir;
2238 SkPath::Convexity fConvexity; 2280 SkPath::Convexity fConvexity;
2239 SkPath::Direction fDirection; 2281 SkPath::Direction fDirection;
2240 int fDx, fDy, fSx, fSy; 2282 int fDx, fDy, fSx, fSy;
2241 }; 2283 };
2242 2284
2243 SkPath::Convexity SkPath::internalGetConvexity() const { 2285 SkPath::Convexity SkPath::internalGetConvexity() const {
2244 SkASSERT(kUnknown_Convexity == fConvexity); 2286 SkASSERT(kUnknown_Convexity == fConvexity);
2245 SkPoint pts[4]; 2287 SkPoint pts[4];
2246 SkPath::Verb verb; 2288 SkPath::Verb verb;
2247 SkPath::Iter iter(*this, true); 2289 SkPath::Iter iter(*this, true);
(...skipping 544 matching lines...) Expand 10 before | Expand all | Expand 10 after
2792 switch (this->getFillType()) { 2834 switch (this->getFillType()) {
2793 case SkPath::kEvenOdd_FillType: 2835 case SkPath::kEvenOdd_FillType:
2794 case SkPath::kInverseEvenOdd_FillType: 2836 case SkPath::kInverseEvenOdd_FillType:
2795 w &= 1; 2837 w &= 1;
2796 break; 2838 break;
2797 default: 2839 default:
2798 break; 2840 break;
2799 } 2841 }
2800 return SkToBool(w); 2842 return SkToBool(w);
2801 } 2843 }
OLDNEW
« no previous file with comments | « no previous file | tests/PathTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698