Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
michael@0 | 1 | /* |
michael@0 | 2 | * Copyright 2012 Google Inc. |
michael@0 | 3 | * |
michael@0 | 4 | * Use of this source code is governed by a BSD-style license that can be |
michael@0 | 5 | * found in the LICENSE file. |
michael@0 | 6 | */ |
michael@0 | 7 | #include "SkIntersections.h" |
michael@0 | 8 | #include "SkPathOpsCubic.h" |
michael@0 | 9 | #include "SkPathOpsLine.h" |
michael@0 | 10 | |
michael@0 | 11 | /* |
michael@0 | 12 | Find the interection of a line and cubic by solving for valid t values. |
michael@0 | 13 | |
michael@0 | 14 | Analogous to line-quadratic intersection, solve line-cubic intersection by |
michael@0 | 15 | representing the cubic as: |
michael@0 | 16 | x = a(1-t)^3 + 2b(1-t)^2t + c(1-t)t^2 + dt^3 |
michael@0 | 17 | y = e(1-t)^3 + 2f(1-t)^2t + g(1-t)t^2 + ht^3 |
michael@0 | 18 | and the line as: |
michael@0 | 19 | y = i*x + j (if the line is more horizontal) |
michael@0 | 20 | or: |
michael@0 | 21 | x = i*y + j (if the line is more vertical) |
michael@0 | 22 | |
michael@0 | 23 | Then using Mathematica, solve for the values of t where the cubic intersects the |
michael@0 | 24 | line: |
michael@0 | 25 | |
michael@0 | 26 | (in) Resultant[ |
michael@0 | 27 | a*(1 - t)^3 + 3*b*(1 - t)^2*t + 3*c*(1 - t)*t^2 + d*t^3 - x, |
michael@0 | 28 | e*(1 - t)^3 + 3*f*(1 - t)^2*t + 3*g*(1 - t)*t^2 + h*t^3 - i*x - j, x] |
michael@0 | 29 | (out) -e + j + |
michael@0 | 30 | 3 e t - 3 f t - |
michael@0 | 31 | 3 e t^2 + 6 f t^2 - 3 g t^2 + |
michael@0 | 32 | e t^3 - 3 f t^3 + 3 g t^3 - h t^3 + |
michael@0 | 33 | i ( a - |
michael@0 | 34 | 3 a t + 3 b t + |
michael@0 | 35 | 3 a t^2 - 6 b t^2 + 3 c t^2 - |
michael@0 | 36 | a t^3 + 3 b t^3 - 3 c t^3 + d t^3 ) |
michael@0 | 37 | |
michael@0 | 38 | if i goes to infinity, we can rewrite the line in terms of x. Mathematica: |
michael@0 | 39 | |
michael@0 | 40 | (in) Resultant[ |
michael@0 | 41 | a*(1 - t)^3 + 3*b*(1 - t)^2*t + 3*c*(1 - t)*t^2 + d*t^3 - i*y - j, |
michael@0 | 42 | e*(1 - t)^3 + 3*f*(1 - t)^2*t + 3*g*(1 - t)*t^2 + h*t^3 - y, y] |
michael@0 | 43 | (out) a - j - |
michael@0 | 44 | 3 a t + 3 b t + |
michael@0 | 45 | 3 a t^2 - 6 b t^2 + 3 c t^2 - |
michael@0 | 46 | a t^3 + 3 b t^3 - 3 c t^3 + d t^3 - |
michael@0 | 47 | i ( e - |
michael@0 | 48 | 3 e t + 3 f t + |
michael@0 | 49 | 3 e t^2 - 6 f t^2 + 3 g t^2 - |
michael@0 | 50 | e t^3 + 3 f t^3 - 3 g t^3 + h t^3 ) |
michael@0 | 51 | |
michael@0 | 52 | Solving this with Mathematica produces an expression with hundreds of terms; |
michael@0 | 53 | instead, use Numeric Solutions recipe to solve the cubic. |
michael@0 | 54 | |
michael@0 | 55 | The near-horizontal case, in terms of: Ax^3 + Bx^2 + Cx + D == 0 |
michael@0 | 56 | A = (-(-e + 3*f - 3*g + h) + i*(-a + 3*b - 3*c + d) ) |
michael@0 | 57 | B = 3*(-( e - 2*f + g ) + i*( a - 2*b + c ) ) |
michael@0 | 58 | C = 3*(-(-e + f ) + i*(-a + b ) ) |
michael@0 | 59 | D = (-( e ) + i*( a ) + j ) |
michael@0 | 60 | |
michael@0 | 61 | The near-vertical case, in terms of: Ax^3 + Bx^2 + Cx + D == 0 |
michael@0 | 62 | A = ( (-a + 3*b - 3*c + d) - i*(-e + 3*f - 3*g + h) ) |
michael@0 | 63 | B = 3*( ( a - 2*b + c ) - i*( e - 2*f + g ) ) |
michael@0 | 64 | C = 3*( (-a + b ) - i*(-e + f ) ) |
michael@0 | 65 | D = ( ( a ) - i*( e ) - j ) |
michael@0 | 66 | |
michael@0 | 67 | For horizontal lines: |
michael@0 | 68 | (in) Resultant[ |
michael@0 | 69 | a*(1 - t)^3 + 3*b*(1 - t)^2*t + 3*c*(1 - t)*t^2 + d*t^3 - j, |
michael@0 | 70 | e*(1 - t)^3 + 3*f*(1 - t)^2*t + 3*g*(1 - t)*t^2 + h*t^3 - y, y] |
michael@0 | 71 | (out) e - j - |
michael@0 | 72 | 3 e t + 3 f t + |
michael@0 | 73 | 3 e t^2 - 6 f t^2 + 3 g t^2 - |
michael@0 | 74 | e t^3 + 3 f t^3 - 3 g t^3 + h t^3 |
michael@0 | 75 | */ |
michael@0 | 76 | |
michael@0 | 77 | class LineCubicIntersections { |
michael@0 | 78 | public: |
michael@0 | 79 | enum PinTPoint { |
michael@0 | 80 | kPointUninitialized, |
michael@0 | 81 | kPointInitialized |
michael@0 | 82 | }; |
michael@0 | 83 | |
michael@0 | 84 | LineCubicIntersections(const SkDCubic& c, const SkDLine& l, SkIntersections* i) |
michael@0 | 85 | : fCubic(c) |
michael@0 | 86 | , fLine(l) |
michael@0 | 87 | , fIntersections(i) |
michael@0 | 88 | , fAllowNear(true) { |
michael@0 | 89 | i->setMax(3); |
michael@0 | 90 | } |
michael@0 | 91 | |
michael@0 | 92 | void allowNear(bool allow) { |
michael@0 | 93 | fAllowNear = allow; |
michael@0 | 94 | } |
michael@0 | 95 | |
michael@0 | 96 | // see parallel routine in line quadratic intersections |
michael@0 | 97 | int intersectRay(double roots[3]) { |
michael@0 | 98 | double adj = fLine[1].fX - fLine[0].fX; |
michael@0 | 99 | double opp = fLine[1].fY - fLine[0].fY; |
michael@0 | 100 | SkDCubic r; |
michael@0 | 101 | for (int n = 0; n < 4; ++n) { |
michael@0 | 102 | r[n].fX = (fCubic[n].fY - fLine[0].fY) * adj - (fCubic[n].fX - fLine[0].fX) * opp; |
michael@0 | 103 | } |
michael@0 | 104 | double A, B, C, D; |
michael@0 | 105 | SkDCubic::Coefficients(&r[0].fX, &A, &B, &C, &D); |
michael@0 | 106 | return SkDCubic::RootsValidT(A, B, C, D, roots); |
michael@0 | 107 | } |
michael@0 | 108 | |
michael@0 | 109 | int intersect() { |
michael@0 | 110 | addExactEndPoints(); |
michael@0 | 111 | if (fAllowNear) { |
michael@0 | 112 | addNearEndPoints(); |
michael@0 | 113 | } |
michael@0 | 114 | double rootVals[3]; |
michael@0 | 115 | int roots = intersectRay(rootVals); |
michael@0 | 116 | for (int index = 0; index < roots; ++index) { |
michael@0 | 117 | double cubicT = rootVals[index]; |
michael@0 | 118 | double lineT = findLineT(cubicT); |
michael@0 | 119 | SkDPoint pt; |
michael@0 | 120 | if (pinTs(&cubicT, &lineT, &pt, kPointUninitialized)) { |
michael@0 | 121 | #if ONE_OFF_DEBUG |
michael@0 | 122 | SkDPoint cPt = fCubic.ptAtT(cubicT); |
michael@0 | 123 | SkDebugf("%s pt=(%1.9g,%1.9g) cPt=(%1.9g,%1.9g)\n", __FUNCTION__, pt.fX, pt.fY, |
michael@0 | 124 | cPt.fX, cPt.fY); |
michael@0 | 125 | #endif |
michael@0 | 126 | for (int inner = 0; inner < fIntersections->used(); ++inner) { |
michael@0 | 127 | if (fIntersections->pt(inner) != pt) { |
michael@0 | 128 | continue; |
michael@0 | 129 | } |
michael@0 | 130 | double existingCubicT = (*fIntersections)[0][inner]; |
michael@0 | 131 | if (cubicT == existingCubicT) { |
michael@0 | 132 | goto skipInsert; |
michael@0 | 133 | } |
michael@0 | 134 | // check if midway on cubic is also same point. If so, discard this |
michael@0 | 135 | double cubicMidT = (existingCubicT + cubicT) / 2; |
michael@0 | 136 | SkDPoint cubicMidPt = fCubic.ptAtT(cubicMidT); |
michael@0 | 137 | if (cubicMidPt.approximatelyEqual(pt)) { |
michael@0 | 138 | goto skipInsert; |
michael@0 | 139 | } |
michael@0 | 140 | } |
michael@0 | 141 | fIntersections->insert(cubicT, lineT, pt); |
michael@0 | 142 | skipInsert: |
michael@0 | 143 | ; |
michael@0 | 144 | } |
michael@0 | 145 | } |
michael@0 | 146 | return fIntersections->used(); |
michael@0 | 147 | } |
michael@0 | 148 | |
michael@0 | 149 | int horizontalIntersect(double axisIntercept, double roots[3]) { |
michael@0 | 150 | double A, B, C, D; |
michael@0 | 151 | SkDCubic::Coefficients(&fCubic[0].fY, &A, &B, &C, &D); |
michael@0 | 152 | D -= axisIntercept; |
michael@0 | 153 | return SkDCubic::RootsValidT(A, B, C, D, roots); |
michael@0 | 154 | } |
michael@0 | 155 | |
michael@0 | 156 | int horizontalIntersect(double axisIntercept, double left, double right, bool flipped) { |
michael@0 | 157 | addExactHorizontalEndPoints(left, right, axisIntercept); |
michael@0 | 158 | if (fAllowNear) { |
michael@0 | 159 | addNearHorizontalEndPoints(left, right, axisIntercept); |
michael@0 | 160 | } |
michael@0 | 161 | double rootVals[3]; |
michael@0 | 162 | int roots = horizontalIntersect(axisIntercept, rootVals); |
michael@0 | 163 | for (int index = 0; index < roots; ++index) { |
michael@0 | 164 | double cubicT = rootVals[index]; |
michael@0 | 165 | SkDPoint pt = fCubic.ptAtT(cubicT); |
michael@0 | 166 | double lineT = (pt.fX - left) / (right - left); |
michael@0 | 167 | if (pinTs(&cubicT, &lineT, &pt, kPointInitialized)) { |
michael@0 | 168 | fIntersections->insert(cubicT, lineT, pt); |
michael@0 | 169 | } |
michael@0 | 170 | } |
michael@0 | 171 | if (flipped) { |
michael@0 | 172 | fIntersections->flip(); |
michael@0 | 173 | } |
michael@0 | 174 | return fIntersections->used(); |
michael@0 | 175 | } |
michael@0 | 176 | |
michael@0 | 177 | int verticalIntersect(double axisIntercept, double roots[3]) { |
michael@0 | 178 | double A, B, C, D; |
michael@0 | 179 | SkDCubic::Coefficients(&fCubic[0].fX, &A, &B, &C, &D); |
michael@0 | 180 | D -= axisIntercept; |
michael@0 | 181 | return SkDCubic::RootsValidT(A, B, C, D, roots); |
michael@0 | 182 | } |
michael@0 | 183 | |
michael@0 | 184 | int verticalIntersect(double axisIntercept, double top, double bottom, bool flipped) { |
michael@0 | 185 | addExactVerticalEndPoints(top, bottom, axisIntercept); |
michael@0 | 186 | if (fAllowNear) { |
michael@0 | 187 | addNearVerticalEndPoints(top, bottom, axisIntercept); |
michael@0 | 188 | } |
michael@0 | 189 | double rootVals[3]; |
michael@0 | 190 | int roots = verticalIntersect(axisIntercept, rootVals); |
michael@0 | 191 | for (int index = 0; index < roots; ++index) { |
michael@0 | 192 | double cubicT = rootVals[index]; |
michael@0 | 193 | SkDPoint pt = fCubic.ptAtT(cubicT); |
michael@0 | 194 | double lineT = (pt.fY - top) / (bottom - top); |
michael@0 | 195 | if (pinTs(&cubicT, &lineT, &pt, kPointInitialized)) { |
michael@0 | 196 | fIntersections->insert(cubicT, lineT, pt); |
michael@0 | 197 | } |
michael@0 | 198 | } |
michael@0 | 199 | if (flipped) { |
michael@0 | 200 | fIntersections->flip(); |
michael@0 | 201 | } |
michael@0 | 202 | return fIntersections->used(); |
michael@0 | 203 | } |
michael@0 | 204 | |
michael@0 | 205 | protected: |
michael@0 | 206 | |
michael@0 | 207 | void addExactEndPoints() { |
michael@0 | 208 | for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
michael@0 | 209 | double lineT = fLine.exactPoint(fCubic[cIndex]); |
michael@0 | 210 | if (lineT < 0) { |
michael@0 | 211 | continue; |
michael@0 | 212 | } |
michael@0 | 213 | double cubicT = (double) (cIndex >> 1); |
michael@0 | 214 | fIntersections->insert(cubicT, lineT, fCubic[cIndex]); |
michael@0 | 215 | } |
michael@0 | 216 | } |
michael@0 | 217 | |
michael@0 | 218 | /* Note that this does not look for endpoints of the line that are near the cubic. |
michael@0 | 219 | These points are found later when check ends looks for missing points */ |
michael@0 | 220 | void addNearEndPoints() { |
michael@0 | 221 | for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
michael@0 | 222 | double cubicT = (double) (cIndex >> 1); |
michael@0 | 223 | if (fIntersections->hasT(cubicT)) { |
michael@0 | 224 | continue; |
michael@0 | 225 | } |
michael@0 | 226 | double lineT = fLine.nearPoint(fCubic[cIndex]); |
michael@0 | 227 | if (lineT < 0) { |
michael@0 | 228 | continue; |
michael@0 | 229 | } |
michael@0 | 230 | fIntersections->insert(cubicT, lineT, fCubic[cIndex]); |
michael@0 | 231 | } |
michael@0 | 232 | } |
michael@0 | 233 | |
michael@0 | 234 | void addExactHorizontalEndPoints(double left, double right, double y) { |
michael@0 | 235 | for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
michael@0 | 236 | double lineT = SkDLine::ExactPointH(fCubic[cIndex], left, right, y); |
michael@0 | 237 | if (lineT < 0) { |
michael@0 | 238 | continue; |
michael@0 | 239 | } |
michael@0 | 240 | double cubicT = (double) (cIndex >> 1); |
michael@0 | 241 | fIntersections->insert(cubicT, lineT, fCubic[cIndex]); |
michael@0 | 242 | } |
michael@0 | 243 | } |
michael@0 | 244 | |
michael@0 | 245 | void addNearHorizontalEndPoints(double left, double right, double y) { |
michael@0 | 246 | for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
michael@0 | 247 | double cubicT = (double) (cIndex >> 1); |
michael@0 | 248 | if (fIntersections->hasT(cubicT)) { |
michael@0 | 249 | continue; |
michael@0 | 250 | } |
michael@0 | 251 | double lineT = SkDLine::NearPointH(fCubic[cIndex], left, right, y); |
michael@0 | 252 | if (lineT < 0) { |
michael@0 | 253 | continue; |
michael@0 | 254 | } |
michael@0 | 255 | fIntersections->insert(cubicT, lineT, fCubic[cIndex]); |
michael@0 | 256 | } |
michael@0 | 257 | // FIXME: see if line end is nearly on cubic |
michael@0 | 258 | } |
michael@0 | 259 | |
michael@0 | 260 | void addExactVerticalEndPoints(double top, double bottom, double x) { |
michael@0 | 261 | for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
michael@0 | 262 | double lineT = SkDLine::ExactPointV(fCubic[cIndex], top, bottom, x); |
michael@0 | 263 | if (lineT < 0) { |
michael@0 | 264 | continue; |
michael@0 | 265 | } |
michael@0 | 266 | double cubicT = (double) (cIndex >> 1); |
michael@0 | 267 | fIntersections->insert(cubicT, lineT, fCubic[cIndex]); |
michael@0 | 268 | } |
michael@0 | 269 | } |
michael@0 | 270 | |
michael@0 | 271 | void addNearVerticalEndPoints(double top, double bottom, double x) { |
michael@0 | 272 | for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
michael@0 | 273 | double cubicT = (double) (cIndex >> 1); |
michael@0 | 274 | if (fIntersections->hasT(cubicT)) { |
michael@0 | 275 | continue; |
michael@0 | 276 | } |
michael@0 | 277 | double lineT = SkDLine::NearPointV(fCubic[cIndex], top, bottom, x); |
michael@0 | 278 | if (lineT < 0) { |
michael@0 | 279 | continue; |
michael@0 | 280 | } |
michael@0 | 281 | fIntersections->insert(cubicT, lineT, fCubic[cIndex]); |
michael@0 | 282 | } |
michael@0 | 283 | // FIXME: see if line end is nearly on cubic |
michael@0 | 284 | } |
michael@0 | 285 | |
michael@0 | 286 | double findLineT(double t) { |
michael@0 | 287 | SkDPoint xy = fCubic.ptAtT(t); |
michael@0 | 288 | double dx = fLine[1].fX - fLine[0].fX; |
michael@0 | 289 | double dy = fLine[1].fY - fLine[0].fY; |
michael@0 | 290 | if (fabs(dx) > fabs(dy)) { |
michael@0 | 291 | return (xy.fX - fLine[0].fX) / dx; |
michael@0 | 292 | } |
michael@0 | 293 | return (xy.fY - fLine[0].fY) / dy; |
michael@0 | 294 | } |
michael@0 | 295 | |
michael@0 | 296 | bool pinTs(double* cubicT, double* lineT, SkDPoint* pt, PinTPoint ptSet) { |
michael@0 | 297 | if (!approximately_one_or_less(*lineT)) { |
michael@0 | 298 | return false; |
michael@0 | 299 | } |
michael@0 | 300 | if (!approximately_zero_or_more(*lineT)) { |
michael@0 | 301 | return false; |
michael@0 | 302 | } |
michael@0 | 303 | double cT = *cubicT = SkPinT(*cubicT); |
michael@0 | 304 | double lT = *lineT = SkPinT(*lineT); |
michael@0 | 305 | if (lT == 0 || lT == 1 || (ptSet == kPointUninitialized && cT != 0 && cT != 1)) { |
michael@0 | 306 | *pt = fLine.ptAtT(lT); |
michael@0 | 307 | } else if (ptSet == kPointUninitialized) { |
michael@0 | 308 | *pt = fCubic.ptAtT(cT); |
michael@0 | 309 | } |
michael@0 | 310 | SkPoint gridPt = pt->asSkPoint(); |
michael@0 | 311 | if (gridPt == fLine[0].asSkPoint()) { |
michael@0 | 312 | *lineT = 0; |
michael@0 | 313 | } else if (gridPt == fLine[1].asSkPoint()) { |
michael@0 | 314 | *lineT = 1; |
michael@0 | 315 | } |
michael@0 | 316 | if (gridPt == fCubic[0].asSkPoint() && approximately_equal(*cubicT, 0)) { |
michael@0 | 317 | *cubicT = 0; |
michael@0 | 318 | } else if (gridPt == fCubic[3].asSkPoint() && approximately_equal(*cubicT, 1)) { |
michael@0 | 319 | *cubicT = 1; |
michael@0 | 320 | } |
michael@0 | 321 | return true; |
michael@0 | 322 | } |
michael@0 | 323 | |
michael@0 | 324 | private: |
michael@0 | 325 | const SkDCubic& fCubic; |
michael@0 | 326 | const SkDLine& fLine; |
michael@0 | 327 | SkIntersections* fIntersections; |
michael@0 | 328 | bool fAllowNear; |
michael@0 | 329 | }; |
michael@0 | 330 | |
michael@0 | 331 | int SkIntersections::horizontal(const SkDCubic& cubic, double left, double right, double y, |
michael@0 | 332 | bool flipped) { |
michael@0 | 333 | SkDLine line = {{{ left, y }, { right, y }}}; |
michael@0 | 334 | LineCubicIntersections c(cubic, line, this); |
michael@0 | 335 | return c.horizontalIntersect(y, left, right, flipped); |
michael@0 | 336 | } |
michael@0 | 337 | |
michael@0 | 338 | int SkIntersections::vertical(const SkDCubic& cubic, double top, double bottom, double x, |
michael@0 | 339 | bool flipped) { |
michael@0 | 340 | SkDLine line = {{{ x, top }, { x, bottom }}}; |
michael@0 | 341 | LineCubicIntersections c(cubic, line, this); |
michael@0 | 342 | return c.verticalIntersect(x, top, bottom, flipped); |
michael@0 | 343 | } |
michael@0 | 344 | |
michael@0 | 345 | int SkIntersections::intersect(const SkDCubic& cubic, const SkDLine& line) { |
michael@0 | 346 | LineCubicIntersections c(cubic, line, this); |
michael@0 | 347 | c.allowNear(fAllowNear); |
michael@0 | 348 | return c.intersect(); |
michael@0 | 349 | } |
michael@0 | 350 | |
michael@0 | 351 | int SkIntersections::intersectRay(const SkDCubic& cubic, const SkDLine& line) { |
michael@0 | 352 | LineCubicIntersections c(cubic, line, this); |
michael@0 | 353 | fUsed = c.intersectRay(fT[0]); |
michael@0 | 354 | for (int index = 0; index < fUsed; ++index) { |
michael@0 | 355 | fPt[index] = cubic.ptAtT(fT[0][index]); |
michael@0 | 356 | } |
michael@0 | 357 | return fUsed; |
michael@0 | 358 | } |