1use 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
19const NEARLY_ZERO: f32 = 1.0 / 4096.0;
21
22pub struct Allocation<'a, T: 'a> {
25 vec: &'a mut Vec<T>,
26 index: usize,
27}
28
29impl<'a, T> Allocation<'a, T> {
30 #[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
43pub 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 fn alloc(&mut self) -> Allocation<T>;
62 fn entry(&mut self, index: usize) -> VecEntry<T>;
65
66 fn take(&mut self) -> Self;
68
69 fn cleared(self) -> Self;
71
72 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#[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 pub fn from_transform<F, T>(
148 m: &Transform3D<f32, F, T>,
149 ) -> Option<ScaleOffset> {
150
151 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 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 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 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 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 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
368pub trait MatrixHelpers<Src, Dst> {
370 fn preserves_2d_axis_alignment(&self) -> bool;
373 fn has_perspective_component(&self) -> bool;
374 fn has_2d_inverse(&self) -> bool;
375 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 fn determinant_2d(&self) -> f32;
386 fn inverse_project_2d_origin(&self) -> Option<Point2D<f32, Src>>;
390 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 fn inverse_project(&self, target: &Point2D<f32, Dst>) -> Option<Point2D<f32, Src>> {
447 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 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 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 }
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 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
670pub fn extract_inner_rect_safe<U>(
673 rect: &Box2D<f32, U>,
674 radii: &BorderRadius,
675) -> Option<Box2D<f32, U>> {
676 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 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 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 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 let rp = project_rect(&m, &r, &Box2D::from_size(Size2D::new(1000.0, 1000.0))).unwrap();
739 println!("Projected {:?}", rp);
740 assert_eq!(m.inverse_project(&rp.min), None);
742 if let Some(ri) = m.inverse_rect_footprint(&rp) {
744 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 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 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 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 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 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 let rect = LayoutRect::from_size(LayoutSize::new(10.0, 10.0));
920
921 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 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 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 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 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#[derive(Debug, MallocSizeOf)]
993pub enum FastTransform<Src, Dst> {
994 Offset(Vector2D<f32, Src>),
996
997 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 #[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 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 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 .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); homo.to_point2d().unwrap()
1228 })
1229 ))
1230 } else {
1231 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
1250pub 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 const MAX_EXTRA_CAPACITY_PERCENT: usize = 200;
1320 const MIN_EXTRA_CAPACITY_PERCENT: usize = 20;
1322 const MIN_VECTOR_LENGTH: usize = 16;
1324
1325 pub fn new() -> Self {
1326 Recycler {
1327 num_allocations: 0,
1328 }
1329 }
1330
1331 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 *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#[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 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 pub fn preallocation_size(&self) -> usize {
1375 (self.size + 15) & !15
1378 }
1379
1380 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#[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 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
1444pub fn scale_factors<Src, Dst>(
1452 mat: &Transform3D<f32, Src, Dst>
1453) -> (f32, f32) {
1454 let det = mat.m11 * mat.m22 - mat.m12 * mat.m21;
1456 if det == 0.0 {
1457 return (0.0, 0.0);
1458 }
1459
1460 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
1469pub fn clamp_to_scale_factor(val: f32, round_down: bool) -> f32 {
1476 const SCALE_RESOLUTION: f32 = 2.0;
1480
1481 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 let power = if (power - power.round()).abs() < 1e-5 {
1497 power.round()
1498 } else if inverse != round_down {
1499 power.floor()
1502 } else {
1503 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
1517pub 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
1536pub fn conservative_union_rect<U>(r1: &Box2D<f32, U>, r2: &Box2D<f32, U>) -> Box2D<f32, U> {
1538 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 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 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 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 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 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 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 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 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
1672pub 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 if self.inner.len() * 3 < self.inner.capacity() {
1690 self.inner.shrink_to_fit();
1694 } else {
1695 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 for _ in 0..target_count*2 {
1729 tbl.insert(Arc::downgrade(&Arc::new(vec![5])))
1730 }
1731 assert!(tbl.inner.capacity() <= 4);
1732}