gfx/skia/trunk/src/core/SkLineClipper.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

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 /*
michael@0 3 * Copyright 2011 Google Inc.
michael@0 4 *
michael@0 5 * Use of this source code is governed by a BSD-style license that can be
michael@0 6 * found in the LICENSE file.
michael@0 7 */
michael@0 8 #include "SkLineClipper.h"
michael@0 9
michael@0 10 template <typename T> T pin_unsorted(T value, T limit0, T limit1) {
michael@0 11 if (limit1 < limit0) {
michael@0 12 SkTSwap(limit0, limit1);
michael@0 13 }
michael@0 14 // now the limits are sorted
michael@0 15 SkASSERT(limit0 <= limit1);
michael@0 16
michael@0 17 if (value < limit0) {
michael@0 18 value = limit0;
michael@0 19 } else if (value > limit1) {
michael@0 20 value = limit1;
michael@0 21 }
michael@0 22 return value;
michael@0 23 }
michael@0 24
michael@0 25 // return X coordinate of intersection with horizontal line at Y
michael@0 26 static SkScalar sect_with_horizontal(const SkPoint src[2], SkScalar Y) {
michael@0 27 SkScalar dy = src[1].fY - src[0].fY;
michael@0 28 if (SkScalarNearlyZero(dy)) {
michael@0 29 return SkScalarAve(src[0].fX, src[1].fX);
michael@0 30 } else {
michael@0 31 // need the extra precision so we don't compute a value that exceeds
michael@0 32 // our original limits
michael@0 33 double X0 = src[0].fX;
michael@0 34 double Y0 = src[0].fY;
michael@0 35 double X1 = src[1].fX;
michael@0 36 double Y1 = src[1].fY;
michael@0 37 double result = X0 + ((double)Y - Y0) * (X1 - X0) / (Y1 - Y0);
michael@0 38
michael@0 39 // The computed X value might still exceed [X0..X1] due to quantum flux
michael@0 40 // when the doubles were added and subtracted, so we have to pin the
michael@0 41 // answer :(
michael@0 42 return (float)pin_unsorted(result, X0, X1);
michael@0 43 }
michael@0 44 }
michael@0 45
michael@0 46 // return Y coordinate of intersection with vertical line at X
michael@0 47 static SkScalar sect_with_vertical(const SkPoint src[2], SkScalar X) {
michael@0 48 SkScalar dx = src[1].fX - src[0].fX;
michael@0 49 if (SkScalarNearlyZero(dx)) {
michael@0 50 return SkScalarAve(src[0].fY, src[1].fY);
michael@0 51 } else {
michael@0 52 // need the extra precision so we don't compute a value that exceeds
michael@0 53 // our original limits
michael@0 54 double X0 = src[0].fX;
michael@0 55 double Y0 = src[0].fY;
michael@0 56 double X1 = src[1].fX;
michael@0 57 double Y1 = src[1].fY;
michael@0 58 double result = Y0 + ((double)X - X0) * (Y1 - Y0) / (X1 - X0);
michael@0 59 return (float)result;
michael@0 60 }
michael@0 61 }
michael@0 62
michael@0 63 ///////////////////////////////////////////////////////////////////////////////
michael@0 64
michael@0 65 static inline bool nestedLT(SkScalar a, SkScalar b, SkScalar dim) {
michael@0 66 return a <= b && (a < b || dim > 0);
michael@0 67 }
michael@0 68
michael@0 69 // returns true if outer contains inner, even if inner is empty.
michael@0 70 // note: outer.contains(inner) always returns false if inner is empty.
michael@0 71 static inline bool containsNoEmptyCheck(const SkRect& outer,
michael@0 72 const SkRect& inner) {
michael@0 73 return outer.fLeft <= inner.fLeft && outer.fTop <= inner.fTop &&
michael@0 74 outer.fRight >= inner.fRight && outer.fBottom >= inner.fBottom;
michael@0 75 }
michael@0 76
michael@0 77 bool SkLineClipper::IntersectLine(const SkPoint src[2], const SkRect& clip,
michael@0 78 SkPoint dst[2]) {
michael@0 79 SkRect bounds;
michael@0 80
michael@0 81 bounds.set(src, 2);
michael@0 82 if (containsNoEmptyCheck(clip, bounds)) {
michael@0 83 if (src != dst) {
michael@0 84 memcpy(dst, src, 2 * sizeof(SkPoint));
michael@0 85 }
michael@0 86 return true;
michael@0 87 }
michael@0 88 // check for no overlap, and only permit coincident edges if the line
michael@0 89 // and the edge are colinear
michael@0 90 if (nestedLT(bounds.fRight, clip.fLeft, bounds.width()) ||
michael@0 91 nestedLT(clip.fRight, bounds.fLeft, bounds.width()) ||
michael@0 92 nestedLT(bounds.fBottom, clip.fTop, bounds.height()) ||
michael@0 93 nestedLT(clip.fBottom, bounds.fTop, bounds.height())) {
michael@0 94 return false;
michael@0 95 }
michael@0 96
michael@0 97 int index0, index1;
michael@0 98
michael@0 99 if (src[0].fY < src[1].fY) {
michael@0 100 index0 = 0;
michael@0 101 index1 = 1;
michael@0 102 } else {
michael@0 103 index0 = 1;
michael@0 104 index1 = 0;
michael@0 105 }
michael@0 106
michael@0 107 SkPoint tmp[2];
michael@0 108 memcpy(tmp, src, sizeof(tmp));
michael@0 109
michael@0 110 // now compute Y intersections
michael@0 111 if (tmp[index0].fY < clip.fTop) {
michael@0 112 tmp[index0].set(sect_with_horizontal(src, clip.fTop), clip.fTop);
michael@0 113 }
michael@0 114 if (tmp[index1].fY > clip.fBottom) {
michael@0 115 tmp[index1].set(sect_with_horizontal(src, clip.fBottom), clip.fBottom);
michael@0 116 }
michael@0 117
michael@0 118 if (tmp[0].fX < tmp[1].fX) {
michael@0 119 index0 = 0;
michael@0 120 index1 = 1;
michael@0 121 } else {
michael@0 122 index0 = 1;
michael@0 123 index1 = 0;
michael@0 124 }
michael@0 125
michael@0 126 // check for quick-reject in X again, now that we may have been chopped
michael@0 127 if ((tmp[index1].fX <= clip.fLeft || tmp[index0].fX >= clip.fRight) &&
michael@0 128 tmp[index0].fX < tmp[index1].fX) {
michael@0 129 // only reject if we have a non-zero width
michael@0 130 return false;
michael@0 131 }
michael@0 132
michael@0 133 if (tmp[index0].fX < clip.fLeft) {
michael@0 134 tmp[index0].set(clip.fLeft, sect_with_vertical(src, clip.fLeft));
michael@0 135 }
michael@0 136 if (tmp[index1].fX > clip.fRight) {
michael@0 137 tmp[index1].set(clip.fRight, sect_with_vertical(src, clip.fRight));
michael@0 138 }
michael@0 139 #ifdef SK_DEBUG
michael@0 140 bounds.set(tmp, 2);
michael@0 141 SkASSERT(containsNoEmptyCheck(clip, bounds));
michael@0 142 #endif
michael@0 143 memcpy(dst, tmp, sizeof(tmp));
michael@0 144 return true;
michael@0 145 }
michael@0 146
michael@0 147 #ifdef SK_DEBUG
michael@0 148 // return value between the two limits, where the limits are either ascending
michael@0 149 // or descending.
michael@0 150 static bool is_between_unsorted(SkScalar value,
michael@0 151 SkScalar limit0, SkScalar limit1) {
michael@0 152 if (limit0 < limit1) {
michael@0 153 return limit0 <= value && value <= limit1;
michael@0 154 } else {
michael@0 155 return limit1 <= value && value <= limit0;
michael@0 156 }
michael@0 157 }
michael@0 158 #endif
michael@0 159
michael@0 160 #ifdef SK_DEBUG
michael@0 161 // This is an example of why we need to pin the result computed in
michael@0 162 // sect_with_horizontal. If we didn't explicitly pin, is_between_unsorted would
michael@0 163 // fail.
michael@0 164 //
michael@0 165 static void sect_with_horizontal_test_for_pin_results() {
michael@0 166 const SkPoint pts[] = {
michael@0 167 { -540000, -720000 },
michael@0 168 { -9.10000017e-05f, 9.99999996e-13f }
michael@0 169 };
michael@0 170 float x = sect_with_horizontal(pts, 0);
michael@0 171 SkASSERT(is_between_unsorted(x, pts[0].fX, pts[1].fX));
michael@0 172 }
michael@0 173 #endif
michael@0 174
michael@0 175 int SkLineClipper::ClipLine(const SkPoint pts[], const SkRect& clip,
michael@0 176 SkPoint lines[]) {
michael@0 177 #ifdef SK_DEBUG
michael@0 178 {
michael@0 179 static bool gOnce;
michael@0 180 if (!gOnce) {
michael@0 181 sect_with_horizontal_test_for_pin_results();
michael@0 182 gOnce = true;
michael@0 183 }
michael@0 184 }
michael@0 185 #endif
michael@0 186
michael@0 187 int index0, index1;
michael@0 188
michael@0 189 if (pts[0].fY < pts[1].fY) {
michael@0 190 index0 = 0;
michael@0 191 index1 = 1;
michael@0 192 } else {
michael@0 193 index0 = 1;
michael@0 194 index1 = 0;
michael@0 195 }
michael@0 196
michael@0 197 // Check if we're completely clipped out in Y (above or below
michael@0 198
michael@0 199 if (pts[index1].fY <= clip.fTop) { // we're above the clip
michael@0 200 return 0;
michael@0 201 }
michael@0 202 if (pts[index0].fY >= clip.fBottom) { // we're below the clip
michael@0 203 return 0;
michael@0 204 }
michael@0 205
michael@0 206 // Chop in Y to produce a single segment, stored in tmp[0..1]
michael@0 207
michael@0 208 SkPoint tmp[2];
michael@0 209 memcpy(tmp, pts, sizeof(tmp));
michael@0 210
michael@0 211 // now compute intersections
michael@0 212 if (pts[index0].fY < clip.fTop) {
michael@0 213 tmp[index0].set(sect_with_horizontal(pts, clip.fTop), clip.fTop);
michael@0 214 SkASSERT(is_between_unsorted(tmp[index0].fX, pts[0].fX, pts[1].fX));
michael@0 215 }
michael@0 216 if (tmp[index1].fY > clip.fBottom) {
michael@0 217 tmp[index1].set(sect_with_horizontal(pts, clip.fBottom), clip.fBottom);
michael@0 218 SkASSERT(is_between_unsorted(tmp[index1].fX, pts[0].fX, pts[1].fX));
michael@0 219 }
michael@0 220
michael@0 221 // Chop it into 1..3 segments that are wholly within the clip in X.
michael@0 222
michael@0 223 // temp storage for up to 3 segments
michael@0 224 SkPoint resultStorage[kMaxPoints];
michael@0 225 SkPoint* result; // points to our results, either tmp or resultStorage
michael@0 226 int lineCount = 1;
michael@0 227 bool reverse;
michael@0 228
michael@0 229 if (pts[0].fX < pts[1].fX) {
michael@0 230 index0 = 0;
michael@0 231 index1 = 1;
michael@0 232 reverse = false;
michael@0 233 } else {
michael@0 234 index0 = 1;
michael@0 235 index1 = 0;
michael@0 236 reverse = true;
michael@0 237 }
michael@0 238
michael@0 239 if (tmp[index1].fX <= clip.fLeft) { // wholly to the left
michael@0 240 tmp[0].fX = tmp[1].fX = clip.fLeft;
michael@0 241 result = tmp;
michael@0 242 reverse = false;
michael@0 243 } else if (tmp[index0].fX >= clip.fRight) { // wholly to the right
michael@0 244 tmp[0].fX = tmp[1].fX = clip.fRight;
michael@0 245 result = tmp;
michael@0 246 reverse = false;
michael@0 247 } else {
michael@0 248 result = resultStorage;
michael@0 249 SkPoint* r = result;
michael@0 250
michael@0 251 if (tmp[index0].fX < clip.fLeft) {
michael@0 252 r->set(clip.fLeft, tmp[index0].fY);
michael@0 253 r += 1;
michael@0 254 r->set(clip.fLeft, sect_with_vertical(tmp, clip.fLeft));
michael@0 255 SkASSERT(is_between_unsorted(r->fY, tmp[0].fY, tmp[1].fY));
michael@0 256 } else {
michael@0 257 *r = tmp[index0];
michael@0 258 }
michael@0 259 r += 1;
michael@0 260
michael@0 261 if (tmp[index1].fX > clip.fRight) {
michael@0 262 r->set(clip.fRight, sect_with_vertical(tmp, clip.fRight));
michael@0 263 SkASSERT(is_between_unsorted(r->fY, tmp[0].fY, tmp[1].fY));
michael@0 264 r += 1;
michael@0 265 r->set(clip.fRight, tmp[index1].fY);
michael@0 266 } else {
michael@0 267 *r = tmp[index1];
michael@0 268 }
michael@0 269
michael@0 270 lineCount = SkToInt(r - result);
michael@0 271 }
michael@0 272
michael@0 273 // Now copy the results into the caller's lines[] parameter
michael@0 274 if (reverse) {
michael@0 275 // copy the pts in reverse order to maintain winding order
michael@0 276 for (int i = 0; i <= lineCount; i++) {
michael@0 277 lines[lineCount - i] = result[i];
michael@0 278 }
michael@0 279 } else {
michael@0 280 memcpy(lines, result, (lineCount + 1) * sizeof(SkPoint));
michael@0 281 }
michael@0 282 return lineCount;
michael@0 283 }

mercurial