1use api::BorderRadius;
6use api::units::*;
7use euclid::{Point2D, Rect, Box2D, Size2D, Vector2D, point2, point3};
8use euclid::{default, Transform2D, Transform3D, Scale, approxeq::ApproxEq};
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
18use crate::internal_types::FrameVec;
19
20const NEARLY_ZERO: f32 = 1.0 / 4096.0;
22
23pub struct Allocation<'a, T: 'a> {
26 vec: &'a mut Vec<T>,
27 index: usize,
28}
29
30impl<'a, T> Allocation<'a, T> {
31 #[inline(always)]
35 pub fn init(self, value: T) -> usize {
36 unsafe {
37 ptr::write(self.vec.as_mut_ptr().add(self.index), value);
38 self.vec.set_len(self.index + 1);
39 }
40 self.index
41 }
42}
43
44pub enum VecEntry<'a, T: 'a> {
46 Vacant(Allocation<'a, T>),
47 Occupied(&'a mut T),
48}
49
50impl<'a, T> VecEntry<'a, T> {
51 #[inline(always)]
52 pub fn set(self, value: T) {
53 match self {
54 VecEntry::Vacant(alloc) => { alloc.init(value); }
55 VecEntry::Occupied(slot) => { *slot = value; }
56 }
57 }
58}
59
60pub trait VecHelper<T> {
61 fn alloc(&mut self) -> Allocation<T>;
63 fn entry(&mut self, index: usize) -> VecEntry<T>;
66
67 fn take(&mut self) -> Self;
69
70 fn take_and_preallocate(&mut self) -> Self;
74}
75
76impl<T> VecHelper<T> for Vec<T> {
77 fn alloc(&mut self) -> Allocation<T> {
78 let index = self.len();
79 if self.capacity() == index {
80 self.reserve(1);
81 }
82 Allocation {
83 vec: self,
84 index,
85 }
86 }
87
88 fn entry(&mut self, index: usize) -> VecEntry<T> {
89 if index < self.len() {
90 VecEntry::Occupied(unsafe {
91 self.get_unchecked_mut(index)
92 })
93 } else {
94 assert_eq!(index, self.len());
95 VecEntry::Vacant(self.alloc())
96 }
97 }
98
99 fn take(&mut self) -> Self {
100 replace(self, Vec::new())
101 }
102
103 fn take_and_preallocate(&mut self) -> Self {
104 let len = self.len();
105 if len == 0 {
106 self.clear();
107 return Vec::new();
108 }
109 replace(self, Vec::with_capacity(len + 8))
110 }
111}
112
113#[repr(C)]
121#[derive(Debug, Clone, Copy, MallocSizeOf, PartialEq)]
122#[cfg_attr(feature = "capture", derive(Serialize))]
123#[cfg_attr(feature = "replay", derive(Deserialize))]
124pub struct ScaleOffset {
125 pub scale: euclid::Vector2D<f32, euclid::UnknownUnit>,
126 pub offset: euclid::Vector2D<f32, euclid::UnknownUnit>,
127}
128
129impl ScaleOffset {
130 pub fn new(sx: f32, sy: f32, tx: f32, ty: f32) -> Self {
131 ScaleOffset {
132 scale: Vector2D::new(sx, sy),
133 offset: Vector2D::new(tx, ty),
134 }
135 }
136
137 pub fn identity() -> Self {
138 ScaleOffset {
139 scale: Vector2D::new(1.0, 1.0),
140 offset: Vector2D::zero(),
141 }
142 }
143
144 pub fn from_transform<F, T>(
147 m: &Transform3D<f32, F, T>,
148 ) -> Option<ScaleOffset> {
149
150 if m.m12.abs() > NEARLY_ZERO ||
156 m.m13.abs() > NEARLY_ZERO ||
157 m.m14.abs() > NEARLY_ZERO ||
158 m.m21.abs() > NEARLY_ZERO ||
159 m.m23.abs() > NEARLY_ZERO ||
160 m.m24.abs() > NEARLY_ZERO ||
161 m.m31.abs() > NEARLY_ZERO ||
162 m.m32.abs() > NEARLY_ZERO ||
163 (m.m33 - 1.0).abs() > NEARLY_ZERO ||
164 m.m34.abs() > NEARLY_ZERO ||
165 m.m43.abs() > NEARLY_ZERO ||
166 (m.m44 - 1.0).abs() > NEARLY_ZERO {
167 return None;
168 }
169
170 Some(ScaleOffset {
171 scale: Vector2D::new(m.m11, m.m22),
172 offset: Vector2D::new(m.m41, m.m42),
173 })
174 }
175
176 pub fn from_offset(offset: default::Vector2D<f32>) -> Self {
177 ScaleOffset {
178 scale: Vector2D::new(1.0, 1.0),
179 offset,
180 }
181 }
182
183 pub fn from_scale(scale: default::Vector2D<f32>) -> Self {
184 ScaleOffset {
185 scale,
186 offset: Vector2D::new(0.0, 0.0),
187 }
188 }
189
190 pub fn inverse(&self) -> Self {
191 if self.scale.x.approx_eq(&0.0) || self.scale.y.approx_eq(&0.0) {
196 return ScaleOffset::new(0.0, 0.0, 0.0, 0.0);
197 }
198
199 ScaleOffset {
200 scale: Vector2D::new(
201 1.0 / self.scale.x,
202 1.0 / self.scale.y,
203 ),
204 offset: Vector2D::new(
205 -self.offset.x / self.scale.x,
206 -self.offset.y / self.scale.y,
207 ),
208 }
209 }
210
211 pub fn pre_offset(&self, offset: default::Vector2D<f32>) -> Self {
212 self.pre_transform(
213 &ScaleOffset {
214 scale: Vector2D::new(1.0, 1.0),
215 offset,
216 }
217 )
218 }
219
220 pub fn pre_scale(&self, scale: f32) -> Self {
221 ScaleOffset {
222 scale: self.scale * scale,
223 offset: self.offset,
224 }
225 }
226
227 pub fn then_scale(&self, scale: f32) -> Self {
228 ScaleOffset {
229 scale: self.scale * scale,
230 offset: self.offset * scale,
231 }
232 }
233
234 pub fn pre_transform(&self, other: &ScaleOffset) -> Self {
238 ScaleOffset {
239 scale: Vector2D::new(
240 self.scale.x * other.scale.x,
241 self.scale.y * other.scale.y,
242 ),
243 offset: Vector2D::new(
244 self.offset.x + self.scale.x * other.offset.x,
245 self.offset.y + self.scale.y * other.offset.y,
246 ),
247 }
248 }
249
250 #[allow(unused)]
254 pub fn then(&self, other: &ScaleOffset) -> Self {
255 ScaleOffset {
256 scale: Vector2D::new(
257 self.scale.x * other.scale.x,
258 self.scale.y * other.scale.y,
259 ),
260 offset: Vector2D::new(
261 other.scale.x * self.offset.x + other.offset.x,
262 other.scale.y * self.offset.y + other.offset.y,
263 ),
264 }
265 }
266
267
268 pub fn map_rect<F, T>(&self, rect: &Box2D<f32, F>) -> Box2D<f32, T> {
269 let w = rect.width().max(0.0);
278 let h = rect.height().max(0.0);
279
280 let mut x0 = rect.min.x * self.scale.x + self.offset.x;
281 let mut y0 = rect.min.y * self.scale.y + self.offset.y;
282
283 let mut sx = w * self.scale.x;
284 let mut sy = h * self.scale.y;
285 if self.scale.x < 0.0 {
292 x0 += sx;
293 sx = -sx;
294 }
295 if self.scale.y < 0.0 {
296 y0 += sy;
297 sy = -sy;
298 }
299
300 Box2D::from_origin_and_size(
301 Point2D::new(x0, y0),
302 Size2D::new(sx, sy),
303 )
304 }
305
306 pub fn unmap_rect<F, T>(&self, rect: &Box2D<f32, F>) -> Box2D<f32, T> {
307 let w = rect.width().max(0.0);
316 let h = rect.height().max(0.0);
317
318 let mut x0 = (rect.min.x - self.offset.x) / self.scale.x;
319 let mut y0 = (rect.min.y - self.offset.y) / self.scale.y;
320
321 let mut sx = w / self.scale.x;
322 let mut sy = h / self.scale.y;
323
324 if self.scale.x < 0.0 {
331 x0 += sx;
332 sx = -sx;
333 }
334 if self.scale.y < 0.0 {
335 y0 += sy;
336 sy = -sy;
337 }
338
339 Box2D::from_origin_and_size(
340 Point2D::new(x0, y0),
341 Size2D::new(sx, sy),
342 )
343 }
344
345 pub fn map_vector<F, T>(&self, vector: &Vector2D<f32, F>) -> Vector2D<f32, T> {
346 Vector2D::new(
347 vector.x * self.scale.x,
348 vector.y * self.scale.y,
349 )
350 }
351
352 pub fn map_size<F, T>(&self, size: &Size2D<f32, F>) -> Size2D<f32, T> {
353 Size2D::new(
354 size.width * self.scale.x,
355 size.height * self.scale.y,
356 )
357 }
358
359 pub fn unmap_vector<F, T>(&self, vector: &Vector2D<f32, F>) -> Vector2D<f32, T> {
360 Vector2D::new(
361 vector.x / self.scale.x,
362 vector.y / self.scale.y,
363 )
364 }
365
366 pub fn map_point<F, T>(&self, point: &Point2D<f32, F>) -> Point2D<f32, T> {
367 Point2D::new(
368 point.x * self.scale.x + self.offset.x,
369 point.y * self.scale.y + self.offset.y,
370 )
371 }
372
373 pub fn unmap_point<F, T>(&self, point: &Point2D<f32, F>) -> Point2D<f32, T> {
374 Point2D::new(
375 (point.x - self.offset.x) / self.scale.x,
376 (point.y - self.offset.y) / self.scale.y,
377 )
378 }
379
380 pub fn to_transform<F, T>(&self) -> Transform3D<f32, F, T> {
381 Transform3D::new(
382 self.scale.x,
383 0.0,
384 0.0,
385 0.0,
386
387 0.0,
388 self.scale.y,
389 0.0,
390 0.0,
391
392 0.0,
393 0.0,
394 1.0,
395 0.0,
396
397 self.offset.x,
398 self.offset.y,
399 0.0,
400 1.0,
401 )
402 }
403}
404
405pub trait MatrixHelpers<Src, Dst> {
407 fn preserves_2d_axis_alignment(&self) -> bool;
410 fn has_perspective_component(&self) -> bool;
411 fn has_2d_inverse(&self) -> bool;
412 fn exceeds_2d_scale(&self, limit: f64) -> bool;
415 fn inverse_project(&self, target: &Point2D<f32, Dst>) -> Option<Point2D<f32, Src>>;
416 fn inverse_rect_footprint(&self, rect: &Box2D<f32, Dst>) -> Option<Box2D<f32, Src>>;
417 fn transform_kind(&self) -> TransformedRectKind;
418 fn is_simple_translation(&self) -> bool;
419 fn is_simple_2d_translation(&self) -> bool;
420 fn is_2d_scale_translation(&self) -> bool;
421 fn determinant_2d(&self) -> f32;
423 fn flatten_z_output(&mut self);
426
427 fn cast_unit<NewSrc, NewDst>(&self) -> Transform3D<f32, NewSrc, NewDst>;
428}
429
430impl<Src, Dst> MatrixHelpers<Src, Dst> for Transform3D<f32, Src, Dst> {
431 fn preserves_2d_axis_alignment(&self) -> bool {
432 if self.m14 != 0.0 || self.m24 != 0.0 {
433 return false;
434 }
435
436 let mut col0 = 0;
437 let mut col1 = 0;
438 let mut row0 = 0;
439 let mut row1 = 0;
440
441 if self.m11.abs() > NEARLY_ZERO {
442 col0 += 1;
443 row0 += 1;
444 }
445 if self.m12.abs() > NEARLY_ZERO {
446 col1 += 1;
447 row0 += 1;
448 }
449 if self.m21.abs() > NEARLY_ZERO {
450 col0 += 1;
451 row1 += 1;
452 }
453 if self.m22.abs() > NEARLY_ZERO {
454 col1 += 1;
455 row1 += 1;
456 }
457
458 col0 < 2 && col1 < 2 && row0 < 2 && row1 < 2
459 }
460
461 fn has_perspective_component(&self) -> bool {
462 self.m14.abs() > NEARLY_ZERO ||
463 self.m24.abs() > NEARLY_ZERO ||
464 self.m34.abs() > NEARLY_ZERO ||
465 (self.m44 - 1.0).abs() > NEARLY_ZERO
466 }
467
468 fn has_2d_inverse(&self) -> bool {
469 self.determinant_2d() != 0.0
470 }
471
472 fn exceeds_2d_scale(&self, limit: f64) -> bool {
473 let limit2 = (limit * limit) as f32;
474 self.m11 * self.m11 + self.m12 * self.m12 > limit2 ||
475 self.m21 * self.m21 + self.m22 * self.m22 > limit2
476 }
477
478 fn inverse_project(&self, target: &Point2D<f32, Dst>) -> Option<Point2D<f32, Src>> {
480 let m = Transform2D::<f32, Src, Dst>::new(
482 self.m11 - target.x * self.m14, self.m12 - target.y * self.m14,
483 self.m21 - target.x * self.m24, self.m22 - target.y * self.m24,
484 self.m41 - target.x * self.m44, self.m42 - target.y * self.m44,
485 );
486 let inv = m.inverse()?;
487 if inv.m31 * self.m14 + inv.m32 * self.m24 + self.m44 > 0.0 {
489 Some(Point2D::new(inv.m31, inv.m32))
490 } else {
491 None
492 }
493 }
494
495 fn inverse_rect_footprint(&self, rect: &Box2D<f32, Dst>) -> Option<Box2D<f32, Src>> {
496 Some(Box2D::from_points(&[
497 self.inverse_project(&rect.top_left())?,
498 self.inverse_project(&rect.top_right())?,
499 self.inverse_project(&rect.bottom_left())?,
500 self.inverse_project(&rect.bottom_right())?,
501 ]))
502 }
503
504 fn transform_kind(&self) -> TransformedRectKind {
505 if self.preserves_2d_axis_alignment() {
506 TransformedRectKind::AxisAligned
507 } else {
508 TransformedRectKind::Complex
509 }
510 }
511
512 fn is_simple_translation(&self) -> bool {
513 if (self.m11 - 1.0).abs() > NEARLY_ZERO ||
514 (self.m22 - 1.0).abs() > NEARLY_ZERO ||
515 (self.m33 - 1.0).abs() > NEARLY_ZERO ||
516 (self.m44 - 1.0).abs() > NEARLY_ZERO {
517 return false;
518 }
519
520 self.m12.abs() < NEARLY_ZERO && self.m13.abs() < NEARLY_ZERO &&
521 self.m14.abs() < NEARLY_ZERO && self.m21.abs() < NEARLY_ZERO &&
522 self.m23.abs() < NEARLY_ZERO && self.m24.abs() < NEARLY_ZERO &&
523 self.m31.abs() < NEARLY_ZERO && self.m32.abs() < NEARLY_ZERO &&
524 self.m34.abs() < NEARLY_ZERO
525 }
526
527 fn is_simple_2d_translation(&self) -> bool {
528 if !self.is_simple_translation() {
529 return false;
530 }
531
532 self.m43.abs() < NEARLY_ZERO
533 }
534
535 fn is_2d_scale_translation(&self) -> bool {
542 (self.m33 - 1.0).abs() < NEARLY_ZERO &&
543 (self.m44 - 1.0).abs() < NEARLY_ZERO &&
544 self.m12.abs() < NEARLY_ZERO && self.m13.abs() < NEARLY_ZERO && self.m14.abs() < NEARLY_ZERO &&
545 self.m21.abs() < NEARLY_ZERO && self.m23.abs() < NEARLY_ZERO && self.m24.abs() < NEARLY_ZERO &&
546 self.m31.abs() < NEARLY_ZERO && self.m32.abs() < NEARLY_ZERO && self.m34.abs() < NEARLY_ZERO &&
547 self.m43.abs() < NEARLY_ZERO
548 }
549
550 fn determinant_2d(&self) -> f32 {
551 self.m11 * self.m22 - self.m12 * self.m21
552 }
553
554 fn flatten_z_output(&mut self) {
555 self.m13 = 0.0;
556 self.m23 = 0.0;
557 self.m33 = 1.0;
558 self.m43 = 0.0;
559 }
561
562 fn cast_unit<NewSrc, NewDst>(&self) -> Transform3D<f32, NewSrc, NewDst> {
563 Transform3D::new(
564 self.m11, self.m12, self.m13, self.m14,
565 self.m21, self.m22, self.m23, self.m24,
566 self.m31, self.m32, self.m33, self.m34,
567 self.m41, self.m42, self.m43, self.m44,
568 )
569 }
570}
571
572pub trait PointHelpers<U>
573where
574 Self: Sized,
575{
576 fn snap(&self) -> Self;
577}
578
579impl<U> PointHelpers<U> for Point2D<f32, U> {
580 fn snap(&self) -> Self {
581 Point2D::new(
582 (self.x + 0.5).floor(),
583 (self.y + 0.5).floor(),
584 )
585 }
586}
587
588pub trait RectHelpers<U>
589where
590 Self: Sized,
591{
592 fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self;
593 fn snap(&self) -> Self;
594}
595
596impl<U> RectHelpers<U> for Rect<f32, U> {
597 fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self {
598 Rect::new(
599 Point2D::new(x0, y0),
600 Size2D::new(x1 - x0, y1 - y0),
601 )
602 }
603
604 fn snap(&self) -> Self {
605 let origin = Point2D::new(
606 (self.origin.x + 0.5).floor(),
607 (self.origin.y + 0.5).floor(),
608 );
609 Rect::new(
610 origin,
611 Size2D::new(
612 (self.origin.x + self.size.width + 0.5).floor() - origin.x,
613 (self.origin.y + self.size.height + 0.5).floor() - origin.y,
614 ),
615 )
616 }
617}
618
619impl<U> RectHelpers<U> for Box2D<f32, U> {
620 fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self {
621 Box2D {
622 min: Point2D::new(x0, y0),
623 max: Point2D::new(x1, y1),
624 }
625 }
626
627 fn snap(&self) -> Self {
628 self.round()
629 }
630}
631
632pub fn lerp(a: f32, b: f32, t: f32) -> f32 {
633 (b - a) * t + a
634}
635
636#[repr(u32)]
637#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
638#[cfg_attr(feature = "capture", derive(Serialize))]
639#[cfg_attr(feature = "replay", derive(Deserialize))]
640pub enum TransformedRectKind {
641 AxisAligned = 0,
642 Complex = 1,
643}
644
645#[inline(always)]
646pub fn pack_as_float(value: u32) -> f32 {
647 value as f32 + 0.5
648}
649
650#[inline]
651fn extract_inner_rect_impl<U>(
652 rect: &Box2D<f32, U>,
653 radii: &BorderRadius,
654 k: f32,
655) -> Option<Box2D<f32, U>> {
656 let xl = (k * radii.top_left.width.max(radii.bottom_left.width)).ceil();
661 let xr = (rect.width() - k * radii.top_right.width.max(radii.bottom_right.width)).floor();
662 let yt = (k * radii.top_left.height.max(radii.top_right.height)).ceil();
663 let yb =
664 (rect.height() - k * radii.bottom_left.height.max(radii.bottom_right.height)).floor();
665
666 if xl <= xr && yt <= yb {
667 Some(Box2D::from_origin_and_size(
668 Point2D::new(rect.min.x + xl, rect.min.y + yt),
669 Size2D::new(xr - xl, yb - yt),
670 ))
671 } else {
672 None
673 }
674}
675
676pub fn extract_inner_rect_safe<U>(
679 rect: &Box2D<f32, U>,
680 radii: &BorderRadius,
681) -> Option<Box2D<f32, U>> {
682 extract_inner_rect_impl(rect, radii, 1.0)
685}
686
687pub fn extract_inner_rect_k<U>(
691 rect: &Box2D<f32, U>,
692 radii: &BorderRadius,
693 k: f32,
694) -> Option<Box2D<f32, U>> {
695 extract_inner_rect_impl(rect, radii, k)
696}
697
698#[cfg(test)]
699use euclid::vec3;
700
701#[cfg(test)]
702pub mod test {
703 use super::*;
704 use euclid::default::{Point2D, Size2D, Transform3D};
705 use euclid::{Angle, approxeq::ApproxEq};
706 use std::f32::consts::PI;
707 use crate::clip::{is_left_of_line, polygon_contains_point};
708 use crate::prim_store::PolygonKey;
709 use api::FillRule;
710
711 #[test]
712 fn inverse_project() {
713 let m0 = Transform3D::identity();
714 let p0 = Point2D::new(1.0, 2.0);
715 assert_eq!(m0.inverse_project(&p0), Some(p0));
717 let m1 = Transform3D::rotation(0.0, 1.0, 0.0, Angle::radians(-PI / 3.0));
718 assert_eq!(m1.inverse_project(&p0), Some(Point2D::new(2.0, 2.0)));
720 }
721
722 #[test]
723 fn inverse_project_footprint() {
724 let m = Transform3D::new(
725 0.477499992, 0.135000005, -1.0, 0.000624999986,
726 -0.642787635, 0.766044438, 0.0, 0.0,
727 0.766044438, 0.642787635, 0.0, 0.0,
728 1137.10986, 113.71286, 402.0, 0.748749971,
729 );
730 let r = Box2D::from_size(Size2D::new(804.0, 804.0));
731 {
732 let points = &[
733 r.top_left(),
734 r.top_right(),
735 r.bottom_left(),
736 r.bottom_right(),
737 ];
738 let mi = m.inverse().unwrap();
739 info!("Points:");
743 for p in points {
744 let pp = m.transform_point2d_homogeneous(*p);
745 let p3 = pp.to_point3d().unwrap();
746 let pi = mi.transform_point3d_homogeneous(p3);
747 let px = pi.to_point2d().unwrap();
748 let py = m.inverse_project(&pp.to_point2d().unwrap()).unwrap();
749 info!("\t{:?} -> {:?} -> {:?} -> ({:?} -> {:?}, {:?})", p, pp, p3, pi, px, py);
750 assert!(px.approx_eq_eps(p, &Point2D::new(0.001, 0.001)));
751 assert!(py.approx_eq_eps(p, &Point2D::new(0.001, 0.001)));
752 }
753 }
754 let rp = project_rect(&m, &r, &Box2D::from_size(Size2D::new(1000.0, 1000.0))).unwrap();
756 info!("Projected {:?}", rp);
757 assert_eq!(m.inverse_project(&rp.min), None);
759 if let Some(ri) = m.inverse_rect_footprint(&rp) {
761 assert!(ri.contains_box(&r), "Inverse {:?}", ri);
763 }
764 }
765
766 fn validate_convert(xref: &LayoutTransform) {
767 let so = ScaleOffset::from_transform(xref).unwrap();
768 let xf = so.to_transform();
769 assert!(xref.approx_eq(&xf));
770 }
771
772 #[test]
773 fn negative_scale_map_unmap() {
774 let xref = LayoutTransform::scale(1.0, -1.0, 1.0)
775 .pre_translate(LayoutVector3D::new(124.0, 38.0, 0.0));
776 let so = ScaleOffset::from_transform(&xref).unwrap();
777 let local_rect = Box2D {
778 min: LayoutPoint::new(50.0, -100.0),
779 max: LayoutPoint::new(250.0, 300.0),
780 };
781
782 let mapped_rect = so.map_rect::<LayoutPixel, DevicePixel>(&local_rect);
783 let xf_rect = project_rect(
784 &xref,
785 &local_rect,
786 &LayoutRect::max_rect(),
787 ).unwrap();
788
789 assert!(mapped_rect.min.x.approx_eq(&xf_rect.min.x));
790 assert!(mapped_rect.min.y.approx_eq(&xf_rect.min.y));
791 assert!(mapped_rect.max.x.approx_eq(&xf_rect.max.x));
792 assert!(mapped_rect.max.y.approx_eq(&xf_rect.max.y));
793
794 let unmapped_rect = so.unmap_rect::<DevicePixel, LayoutPixel>(&mapped_rect);
795 assert!(unmapped_rect.min.x.approx_eq(&local_rect.min.x));
796 assert!(unmapped_rect.min.y.approx_eq(&local_rect.min.y));
797 assert!(unmapped_rect.max.x.approx_eq(&local_rect.max.x));
798 assert!(unmapped_rect.max.y.approx_eq(&local_rect.max.y));
799 }
800
801 #[test]
802 fn scale_offset_convert() {
803 let xref = LayoutTransform::translation(130.0, 200.0, 0.0);
804 validate_convert(&xref);
805
806 let xref = LayoutTransform::scale(13.0, 8.0, 1.0);
807 validate_convert(&xref);
808
809 let xref = LayoutTransform::scale(0.5, 0.5, 1.0)
810 .pre_translate(LayoutVector3D::new(124.0, 38.0, 0.0));
811 validate_convert(&xref);
812
813 let xref = LayoutTransform::scale(30.0, 11.0, 1.0)
814 .then_translate(vec3(50.0, 240.0, 0.0));
815 validate_convert(&xref);
816 }
817
818 fn validate_inverse(xref: &LayoutTransform) {
819 let s0 = ScaleOffset::from_transform(xref).unwrap();
820 let s1 = s0.inverse().pre_transform(&s0);
821 assert!((s1.scale.x - 1.0).abs() < NEARLY_ZERO &&
822 (s1.scale.y - 1.0).abs() < NEARLY_ZERO &&
823 s1.offset.x.abs() < NEARLY_ZERO &&
824 s1.offset.y.abs() < NEARLY_ZERO,
825 "{:?}",
826 s1);
827 }
828
829 #[test]
830 fn scale_offset_inverse() {
831 let xref = LayoutTransform::translation(130.0, 200.0, 0.0);
832 validate_inverse(&xref);
833
834 let xref = LayoutTransform::scale(13.0, 8.0, 1.0);
835 validate_inverse(&xref);
836
837 let xref = LayoutTransform::translation(124.0, 38.0, 0.0).
838 then_scale(0.5, 0.5, 1.0);
839
840 validate_inverse(&xref);
841
842 let xref = LayoutTransform::scale(30.0, 11.0, 1.0)
843 .then_translate(vec3(50.0, 240.0, 0.0));
844 validate_inverse(&xref);
845 }
846
847 fn validate_accumulate(x0: &LayoutTransform, x1: &LayoutTransform) {
848 let x = x1.then(&x0);
849
850 let s0 = ScaleOffset::from_transform(x0).unwrap();
851 let s1 = ScaleOffset::from_transform(x1).unwrap();
852
853 let s = s0.pre_transform(&s1).to_transform();
854
855 assert!(x.approx_eq(&s), "{:?}\n{:?}", x, s);
856 }
857
858 #[test]
859 fn scale_offset_accumulate() {
860 let x0 = LayoutTransform::translation(130.0, 200.0, 0.0);
861 let x1 = LayoutTransform::scale(7.0, 3.0, 1.0);
862
863 validate_accumulate(&x0, &x1);
864 }
865
866 #[test]
867 fn scale_offset_invalid_scale() {
868 let s0 = ScaleOffset::new(0.0, 1.0, 10.0, 20.0);
869 let i0 = s0.inverse();
870 assert_eq!(i0, ScaleOffset::new(0.0, 0.0, 0.0, 0.0));
871
872 let s1 = ScaleOffset::new(1.0, 0.0, 10.0, 20.0);
873 let i1 = s1.inverse();
874 assert_eq!(i1, ScaleOffset::new(0.0, 0.0, 0.0, 0.0));
875 }
876
877 #[test]
878 fn polygon_clip_is_left_of_point() {
879 let p0_x = 1.0;
885 let p0_y = -3.0;
886 let p1_x = -2.0;
887 let p1_y = 6.0;
888
889 assert!(is_left_of_line(-9.0, 0.0, p0_x, p0_y, p1_x, p1_y) > 0.0);
891 assert!(is_left_of_line(-1.0, 1.0, p0_x, p0_y, p1_x, p1_y) > 0.0);
892 assert!(is_left_of_line(1.0, -4.0, p0_x, p0_y, p1_x, p1_y) > 0.0);
893
894 assert!(is_left_of_line(-3.0, 9.0, p0_x, p0_y, p1_x, p1_y) == 0.0);
896 assert!(is_left_of_line(0.0, 0.0, p0_x, p0_y, p1_x, p1_y) == 0.0);
897 assert!(is_left_of_line(100.0, -300.0, p0_x, p0_y, p1_x, p1_y) == 0.0);
898
899 assert!(is_left_of_line(0.0, 1.0, p0_x, p0_y, p1_x, p1_y) < 0.0);
901 assert!(is_left_of_line(-4.0, 13.0, p0_x, p0_y, p1_x, p1_y) < 0.0);
902 assert!(is_left_of_line(5.0, -12.0, p0_x, p0_y, p1_x, p1_y) < 0.0);
903 }
904
905 #[test]
906 fn polygon_clip_contains_point() {
907 let p0 = LayoutPoint::new(4.0, 4.0);
910 let p1 = LayoutPoint::new(6.0, 4.0);
911 let p2 = LayoutPoint::new(4.0, 7.0);
912 let p3 = LayoutPoint::new(2.0, 1.0);
913 let p4 = LayoutPoint::new(8.0, 1.0);
914 let p5 = LayoutPoint::new(6.0, 7.0);
915
916 let poly_clockwise_nonzero = PolygonKey::new(
917 &[p5, p4, p3, p2, p1, p0].to_vec(), FillRule::Nonzero
918 );
919 let poly_clockwise_evenodd = PolygonKey::new(
920 &[p5, p4, p3, p2, p1, p0].to_vec(), FillRule::Evenodd
921 );
922 let poly_counter_clockwise_nonzero = PolygonKey::new(
923 &[p0, p1, p2, p3, p4, p5].to_vec(), FillRule::Nonzero
924 );
925 let poly_counter_clockwise_evenodd = PolygonKey::new(
926 &[p0, p1, p2, p3, p4, p5].to_vec(), FillRule::Evenodd
927 );
928
929 let rect = LayoutRect::from_size(LayoutSize::new(10.0, 10.0));
932
933 let p_inside_once = LayoutPoint::new(5.0, 3.0);
935 let p_inside_twice = LayoutPoint::new(5.0, 5.0);
936 let p_outside = LayoutPoint::new(9.0, 9.0);
937
938 for poly_nonzero in vec![poly_clockwise_nonzero, poly_counter_clockwise_nonzero].iter() {
942 assert_eq!(polygon_contains_point(&p_inside_once, &rect, &poly_nonzero), true);
943 assert_eq!(polygon_contains_point(&p_inside_twice, &rect, &poly_nonzero), true);
944 assert_eq!(polygon_contains_point(&p_outside, &rect, &poly_nonzero), false);
945 }
946 for poly_evenodd in vec![poly_clockwise_evenodd, poly_counter_clockwise_evenodd].iter() {
948 assert_eq!(polygon_contains_point(&p_inside_once, &rect, &poly_evenodd), true);
949 assert_eq!(polygon_contains_point(&p_inside_twice, &rect, &poly_evenodd), false);
950 assert_eq!(polygon_contains_point(&p_outside, &rect, &poly_evenodd), false);
951 }
952 }
953}
954
955pub trait MaxRect {
956 fn max_rect() -> Self;
957}
958
959impl MaxRect for DeviceIntRect {
960 fn max_rect() -> Self {
961 DeviceIntRect::from_origin_and_size(
962 DeviceIntPoint::new(i32::MIN / 2, i32::MIN / 2),
963 DeviceIntSize::new(i32::MAX, i32::MAX),
964 )
965 }
966}
967
968impl<U> MaxRect for Rect<f32, U> {
969 fn max_rect() -> Self {
970 const MAX_COORD: f32 = 1.0e9;
977
978 Rect::new(
979 Point2D::new(-MAX_COORD, -MAX_COORD),
980 Size2D::new(2.0 * MAX_COORD, 2.0 * MAX_COORD),
981 )
982 }
983}
984
985impl<U> MaxRect for Box2D<f32, U> {
986 fn max_rect() -> Self {
987 const MAX_COORD: f32 = 1.0e9;
994
995 Box2D::new(
996 Point2D::new(-MAX_COORD, -MAX_COORD),
997 Point2D::new(MAX_COORD, MAX_COORD),
998 )
999 }
1000}
1001
1002#[derive(Debug, MallocSizeOf)]
1005#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1006pub enum FastTransform<Src, Dst> {
1007 Offset(Vector2D<f32, Src>),
1009
1010 Transform {
1012 transform: Transform3D<f32, Src, Dst>,
1013 inverse: Option<Transform3D<f32, Dst, Src>>,
1014 is_2d: bool,
1015 },
1016}
1017
1018impl<Src, Dst> Clone for FastTransform<Src, Dst> {
1019 fn clone(&self) -> Self {
1020 *self
1021 }
1022}
1023
1024impl<Src, Dst> Copy for FastTransform<Src, Dst> { }
1025
1026impl<Src, Dst> Default for FastTransform<Src, Dst> {
1027 fn default() -> Self {
1028 Self::identity()
1029 }
1030}
1031
1032impl<Src, Dst> FastTransform<Src, Dst> {
1033 pub fn identity() -> Self {
1034 FastTransform::Offset(Vector2D::zero())
1035 }
1036
1037 pub fn with_vector(offset: Vector2D<f32, Src>) -> Self {
1038 FastTransform::Offset(offset)
1039 }
1040
1041 pub fn with_scale_offset(scale_offset: ScaleOffset) -> Self {
1042 if scale_offset.scale == Vector2D::new(1.0, 1.0) {
1043 FastTransform::Offset(Vector2D::from_untyped(scale_offset.offset))
1044 } else {
1045 FastTransform::Transform {
1046 transform: scale_offset.to_transform(),
1047 inverse: Some(scale_offset.inverse().to_transform()),
1048 is_2d: true,
1049 }
1050 }
1051 }
1052
1053 #[inline(always)]
1054 pub fn with_transform(transform: Transform3D<f32, Src, Dst>) -> Self {
1055 if transform.is_simple_2d_translation() {
1056 return FastTransform::Offset(Vector2D::new(transform.m41, transform.m42));
1057 }
1058 let inverse = transform.inverse();
1059 let is_2d = transform.is_2d();
1060 FastTransform::Transform { transform, inverse, is_2d}
1061 }
1062
1063 pub fn to_transform(&self) -> Cow<Transform3D<f32, Src, Dst>> {
1064 match *self {
1065 FastTransform::Offset(offset) => Cow::Owned(
1066 Transform3D::translation(offset.x, offset.y, 0.0)
1067 ),
1068 FastTransform::Transform { ref transform, .. } => Cow::Borrowed(transform),
1069 }
1070 }
1071
1072 #[allow(unused)]
1074 pub fn is_identity(&self)-> bool {
1075 match *self {
1076 FastTransform::Offset(offset) => {
1077 offset == Vector2D::zero()
1078 }
1079 FastTransform::Transform { ref transform, .. } => {
1080 *transform == Transform3D::identity()
1081 }
1082 }
1083 }
1084
1085 pub fn then<NewDst>(&self, other: &FastTransform<Dst, NewDst>) -> FastTransform<Src, NewDst> {
1086 match *self {
1087 FastTransform::Offset(offset) => match *other {
1088 FastTransform::Offset(other_offset) => {
1089 FastTransform::Offset(offset + other_offset * Scale::<_, _, Src>::new(1.0))
1090 }
1091 FastTransform::Transform { transform: ref other_transform, .. } => {
1092 FastTransform::with_transform(
1093 other_transform
1094 .with_source::<Src>()
1095 .pre_translate(offset.to_3d())
1096 )
1097 }
1098 }
1099 FastTransform::Transform { ref transform, ref inverse, is_2d } => match *other {
1100 FastTransform::Offset(other_offset) => {
1101 FastTransform::with_transform(
1102 transform
1103 .then_translate(other_offset.to_3d())
1104 .with_destination::<NewDst>()
1105 )
1106 }
1107 FastTransform::Transform { transform: ref other_transform, inverse: ref other_inverse, is_2d: other_is_2d } => {
1108 FastTransform::Transform {
1109 transform: transform.then(other_transform),
1110 inverse: inverse.as_ref().and_then(|self_inv|
1111 other_inverse.as_ref().map(|other_inv| other_inv.then(self_inv))
1112 ),
1113 is_2d: is_2d & other_is_2d,
1114 }
1115 }
1116 }
1117 }
1118 }
1119
1120 pub fn pre_transform<NewSrc>(
1121 &self,
1122 other: &FastTransform<NewSrc, Src>
1123 ) -> FastTransform<NewSrc, Dst> {
1124 other.then(self)
1125 }
1126
1127 pub fn pre_translate(&self, other_offset: Vector2D<f32, Src>) -> Self {
1128 match *self {
1129 FastTransform::Offset(offset) =>
1130 FastTransform::Offset(offset + other_offset),
1131 FastTransform::Transform { transform, .. } =>
1132 FastTransform::with_transform(transform.pre_translate(other_offset.to_3d()))
1133 }
1134 }
1135
1136 pub fn then_translate(&self, other_offset: Vector2D<f32, Dst>) -> Self {
1137 match *self {
1138 FastTransform::Offset(offset) => {
1139 FastTransform::Offset(offset + other_offset * Scale::<_, _, Src>::new(1.0))
1140 }
1141 FastTransform::Transform { ref transform, .. } => {
1142 let transform = transform.then_translate(other_offset.to_3d());
1143 FastTransform::with_transform(transform)
1144 }
1145 }
1146 }
1147
1148 #[inline(always)]
1149 pub fn is_backface_visible(&self) -> bool {
1150 match *self {
1151 FastTransform::Offset(..) => false,
1152 FastTransform::Transform { inverse: None, .. } => false,
1153 FastTransform::Transform { inverse: Some(ref inverse), .. } => inverse.m33 < 0.0,
1156 }
1157 }
1158
1159 #[inline(always)]
1160 pub fn transform_point2d(&self, point: Point2D<f32, Src>) -> Option<Point2D<f32, Dst>> {
1161 match *self {
1162 FastTransform::Offset(offset) => {
1163 let new_point = point + offset;
1164 Some(Point2D::from_untyped(new_point.to_untyped()))
1165 }
1166 FastTransform::Transform { ref transform, .. } => transform.transform_point2d(point),
1167 }
1168 }
1169
1170 #[inline(always)]
1171 pub fn project_point2d(&self, point: Point2D<f32, Src>) -> Option<Point2D<f32, Dst>> {
1172 match* self {
1173 FastTransform::Offset(..) => self.transform_point2d(point),
1174 FastTransform::Transform{ref transform, ..} => {
1175 let z = -(point.x * transform.m13 + point.y * transform.m23 + transform.m43) / transform.m33;
1182
1183 transform.transform_point3d(point3(point.x, point.y, z)).map(| p3 | point2(p3.x, p3.y))
1184 }
1185 }
1186 }
1187
1188 #[inline(always)]
1189 pub fn inverse(&self) -> Option<FastTransform<Dst, Src>> {
1190 match *self {
1191 FastTransform::Offset(offset) =>
1192 Some(FastTransform::Offset(Vector2D::new(-offset.x, -offset.y))),
1193 FastTransform::Transform { transform, inverse: Some(inverse), is_2d, } =>
1194 Some(FastTransform::Transform {
1195 transform: inverse,
1196 inverse: Some(transform),
1197 is_2d
1198 }),
1199 FastTransform::Transform { inverse: None, .. } => None,
1200
1201 }
1202 }
1203}
1204
1205impl<Src, Dst> From<Transform3D<f32, Src, Dst>> for FastTransform<Src, Dst> {
1206 fn from(transform: Transform3D<f32, Src, Dst>) -> Self {
1207 FastTransform::with_transform(transform)
1208 }
1209}
1210
1211impl<Src, Dst> From<Vector2D<f32, Src>> for FastTransform<Src, Dst> {
1212 fn from(vector: Vector2D<f32, Src>) -> Self {
1213 FastTransform::with_vector(vector)
1214 }
1215}
1216
1217pub type LayoutFastTransform = FastTransform<LayoutPixel, LayoutPixel>;
1218pub type LayoutToWorldFastTransform = FastTransform<LayoutPixel, WorldPixel>;
1219
1220pub fn project_rect<F, T>(
1221 transform: &Transform3D<f32, F, T>,
1222 rect: &Box2D<f32, F>,
1223 bounds: &Box2D<f32, T>,
1224) -> Option<Box2D<f32, T>>
1225 where F: fmt::Debug
1226{
1227 let homogens = [
1228 transform.transform_point2d_homogeneous(rect.top_left()),
1229 transform.transform_point2d_homogeneous(rect.top_right()),
1230 transform.transform_point2d_homogeneous(rect.bottom_left()),
1231 transform.transform_point2d_homogeneous(rect.bottom_right()),
1232 ];
1233
1234 if homogens.iter().any(|h| h.w <= 0.0 || h.w.is_nan()) {
1237 let mut clipper = Clipper::new();
1238 let polygon = Polygon::from_rect(rect.to_rect().cast().cast_unit(), 1);
1239
1240 let planes = match Clipper::<usize>::frustum_planes(
1241 &transform.cast_unit().cast(),
1242 Some(bounds.to_rect().cast_unit().to_f64()),
1243 ) {
1244 Ok(planes) => planes,
1245 Err(..) => return None,
1246 };
1247
1248 for plane in planes {
1249 clipper.add(plane);
1250 }
1251
1252 let results = clipper.clip(polygon);
1253 if results.is_empty() {
1254 return None
1255 }
1256
1257 Some(Box2D::from_points(results
1258 .into_iter()
1259 .flat_map(|poly| &poly.points)
1261 .map(|p| {
1262 let mut homo = transform.transform_point2d_homogeneous(p.to_2d().to_f32().cast_unit());
1263 homo.w = homo.w.max(0.00000001); homo.to_point2d().unwrap()
1265 })
1266 ))
1267 } else {
1268 Some(Box2D::from_points(&[
1270 homogens[0].to_point2d().unwrap(),
1271 homogens[1].to_point2d().unwrap(),
1272 homogens[2].to_point2d().unwrap(),
1273 homogens[3].to_point2d().unwrap(),
1274 ]))
1275 }
1276}
1277
1278pub fn drain_filter<T, Filter, Action>(
1320 vec: &mut Vec<T>,
1321 mut filter: Filter,
1322 mut action: Action,
1323)
1324where
1325 Filter: FnMut(&mut T) -> bool,
1326 Action: FnMut(T)
1327{
1328 let mut i = 0;
1329 while i != vec.len() {
1330 if filter(&mut vec[i]) {
1331 action(vec.remove(i));
1332 } else {
1333 i += 1;
1334 }
1335 }
1336}
1337
1338
1339#[derive(Debug)]
1340pub struct Recycler {
1341 pub num_allocations: usize,
1342}
1343
1344impl Recycler {
1345 const MAX_EXTRA_CAPACITY_PERCENT: usize = 200;
1348 const MIN_EXTRA_CAPACITY_PERCENT: usize = 20;
1350 const MIN_VECTOR_LENGTH: usize = 16;
1352
1353 pub fn new() -> Self {
1354 Recycler {
1355 num_allocations: 0,
1356 }
1357 }
1358
1359 pub fn recycle_vec<T>(&mut self, vec: &mut Vec<T>) {
1362 let extra_capacity = (vec.capacity() - vec.len()) * 100 / vec.len().max(Self::MIN_VECTOR_LENGTH);
1363
1364 if extra_capacity > Self::MAX_EXTRA_CAPACITY_PERCENT {
1365 *vec = Vec::with_capacity(vec.len() + vec.len() * Self::MIN_EXTRA_CAPACITY_PERCENT / 100);
1370 self.num_allocations += 1;
1371 } else {
1372 vec.clear();
1373 }
1374 }
1375}
1376
1377#[derive(Copy, Clone, Debug)]
1380pub struct Preallocator {
1381 size: usize,
1382}
1383
1384impl Preallocator {
1385 pub fn new(initial_size: usize) -> Self {
1386 Preallocator {
1387 size: initial_size,
1388 }
1389 }
1390
1391 pub fn record_vec<T>(&mut self, vec: &[T]) {
1393 let len = vec.len();
1394 if len > self.size {
1395 self.size = len;
1396 } else {
1397 self.size = (self.size + len) / 2;
1398 }
1399 }
1400
1401 pub fn preallocation_size(&self) -> usize {
1403 (self.size + 15) & !15
1406 }
1407
1408 pub fn preallocate_vec<T>(&self, vec: &mut Vec<T>) {
1413 let len = vec.len();
1414 let cap = self.preallocation_size();
1415 if len < cap {
1416 vec.reserve(cap - len);
1417 }
1418 }
1419
1420 pub fn preallocate_framevec<T>(&self, vec: &mut FrameVec<T>) {
1425 let len = vec.len();
1426 let cap = self.preallocation_size();
1427 if len < cap {
1428 vec.reserve(cap - len);
1429 }
1430 }
1431}
1432
1433impl Default for Preallocator {
1434 fn default() -> Self {
1435 Self::new(0)
1436 }
1437}
1438
1439#[cfg_attr(feature = "capture", derive(Serialize))]
1452#[cfg_attr(feature = "replay", derive(Deserialize))]
1453#[derive(Clone, Debug, Hash, PartialEq, Eq)]
1454pub struct PrimaryArc<T>(pub Arc<T>);
1455
1456impl<T> ::std::ops::Deref for PrimaryArc<T> {
1457 type Target = Arc<T>;
1458
1459 #[inline]
1460 fn deref(&self) -> &Arc<T> {
1461 &self.0
1462 }
1463}
1464
1465impl<T> MallocShallowSizeOf for PrimaryArc<T> {
1466 fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1467 unsafe {
1468 let raw_arc_ptr: *const Arc<T> = &self.0;
1471 let raw_ptr_ptr: *const *const c_void = raw_arc_ptr as _;
1472 let raw_ptr = *raw_ptr_ptr;
1473 (ops.size_of_op)(raw_ptr)
1474 }
1475 }
1476}
1477
1478impl<T: MallocSizeOf> MallocSizeOf for PrimaryArc<T> {
1479 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1480 self.shallow_size_of(ops) + (**self).size_of(ops)
1481 }
1482}
1483
1484pub fn scale_factors<Src, Dst>(
1493 mat: &Transform3D<f32, Src, Dst>
1494) -> (f32, f32) {
1495 let m11 = mat.m11 as f64;
1496 let m12 = mat.m12 as f64;
1497 let det = m11 * mat.m22 as f64 - m12 * mat.m21 as f64;
1499 if det == 0.0 {
1500 return (0.0, 0.0);
1501 }
1502
1503 let det = det.abs();
1505
1506 let major = (m11 * m11 + m12 * m12).sqrt();
1507 let minor = if major != 0.0 { det / major } else { 0.0 };
1508
1509 (major as f32, minor as f32)
1510}
1511
1512#[test]
1513fn scale_factors_large() {
1514 let mat = Transform3D::<f32, (), ()>::new(
1516 1.6534229920333123e27, 3.673100922561787e27, 0.0, 0.0,
1517 -3.673100922561787e27, 1.6534229920333123e27, 0.0, 0.0,
1518 0.0, 0.0, 1.0, 0.0,
1519 -828140552192.0, -1771307401216.0, 0.0, 1.0,
1520 );
1521 let (major, minor) = scale_factors(&mat);
1522 assert!(major.is_normal() && minor.is_normal());
1523}
1524
1525pub fn clamp_to_scale_factor(val: f32, round_down: bool) -> f32 {
1532 const SCALE_RESOLUTION: f32 = 2.0;
1536
1537 let val = val.abs();
1540
1541 let (val, inverse) = if val < 1.0 {
1542 (1.0 / val, true)
1543 } else {
1544 (val, false)
1545 };
1546
1547 let power = val.log2() / SCALE_RESOLUTION.log2();
1548
1549 let power = if (power - power.round()).abs() < 1e-5 {
1553 power.round()
1554 } else if inverse != round_down {
1555 power.floor()
1558 } else {
1559 power.ceil()
1562 };
1563
1564 let scale = SCALE_RESOLUTION.powf(power);
1565
1566 if inverse {
1567 1.0 / scale
1568 } else {
1569 scale
1570 }
1571}
1572
1573pub fn round_up_to_multiple(val: usize, mul: NonZeroUsize) -> usize {
1575 match val % mul.get() {
1576 0 => val,
1577 rem => val - rem + mul.get(),
1578 }
1579}
1580
1581
1582#[macro_export]
1583macro_rules! c_str {
1584 ($lit:expr) => {
1585 unsafe {
1586 std::ffi::CStr::from_ptr(concat!($lit, "\0").as_ptr()
1587 as *const std::os::raw::c_char)
1588 }
1589 }
1590}
1591
1592pub struct WeakTable {
1595 inner: Vec<std::sync::Weak<Vec<u8>>>
1596}
1597
1598impl WeakTable {
1599 pub fn new() -> WeakTable {
1600 WeakTable { inner: Vec::new() }
1601 }
1602 pub fn insert(&mut self, x: std::sync::Weak<Vec<u8>>) {
1603 if self.inner.len() == self.inner.capacity() {
1604 self.remove_expired();
1605
1606 if self.inner.len() * 3 < self.inner.capacity() {
1610 self.inner.shrink_to_fit();
1614 } else {
1615 self.inner.reserve(self.inner.len())
1617 }
1618 }
1619 self.inner.push(x);
1620 }
1621
1622 fn remove_expired(&mut self) {
1623 self.inner.retain(|x| x.strong_count() > 0)
1624 }
1625
1626 pub fn iter(&self) -> impl Iterator<Item = Arc<Vec<u8>>> + '_ {
1627 self.inner.iter().filter_map(|x| x.upgrade())
1628 }
1629}
1630
1631#[test]
1632fn weak_table() {
1633 let mut tbl = WeakTable::new();
1634 let mut things = Vec::new();
1635 let target_count = 50;
1636 for _ in 0..target_count {
1637 things.push(Arc::new(vec![4]));
1638 }
1639 for i in &things {
1640 tbl.insert(Arc::downgrade(i))
1641 }
1642 assert_eq!(tbl.inner.len(), target_count);
1643 drop(things);
1644 assert_eq!(tbl.iter().count(), 0);
1645
1646 for _ in 0..target_count*2 {
1649 tbl.insert(Arc::downgrade(&Arc::new(vec![5])))
1650 }
1651 assert!(tbl.inner.capacity() <= 4);
1652}
1653
1654#[test]
1655fn scale_offset_pre_post() {
1656 let a = ScaleOffset::new(1.0, 2.0, 3.0, 4.0);
1657 let b = ScaleOffset::new(5.0, 6.0, 7.0, 8.0);
1658
1659 assert_eq!(a.then(&b), b.pre_transform(&a));
1660 assert_eq!(a.then_scale(10.0), a.then(&ScaleOffset::from_scale(Vector2D::new(10.0, 10.0))));
1661 assert_eq!(a.pre_scale(10.0), a.pre_transform(&ScaleOffset::from_scale(Vector2D::new(10.0, 10.0))));
1662}