azul_webrender/
util.rs

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