Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / third_party / google_input_tools / third_party / closure_library / closure / goog / math / box.js
1 // Copyright 2006 The Closure Library Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS-IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 /**
16  * @fileoverview A utility class for representing a numeric box.
17  */
18
19
20 goog.provide('goog.math.Box');
21
22 goog.require('goog.math.Coordinate');
23
24
25
26 /**
27  * Class for representing a box. A box is specified as a top, right, bottom,
28  * and left. A box is useful for representing margins and padding.
29  *
30  * This class assumes 'screen coordinates': larger Y coordinates are further
31  * from the top of the screen.
32  *
33  * @param {number} top Top.
34  * @param {number} right Right.
35  * @param {number} bottom Bottom.
36  * @param {number} left Left.
37  * @constructor
38  */
39 goog.math.Box = function(top, right, bottom, left) {
40   /**
41    * Top
42    * @type {number}
43    */
44   this.top = top;
45
46   /**
47    * Right
48    * @type {number}
49    */
50   this.right = right;
51
52   /**
53    * Bottom
54    * @type {number}
55    */
56   this.bottom = bottom;
57
58   /**
59    * Left
60    * @type {number}
61    */
62   this.left = left;
63 };
64
65
66 /**
67  * Creates a Box by bounding a collection of goog.math.Coordinate objects
68  * @param {...goog.math.Coordinate} var_args Coordinates to be included inside
69  *     the box.
70  * @return {!goog.math.Box} A Box containing all the specified Coordinates.
71  */
72 goog.math.Box.boundingBox = function(var_args) {
73   var box = new goog.math.Box(arguments[0].y, arguments[0].x,
74                               arguments[0].y, arguments[0].x);
75   for (var i = 1; i < arguments.length; i++) {
76     var coord = arguments[i];
77     box.top = Math.min(box.top, coord.y);
78     box.right = Math.max(box.right, coord.x);
79     box.bottom = Math.max(box.bottom, coord.y);
80     box.left = Math.min(box.left, coord.x);
81   }
82   return box;
83 };
84
85
86 /**
87  * @return {number} width The width of this Box.
88  */
89 goog.math.Box.prototype.getWidth = function() {
90   return this.right - this.left;
91 };
92
93
94 /**
95  * @return {number} height The height of this Box.
96  */
97 goog.math.Box.prototype.getHeight = function() {
98   return this.bottom - this.top;
99 };
100
101
102 /**
103  * Creates a copy of the box with the same dimensions.
104  * @return {!goog.math.Box} A clone of this Box.
105  */
106 goog.math.Box.prototype.clone = function() {
107   return new goog.math.Box(this.top, this.right, this.bottom, this.left);
108 };
109
110
111 if (goog.DEBUG) {
112   /**
113    * Returns a nice string representing the box.
114    * @return {string} In the form (50t, 73r, 24b, 13l).
115    * @override
116    */
117   goog.math.Box.prototype.toString = function() {
118     return '(' + this.top + 't, ' + this.right + 'r, ' + this.bottom + 'b, ' +
119            this.left + 'l)';
120   };
121 }
122
123
124 /**
125  * Returns whether the box contains a coordinate or another box.
126  *
127  * @param {goog.math.Coordinate|goog.math.Box} other A Coordinate or a Box.
128  * @return {boolean} Whether the box contains the coordinate or other box.
129  */
130 goog.math.Box.prototype.contains = function(other) {
131   return goog.math.Box.contains(this, other);
132 };
133
134
135 /**
136  * Expands box with the given margins.
137  *
138  * @param {number|goog.math.Box} top Top margin or box with all margins.
139  * @param {number=} opt_right Right margin.
140  * @param {number=} opt_bottom Bottom margin.
141  * @param {number=} opt_left Left margin.
142  * @return {!goog.math.Box} A reference to this Box.
143  */
144 goog.math.Box.prototype.expand = function(top, opt_right, opt_bottom,
145     opt_left) {
146   if (goog.isObject(top)) {
147     this.top -= top.top;
148     this.right += top.right;
149     this.bottom += top.bottom;
150     this.left -= top.left;
151   } else {
152     this.top -= top;
153     this.right += opt_right;
154     this.bottom += opt_bottom;
155     this.left -= opt_left;
156   }
157
158   return this;
159 };
160
161
162 /**
163  * Expand this box to include another box.
164  * NOTE(user): This is used in code that needs to be very fast, please don't
165  * add functionality to this function at the expense of speed (variable
166  * arguments, accepting multiple argument types, etc).
167  * @param {goog.math.Box} box The box to include in this one.
168  */
169 goog.math.Box.prototype.expandToInclude = function(box) {
170   this.left = Math.min(this.left, box.left);
171   this.top = Math.min(this.top, box.top);
172   this.right = Math.max(this.right, box.right);
173   this.bottom = Math.max(this.bottom, box.bottom);
174 };
175
176
177 /**
178  * Compares boxes for equality.
179  * @param {goog.math.Box} a A Box.
180  * @param {goog.math.Box} b A Box.
181  * @return {boolean} True iff the boxes are equal, or if both are null.
182  */
183 goog.math.Box.equals = function(a, b) {
184   if (a == b) {
185     return true;
186   }
187   if (!a || !b) {
188     return false;
189   }
190   return a.top == b.top && a.right == b.right &&
191          a.bottom == b.bottom && a.left == b.left;
192 };
193
194
195 /**
196  * Returns whether a box contains a coordinate or another box.
197  *
198  * @param {goog.math.Box} box A Box.
199  * @param {goog.math.Coordinate|goog.math.Box} other A Coordinate or a Box.
200  * @return {boolean} Whether the box contains the coordinate or other box.
201  */
202 goog.math.Box.contains = function(box, other) {
203   if (!box || !other) {
204     return false;
205   }
206
207   if (other instanceof goog.math.Box) {
208     return other.left >= box.left && other.right <= box.right &&
209         other.top >= box.top && other.bottom <= box.bottom;
210   }
211
212   // other is a Coordinate.
213   return other.x >= box.left && other.x <= box.right &&
214          other.y >= box.top && other.y <= box.bottom;
215 };
216
217
218 /**
219  * Returns the relative x position of a coordinate compared to a box.  Returns
220  * zero if the coordinate is inside the box.
221  *
222  * @param {goog.math.Box} box A Box.
223  * @param {goog.math.Coordinate} coord A Coordinate.
224  * @return {number} The x position of {@code coord} relative to the nearest
225  *     side of {@code box}, or zero if {@code coord} is inside {@code box}.
226  */
227 goog.math.Box.relativePositionX = function(box, coord) {
228   if (coord.x < box.left) {
229     return coord.x - box.left;
230   } else if (coord.x > box.right) {
231     return coord.x - box.right;
232   }
233   return 0;
234 };
235
236
237 /**
238  * Returns the relative y position of a coordinate compared to a box.  Returns
239  * zero if the coordinate is inside the box.
240  *
241  * @param {goog.math.Box} box A Box.
242  * @param {goog.math.Coordinate} coord A Coordinate.
243  * @return {number} The y position of {@code coord} relative to the nearest
244  *     side of {@code box}, or zero if {@code coord} is inside {@code box}.
245  */
246 goog.math.Box.relativePositionY = function(box, coord) {
247   if (coord.y < box.top) {
248     return coord.y - box.top;
249   } else if (coord.y > box.bottom) {
250     return coord.y - box.bottom;
251   }
252   return 0;
253 };
254
255
256 /**
257  * Returns the distance between a coordinate and the nearest corner/side of a
258  * box. Returns zero if the coordinate is inside the box.
259  *
260  * @param {goog.math.Box} box A Box.
261  * @param {goog.math.Coordinate} coord A Coordinate.
262  * @return {number} The distance between {@code coord} and the nearest
263  *     corner/side of {@code box}, or zero if {@code coord} is inside
264  *     {@code box}.
265  */
266 goog.math.Box.distance = function(box, coord) {
267   var x = goog.math.Box.relativePositionX(box, coord);
268   var y = goog.math.Box.relativePositionY(box, coord);
269   return Math.sqrt(x * x + y * y);
270 };
271
272
273 /**
274  * Returns whether two boxes intersect.
275  *
276  * @param {goog.math.Box} a A Box.
277  * @param {goog.math.Box} b A second Box.
278  * @return {boolean} Whether the boxes intersect.
279  */
280 goog.math.Box.intersects = function(a, b) {
281   return (a.left <= b.right && b.left <= a.right &&
282           a.top <= b.bottom && b.top <= a.bottom);
283 };
284
285
286 /**
287  * Returns whether two boxes would intersect with additional padding.
288  *
289  * @param {goog.math.Box} a A Box.
290  * @param {goog.math.Box} b A second Box.
291  * @param {number} padding The additional padding.
292  * @return {boolean} Whether the boxes intersect.
293  */
294 goog.math.Box.intersectsWithPadding = function(a, b, padding) {
295   return (a.left <= b.right + padding && b.left <= a.right + padding &&
296           a.top <= b.bottom + padding && b.top <= a.bottom + padding);
297 };
298
299
300 /**
301  * Rounds the fields to the next larger integer values.
302  *
303  * @return {!goog.math.Box} This box with ceil'd fields.
304  */
305 goog.math.Box.prototype.ceil = function() {
306   this.top = Math.ceil(this.top);
307   this.right = Math.ceil(this.right);
308   this.bottom = Math.ceil(this.bottom);
309   this.left = Math.ceil(this.left);
310   return this;
311 };
312
313
314 /**
315  * Rounds the fields to the next smaller integer values.
316  *
317  * @return {!goog.math.Box} This box with floored fields.
318  */
319 goog.math.Box.prototype.floor = function() {
320   this.top = Math.floor(this.top);
321   this.right = Math.floor(this.right);
322   this.bottom = Math.floor(this.bottom);
323   this.left = Math.floor(this.left);
324   return this;
325 };
326
327
328 /**
329  * Rounds the fields to nearest integer values.
330  *
331  * @return {!goog.math.Box} This box with rounded fields.
332  */
333 goog.math.Box.prototype.round = function() {
334   this.top = Math.round(this.top);
335   this.right = Math.round(this.right);
336   this.bottom = Math.round(this.bottom);
337   this.left = Math.round(this.left);
338   return this;
339 };
340
341
342 /**
343  * Translates this box by the given offsets. If a {@code goog.math.Coordinate}
344  * is given, then the left and right values are translated by the coordinate's
345  * x value and the top and bottom values are translated by the coordinate's y
346  * value.  Otherwise, {@code tx} and {@code opt_ty} are used to translate the x
347  * and y dimension values.
348  *
349  * @param {number|goog.math.Coordinate} tx The value to translate the x
350  *     dimension values by or the the coordinate to translate this box by.
351  * @param {number=} opt_ty The value to translate y dimension values by.
352  * @return {!goog.math.Box} This box after translating.
353  */
354 goog.math.Box.prototype.translate = function(tx, opt_ty) {
355   if (tx instanceof goog.math.Coordinate) {
356     this.left += tx.x;
357     this.right += tx.x;
358     this.top += tx.y;
359     this.bottom += tx.y;
360   } else {
361     this.left += tx;
362     this.right += tx;
363     if (goog.isNumber(opt_ty)) {
364       this.top += opt_ty;
365       this.bottom += opt_ty;
366     }
367   }
368   return this;
369 };
370
371
372 /**
373  * Scales this coordinate by the given scale factors. The x and y dimension
374  * values are scaled by {@code sx} and {@code opt_sy} respectively.
375  * If {@code opt_sy} is not given, then {@code sx} is used for both x and y.
376  *
377  * @param {number} sx The scale factor to use for the x dimension.
378  * @param {number=} opt_sy The scale factor to use for the y dimension.
379  * @return {!goog.math.Box} This box after scaling.
380  */
381 goog.math.Box.prototype.scale = function(sx, opt_sy) {
382   var sy = goog.isNumber(opt_sy) ? opt_sy : sx;
383   this.left *= sx;
384   this.right *= sx;
385   this.top *= sy;
386   this.bottom *= sy;
387   return this;
388 };