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