gfx/skia/trunk/src/pathops/SkReduceOrder.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 * 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 "SkReduceOrder.h"
michael@0 8
michael@0 9 int SkReduceOrder::reduce(const SkDLine& line) {
michael@0 10 fLine[0] = line[0];
michael@0 11 int different = line[0] != line[1];
michael@0 12 fLine[1] = line[different];
michael@0 13 return 1 + different;
michael@0 14 }
michael@0 15
michael@0 16 static int coincident_line(const SkDQuad& quad, SkDQuad& reduction) {
michael@0 17 reduction[0] = reduction[1] = quad[0];
michael@0 18 return 1;
michael@0 19 }
michael@0 20
michael@0 21 static int reductionLineCount(const SkDQuad& reduction) {
michael@0 22 return 1 + !reduction[0].approximatelyEqual(reduction[1]);
michael@0 23 }
michael@0 24
michael@0 25 static int vertical_line(const SkDQuad& quad, SkDQuad& reduction) {
michael@0 26 reduction[0] = quad[0];
michael@0 27 reduction[1] = quad[2];
michael@0 28 return reductionLineCount(reduction);
michael@0 29 }
michael@0 30
michael@0 31 static int horizontal_line(const SkDQuad& quad, SkDQuad& reduction) {
michael@0 32 reduction[0] = quad[0];
michael@0 33 reduction[1] = quad[2];
michael@0 34 return reductionLineCount(reduction);
michael@0 35 }
michael@0 36
michael@0 37 static int check_linear(const SkDQuad& quad,
michael@0 38 int minX, int maxX, int minY, int maxY, SkDQuad& reduction) {
michael@0 39 int startIndex = 0;
michael@0 40 int endIndex = 2;
michael@0 41 while (quad[startIndex].approximatelyEqual(quad[endIndex])) {
michael@0 42 --endIndex;
michael@0 43 if (endIndex == 0) {
michael@0 44 SkDebugf("%s shouldn't get here if all four points are about equal", __FUNCTION__);
michael@0 45 SkASSERT(0);
michael@0 46 }
michael@0 47 }
michael@0 48 if (!quad.isLinear(startIndex, endIndex)) {
michael@0 49 return 0;
michael@0 50 }
michael@0 51 // four are colinear: return line formed by outside
michael@0 52 reduction[0] = quad[0];
michael@0 53 reduction[1] = quad[2];
michael@0 54 return reductionLineCount(reduction);
michael@0 55 }
michael@0 56
michael@0 57 // reduce to a quadratic or smaller
michael@0 58 // look for identical points
michael@0 59 // look for all four points in a line
michael@0 60 // note that three points in a line doesn't simplify a cubic
michael@0 61 // look for approximation with single quadratic
michael@0 62 // save approximation with multiple quadratics for later
michael@0 63 int SkReduceOrder::reduce(const SkDQuad& quad) {
michael@0 64 int index, minX, maxX, minY, maxY;
michael@0 65 int minXSet, minYSet;
michael@0 66 minX = maxX = minY = maxY = 0;
michael@0 67 minXSet = minYSet = 0;
michael@0 68 for (index = 1; index < 3; ++index) {
michael@0 69 if (quad[minX].fX > quad[index].fX) {
michael@0 70 minX = index;
michael@0 71 }
michael@0 72 if (quad[minY].fY > quad[index].fY) {
michael@0 73 minY = index;
michael@0 74 }
michael@0 75 if (quad[maxX].fX < quad[index].fX) {
michael@0 76 maxX = index;
michael@0 77 }
michael@0 78 if (quad[maxY].fY < quad[index].fY) {
michael@0 79 maxY = index;
michael@0 80 }
michael@0 81 }
michael@0 82 for (index = 0; index < 3; ++index) {
michael@0 83 if (AlmostEqualUlps(quad[index].fX, quad[minX].fX)) {
michael@0 84 minXSet |= 1 << index;
michael@0 85 }
michael@0 86 if (AlmostEqualUlps(quad[index].fY, quad[minY].fY)) {
michael@0 87 minYSet |= 1 << index;
michael@0 88 }
michael@0 89 }
michael@0 90 if (minXSet == 0x7) { // test for vertical line
michael@0 91 if (minYSet == 0x7) { // return 1 if all four are coincident
michael@0 92 return coincident_line(quad, fQuad);
michael@0 93 }
michael@0 94 return vertical_line(quad, fQuad);
michael@0 95 }
michael@0 96 if (minYSet == 0xF) { // test for horizontal line
michael@0 97 return horizontal_line(quad, fQuad);
michael@0 98 }
michael@0 99 int result = check_linear(quad, minX, maxX, minY, maxY, fQuad);
michael@0 100 if (result) {
michael@0 101 return result;
michael@0 102 }
michael@0 103 fQuad = quad;
michael@0 104 return 3;
michael@0 105 }
michael@0 106
michael@0 107 ////////////////////////////////////////////////////////////////////////////////////
michael@0 108
michael@0 109 static int coincident_line(const SkDCubic& cubic, SkDCubic& reduction) {
michael@0 110 reduction[0] = reduction[1] = cubic[0];
michael@0 111 return 1;
michael@0 112 }
michael@0 113
michael@0 114 static int reductionLineCount(const SkDCubic& reduction) {
michael@0 115 return 1 + !reduction[0].approximatelyEqual(reduction[1]);
michael@0 116 }
michael@0 117
michael@0 118 static int vertical_line(const SkDCubic& cubic, SkDCubic& reduction) {
michael@0 119 reduction[0] = cubic[0];
michael@0 120 reduction[1] = cubic[3];
michael@0 121 return reductionLineCount(reduction);
michael@0 122 }
michael@0 123
michael@0 124 static int horizontal_line(const SkDCubic& cubic, SkDCubic& reduction) {
michael@0 125 reduction[0] = cubic[0];
michael@0 126 reduction[1] = cubic[3];
michael@0 127 return reductionLineCount(reduction);
michael@0 128 }
michael@0 129
michael@0 130 // check to see if it is a quadratic or a line
michael@0 131 static int check_quadratic(const SkDCubic& cubic, SkDCubic& reduction) {
michael@0 132 double dx10 = cubic[1].fX - cubic[0].fX;
michael@0 133 double dx23 = cubic[2].fX - cubic[3].fX;
michael@0 134 double midX = cubic[0].fX + dx10 * 3 / 2;
michael@0 135 double sideAx = midX - cubic[3].fX;
michael@0 136 double sideBx = dx23 * 3 / 2;
michael@0 137 if (approximately_zero(sideAx) ? !approximately_equal(sideAx, sideBx)
michael@0 138 : !AlmostEqualUlps(sideAx, sideBx)) {
michael@0 139 return 0;
michael@0 140 }
michael@0 141 double dy10 = cubic[1].fY - cubic[0].fY;
michael@0 142 double dy23 = cubic[2].fY - cubic[3].fY;
michael@0 143 double midY = cubic[0].fY + dy10 * 3 / 2;
michael@0 144 double sideAy = midY - cubic[3].fY;
michael@0 145 double sideBy = dy23 * 3 / 2;
michael@0 146 if (approximately_zero(sideAy) ? !approximately_equal(sideAy, sideBy)
michael@0 147 : !AlmostEqualUlps(sideAy, sideBy)) {
michael@0 148 return 0;
michael@0 149 }
michael@0 150 reduction[0] = cubic[0];
michael@0 151 reduction[1].fX = midX;
michael@0 152 reduction[1].fY = midY;
michael@0 153 reduction[2] = cubic[3];
michael@0 154 return 3;
michael@0 155 }
michael@0 156
michael@0 157 static int check_linear(const SkDCubic& cubic,
michael@0 158 int minX, int maxX, int minY, int maxY, SkDCubic& reduction) {
michael@0 159 int startIndex = 0;
michael@0 160 int endIndex = 3;
michael@0 161 while (cubic[startIndex].approximatelyEqual(cubic[endIndex])) {
michael@0 162 --endIndex;
michael@0 163 if (endIndex == 0) {
michael@0 164 SkDebugf("%s shouldn't get here if all four points are about equal\n", __FUNCTION__);
michael@0 165 SkASSERT(0);
michael@0 166 }
michael@0 167 }
michael@0 168 if (!cubic.isLinear(startIndex, endIndex)) {
michael@0 169 return 0;
michael@0 170 }
michael@0 171 // four are colinear: return line formed by outside
michael@0 172 reduction[0] = cubic[0];
michael@0 173 reduction[1] = cubic[3];
michael@0 174 return reductionLineCount(reduction);
michael@0 175 }
michael@0 176
michael@0 177 /* food for thought:
michael@0 178 http://objectmix.com/graphics/132906-fast-precision-driven-cubic-quadratic-piecewise-degree-reduction-algos-2-a.html
michael@0 179
michael@0 180 Given points c1, c2, c3 and c4 of a cubic Bezier, the points of the
michael@0 181 corresponding quadratic Bezier are (given in convex combinations of
michael@0 182 points):
michael@0 183
michael@0 184 q1 = (11/13)c1 + (3/13)c2 -(3/13)c3 + (2/13)c4
michael@0 185 q2 = -c1 + (3/2)c2 + (3/2)c3 - c4
michael@0 186 q3 = (2/13)c1 - (3/13)c2 + (3/13)c3 + (11/13)c4
michael@0 187
michael@0 188 Of course, this curve does not interpolate the end-points, but it would
michael@0 189 be interesting to see the behaviour of such a curve in an applet.
michael@0 190
michael@0 191 --
michael@0 192 Kalle Rutanen
michael@0 193 http://kaba.hilvi.org
michael@0 194
michael@0 195 */
michael@0 196
michael@0 197 // reduce to a quadratic or smaller
michael@0 198 // look for identical points
michael@0 199 // look for all four points in a line
michael@0 200 // note that three points in a line doesn't simplify a cubic
michael@0 201 // look for approximation with single quadratic
michael@0 202 // save approximation with multiple quadratics for later
michael@0 203 int SkReduceOrder::reduce(const SkDCubic& cubic, Quadratics allowQuadratics) {
michael@0 204 int index, minX, maxX, minY, maxY;
michael@0 205 int minXSet, minYSet;
michael@0 206 minX = maxX = minY = maxY = 0;
michael@0 207 minXSet = minYSet = 0;
michael@0 208 for (index = 1; index < 4; ++index) {
michael@0 209 if (cubic[minX].fX > cubic[index].fX) {
michael@0 210 minX = index;
michael@0 211 }
michael@0 212 if (cubic[minY].fY > cubic[index].fY) {
michael@0 213 minY = index;
michael@0 214 }
michael@0 215 if (cubic[maxX].fX < cubic[index].fX) {
michael@0 216 maxX = index;
michael@0 217 }
michael@0 218 if (cubic[maxY].fY < cubic[index].fY) {
michael@0 219 maxY = index;
michael@0 220 }
michael@0 221 }
michael@0 222 for (index = 0; index < 4; ++index) {
michael@0 223 double cx = cubic[index].fX;
michael@0 224 double cy = cubic[index].fY;
michael@0 225 double denom = SkTMax(fabs(cx), SkTMax(fabs(cy),
michael@0 226 SkTMax(fabs(cubic[minX].fX), fabs(cubic[minY].fY))));
michael@0 227 if (denom == 0) {
michael@0 228 minXSet |= 1 << index;
michael@0 229 minYSet |= 1 << index;
michael@0 230 continue;
michael@0 231 }
michael@0 232 double inv = 1 / denom;
michael@0 233 if (approximately_equal_half(cx * inv, cubic[minX].fX * inv)) {
michael@0 234 minXSet |= 1 << index;
michael@0 235 }
michael@0 236 if (approximately_equal_half(cy * inv, cubic[minY].fY * inv)) {
michael@0 237 minYSet |= 1 << index;
michael@0 238 }
michael@0 239 }
michael@0 240 if (minXSet == 0xF) { // test for vertical line
michael@0 241 if (minYSet == 0xF) { // return 1 if all four are coincident
michael@0 242 return coincident_line(cubic, fCubic);
michael@0 243 }
michael@0 244 return vertical_line(cubic, fCubic);
michael@0 245 }
michael@0 246 if (minYSet == 0xF) { // test for horizontal line
michael@0 247 return horizontal_line(cubic, fCubic);
michael@0 248 }
michael@0 249 int result = check_linear(cubic, minX, maxX, minY, maxY, fCubic);
michael@0 250 if (result) {
michael@0 251 return result;
michael@0 252 }
michael@0 253 if (allowQuadratics == SkReduceOrder::kAllow_Quadratics
michael@0 254 && (result = check_quadratic(cubic, fCubic))) {
michael@0 255 return result;
michael@0 256 }
michael@0 257 fCubic = cubic;
michael@0 258 return 4;
michael@0 259 }
michael@0 260
michael@0 261 SkPath::Verb SkReduceOrder::Quad(const SkPoint a[3], SkPoint* reducePts) {
michael@0 262 SkDQuad quad;
michael@0 263 quad.set(a);
michael@0 264 SkReduceOrder reducer;
michael@0 265 int order = reducer.reduce(quad);
michael@0 266 if (order == 2) { // quad became line
michael@0 267 for (int index = 0; index < order; ++index) {
michael@0 268 *reducePts++ = reducer.fLine[index].asSkPoint();
michael@0 269 }
michael@0 270 }
michael@0 271 return SkPathOpsPointsToVerb(order - 1);
michael@0 272 }
michael@0 273
michael@0 274 SkPath::Verb SkReduceOrder::Cubic(const SkPoint a[4], SkPoint* reducePts) {
michael@0 275 SkDCubic cubic;
michael@0 276 cubic.set(a);
michael@0 277 SkReduceOrder reducer;
michael@0 278 int order = reducer.reduce(cubic, kAllow_Quadratics);
michael@0 279 if (order == 2 || order == 3) { // cubic became line or quad
michael@0 280 for (int index = 0; index < order; ++index) {
michael@0 281 *reducePts++ = reducer.fQuad[index].asSkPoint();
michael@0 282 }
michael@0 283 }
michael@0 284 return SkPathOpsPointsToVerb(order - 1);
michael@0 285 }

mercurial