tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

avatarSelectionHelpers.mjs (7692B)


      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/. */
      4 
      5 const MIN_SELECTION_SIZE = 48;
      6 
      7 /**
      8 * This class is copied from https://searchfox.org/mozilla-central/source/browser/components/screenshots/overlayHelpers.mjs
      9 * with some slight modifications such as forcing the region to be a square.
     10 * Bug 1974999: Actually import and use the screenshots Region class.
     11 * The class holds references to each side the of region.
     12 * x1 is the left boundary, x2 is the right boundary, y1 is the top boundary,
     13 * and y2 is the bottom boundary. Sometimes the sides can get switched where
     14 * x1 > x2 or y1 > y2. To mitigate this, the getters (left, right, top, bottom)
     15 * will choose to return the "correct" value. For example, the left getter
     16 * returns the min of x1 and x2. The same goes for the other three getters.
     17 */
     18 export class Region {
     19  #x1;
     20  #x2;
     21  #y1;
     22  #y2;
     23  #viewDimensions;
     24 
     25  constructor(viewDimensions) {
     26    this.resetDimensions();
     27    this.#viewDimensions = viewDimensions;
     28  }
     29 
     30  /**
     31   * Sets the dimensions if the given dimension is defined.
     32   * Otherwise will reset the dimensions
     33   *
     34   * @param {object} dims The new region dimensions
     35   *  {
     36   *    left: new left dimension value or undefined
     37   *    top: new top dimension value or undefined
     38   *    right: new right dimension value or undefined
     39   *    bottom: new bottom dimension value or undefined
     40   *   }
     41   */
     42  set #dimensions(dims) {
     43    if (dims == null) {
     44      this.resetDimensions();
     45      return;
     46    }
     47 
     48    if (dims.left != null) {
     49      this.left = dims.left;
     50    }
     51    if (dims.top != null) {
     52      this.top = dims.top;
     53    }
     54    if (dims.right != null) {
     55      this.right = dims.right;
     56    }
     57    if (dims.bottom != null) {
     58      this.bottom = dims.bottom;
     59    }
     60  }
     61 
     62  /**
     63   * Set the new dimension for the region. This is called from pointer move
     64   * events where the region is being moved.
     65   *
     66   * @param {object} dims The new dimensions. The object should contain left,
     67   *   top, right, bottom.
     68   * @param {string} direction The corner of the region being dragged. It is
     69   *   used to determine which sides of the region to contain to a square.
     70   */
     71  resizeToSquare(dims, direction) {
     72    // eslint-disable-next-line no-shadow
     73    let { left, right, top, bottom } = dims;
     74    switch (direction) {
     75      case "mover-topLeft": {
     76        let newDiameter = Math.max(
     77          MIN_SELECTION_SIZE,
     78          this.right - left,
     79          this.bottom - top
     80        );
     81        this.left = this.right - newDiameter;
     82        this.top = this.bottom - newDiameter;
     83        break;
     84      }
     85      case "mover-topRight": {
     86        let newDiameter = Math.max(
     87          MIN_SELECTION_SIZE,
     88          right - this.left,
     89          this.bottom - top
     90        );
     91        this.right = this.left + newDiameter;
     92        this.top = this.bottom - newDiameter;
     93        break;
     94      }
     95      case "mover-bottomRight": {
     96        let newDiameter = Math.max(
     97          MIN_SELECTION_SIZE,
     98          right - this.left,
     99          bottom - this.top
    100        );
    101        this.right = this.left + newDiameter;
    102        this.bottom = this.top + newDiameter;
    103        break;
    104      }
    105      case "mover-bottomLeft": {
    106        let newDiameter = Math.max(
    107          MIN_SELECTION_SIZE,
    108          this.right - left,
    109          bottom - this.top
    110        );
    111        this.left = this.right - newDiameter;
    112        this.bottom = this.top + newDiameter;
    113        break;
    114      }
    115      default: {
    116        if (
    117          left < 0 ||
    118          right > this.#viewDimensions.width ||
    119          top < 0 ||
    120          bottom > this.#viewDimensions.height
    121        ) {
    122          // The region would be invalid so just return
    123          return;
    124        }
    125        this.#dimensions = dims;
    126        break;
    127      }
    128    }
    129 
    130    this.forceSquare(direction);
    131  }
    132 
    133  get dimensions() {
    134    return {
    135      left: this.left,
    136      top: this.top,
    137      right: this.right,
    138      bottom: this.bottom,
    139      width: this.width,
    140      height: this.height,
    141      radius: this.radius,
    142    };
    143  }
    144 
    145  resetDimensions() {
    146    this.#x1 = 0;
    147    this.#x2 = 0;
    148    this.#y1 = 0;
    149    this.#y2 = 0;
    150  }
    151 
    152  /**
    153   * Sort the coordinates so x1 < x2 and y1 < y2
    154   */
    155  sortCoords() {
    156    if (this.#x1 > this.#x2) {
    157      [this.#x1, this.#x2] = [this.#x2, this.#x1];
    158    }
    159    if (this.#y1 > this.#y2) {
    160      [this.#y1, this.#y2] = [this.#y2, this.#y1];
    161    }
    162  }
    163 
    164  forceSquare(direction) {
    165    if (this.width === this.height && this.width >= MIN_SELECTION_SIZE) {
    166      // Already square and large enough
    167      return;
    168    }
    169 
    170    let newDiameter = Math.max(
    171      MIN_SELECTION_SIZE,
    172      Math.min(this.width, this.height)
    173    );
    174    switch (direction) {
    175      case "mover-topLeft": {
    176        this.left = this.right - newDiameter;
    177        this.top = this.bottom - newDiameter;
    178        break;
    179      }
    180      case "mover-topRight": {
    181        this.right = this.left + newDiameter;
    182        this.top = this.bottom - newDiameter;
    183        break;
    184      }
    185      case "mover-bottomRight": {
    186        this.right = this.left + newDiameter;
    187        this.bottom = this.top + newDiameter;
    188        break;
    189      }
    190      case "mover-bottomLeft": {
    191        this.left = this.right - newDiameter;
    192        this.bottom = this.top + newDiameter;
    193        break;
    194      }
    195      default: {
    196        newDiameter = Math.max(MIN_SELECTION_SIZE, this.width, this.height);
    197        if (this.left === 0) {
    198          this.right = newDiameter;
    199        }
    200        if (this.right === this.#viewDimensions.width) {
    201          this.left = this.right - newDiameter;
    202        }
    203        if (this.top === 0) {
    204          this.bottom = newDiameter;
    205        }
    206        if (this.bottom === this.#viewDimensions.height) {
    207          this.top = this.bottom - newDiameter;
    208        }
    209      }
    210    }
    211  }
    212 
    213  get top() {
    214    return Math.min(this.#y1, this.#y2);
    215  }
    216  set top(val) {
    217    this.#y1 = Math.min(this.#viewDimensions.height, Math.max(0, val));
    218  }
    219 
    220  get left() {
    221    return Math.min(this.#x1, this.#x2);
    222  }
    223  set left(val) {
    224    this.#x1 = Math.min(this.#viewDimensions.width, Math.max(0, val));
    225  }
    226 
    227  get right() {
    228    return Math.max(this.#x1, this.#x2);
    229  }
    230  set right(val) {
    231    this.#x2 = Math.min(this.#viewDimensions.width, Math.max(0, val));
    232  }
    233 
    234  get bottom() {
    235    return Math.max(this.#y1, this.#y2);
    236  }
    237  set bottom(val) {
    238    this.#y2 = Math.min(this.#viewDimensions.height, Math.max(0, val));
    239  }
    240 
    241  get width() {
    242    return Math.abs(this.#x2 - this.#x1);
    243  }
    244  get height() {
    245    return Math.abs(this.#y2 - this.#y1);
    246  }
    247 
    248  get radius() {
    249    return Math.floor(this.width / 2);
    250  }
    251 
    252  get x1() {
    253    return this.#x1;
    254  }
    255  get x2() {
    256    return this.#x2;
    257  }
    258  get y1() {
    259    return this.#y1;
    260  }
    261  get y2() {
    262    return this.#y2;
    263  }
    264 }
    265 
    266 /**
    267 * A class which saves the current view dimensions.
    268 */
    269 export class ViewDimensions {
    270  #height = null;
    271  #width = null;
    272  #devicePixelRatio = null;
    273 
    274  set dimensions(dimensions) {
    275    if (dimensions.height != null) {
    276      this.#height = dimensions.height;
    277    }
    278    if (dimensions.width != null) {
    279      this.#width = dimensions.width;
    280    }
    281    if (dimensions.devicePixelRatio != null) {
    282      this.#devicePixelRatio = dimensions.devicePixelRatio;
    283    }
    284  }
    285 
    286  get dimensions() {
    287    return {
    288      height: this.height,
    289      width: this.width,
    290      devicePixelRatio: this.devicePixelRatio,
    291    };
    292  }
    293 
    294  get width() {
    295    return this.#width;
    296  }
    297 
    298  get height() {
    299    return this.#height;
    300  }
    301 
    302  get devicePixelRatio() {
    303    return this.#devicePixelRatio;
    304  }
    305 
    306  reset() {
    307    this.#width = 0;
    308    this.#height = 0;
    309  }
    310 }