tor-browser

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

util.rs (54788B)


      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 use api::BorderRadius;
      6 use api::units::*;
      7 use euclid::{Point2D, Rect, Box2D, Size2D, Vector2D, point2, point3};
      8 use euclid::{default, Transform2D, Transform3D, Scale, approxeq::ApproxEq};
      9 use plane_split::{Clipper, Polygon};
     10 use std::{i32, f32, fmt, ptr};
     11 use std::borrow::Cow;
     12 use std::num::NonZeroUsize;
     13 use std::sync::Arc;
     14 use std::mem::replace;
     15 
     16 use crate::internal_types::FrameVec;
     17 
     18 // Matches the definition of SK_ScalarNearlyZero in Skia.
     19 const NEARLY_ZERO: f32 = 1.0 / 4096.0;
     20 
     21 /// A typesafe helper that separates new value construction from
     22 /// vector growing, allowing LLVM to ideally construct the element in place.
     23 pub struct Allocation<'a, T: 'a> {
     24    vec: &'a mut Vec<T>,
     25    index: usize,
     26 }
     27 
     28 impl<'a, T> Allocation<'a, T> {
     29    // writing is safe because alloc() ensured enough capacity
     30    // and `Allocation` holds a mutable borrow to prevent anyone else
     31    // from breaking this invariant.
     32    #[inline(always)]
     33    pub fn init(self, value: T) -> usize {
     34        unsafe {
     35            ptr::write(self.vec.as_mut_ptr().add(self.index), value);
     36            self.vec.set_len(self.index + 1);
     37        }
     38        self.index
     39    }
     40 }
     41 
     42 /// An entry into a vector, similar to `std::collections::hash_map::Entry`.
     43 pub enum VecEntry<'a, T: 'a> {
     44    Vacant(Allocation<'a, T>),
     45    Occupied(&'a mut T),
     46 }
     47 
     48 impl<'a, T> VecEntry<'a, T> {
     49    #[inline(always)]
     50    pub fn set(self, value: T) {
     51        match self {
     52            VecEntry::Vacant(alloc) => { alloc.init(value); }
     53            VecEntry::Occupied(slot) => { *slot = value; }
     54        }
     55    }
     56 }
     57 
     58 pub trait VecHelper<T> {
     59    /// Growns the vector by a single entry, returning the allocation.
     60    fn alloc(&mut self) -> Allocation<T>;
     61    /// Either returns an existing elemenet, or grows the vector by one.
     62    /// Doesn't expect indices to be higher than the current length.
     63    fn entry(&mut self, index: usize) -> VecEntry<T>;
     64 
     65    /// Equivalent to `mem::replace(&mut vec, Vec::new())`
     66    fn take(&mut self) -> Self;
     67 
     68    /// Functionally equivalent to `mem::replace(&mut vec, Vec::new())` but tries
     69    /// to keep the allocation in the caller if it is empty or replace it with a
     70    /// pre-allocated vector.
     71    fn take_and_preallocate(&mut self) -> Self;
     72 }
     73 
     74 impl<T> VecHelper<T> for Vec<T> {
     75    fn alloc(&mut self) -> Allocation<T> {
     76        let index = self.len();
     77        if self.capacity() == index {
     78            self.reserve(1);
     79        }
     80        Allocation {
     81            vec: self,
     82            index,
     83        }
     84    }
     85 
     86    fn entry(&mut self, index: usize) -> VecEntry<T> {
     87        if index < self.len() {
     88            VecEntry::Occupied(unsafe {
     89                self.get_unchecked_mut(index)
     90            })
     91        } else {
     92            assert_eq!(index, self.len());
     93            VecEntry::Vacant(self.alloc())
     94        }
     95    }
     96 
     97    fn take(&mut self) -> Self {
     98        replace(self, Vec::new())
     99    }
    100 
    101    fn take_and_preallocate(&mut self) -> Self {
    102        let len = self.len();
    103        if len == 0 {
    104            self.clear();
    105            return Vec::new();
    106        }
    107        replace(self, Vec::with_capacity(len + 8))
    108    }
    109 }
    110 
    111 // Represents an optimized transform where there is only
    112 // a scale and translation (which are guaranteed to maintain
    113 // an axis align rectangle under transformation). The
    114 // scaling is applied first, followed by the translation.
    115 // TODO(gw): We should try and incorporate F <-> T units here,
    116 //           but it's a bit tricky to do that now with the
    117 //           way the current spatial tree works.
    118 #[repr(C)]
    119 #[derive(Debug, Clone, Copy, MallocSizeOf, PartialEq)]
    120 #[cfg_attr(feature = "capture", derive(Serialize))]
    121 #[cfg_attr(feature = "replay", derive(Deserialize))]
    122 pub struct ScaleOffset {
    123    pub scale: euclid::Vector2D<f32, euclid::UnknownUnit>,
    124    pub offset: euclid::Vector2D<f32, euclid::UnknownUnit>,
    125 }
    126 
    127 impl ScaleOffset {
    128    pub fn new(sx: f32, sy: f32, tx: f32, ty: f32) -> Self {
    129        ScaleOffset {
    130            scale: Vector2D::new(sx, sy),
    131            offset: Vector2D::new(tx, ty),
    132        }
    133    }
    134 
    135    pub fn identity() -> Self {
    136        ScaleOffset {
    137            scale: Vector2D::new(1.0, 1.0),
    138            offset: Vector2D::zero(),
    139        }
    140    }
    141 
    142    // Construct a ScaleOffset from a transform. Returns
    143    // None if the matrix is not a pure scale / translation.
    144    pub fn from_transform<F, T>(
    145        m: &Transform3D<f32, F, T>,
    146    ) -> Option<ScaleOffset> {
    147 
    148        // To check that we have a pure scale / translation:
    149        // Every field must match an identity matrix, except:
    150        //  - Any value present in tx,ty
    151        //  - Any value present in sx,sy
    152 
    153        if m.m12.abs() > NEARLY_ZERO ||
    154           m.m13.abs() > NEARLY_ZERO ||
    155           m.m14.abs() > NEARLY_ZERO ||
    156           m.m21.abs() > NEARLY_ZERO ||
    157           m.m23.abs() > NEARLY_ZERO ||
    158           m.m24.abs() > NEARLY_ZERO ||
    159           m.m31.abs() > NEARLY_ZERO ||
    160           m.m32.abs() > NEARLY_ZERO ||
    161           (m.m33 - 1.0).abs() > NEARLY_ZERO ||
    162           m.m34.abs() > NEARLY_ZERO ||
    163           m.m43.abs() > NEARLY_ZERO ||
    164           (m.m44 - 1.0).abs() > NEARLY_ZERO {
    165            return None;
    166        }
    167 
    168        Some(ScaleOffset {
    169            scale: Vector2D::new(m.m11, m.m22),
    170            offset: Vector2D::new(m.m41, m.m42),
    171        })
    172    }
    173 
    174    pub fn from_offset(offset: default::Vector2D<f32>) -> Self {
    175        ScaleOffset {
    176            scale: Vector2D::new(1.0, 1.0),
    177            offset,
    178        }
    179    }
    180 
    181    pub fn from_scale(scale: default::Vector2D<f32>) -> Self {
    182        ScaleOffset {
    183            scale,
    184            offset: Vector2D::new(0.0, 0.0),
    185        }
    186    }
    187 
    188    pub fn inverse(&self) -> Self {
    189        // If either of the scale factors is 0, inverse also has scale 0
    190        // TODO(gw): Consider making this return Option<Self> in future
    191        //           so that callers can detect and handle when inverse
    192        //           fails here.
    193        if self.scale.x.approx_eq(&0.0) || self.scale.y.approx_eq(&0.0) {
    194            return ScaleOffset::new(0.0, 0.0, 0.0, 0.0);
    195        }
    196 
    197        ScaleOffset {
    198            scale: Vector2D::new(
    199                1.0 / self.scale.x,
    200                1.0 / self.scale.y,
    201            ),
    202            offset: Vector2D::new(
    203                -self.offset.x / self.scale.x,
    204                -self.offset.y / self.scale.y,
    205            ),
    206        }
    207    }
    208 
    209    pub fn pre_offset(&self, offset: default::Vector2D<f32>) -> Self {
    210        self.pre_transform(
    211            &ScaleOffset {
    212                scale: Vector2D::new(1.0, 1.0),
    213                offset,
    214            }
    215        )
    216    }
    217 
    218    pub fn pre_scale(&self, scale: f32) -> Self {
    219        ScaleOffset {
    220            scale: self.scale * scale,
    221            offset: self.offset,
    222        }
    223    }
    224 
    225    pub fn then_scale(&self, scale: f32) -> Self {
    226        ScaleOffset {
    227            scale: self.scale * scale,
    228            offset: self.offset * scale,
    229        }
    230    }
    231 
    232    /// Produce a ScaleOffset that includes both self and other.
    233    /// The 'self' ScaleOffset is applied after `other`.
    234    /// This is equivalent to `Transform3D::pre_transform`.
    235    pub fn pre_transform(&self, other: &ScaleOffset) -> Self {
    236        ScaleOffset {
    237            scale: Vector2D::new(
    238                self.scale.x * other.scale.x,
    239                self.scale.y * other.scale.y,
    240            ),
    241            offset: Vector2D::new(
    242                self.offset.x + self.scale.x * other.offset.x,
    243                self.offset.y + self.scale.y * other.offset.y,
    244            ),
    245        }
    246    }
    247 
    248    /// Produce a ScaleOffset that includes both self and other.
    249    /// The 'other' ScaleOffset is applied after `self`.
    250    /// This is equivalent to `Transform3D::then`.
    251    #[allow(unused)]
    252    pub fn then(&self, other: &ScaleOffset) -> Self {
    253        ScaleOffset {
    254            scale: Vector2D::new(
    255                self.scale.x * other.scale.x,
    256                self.scale.y * other.scale.y,
    257            ),
    258            offset: Vector2D::new(
    259                other.scale.x * self.offset.x + other.offset.x,
    260                other.scale.y * self.offset.y + other.offset.y,
    261            ),
    262        }
    263    }
    264 
    265 
    266    pub fn map_rect<F, T>(&self, rect: &Box2D<f32, F>) -> Box2D<f32, T> {
    267        // TODO(gw): The logic below can return an unexpected result if the supplied
    268        //           rect is invalid (has size < 0). Since Gecko currently supplied
    269        //           invalid rects in some cases, adding a max(0) here ensures that
    270        //           mapping an invalid rect retains the property that rect.is_empty()
    271        //           will return true (the mapped rect output will have size 0 instead
    272        //           of a negative size). In future we could catch / assert / fix
    273        //           these invalid rects earlier, and assert here instead.
    274 
    275        let w = rect.width().max(0.0);
    276        let h = rect.height().max(0.0);
    277 
    278        let mut x0 = rect.min.x * self.scale.x + self.offset.x;
    279        let mut y0 = rect.min.y * self.scale.y + self.offset.y;
    280 
    281        let mut sx = w * self.scale.x;
    282        let mut sy = h * self.scale.y;
    283        // Handle negative scale. Previously, branchless float math was used to find the
    284        // min / max vertices and size. However, that sequence of operations was producind
    285        // additional floating point accuracy on android emulator builds, causing one test
    286        // to fail an assert. Instead, we retain the same math as previously, and adjust
    287        // the origin / size if required.
    288 
    289        if self.scale.x < 0.0 {
    290            x0 += sx;
    291            sx = -sx;
    292        }
    293        if self.scale.y < 0.0 {
    294            y0 += sy;
    295            sy = -sy;
    296        }
    297 
    298        Box2D::from_origin_and_size(
    299            Point2D::new(x0, y0),
    300            Size2D::new(sx, sy),
    301        )
    302    }
    303 
    304    pub fn unmap_rect<F, T>(&self, rect: &Box2D<f32, F>) -> Box2D<f32, T> {
    305        // TODO(gw): The logic below can return an unexpected result if the supplied
    306        //           rect is invalid (has size < 0). Since Gecko currently supplied
    307        //           invalid rects in some cases, adding a max(0) here ensures that
    308        //           mapping an invalid rect retains the property that rect.is_empty()
    309        //           will return true (the mapped rect output will have size 0 instead
    310        //           of a negative size). In future we could catch / assert / fix
    311        //           these invalid rects earlier, and assert here instead.
    312 
    313        let w = rect.width().max(0.0);
    314        let h = rect.height().max(0.0);
    315 
    316        let mut x0 = (rect.min.x - self.offset.x) / self.scale.x;
    317        let mut y0 = (rect.min.y - self.offset.y) / self.scale.y;
    318 
    319        let mut sx = w / self.scale.x;
    320        let mut sy = h / self.scale.y;
    321 
    322        // Handle negative scale. Previously, branchless float math was used to find the
    323        // min / max vertices and size. However, that sequence of operations was producind
    324        // additional floating point accuracy on android emulator builds, causing one test
    325        // to fail an assert. Instead, we retain the same math as previously, and adjust
    326        // the origin / size if required.
    327 
    328        if self.scale.x < 0.0 {
    329            x0 += sx;
    330            sx = -sx;
    331        }
    332        if self.scale.y < 0.0 {
    333            y0 += sy;
    334            sy = -sy;
    335        }
    336 
    337        Box2D::from_origin_and_size(
    338            Point2D::new(x0, y0),
    339            Size2D::new(sx, sy),
    340        )
    341    }
    342 
    343    pub fn map_vector<F, T>(&self, vector: &Vector2D<f32, F>) -> Vector2D<f32, T> {
    344        Vector2D::new(
    345            vector.x * self.scale.x,
    346            vector.y * self.scale.y,
    347        )
    348    }
    349 
    350    pub fn map_size<F, T>(&self, size: &Size2D<f32, F>) -> Size2D<f32, T> {
    351        Size2D::new(
    352            size.width * self.scale.x,
    353            size.height * self.scale.y,
    354        )
    355    }
    356 
    357    pub fn unmap_vector<F, T>(&self, vector: &Vector2D<f32, F>) -> Vector2D<f32, T> {
    358        Vector2D::new(
    359            vector.x / self.scale.x,
    360            vector.y / self.scale.y,
    361        )
    362    }
    363 
    364    pub fn map_point<F, T>(&self, point: &Point2D<f32, F>) -> Point2D<f32, T> {
    365        Point2D::new(
    366            point.x * self.scale.x + self.offset.x,
    367            point.y * self.scale.y + self.offset.y,
    368        )
    369    }
    370 
    371    pub fn unmap_point<F, T>(&self, point: &Point2D<f32, F>) -> Point2D<f32, T> {
    372        Point2D::new(
    373            (point.x - self.offset.x) / self.scale.x,
    374            (point.y - self.offset.y) / self.scale.y,
    375        )
    376    }
    377 
    378    pub fn to_transform<F, T>(&self) -> Transform3D<f32, F, T> {
    379        Transform3D::new(
    380            self.scale.x,
    381            0.0,
    382            0.0,
    383            0.0,
    384 
    385            0.0,
    386            self.scale.y,
    387            0.0,
    388            0.0,
    389 
    390            0.0,
    391            0.0,
    392            1.0,
    393            0.0,
    394 
    395            self.offset.x,
    396            self.offset.y,
    397            0.0,
    398            1.0,
    399        )
    400    }
    401 }
    402 
    403 // TODO: Implement these in euclid!
    404 pub trait MatrixHelpers<Src, Dst> {
    405    /// A port of the preserves2dAxisAlignment function in Skia.
    406    /// Defined in the SkMatrix44 class.
    407    fn preserves_2d_axis_alignment(&self) -> bool;
    408    fn has_perspective_component(&self) -> bool;
    409    fn has_2d_inverse(&self) -> bool;
    410    /// Check if the matrix post-scaling on either the X or Y axes could cause geometry
    411    /// transformed by this matrix to have scaling exceeding the supplied limit.
    412    fn exceeds_2d_scale(&self, limit: f64) -> bool;
    413    fn inverse_project(&self, target: &Point2D<f32, Dst>) -> Option<Point2D<f32, Src>>;
    414    fn inverse_rect_footprint(&self, rect: &Box2D<f32, Dst>) -> Option<Box2D<f32, Src>>;
    415    fn transform_kind(&self) -> TransformedRectKind;
    416    fn is_simple_translation(&self) -> bool;
    417    fn is_simple_2d_translation(&self) -> bool;
    418    fn is_2d_scale_translation(&self) -> bool;
    419    /// Return the determinant of the 2D part of the matrix.
    420    fn determinant_2d(&self) -> f32;
    421    /// Turn Z transformation into identity. This is useful when crossing "flat"
    422    /// transform styled stacking contexts upon traversing the coordinate systems.
    423    fn flatten_z_output(&mut self);
    424 
    425    fn cast_unit<NewSrc, NewDst>(&self) -> Transform3D<f32, NewSrc, NewDst>;
    426 }
    427 
    428 impl<Src, Dst> MatrixHelpers<Src, Dst> for Transform3D<f32, Src, Dst> {
    429    fn preserves_2d_axis_alignment(&self) -> bool {
    430        if self.m14 != 0.0 || self.m24 != 0.0 {
    431            return false;
    432        }
    433 
    434        let mut col0 = 0;
    435        let mut col1 = 0;
    436        let mut row0 = 0;
    437        let mut row1 = 0;
    438 
    439        if self.m11.abs() > NEARLY_ZERO {
    440            col0 += 1;
    441            row0 += 1;
    442        }
    443        if self.m12.abs() > NEARLY_ZERO {
    444            col1 += 1;
    445            row0 += 1;
    446        }
    447        if self.m21.abs() > NEARLY_ZERO {
    448            col0 += 1;
    449            row1 += 1;
    450        }
    451        if self.m22.abs() > NEARLY_ZERO {
    452            col1 += 1;
    453            row1 += 1;
    454        }
    455 
    456        col0 < 2 && col1 < 2 && row0 < 2 && row1 < 2
    457    }
    458 
    459    fn has_perspective_component(&self) -> bool {
    460         self.m14.abs() > NEARLY_ZERO ||
    461         self.m24.abs() > NEARLY_ZERO ||
    462         self.m34.abs() > NEARLY_ZERO ||
    463         (self.m44 - 1.0).abs() > NEARLY_ZERO
    464    }
    465 
    466    fn has_2d_inverse(&self) -> bool {
    467        self.determinant_2d() != 0.0
    468    }
    469 
    470    fn exceeds_2d_scale(&self, limit: f64) -> bool {
    471        let limit2 = (limit * limit) as f32;
    472        self.m11 * self.m11 + self.m12 * self.m12 > limit2 ||
    473        self.m21 * self.m21 + self.m22 * self.m22 > limit2
    474    }
    475 
    476    /// Find out a point in `Src` that would be projected into the `target`.
    477    fn inverse_project(&self, target: &Point2D<f32, Dst>) -> Option<Point2D<f32, Src>> {
    478        // form the linear equation for the hyperplane intersection
    479        let m = Transform2D::<f32, Src, Dst>::new(
    480            self.m11 - target.x * self.m14, self.m12 - target.y * self.m14,
    481            self.m21 - target.x * self.m24, self.m22 - target.y * self.m24,
    482            self.m41 - target.x * self.m44, self.m42 - target.y * self.m44,
    483        );
    484        let inv = m.inverse()?;
    485        // we found the point, now check if it maps to the positive hemisphere
    486        if inv.m31 * self.m14 + inv.m32 * self.m24 + self.m44 > 0.0 {
    487            Some(Point2D::new(inv.m31, inv.m32))
    488        } else {
    489            None
    490        }
    491    }
    492 
    493    fn inverse_rect_footprint(&self, rect: &Box2D<f32, Dst>) -> Option<Box2D<f32, Src>> {
    494        Some(Box2D::from_points(&[
    495            self.inverse_project(&rect.top_left())?,
    496            self.inverse_project(&rect.top_right())?,
    497            self.inverse_project(&rect.bottom_left())?,
    498            self.inverse_project(&rect.bottom_right())?,
    499        ]))
    500    }
    501 
    502    fn transform_kind(&self) -> TransformedRectKind {
    503        if self.preserves_2d_axis_alignment() {
    504            TransformedRectKind::AxisAligned
    505        } else {
    506            TransformedRectKind::Complex
    507        }
    508    }
    509 
    510    fn is_simple_translation(&self) -> bool {
    511        if (self.m11 - 1.0).abs() > NEARLY_ZERO ||
    512            (self.m22 - 1.0).abs() > NEARLY_ZERO ||
    513            (self.m33 - 1.0).abs() > NEARLY_ZERO ||
    514            (self.m44 - 1.0).abs() > NEARLY_ZERO {
    515            return false;
    516        }
    517 
    518        self.m12.abs() < NEARLY_ZERO && self.m13.abs() < NEARLY_ZERO &&
    519            self.m14.abs() < NEARLY_ZERO && self.m21.abs() < NEARLY_ZERO &&
    520            self.m23.abs() < NEARLY_ZERO && self.m24.abs() < NEARLY_ZERO &&
    521            self.m31.abs() < NEARLY_ZERO && self.m32.abs() < NEARLY_ZERO &&
    522            self.m34.abs() < NEARLY_ZERO
    523    }
    524 
    525    fn is_simple_2d_translation(&self) -> bool {
    526        if !self.is_simple_translation() {
    527            return false;
    528        }
    529 
    530        self.m43.abs() < NEARLY_ZERO
    531    }
    532 
    533    /*  is this...
    534     *  X  0  0  0
    535     *  0  Y  0  0
    536     *  0  0  1  0
    537     *  a  b  0  1
    538     */
    539    fn is_2d_scale_translation(&self) -> bool {
    540        (self.m33 - 1.0).abs() < NEARLY_ZERO &&
    541            (self.m44 - 1.0).abs() < NEARLY_ZERO &&
    542            self.m12.abs() < NEARLY_ZERO && self.m13.abs() < NEARLY_ZERO && self.m14.abs() < NEARLY_ZERO &&
    543            self.m21.abs() < NEARLY_ZERO && self.m23.abs() < NEARLY_ZERO && self.m24.abs() < NEARLY_ZERO &&
    544            self.m31.abs() < NEARLY_ZERO && self.m32.abs() < NEARLY_ZERO && self.m34.abs() < NEARLY_ZERO &&
    545            self.m43.abs() < NEARLY_ZERO
    546    }
    547 
    548    fn determinant_2d(&self) -> f32 {
    549        self.m11 * self.m22 - self.m12 * self.m21
    550    }
    551 
    552    fn flatten_z_output(&mut self) {
    553        self.m13 = 0.0;
    554        self.m23 = 0.0;
    555        self.m33 = 1.0;
    556        self.m43 = 0.0;
    557        //Note: we used to zero out m3? as well, see "reftests/flatten-all-flat.yaml" test
    558    }
    559 
    560    fn cast_unit<NewSrc, NewDst>(&self) -> Transform3D<f32, NewSrc, NewDst> {
    561        Transform3D::new(
    562            self.m11, self.m12, self.m13, self.m14,
    563            self.m21, self.m22, self.m23, self.m24,
    564            self.m31, self.m32, self.m33, self.m34,
    565            self.m41, self.m42, self.m43, self.m44,
    566        )
    567    }
    568 }
    569 
    570 pub trait PointHelpers<U>
    571 where
    572    Self: Sized,
    573 {
    574    fn snap(&self) -> Self;
    575 }
    576 
    577 impl<U> PointHelpers<U> for Point2D<f32, U> {
    578    fn snap(&self) -> Self {
    579        Point2D::new(
    580            self.x.round(),
    581            self.y.round(),
    582        )
    583    }
    584 }
    585 
    586 pub trait VectorHelpers<U>
    587 where
    588    Self: Sized,
    589 {
    590    fn snap(&self) -> Self;
    591 }
    592 
    593 impl<U> VectorHelpers<U> for Vector2D<f32, U> {
    594    fn snap(&self) -> Self {
    595        Vector2D::new(
    596            self.x.round(),
    597            self.y.round(),
    598        )
    599    }
    600 }
    601 
    602 pub trait RectHelpers<U>
    603 where
    604    Self: Sized,
    605 {
    606    fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self;
    607    fn snap(&self) -> Self;
    608 }
    609 
    610 impl<U> RectHelpers<U> for Rect<f32, U> {
    611    fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self {
    612        Rect::new(
    613            Point2D::new(x0, y0),
    614            Size2D::new(x1 - x0, y1 - y0),
    615        )
    616    }
    617 
    618    fn snap(&self) -> Self {
    619        let origin = Point2D::new(
    620            (self.origin.x + 0.5).floor(),
    621            (self.origin.y + 0.5).floor(),
    622        );
    623        Rect::new(
    624            origin,
    625            Size2D::new(
    626                (self.origin.x + self.size.width + 0.5).floor() - origin.x,
    627                (self.origin.y + self.size.height + 0.5).floor() - origin.y,
    628            ),
    629        )
    630    }
    631 }
    632 
    633 impl<U> RectHelpers<U> for Box2D<f32, U> {
    634    fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self {
    635        Box2D {
    636            min: Point2D::new(x0, y0),
    637            max: Point2D::new(x1, y1),
    638        }
    639    }
    640 
    641    fn snap(&self) -> Self {
    642        self.round()
    643    }
    644 }
    645 
    646 pub fn lerp(a: f32, b: f32, t: f32) -> f32 {
    647    (b - a) * t + a
    648 }
    649 
    650 #[repr(u32)]
    651 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
    652 #[cfg_attr(feature = "capture", derive(Serialize))]
    653 #[cfg_attr(feature = "replay", derive(Deserialize))]
    654 pub enum TransformedRectKind {
    655    AxisAligned = 0,
    656    Complex = 1,
    657 }
    658 
    659 #[inline(always)]
    660 pub fn pack_as_float(value: u32) -> f32 {
    661    value as f32 + 0.5
    662 }
    663 
    664 #[inline]
    665 fn extract_inner_rect_impl<U>(
    666    rect: &Box2D<f32, U>,
    667    radii: &BorderRadius,
    668    k: f32,
    669 ) -> Option<Box2D<f32, U>> {
    670    // `k` defines how much border is taken into account
    671    // We enforce the offsets to be rounded to pixel boundaries
    672    // by `ceil`-ing and `floor`-ing them
    673 
    674    let xl = (k * radii.top_left.width.max(radii.bottom_left.width)).ceil();
    675    let xr = (rect.width() - k * radii.top_right.width.max(radii.bottom_right.width)).floor();
    676    let yt = (k * radii.top_left.height.max(radii.top_right.height)).ceil();
    677    let yb =
    678        (rect.height() - k * radii.bottom_left.height.max(radii.bottom_right.height)).floor();
    679 
    680    if xl <= xr && yt <= yb {
    681        Some(Box2D::from_origin_and_size(
    682            Point2D::new(rect.min.x + xl, rect.min.y + yt),
    683            Size2D::new(xr - xl, yb - yt),
    684        ))
    685    } else {
    686        None
    687    }
    688 }
    689 
    690 /// Return an aligned rectangle that is inside the clip region and doesn't intersect
    691 /// any of the bounding rectangles of the rounded corners.
    692 pub fn extract_inner_rect_safe<U>(
    693    rect: &Box2D<f32, U>,
    694    radii: &BorderRadius,
    695 ) -> Option<Box2D<f32, U>> {
    696    // value of `k==1.0` is used for extraction of the corner rectangles
    697    // see `SEGMENT_CORNER_*` in `clip_shared.glsl`
    698    extract_inner_rect_impl(rect, radii, 1.0)
    699 }
    700 
    701 /// Return an aligned rectangle that is inside the clip region and doesn't intersect
    702 /// any of the bounding rectangles of the rounded corners, with a specific k factor
    703 /// to control how much of the rounded corner is included.
    704 pub fn extract_inner_rect_k<U>(
    705    rect: &Box2D<f32, U>,
    706    radii: &BorderRadius,
    707    k: f32,
    708 ) -> Option<Box2D<f32, U>> {
    709    extract_inner_rect_impl(rect, radii, k)
    710 }
    711 
    712 #[cfg(test)]
    713 use euclid::vec3;
    714 
    715 #[cfg(test)]
    716 pub mod test {
    717    use super::*;
    718    use euclid::default::{Point2D, Size2D, Transform3D};
    719    use euclid::{Angle, approxeq::ApproxEq};
    720    use std::f32::consts::PI;
    721    use crate::clip::{is_left_of_line, polygon_contains_point};
    722    use crate::prim_store::PolygonKey;
    723    use api::FillRule;
    724 
    725    #[test]
    726    fn inverse_project() {
    727        let m0 = Transform3D::identity();
    728        let p0 = Point2D::new(1.0, 2.0);
    729        // an identical transform doesn't need any inverse projection
    730        assert_eq!(m0.inverse_project(&p0), Some(p0));
    731        let m1 = Transform3D::rotation(0.0, 1.0, 0.0, Angle::radians(-PI / 3.0));
    732        // rotation by 60 degrees would imply scaling of X component by a factor of 2
    733        assert_eq!(m1.inverse_project(&p0), Some(Point2D::new(2.0, 2.0)));
    734    }
    735 
    736    #[test]
    737    fn inverse_project_footprint() {
    738        let m = Transform3D::new(
    739            0.477499992, 0.135000005, -1.0, 0.000624999986,
    740            -0.642787635, 0.766044438, 0.0, 0.0,
    741            0.766044438, 0.642787635, 0.0, 0.0,
    742            1137.10986, 113.71286, 402.0, 0.748749971,
    743        );
    744        let r = Box2D::from_size(Size2D::new(804.0, 804.0));
    745        {
    746            let points = &[
    747                r.top_left(),
    748                r.top_right(),
    749                r.bottom_left(),
    750                r.bottom_right(),
    751            ];
    752            let mi = m.inverse().unwrap();
    753            // In this section, we do the forward and backward transformation
    754            // to confirm that its bijective.
    755            // We also do the inverse projection path, and confirm it functions the same way.
    756            info!("Points:");
    757            for p in points {
    758                let pp = m.transform_point2d_homogeneous(*p);
    759                let p3 = pp.to_point3d().unwrap();
    760                let pi = mi.transform_point3d_homogeneous(p3);
    761                let px = pi.to_point2d().unwrap();
    762                let py = m.inverse_project(&pp.to_point2d().unwrap()).unwrap();
    763                info!("\t{:?} -> {:?} -> {:?} -> ({:?} -> {:?}, {:?})", p, pp, p3, pi, px, py);
    764                assert!(px.approx_eq_eps(p, &Point2D::new(0.001, 0.001)));
    765                assert!(py.approx_eq_eps(p, &Point2D::new(0.001, 0.001)));
    766            }
    767        }
    768        // project
    769        let rp = project_rect(&m, &r, &Box2D::from_size(Size2D::new(1000.0, 1000.0))).unwrap();
    770        info!("Projected {:?}", rp);
    771        // one of the points ends up in the negative hemisphere
    772        assert_eq!(m.inverse_project(&rp.min), None);
    773        // inverse
    774        if let Some(ri) = m.inverse_rect_footprint(&rp) {
    775            // inverse footprint should be larger, since it doesn't know the original Z
    776            assert!(ri.contains_box(&r), "Inverse {:?}", ri);
    777        }
    778    }
    779 
    780    fn validate_convert(xref: &LayoutTransform) {
    781        let so = ScaleOffset::from_transform(xref).unwrap();
    782        let xf = so.to_transform();
    783        assert!(xref.approx_eq(&xf));
    784    }
    785 
    786    #[test]
    787    fn negative_scale_map_unmap() {
    788        let xref = LayoutTransform::scale(1.0, -1.0, 1.0)
    789                        .pre_translate(LayoutVector3D::new(124.0, 38.0, 0.0));
    790        let so = ScaleOffset::from_transform(&xref).unwrap();
    791        let local_rect = Box2D {
    792            min: LayoutPoint::new(50.0, -100.0),
    793            max: LayoutPoint::new(250.0, 300.0),
    794        };
    795 
    796        let mapped_rect = so.map_rect::<LayoutPixel, DevicePixel>(&local_rect);
    797        let xf_rect = project_rect(
    798            &xref,
    799            &local_rect,
    800            &LayoutRect::max_rect(),
    801        ).unwrap();
    802 
    803        assert!(mapped_rect.min.x.approx_eq(&xf_rect.min.x));
    804        assert!(mapped_rect.min.y.approx_eq(&xf_rect.min.y));
    805        assert!(mapped_rect.max.x.approx_eq(&xf_rect.max.x));
    806        assert!(mapped_rect.max.y.approx_eq(&xf_rect.max.y));
    807 
    808        let unmapped_rect = so.unmap_rect::<DevicePixel, LayoutPixel>(&mapped_rect);
    809        assert!(unmapped_rect.min.x.approx_eq(&local_rect.min.x));
    810        assert!(unmapped_rect.min.y.approx_eq(&local_rect.min.y));
    811        assert!(unmapped_rect.max.x.approx_eq(&local_rect.max.x));
    812        assert!(unmapped_rect.max.y.approx_eq(&local_rect.max.y));
    813    }
    814 
    815    #[test]
    816    fn scale_offset_convert() {
    817        let xref = LayoutTransform::translation(130.0, 200.0, 0.0);
    818        validate_convert(&xref);
    819 
    820        let xref = LayoutTransform::scale(13.0, 8.0, 1.0);
    821        validate_convert(&xref);
    822 
    823        let xref = LayoutTransform::scale(0.5, 0.5, 1.0)
    824                        .pre_translate(LayoutVector3D::new(124.0, 38.0, 0.0));
    825        validate_convert(&xref);
    826 
    827        let xref = LayoutTransform::scale(30.0, 11.0, 1.0)
    828            .then_translate(vec3(50.0, 240.0, 0.0));
    829        validate_convert(&xref);
    830    }
    831 
    832    fn validate_inverse(xref: &LayoutTransform) {
    833        let s0 = ScaleOffset::from_transform(xref).unwrap();
    834        let s1 = s0.inverse().pre_transform(&s0);
    835        assert!((s1.scale.x - 1.0).abs() < NEARLY_ZERO &&
    836                (s1.scale.y - 1.0).abs() < NEARLY_ZERO &&
    837                s1.offset.x.abs() < NEARLY_ZERO &&
    838                s1.offset.y.abs() < NEARLY_ZERO,
    839                "{:?}",
    840                s1);
    841    }
    842 
    843    #[test]
    844    fn scale_offset_inverse() {
    845        let xref = LayoutTransform::translation(130.0, 200.0, 0.0);
    846        validate_inverse(&xref);
    847 
    848        let xref = LayoutTransform::scale(13.0, 8.0, 1.0);
    849        validate_inverse(&xref);
    850 
    851        let xref = LayoutTransform::translation(124.0, 38.0, 0.0).
    852            then_scale(0.5, 0.5, 1.0);
    853 
    854        validate_inverse(&xref);
    855 
    856        let xref = LayoutTransform::scale(30.0, 11.0, 1.0)
    857            .then_translate(vec3(50.0, 240.0, 0.0));
    858        validate_inverse(&xref);
    859    }
    860 
    861    fn validate_accumulate(x0: &LayoutTransform, x1: &LayoutTransform) {
    862        let x = x1.then(&x0);
    863 
    864        let s0 = ScaleOffset::from_transform(x0).unwrap();
    865        let s1 = ScaleOffset::from_transform(x1).unwrap();
    866 
    867        let s = s0.pre_transform(&s1).to_transform();
    868 
    869        assert!(x.approx_eq(&s), "{:?}\n{:?}", x, s);
    870    }
    871 
    872    #[test]
    873    fn scale_offset_accumulate() {
    874        let x0 = LayoutTransform::translation(130.0, 200.0, 0.0);
    875        let x1 = LayoutTransform::scale(7.0, 3.0, 1.0);
    876 
    877        validate_accumulate(&x0, &x1);
    878    }
    879 
    880    #[test]
    881    fn scale_offset_invalid_scale() {
    882        let s0 = ScaleOffset::new(0.0, 1.0, 10.0, 20.0);
    883        let i0 = s0.inverse();
    884        assert_eq!(i0, ScaleOffset::new(0.0, 0.0, 0.0, 0.0));
    885 
    886        let s1 = ScaleOffset::new(1.0, 0.0, 10.0, 20.0);
    887        let i1 = s1.inverse();
    888        assert_eq!(i1, ScaleOffset::new(0.0, 0.0, 0.0, 0.0));
    889    }
    890 
    891    #[test]
    892    fn polygon_clip_is_left_of_point() {
    893        // Define points of a line through (1, -3) and (-2, 6) to test against.
    894        // If the triplet consisting of these two points and the test point
    895        // form a counter-clockwise triangle, then the test point is on the
    896        // left. The easiest way to visualize this is with an "ascending"
    897        // line from low-Y to high-Y.
    898        let p0_x = 1.0;
    899        let p0_y = -3.0;
    900        let p1_x = -2.0;
    901        let p1_y = 6.0;
    902 
    903        // Test some points to the left of the line.
    904        assert!(is_left_of_line(-9.0, 0.0, p0_x, p0_y, p1_x, p1_y) > 0.0);
    905        assert!(is_left_of_line(-1.0, 1.0, p0_x, p0_y, p1_x, p1_y) > 0.0);
    906        assert!(is_left_of_line(1.0, -4.0, p0_x, p0_y, p1_x, p1_y) > 0.0);
    907 
    908        // Test some points on the line.
    909        assert!(is_left_of_line(-3.0, 9.0, p0_x, p0_y, p1_x, p1_y) == 0.0);
    910        assert!(is_left_of_line(0.0, 0.0, p0_x, p0_y, p1_x, p1_y) == 0.0);
    911        assert!(is_left_of_line(100.0, -300.0, p0_x, p0_y, p1_x, p1_y) == 0.0);
    912 
    913        // Test some points to the right of the line.
    914        assert!(is_left_of_line(0.0, 1.0, p0_x, p0_y, p1_x, p1_y) < 0.0);
    915        assert!(is_left_of_line(-4.0, 13.0, p0_x, p0_y, p1_x, p1_y) < 0.0);
    916        assert!(is_left_of_line(5.0, -12.0, p0_x, p0_y, p1_x, p1_y) < 0.0);
    917    }
    918 
    919    #[test]
    920    fn polygon_clip_contains_point() {
    921        // We define the points of a self-overlapping polygon, which we will
    922        // use to create polygons with different windings and fill rules.
    923        let p0 = LayoutPoint::new(4.0, 4.0);
    924        let p1 = LayoutPoint::new(6.0, 4.0);
    925        let p2 = LayoutPoint::new(4.0, 7.0);
    926        let p3 = LayoutPoint::new(2.0, 1.0);
    927        let p4 = LayoutPoint::new(8.0, 1.0);
    928        let p5 = LayoutPoint::new(6.0, 7.0);
    929 
    930        let poly_clockwise_nonzero = PolygonKey::new(
    931            &[p5, p4, p3, p2, p1, p0].to_vec(), FillRule::Nonzero
    932        );
    933        let poly_clockwise_evenodd = PolygonKey::new(
    934            &[p5, p4, p3, p2, p1, p0].to_vec(), FillRule::Evenodd
    935        );
    936        let poly_counter_clockwise_nonzero = PolygonKey::new(
    937            &[p0, p1, p2, p3, p4, p5].to_vec(), FillRule::Nonzero
    938        );
    939        let poly_counter_clockwise_evenodd = PolygonKey::new(
    940            &[p0, p1, p2, p3, p4, p5].to_vec(), FillRule::Evenodd
    941        );
    942 
    943        // We define a rect that provides a bounding clip area of
    944        // the polygon.
    945        let rect = LayoutRect::from_size(LayoutSize::new(10.0, 10.0));
    946 
    947        // And we'll test three points of interest.
    948        let p_inside_once = LayoutPoint::new(5.0, 3.0);
    949        let p_inside_twice = LayoutPoint::new(5.0, 5.0);
    950        let p_outside = LayoutPoint::new(9.0, 9.0);
    951 
    952        // We should get the same results for both clockwise and
    953        // counter-clockwise polygons.
    954        // For nonzero polygons, the inside twice point is considered inside.
    955        for poly_nonzero in vec![poly_clockwise_nonzero, poly_counter_clockwise_nonzero].iter() {
    956            assert_eq!(polygon_contains_point(&p_inside_once, &rect, &poly_nonzero), true);
    957            assert_eq!(polygon_contains_point(&p_inside_twice, &rect, &poly_nonzero), true);
    958            assert_eq!(polygon_contains_point(&p_outside, &rect, &poly_nonzero), false);
    959        }
    960        // For evenodd polygons, the inside twice point is considered outside.
    961        for poly_evenodd in vec![poly_clockwise_evenodd, poly_counter_clockwise_evenodd].iter() {
    962            assert_eq!(polygon_contains_point(&p_inside_once, &rect, &poly_evenodd), true);
    963            assert_eq!(polygon_contains_point(&p_inside_twice, &rect, &poly_evenodd), false);
    964            assert_eq!(polygon_contains_point(&p_outside, &rect, &poly_evenodd), false);
    965        }
    966    }
    967 }
    968 
    969 pub trait MaxRect {
    970    fn max_rect() -> Self;
    971 }
    972 
    973 impl MaxRect for DeviceIntRect {
    974    fn max_rect() -> Self {
    975        DeviceIntRect::from_origin_and_size(
    976            DeviceIntPoint::new(i32::MIN / 2, i32::MIN / 2),
    977            DeviceIntSize::new(i32::MAX, i32::MAX),
    978        )
    979    }
    980 }
    981 
    982 impl<U> MaxRect for Rect<f32, U> {
    983    fn max_rect() -> Self {
    984        // Having an unlimited bounding box is fine up until we try
    985        // to cast it to `i32`, where we get `-2147483648` for any
    986        // values larger than or equal to 2^31.
    987        //
    988        // Note: clamping to i32::MIN and i32::MAX is not a solution,
    989        // with explanation left as an exercise for the reader.
    990        const MAX_COORD: f32 = 1.0e9;
    991 
    992        Rect::new(
    993            Point2D::new(-MAX_COORD, -MAX_COORD),
    994            Size2D::new(2.0 * MAX_COORD, 2.0 * MAX_COORD),
    995        )
    996    }
    997 }
    998 
    999 impl<U> MaxRect for Box2D<f32, U> {
   1000    fn max_rect() -> Self {
   1001        // Having an unlimited bounding box is fine up until we try
   1002        // to cast it to `i32`, where we get `-2147483648` for any
   1003        // values larger than or equal to 2^31.
   1004        //
   1005        // Note: clamping to i32::MIN and i32::MAX is not a solution,
   1006        // with explanation left as an exercise for the reader.
   1007        const MAX_COORD: f32 = 1.0e9;
   1008 
   1009        Box2D::new(
   1010            Point2D::new(-MAX_COORD, -MAX_COORD),
   1011            Point2D::new(MAX_COORD, MAX_COORD),
   1012        )
   1013    }
   1014 }
   1015 
   1016 /// An enum that tries to avoid expensive transformation matrix calculations
   1017 /// when possible when dealing with non-perspective axis-aligned transformations.
   1018 #[derive(Debug, MallocSizeOf)]
   1019 #[cfg_attr(feature = "capture", derive(Serialize))]
   1020 #[cfg_attr(feature = "replay", derive(Deserialize))]
   1021 pub enum FastTransform<Src, Dst> {
   1022    /// A simple offset, which can be used without doing any matrix math.
   1023    Offset(Vector2D<f32, Src>),
   1024 
   1025    /// A 2D transformation with an inverse.
   1026    Transform {
   1027        transform: Transform3D<f32, Src, Dst>,
   1028        inverse: Option<Transform3D<f32, Dst, Src>>,
   1029        is_2d: bool,
   1030    },
   1031 }
   1032 
   1033 impl<Src, Dst> Clone for FastTransform<Src, Dst> {
   1034    fn clone(&self) -> Self {
   1035        *self
   1036    }
   1037 }
   1038 
   1039 impl<Src, Dst> Copy for FastTransform<Src, Dst> { }
   1040 
   1041 impl<Src, Dst> FastTransform<Src, Dst> {
   1042    pub fn identity() -> Self {
   1043        FastTransform::Offset(Vector2D::zero())
   1044    }
   1045 
   1046    pub fn with_vector(offset: Vector2D<f32, Src>) -> Self {
   1047        FastTransform::Offset(offset)
   1048    }
   1049 
   1050    pub fn with_scale_offset(scale_offset: ScaleOffset) -> Self {
   1051        if scale_offset.scale == Vector2D::new(1.0, 1.0) {
   1052            FastTransform::Offset(Vector2D::from_untyped(scale_offset.offset))
   1053        } else {
   1054            FastTransform::Transform {
   1055                transform: scale_offset.to_transform(),
   1056                inverse: Some(scale_offset.inverse().to_transform()),
   1057                is_2d: true,
   1058            }
   1059        }
   1060    }
   1061 
   1062    #[inline(always)]
   1063    pub fn with_transform(transform: Transform3D<f32, Src, Dst>) -> Self {
   1064        if transform.is_simple_2d_translation() {
   1065            return FastTransform::Offset(Vector2D::new(transform.m41, transform.m42));
   1066        }
   1067        let inverse = transform.inverse();
   1068        let is_2d = transform.is_2d();
   1069        FastTransform::Transform { transform, inverse, is_2d}
   1070    }
   1071 
   1072    pub fn to_transform(&self) -> Cow<Transform3D<f32, Src, Dst>> {
   1073        match *self {
   1074            FastTransform::Offset(offset) => Cow::Owned(
   1075                Transform3D::translation(offset.x, offset.y, 0.0)
   1076            ),
   1077            FastTransform::Transform { ref transform, .. } => Cow::Borrowed(transform),
   1078        }
   1079    }
   1080 
   1081    /// Return true if this is an identity transform
   1082    #[allow(unused)]
   1083    pub fn is_identity(&self)-> bool {
   1084        match *self {
   1085            FastTransform::Offset(offset) => {
   1086                offset == Vector2D::zero()
   1087            }
   1088            FastTransform::Transform { ref transform, .. } => {
   1089                *transform == Transform3D::identity()
   1090            }
   1091        }
   1092    }
   1093 
   1094    pub fn then<NewDst>(&self, other: &FastTransform<Dst, NewDst>) -> FastTransform<Src, NewDst> {
   1095        match *self {
   1096            FastTransform::Offset(offset) => match *other {
   1097                FastTransform::Offset(other_offset) => {
   1098                    FastTransform::Offset(offset + other_offset * Scale::<_, _, Src>::new(1.0))
   1099                }
   1100                FastTransform::Transform { transform: ref other_transform, .. } => {
   1101                    FastTransform::with_transform(
   1102                        other_transform
   1103                            .with_source::<Src>()
   1104                            .pre_translate(offset.to_3d())
   1105                    )
   1106                }
   1107            }
   1108            FastTransform::Transform { ref transform, ref inverse, is_2d } => match *other {
   1109                FastTransform::Offset(other_offset) => {
   1110                    FastTransform::with_transform(
   1111                        transform
   1112                            .then_translate(other_offset.to_3d())
   1113                            .with_destination::<NewDst>()
   1114                    )
   1115                }
   1116                FastTransform::Transform { transform: ref other_transform, inverse: ref other_inverse, is_2d: other_is_2d } => {
   1117                    FastTransform::Transform {
   1118                        transform: transform.then(other_transform),
   1119                        inverse: inverse.as_ref().and_then(|self_inv|
   1120                            other_inverse.as_ref().map(|other_inv| other_inv.then(self_inv))
   1121                        ),
   1122                        is_2d: is_2d & other_is_2d,
   1123                    }
   1124                }
   1125            }
   1126        }
   1127    }
   1128 
   1129    pub fn pre_transform<NewSrc>(
   1130        &self,
   1131        other: &FastTransform<NewSrc, Src>
   1132    ) -> FastTransform<NewSrc, Dst> {
   1133        other.then(self)
   1134    }
   1135 
   1136    pub fn pre_translate(&self, other_offset: Vector2D<f32, Src>) -> Self {
   1137        match *self {
   1138            FastTransform::Offset(offset) =>
   1139                FastTransform::Offset(offset + other_offset),
   1140            FastTransform::Transform { transform, .. } =>
   1141                FastTransform::with_transform(transform.pre_translate(other_offset.to_3d()))
   1142        }
   1143    }
   1144 
   1145    pub fn then_translate(&self, other_offset: Vector2D<f32, Dst>) -> Self {
   1146        match *self {
   1147            FastTransform::Offset(offset) => {
   1148                FastTransform::Offset(offset + other_offset * Scale::<_, _, Src>::new(1.0))
   1149            }
   1150            FastTransform::Transform { ref transform, .. } => {
   1151                let transform = transform.then_translate(other_offset.to_3d());
   1152                FastTransform::with_transform(transform)
   1153            }
   1154        }
   1155    }
   1156 
   1157    #[inline(always)]
   1158    pub fn is_backface_visible(&self) -> bool {
   1159        match *self {
   1160            FastTransform::Offset(..) => false,
   1161            FastTransform::Transform { inverse: None, .. } => false,
   1162            //TODO: fix this properly by taking "det|M33| * det|M34| > 0"
   1163            // see https://www.w3.org/Bugs/Public/show_bug.cgi?id=23014
   1164            FastTransform::Transform { inverse: Some(ref inverse), .. } => inverse.m33 < 0.0,
   1165        }
   1166    }
   1167 
   1168    #[inline(always)]
   1169    pub fn transform_point2d(&self, point: Point2D<f32, Src>) -> Option<Point2D<f32, Dst>> {
   1170        match *self {
   1171            FastTransform::Offset(offset) => {
   1172                let new_point = point + offset;
   1173                Some(Point2D::from_untyped(new_point.to_untyped()))
   1174            }
   1175            FastTransform::Transform { ref transform, .. } => transform.transform_point2d(point),
   1176        }
   1177    }
   1178 
   1179    #[inline(always)]
   1180    pub fn project_point2d(&self, point: Point2D<f32, Src>) -> Option<Point2D<f32, Dst>> {
   1181        match* self {
   1182            FastTransform::Offset(..) => self.transform_point2d(point),
   1183            FastTransform::Transform{ref transform, ..} => {
   1184                // Find a value for z that will transform to 0.
   1185 
   1186                // The transformed value of z is computed as:
   1187                // z' = point.x * self.m13 + point.y * self.m23 + z * self.m33 + self.m43
   1188 
   1189                // Solving for z when z' = 0 gives us:
   1190                let z = -(point.x * transform.m13 + point.y * transform.m23 + transform.m43) / transform.m33;
   1191 
   1192                transform.transform_point3d(point3(point.x, point.y, z)).map(| p3 | point2(p3.x, p3.y))
   1193            }
   1194        }
   1195    }
   1196 
   1197    #[inline(always)]
   1198    pub fn inverse(&self) -> Option<FastTransform<Dst, Src>> {
   1199        match *self {
   1200            FastTransform::Offset(offset) =>
   1201                Some(FastTransform::Offset(Vector2D::new(-offset.x, -offset.y))),
   1202            FastTransform::Transform { transform, inverse: Some(inverse), is_2d, } =>
   1203                Some(FastTransform::Transform {
   1204                    transform: inverse,
   1205                    inverse: Some(transform),
   1206                    is_2d
   1207                }),
   1208            FastTransform::Transform { inverse: None, .. } => None,
   1209 
   1210        }
   1211    }
   1212 }
   1213 
   1214 impl<Src, Dst> From<Transform3D<f32, Src, Dst>> for FastTransform<Src, Dst> {
   1215    fn from(transform: Transform3D<f32, Src, Dst>) -> Self {
   1216        FastTransform::with_transform(transform)
   1217    }
   1218 }
   1219 
   1220 impl<Src, Dst> From<Vector2D<f32, Src>> for FastTransform<Src, Dst> {
   1221    fn from(vector: Vector2D<f32, Src>) -> Self {
   1222        FastTransform::with_vector(vector)
   1223    }
   1224 }
   1225 
   1226 pub type LayoutFastTransform = FastTransform<LayoutPixel, LayoutPixel>;
   1227 pub type LayoutToWorldFastTransform = FastTransform<LayoutPixel, WorldPixel>;
   1228 
   1229 pub fn project_rect<F, T>(
   1230    transform: &Transform3D<f32, F, T>,
   1231    rect: &Box2D<f32, F>,
   1232    bounds: &Box2D<f32, T>,
   1233 ) -> Option<Box2D<f32, T>>
   1234 where F: fmt::Debug
   1235 {
   1236    let homogens = [
   1237        transform.transform_point2d_homogeneous(rect.top_left()),
   1238        transform.transform_point2d_homogeneous(rect.top_right()),
   1239        transform.transform_point2d_homogeneous(rect.bottom_left()),
   1240        transform.transform_point2d_homogeneous(rect.bottom_right()),
   1241    ];
   1242 
   1243    // Note: we only do the full frustum collision when the polygon approaches the camera plane.
   1244    // Otherwise, it will be clamped to the screen bounds anyway.
   1245    if homogens.iter().any(|h| h.w <= 0.0 || h.w.is_nan()) {
   1246        let mut clipper = Clipper::new();
   1247        let polygon = Polygon::from_rect(rect.to_rect().cast().cast_unit(), 1);
   1248 
   1249        let planes = match Clipper::<usize>::frustum_planes(
   1250            &transform.cast_unit().cast(),
   1251            Some(bounds.to_rect().cast_unit().to_f64()),
   1252        ) {
   1253            Ok(planes) => planes,
   1254            Err(..) => return None,
   1255        };
   1256 
   1257        for plane in planes {
   1258            clipper.add(plane);
   1259        }
   1260 
   1261        let results = clipper.clip(polygon);
   1262        if results.is_empty() {
   1263            return None
   1264        }
   1265 
   1266        Some(Box2D::from_points(results
   1267            .into_iter()
   1268            // filter out parts behind the view plane
   1269            .flat_map(|poly| &poly.points)
   1270            .map(|p| {
   1271                let mut homo = transform.transform_point2d_homogeneous(p.to_2d().to_f32().cast_unit());
   1272                homo.w = homo.w.max(0.00000001); // avoid infinite values
   1273                homo.to_point2d().unwrap()
   1274            })
   1275        ))
   1276    } else {
   1277        // we just checked for all the points to be in positive hemisphere, so `unwrap` is valid
   1278        Some(Box2D::from_points(&[
   1279            homogens[0].to_point2d().unwrap(),
   1280            homogens[1].to_point2d().unwrap(),
   1281            homogens[2].to_point2d().unwrap(),
   1282            homogens[3].to_point2d().unwrap(),
   1283        ]))
   1284    }
   1285 }
   1286 
   1287 /// Run the first callback over all elements in the array. If the callback returns true,
   1288 /// the element is removed from the array and moved to a second callback.
   1289 ///
   1290 /// This is a simple implementation waiting for Vec::drain_filter to be stable.
   1291 /// When that happens, code like:
   1292 ///
   1293 /// let filter = |op| {
   1294 ///     match *op {
   1295 ///         Enum::Foo | Enum::Bar => true,
   1296 ///         Enum::Baz => false,
   1297 ///     }
   1298 /// };
   1299 /// drain_filter(
   1300 ///     &mut ops,
   1301 ///     filter,
   1302 ///     |op| {
   1303 ///         match op {
   1304 ///             Enum::Foo => { foo(); }
   1305 ///             Enum::Bar => { bar(); }
   1306 ///             Enum::Baz => { unreachable!(); }
   1307 ///         }
   1308 ///     },
   1309 /// );
   1310 ///
   1311 /// Can be rewritten as:
   1312 ///
   1313 /// let filter = |op| {
   1314 ///     match *op {
   1315 ///         Enum::Foo | Enum::Bar => true,
   1316 ///         Enum::Baz => false,
   1317 ///     }
   1318 /// };
   1319 /// for op in ops.drain_filter(filter) {
   1320 ///     match op {
   1321 ///         Enum::Foo => { foo(); }
   1322 ///         Enum::Bar => { bar(); }
   1323 ///         Enum::Baz => { unreachable!(); }
   1324 ///     }
   1325 /// }
   1326 ///
   1327 /// See https://doc.rust-lang.org/std/vec/struct.Vec.html#method.drain_filter
   1328 pub fn drain_filter<T, Filter, Action>(
   1329    vec: &mut Vec<T>,
   1330    mut filter: Filter,
   1331    mut action: Action,
   1332 )
   1333 where
   1334    Filter: FnMut(&mut T) -> bool,
   1335    Action: FnMut(T)
   1336 {
   1337    let mut i = 0;
   1338    while i != vec.len() {
   1339        if filter(&mut vec[i]) {
   1340            action(vec.remove(i));
   1341        } else {
   1342            i += 1;
   1343        }
   1344    }
   1345 }
   1346 
   1347 
   1348 #[derive(Debug)]
   1349 pub struct Recycler {
   1350    pub num_allocations: usize,
   1351 }
   1352 
   1353 impl Recycler {
   1354    /// Maximum extra capacity that a recycled vector is allowed to have. If the actual capacity
   1355    /// is larger, we re-allocate the vector storage with lower capacity.
   1356    const MAX_EXTRA_CAPACITY_PERCENT: usize = 200;
   1357    /// Minimum extra capacity to keep when re-allocating the vector storage.
   1358    const MIN_EXTRA_CAPACITY_PERCENT: usize = 20;
   1359    /// Minimum sensible vector length to consider for re-allocation.
   1360    const MIN_VECTOR_LENGTH: usize = 16;
   1361 
   1362    pub fn new() -> Self {
   1363        Recycler {
   1364            num_allocations: 0,
   1365        }
   1366    }
   1367 
   1368    /// Clear a vector for re-use, while retaining the backing memory buffer. May shrink the buffer
   1369    /// if it's currently much larger than was actually used.
   1370    pub fn recycle_vec<T>(&mut self, vec: &mut Vec<T>) {
   1371        let extra_capacity = (vec.capacity() - vec.len()) * 100 / vec.len().max(Self::MIN_VECTOR_LENGTH);
   1372 
   1373        if extra_capacity > Self::MAX_EXTRA_CAPACITY_PERCENT {
   1374            // Reduce capacity of the buffer if it is a lot larger than it needs to be. This prevents
   1375            // a frame with exceptionally large allocations to cause subsequent frames to retain
   1376            // more memory than they need.
   1377            //TODO: use `shrink_to` when it's stable
   1378            *vec = Vec::with_capacity(vec.len() + vec.len() * Self::MIN_EXTRA_CAPACITY_PERCENT / 100);
   1379            self.num_allocations += 1;
   1380        } else {
   1381            vec.clear();
   1382        }
   1383    }
   1384 }
   1385 
   1386 /// Record the size of a data structure to preallocate a similar size
   1387 /// at the next frame and avoid growing it too many time.
   1388 #[derive(Copy, Clone, Debug)]
   1389 pub struct Preallocator {
   1390    size: usize,
   1391 }
   1392 
   1393 impl Preallocator {
   1394    pub fn new(initial_size: usize) -> Self {
   1395        Preallocator {
   1396            size: initial_size,
   1397        }
   1398    }
   1399 
   1400    /// Record the size of a vector to preallocate it the next frame.
   1401    pub fn record_vec<T>(&mut self, vec: &[T]) {
   1402        let len = vec.len();
   1403        if len > self.size {
   1404            self.size = len;
   1405        } else {
   1406            self.size = (self.size + len) / 2;
   1407        }
   1408    }
   1409 
   1410    /// The size that we'll preallocate the vector with.
   1411    pub fn preallocation_size(&self) -> usize {
   1412        // Round up to multiple of 16 to avoid small tiny
   1413        // variations causing reallocations.
   1414        (self.size + 15) & !15
   1415    }
   1416 
   1417    /// Preallocate vector storage.
   1418    ///
   1419    /// The preallocated amount depends on the length recorded in the last
   1420    /// record_vec call.
   1421    pub fn preallocate_vec<T>(&self, vec: &mut Vec<T>) {
   1422        let len = vec.len();
   1423        let cap = self.preallocation_size();
   1424        if len < cap {
   1425            vec.reserve(cap - len);
   1426        }
   1427    }
   1428 
   1429    /// Preallocate vector storage.
   1430    ///
   1431    /// The preallocated amount depends on the length recorded in the last
   1432    /// record_vec call.
   1433    pub fn preallocate_framevec<T>(&self, vec: &mut FrameVec<T>) {
   1434        let len = vec.len();
   1435        let cap = self.preallocation_size();
   1436        if len < cap {
   1437            vec.reserve(cap - len);
   1438        }
   1439    }
   1440 }
   1441 
   1442 impl Default for Preallocator {
   1443    fn default() -> Self {
   1444        Self::new(0)
   1445    }
   1446 }
   1447 
   1448 /// Computes the scale factors of this matrix; that is,
   1449 /// the amounts each basis vector is scaled by.
   1450 ///
   1451 /// This code comes from gecko gfx/2d/Matrix.h with the following
   1452 /// modifications:
   1453 ///
   1454 /// * Removed `xMajor` parameter.
   1455 /// * All arithmetics is done with double precision.
   1456 pub fn scale_factors<Src, Dst>(
   1457    mat: &Transform3D<f32, Src, Dst>
   1458 ) -> (f32, f32) {
   1459    let m11 = mat.m11 as f64;
   1460    let m12 = mat.m12 as f64;
   1461    // Determinant is just of the 2D component.
   1462    let det = m11 * mat.m22 as f64 - m12 * mat.m21 as f64;
   1463    if det == 0.0 {
   1464        return (0.0, 0.0);
   1465    }
   1466 
   1467    // ignore mirroring
   1468    let det = det.abs();
   1469 
   1470    let major = (m11 * m11 + m12 * m12).sqrt();
   1471    let minor = if major != 0.0 { det / major } else { 0.0 };
   1472 
   1473    (major as f32, minor as f32)
   1474 }
   1475 
   1476 #[test]
   1477 fn scale_factors_large() {
   1478    // https://bugzilla.mozilla.org/show_bug.cgi?id=1748499
   1479    let mat = Transform3D::<f32, (), ()>::new(
   1480        1.6534229920333123e27, 3.673100922561787e27, 0.0, 0.0,
   1481        -3.673100922561787e27, 1.6534229920333123e27, 0.0, 0.0,
   1482        0.0, 0.0, 1.0, 0.0,
   1483        -828140552192.0, -1771307401216.0, 0.0, 1.0,
   1484    );
   1485    let (major, minor) = scale_factors(&mat);
   1486    assert!(major.is_normal() && minor.is_normal());
   1487 }
   1488 
   1489 /// Clamp scaling factor to a power of two.
   1490 ///
   1491 /// This code comes from gecko gfx/thebes/gfxUtils.cpp with the following
   1492 /// modification:
   1493 ///
   1494 /// * logs are taken in base 2 instead of base e.
   1495 pub fn clamp_to_scale_factor(val: f32, round_down: bool) -> f32 {
   1496    // Arbitary scale factor limitation. We can increase this
   1497    // for better scaling performance at the cost of worse
   1498    // quality.
   1499    const SCALE_RESOLUTION: f32 = 2.0;
   1500 
   1501    // Negative scaling is just a flip and irrelevant to
   1502    // our resolution calculation.
   1503    let val = val.abs();
   1504 
   1505    let (val, inverse) = if val < 1.0 {
   1506        (1.0 / val, true)
   1507    } else {
   1508        (val, false)
   1509    };
   1510 
   1511    let power = val.log2() / SCALE_RESOLUTION.log2();
   1512 
   1513    // If power is within 1e-5 of an integer, round to nearest to
   1514    // prevent floating point errors, otherwise round up to the
   1515    // next integer value.
   1516    let power = if (power - power.round()).abs() < 1e-5 {
   1517        power.round()
   1518    } else if inverse != round_down {
   1519        // Use floor when we are either inverted or rounding down, but
   1520        // not both.
   1521        power.floor()
   1522    } else {
   1523        // Otherwise, ceil when we are not inverted and not rounding
   1524        // down, or we are inverted and rounding down.
   1525        power.ceil()
   1526    };
   1527 
   1528    let scale = SCALE_RESOLUTION.powf(power);
   1529 
   1530    if inverse {
   1531        1.0 / scale
   1532    } else {
   1533        scale
   1534    }
   1535 }
   1536 
   1537 /// Rounds a value up to the nearest multiple of mul
   1538 pub fn round_up_to_multiple(val: usize, mul: NonZeroUsize) -> usize {
   1539    match val % mul.get() {
   1540        0 => val,
   1541        rem => val - rem + mul.get(),
   1542    }
   1543 }
   1544 
   1545 
   1546 #[macro_export]
   1547 macro_rules! c_str {
   1548    ($lit:expr) => {
   1549        unsafe {
   1550            std::ffi::CStr::from_ptr(concat!($lit, "\0").as_ptr()
   1551                                     as *const std::os::raw::c_char)
   1552        }
   1553    }
   1554 }
   1555 
   1556 /// This is inspired by the `weak-table` crate.
   1557 /// It holds a Vec of weak pointers that are garbage collected as the Vec
   1558 pub struct WeakTable {
   1559    inner: Vec<std::sync::Weak<Vec<u8>>>
   1560 }
   1561 
   1562 impl WeakTable {
   1563    pub fn new() -> WeakTable {
   1564        WeakTable { inner: Vec::new() }
   1565    }
   1566    pub fn insert(&mut self, x: std::sync::Weak<Vec<u8>>) {
   1567        if self.inner.len() == self.inner.capacity() {
   1568            self.remove_expired();
   1569 
   1570            // We want to make sure that we change capacity()
   1571            // even if remove_expired() removes some entries
   1572            // so that we don't repeatedly hit remove_expired()
   1573            if self.inner.len() * 3 < self.inner.capacity() {
   1574                // We use a different multiple for shrinking then
   1575                // expanding so that we we don't accidentally
   1576                // oscilate.
   1577                self.inner.shrink_to_fit();
   1578            } else {
   1579                // Otherwise double our size
   1580                self.inner.reserve(self.inner.len())
   1581            }
   1582        }
   1583        self.inner.push(x);
   1584    }
   1585 
   1586    fn remove_expired(&mut self) {
   1587        self.inner.retain(|x| x.strong_count() > 0)
   1588    }
   1589 
   1590    pub fn iter(&self) -> impl Iterator<Item = Arc<Vec<u8>>> + '_ {
   1591        self.inner.iter().filter_map(|x| x.upgrade())
   1592    }
   1593 }
   1594 
   1595 #[test]
   1596 fn weak_table() {
   1597    let mut tbl = WeakTable::new();
   1598    let mut things = Vec::new();
   1599    let target_count = 50;
   1600    for _ in 0..target_count {
   1601        things.push(Arc::new(vec![4]));
   1602    }
   1603    for i in &things {
   1604        tbl.insert(Arc::downgrade(i))
   1605    }
   1606    assert_eq!(tbl.inner.len(), target_count);
   1607    drop(things);
   1608    assert_eq!(tbl.iter().count(), 0);
   1609 
   1610    // make sure that we shrink the table if it gets too big
   1611    // by adding a bunch of dead items
   1612    for _ in 0..target_count*2 {
   1613        tbl.insert(Arc::downgrade(&Arc::new(vec![5])))
   1614    }
   1615    assert!(tbl.inner.capacity() <= 4);
   1616 }
   1617 
   1618 #[test]
   1619 fn scale_offset_pre_post() {
   1620    let a = ScaleOffset::new(1.0, 2.0, 3.0, 4.0);
   1621    let b = ScaleOffset::new(5.0, 6.0, 7.0, 8.0);
   1622 
   1623    assert_eq!(a.then(&b), b.pre_transform(&a));
   1624    assert_eq!(a.then_scale(10.0), a.then(&ScaleOffset::from_scale(Vector2D::new(10.0, 10.0))));
   1625    assert_eq!(a.pre_scale(10.0), a.pre_transform(&ScaleOffset::from_scale(Vector2D::new(10.0, 10.0))));
   1626 }