toolkit/modules/Geometry.jsm

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 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 this.EXPORTED_SYMBOLS = ["Point", "Rect"];
michael@0 6
michael@0 7 /**
michael@0 8 * Simple Point class.
michael@0 9 *
michael@0 10 * Any method that takes an x and y may also take a point.
michael@0 11 */
michael@0 12 this.Point = function Point(x, y) {
michael@0 13 this.set(x, y);
michael@0 14 }
michael@0 15
michael@0 16 Point.prototype = {
michael@0 17 clone: function clone() {
michael@0 18 return new Point(this.x, this.y);
michael@0 19 },
michael@0 20
michael@0 21 set: function set(x, y) {
michael@0 22 this.x = x;
michael@0 23 this.y = y;
michael@0 24 return this;
michael@0 25 },
michael@0 26
michael@0 27 equals: function equals(x, y) {
michael@0 28 return this.x == x && this.y == y;
michael@0 29 },
michael@0 30
michael@0 31 toString: function toString() {
michael@0 32 return "(" + this.x + "," + this.y + ")";
michael@0 33 },
michael@0 34
michael@0 35 map: function map(f) {
michael@0 36 this.x = f.call(this, this.x);
michael@0 37 this.y = f.call(this, this.y);
michael@0 38 return this;
michael@0 39 },
michael@0 40
michael@0 41 add: function add(x, y) {
michael@0 42 this.x += x;
michael@0 43 this.y += y;
michael@0 44 return this;
michael@0 45 },
michael@0 46
michael@0 47 subtract: function subtract(x, y) {
michael@0 48 this.x -= x;
michael@0 49 this.y -= y;
michael@0 50 return this;
michael@0 51 },
michael@0 52
michael@0 53 scale: function scale(s) {
michael@0 54 this.x *= s;
michael@0 55 this.y *= s;
michael@0 56 return this;
michael@0 57 },
michael@0 58
michael@0 59 isZero: function() {
michael@0 60 return this.x == 0 && this.y == 0;
michael@0 61 }
michael@0 62 };
michael@0 63
michael@0 64 (function() {
michael@0 65 function takePointOrArgs(f) {
michael@0 66 return function(arg1, arg2) {
michael@0 67 if (arg2 === undefined)
michael@0 68 return f.call(this, arg1.x, arg1.y);
michael@0 69 else
michael@0 70 return f.call(this, arg1, arg2);
michael@0 71 };
michael@0 72 }
michael@0 73
michael@0 74 for each (let f in ['add', 'subtract', 'equals', 'set'])
michael@0 75 Point.prototype[f] = takePointOrArgs(Point.prototype[f]);
michael@0 76 })();
michael@0 77
michael@0 78
michael@0 79 /**
michael@0 80 * Rect is a simple data structure for representation of a rectangle supporting
michael@0 81 * many basic geometric operations.
michael@0 82 *
michael@0 83 * NOTE: Since its operations are closed, rectangles may be empty and will report
michael@0 84 * non-positive widths and heights in that case.
michael@0 85 */
michael@0 86
michael@0 87 this.Rect = function Rect(x, y, w, h) {
michael@0 88 this.left = x;
michael@0 89 this.top = y;
michael@0 90 this.right = x + w;
michael@0 91 this.bottom = y + h;
michael@0 92 };
michael@0 93
michael@0 94 Rect.fromRect = function fromRect(r) {
michael@0 95 return new Rect(r.left, r.top, r.right - r.left, r.bottom - r.top);
michael@0 96 };
michael@0 97
michael@0 98 Rect.prototype = {
michael@0 99 get x() { return this.left; },
michael@0 100 get y() { return this.top; },
michael@0 101 get width() { return this.right - this.left; },
michael@0 102 get height() { return this.bottom - this.top; },
michael@0 103 set x(v) {
michael@0 104 let diff = this.left - v;
michael@0 105 this.left = v;
michael@0 106 this.right -= diff;
michael@0 107 },
michael@0 108 set y(v) {
michael@0 109 let diff = this.top - v;
michael@0 110 this.top = v;
michael@0 111 this.bottom -= diff;
michael@0 112 },
michael@0 113 set width(v) { this.right = this.left + v; },
michael@0 114 set height(v) { this.bottom = this.top + v; },
michael@0 115
michael@0 116 isEmpty: function isEmpty() {
michael@0 117 return this.left >= this.right || this.top >= this.bottom;
michael@0 118 },
michael@0 119
michael@0 120 setRect: function(x, y, w, h) {
michael@0 121 this.left = x;
michael@0 122 this.top = y;
michael@0 123 this.right = x+w;
michael@0 124 this.bottom = y+h;
michael@0 125
michael@0 126 return this;
michael@0 127 },
michael@0 128
michael@0 129 setBounds: function(l, t, r, b) {
michael@0 130 this.top = t;
michael@0 131 this.left = l;
michael@0 132 this.bottom = b;
michael@0 133 this.right = r;
michael@0 134
michael@0 135 return this;
michael@0 136 },
michael@0 137
michael@0 138 equals: function equals(other) {
michael@0 139 return other != null &&
michael@0 140 (this.isEmpty() && other.isEmpty() ||
michael@0 141 this.top == other.top &&
michael@0 142 this.left == other.left &&
michael@0 143 this.bottom == other.bottom &&
michael@0 144 this.right == other.right);
michael@0 145 },
michael@0 146
michael@0 147 clone: function clone() {
michael@0 148 return new Rect(this.left, this.top, this.right - this.left, this.bottom - this.top);
michael@0 149 },
michael@0 150
michael@0 151 center: function center() {
michael@0 152 if (this.isEmpty())
michael@0 153 throw "Empty rectangles do not have centers";
michael@0 154 return new Point(this.left + (this.right - this.left) / 2,
michael@0 155 this.top + (this.bottom - this.top) / 2);
michael@0 156 },
michael@0 157
michael@0 158 copyFrom: function(other) {
michael@0 159 this.top = other.top;
michael@0 160 this.left = other.left;
michael@0 161 this.bottom = other.bottom;
michael@0 162 this.right = other.right;
michael@0 163
michael@0 164 return this;
michael@0 165 },
michael@0 166
michael@0 167 translate: function(x, y) {
michael@0 168 this.left += x;
michael@0 169 this.right += x;
michael@0 170 this.top += y;
michael@0 171 this.bottom += y;
michael@0 172
michael@0 173 return this;
michael@0 174 },
michael@0 175
michael@0 176 toString: function() {
michael@0 177 return "[" + this.x + "," + this.y + "," + this.width + "," + this.height + "]";
michael@0 178 },
michael@0 179
michael@0 180 /** return a new rect that is the union of that one and this one */
michael@0 181 union: function(other) {
michael@0 182 return this.clone().expandToContain(other);
michael@0 183 },
michael@0 184
michael@0 185 contains: function(other) {
michael@0 186 if (other.isEmpty()) return true;
michael@0 187 if (this.isEmpty()) return false;
michael@0 188
michael@0 189 return (other.left >= this.left &&
michael@0 190 other.right <= this.right &&
michael@0 191 other.top >= this.top &&
michael@0 192 other.bottom <= this.bottom);
michael@0 193 },
michael@0 194
michael@0 195 intersect: function(other) {
michael@0 196 return this.clone().restrictTo(other);
michael@0 197 },
michael@0 198
michael@0 199 intersects: function(other) {
michael@0 200 if (this.isEmpty() || other.isEmpty())
michael@0 201 return false;
michael@0 202
michael@0 203 let x1 = Math.max(this.left, other.left);
michael@0 204 let x2 = Math.min(this.right, other.right);
michael@0 205 let y1 = Math.max(this.top, other.top);
michael@0 206 let y2 = Math.min(this.bottom, other.bottom);
michael@0 207 return x1 < x2 && y1 < y2;
michael@0 208 },
michael@0 209
michael@0 210 /** Restrict area of this rectangle to the intersection of both rectangles. */
michael@0 211 restrictTo: function restrictTo(other) {
michael@0 212 if (this.isEmpty() || other.isEmpty())
michael@0 213 return this.setRect(0, 0, 0, 0);
michael@0 214
michael@0 215 let x1 = Math.max(this.left, other.left);
michael@0 216 let x2 = Math.min(this.right, other.right);
michael@0 217 let y1 = Math.max(this.top, other.top);
michael@0 218 let y2 = Math.min(this.bottom, other.bottom);
michael@0 219 // If width or height is 0, the intersection was empty.
michael@0 220 return this.setRect(x1, y1, Math.max(0, x2 - x1), Math.max(0, y2 - y1));
michael@0 221 },
michael@0 222
michael@0 223 /** Expand this rectangle to the union of both rectangles. */
michael@0 224 expandToContain: function expandToContain(other) {
michael@0 225 if (this.isEmpty()) return this.copyFrom(other);
michael@0 226 if (other.isEmpty()) return this;
michael@0 227
michael@0 228 let l = Math.min(this.left, other.left);
michael@0 229 let r = Math.max(this.right, other.right);
michael@0 230 let t = Math.min(this.top, other.top);
michael@0 231 let b = Math.max(this.bottom, other.bottom);
michael@0 232 return this.setRect(l, t, r-l, b-t);
michael@0 233 },
michael@0 234
michael@0 235 /**
michael@0 236 * Expands to the smallest rectangle that contains original rectangle and is bounded
michael@0 237 * by lines with integer coefficients.
michael@0 238 */
michael@0 239 expandToIntegers: function round() {
michael@0 240 this.left = Math.floor(this.left);
michael@0 241 this.top = Math.floor(this.top);
michael@0 242 this.right = Math.ceil(this.right);
michael@0 243 this.bottom = Math.ceil(this.bottom);
michael@0 244 return this;
michael@0 245 },
michael@0 246
michael@0 247 scale: function scale(xscl, yscl) {
michael@0 248 this.left *= xscl;
michael@0 249 this.right *= xscl;
michael@0 250 this.top *= yscl;
michael@0 251 this.bottom *= yscl;
michael@0 252 return this;
michael@0 253 },
michael@0 254
michael@0 255 map: function map(f) {
michael@0 256 this.left = f.call(this, this.left);
michael@0 257 this.top = f.call(this, this.top);
michael@0 258 this.right = f.call(this, this.right);
michael@0 259 this.bottom = f.call(this, this.bottom);
michael@0 260 return this;
michael@0 261 },
michael@0 262
michael@0 263 /** Ensure this rectangle is inside the other, if possible. Preserves w, h. */
michael@0 264 translateInside: function translateInside(other) {
michael@0 265 let offsetX = (this.left <= other.left ? other.left - this.left :
michael@0 266 (this.right > other.right ? other.right - this.right : 0));
michael@0 267 let offsetY = (this.top <= other.top ? other.top - this.top :
michael@0 268 (this.bottom > other.bottom ? other.bottom - this.bottom : 0));
michael@0 269 return this.translate(offsetX, offsetY);
michael@0 270 },
michael@0 271
michael@0 272 /** Subtract other area from this. Returns array of rects whose union is this-other. */
michael@0 273 subtract: function subtract(other) {
michael@0 274 let r = new Rect(0, 0, 0, 0);
michael@0 275 let result = [];
michael@0 276 other = other.intersect(this);
michael@0 277 if (other.isEmpty())
michael@0 278 return [this.clone()];
michael@0 279
michael@0 280 // left strip
michael@0 281 r.setBounds(this.left, this.top, other.left, this.bottom);
michael@0 282 if (!r.isEmpty())
michael@0 283 result.push(r.clone());
michael@0 284 // inside strip
michael@0 285 r.setBounds(other.left, this.top, other.right, other.top);
michael@0 286 if (!r.isEmpty())
michael@0 287 result.push(r.clone());
michael@0 288 r.setBounds(other.left, other.bottom, other.right, this.bottom);
michael@0 289 if (!r.isEmpty())
michael@0 290 result.push(r.clone());
michael@0 291 // right strip
michael@0 292 r.setBounds(other.right, this.top, this.right, this.bottom);
michael@0 293 if (!r.isEmpty())
michael@0 294 result.push(r.clone());
michael@0 295
michael@0 296 return result;
michael@0 297 },
michael@0 298
michael@0 299 /**
michael@0 300 * Blends two rectangles together.
michael@0 301 * @param rect Rectangle to blend this one with
michael@0 302 * @param scalar Ratio from 0 (returns a clone of this rect) to 1 (clone of rect).
michael@0 303 * @return New blended rectangle.
michael@0 304 */
michael@0 305 blend: function blend(rect, scalar) {
michael@0 306 return new Rect(
michael@0 307 this.left + (rect.left - this.left ) * scalar,
michael@0 308 this.top + (rect.top - this.top ) * scalar,
michael@0 309 this.width + (rect.width - this.width ) * scalar,
michael@0 310 this.height + (rect.height - this.height) * scalar);
michael@0 311 },
michael@0 312
michael@0 313 /**
michael@0 314 * Grows or shrinks the rectangle while keeping the center point.
michael@0 315 * Accepts single multipler, or separate for both axes.
michael@0 316 */
michael@0 317 inflate: function inflate(xscl, yscl) {
michael@0 318 let xAdj = (this.width * xscl - this.width) / 2;
michael@0 319 let s = (arguments.length > 1) ? yscl : xscl;
michael@0 320 let yAdj = (this.height * s - this.height) / 2;
michael@0 321 this.left -= xAdj;
michael@0 322 this.right += xAdj;
michael@0 323 this.top -= yAdj;
michael@0 324 this.bottom += yAdj;
michael@0 325 return this;
michael@0 326 }
michael@0 327 };

mercurial