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.

     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 };

mercurial