1use api::BorderRadius;
6use api::units::*;
7use euclid::{Point2D, Rect, Box2D, Size2D, Vector2D, point2, point3};
8use euclid::{default, Transform2D, Transform3D, Scale, approxeq::ApproxEq};
9use plane_split::{Clipper, Polygon};
10use std::{i32, f32, fmt, ptr};
11use std::borrow::Cow;
12use std::num::NonZeroUsize;
13use std::sync::Arc;
14use std::mem::replace;
15
16use crate::internal_types::FrameVec;
17
18const NEARLY_ZERO: f32 = 1.0 / 4096.0;
20
21pub struct Allocation<'a, T: 'a> {
24 vec: &'a mut Vec<T>,
25 index: usize,
26}
27
28impl<'a, T> Allocation<'a, T> {
29 #[inline(always)]
33 pub fn init(self, value: T) -> usize {
34 unsafe {
35 ptr::write(self.vec.as_mut_ptr().add(self.index), value);
36 self.vec.set_len(self.index + 1);
37 }
38 self.index
39 }
40}
41
42pub enum VecEntry<'a, T: 'a> {
44 Vacant(Allocation<'a, T>),
45 Occupied(&'a mut T),
46}
47
48impl<'a, T> VecEntry<'a, T> {
49 #[inline(always)]
50 pub fn set(self, value: T) {
51 match self {
52 VecEntry::Vacant(alloc) => { alloc.init(value); }
53 VecEntry::Occupied(slot) => { *slot = value; }
54 }
55 }
56}
57
58pub trait VecHelper<T> {
59 fn alloc(&mut self) -> Allocation<T>;
61 fn entry(&mut self, index: usize) -> VecEntry<T>;
64
65 fn take(&mut self) -> Self;
67
68 fn take_and_preallocate(&mut self) -> Self;
72}
73
74impl<T> VecHelper<T> for Vec<T> {
75 fn alloc(&mut self) -> Allocation<T> {
76 let index = self.len();
77 if self.capacity() == index {
78 self.reserve(1);
79 }
80 Allocation {
81 vec: self,
82 index,
83 }
84 }
85
86 fn entry(&mut self, index: usize) -> VecEntry<T> {
87 if index < self.len() {
88 VecEntry::Occupied(unsafe {
89 self.get_unchecked_mut(index)
90 })
91 } else {
92 assert_eq!(index, self.len());
93 VecEntry::Vacant(self.alloc())
94 }
95 }
96
97 fn take(&mut self) -> Self {
98 replace(self, Vec::new())
99 }
100
101 fn take_and_preallocate(&mut self) -> Self {
102 let len = self.len();
103 if len == 0 {
104 self.clear();
105 return Vec::new();
106 }
107 replace(self, Vec::with_capacity(len + 8))
108 }
109}
110
111#[repr(C)]
119#[derive(Debug, Clone, Copy, MallocSizeOf, PartialEq)]
120#[cfg_attr(feature = "capture", derive(Serialize))]
121#[cfg_attr(feature = "replay", derive(Deserialize))]
122pub struct ScaleOffset {
123 pub scale: euclid::Vector2D<f32, euclid::UnknownUnit>,
124 pub offset: euclid::Vector2D<f32, euclid::UnknownUnit>,
125}
126
127impl ScaleOffset {
128 pub fn new(sx: f32, sy: f32, tx: f32, ty: f32) -> Self {
129 ScaleOffset {
130 scale: Vector2D::new(sx, sy),
131 offset: Vector2D::new(tx, ty),
132 }
133 }
134
135 pub fn identity() -> Self {
136 ScaleOffset {
137 scale: Vector2D::new(1.0, 1.0),
138 offset: Vector2D::zero(),
139 }
140 }
141
142 pub fn from_transform<F, T>(
145 m: &Transform3D<f32, F, T>,
146 ) -> Option<ScaleOffset> {
147
148 if m.m12.abs() > NEARLY_ZERO ||
154 m.m13.abs() > NEARLY_ZERO ||
155 m.m14.abs() > NEARLY_ZERO ||
156 m.m21.abs() > NEARLY_ZERO ||
157 m.m23.abs() > NEARLY_ZERO ||
158 m.m24.abs() > NEARLY_ZERO ||
159 m.m31.abs() > NEARLY_ZERO ||
160 m.m32.abs() > NEARLY_ZERO ||
161 (m.m33 - 1.0).abs() > NEARLY_ZERO ||
162 m.m34.abs() > NEARLY_ZERO ||
163 m.m43.abs() > NEARLY_ZERO ||
164 (m.m44 - 1.0).abs() > NEARLY_ZERO {
165 return None;
166 }
167
168 Some(ScaleOffset {
169 scale: Vector2D::new(m.m11, m.m22),
170 offset: Vector2D::new(m.m41, m.m42),
171 })
172 }
173
174 pub fn from_offset(offset: default::Vector2D<f32>) -> Self {
175 ScaleOffset {
176 scale: Vector2D::new(1.0, 1.0),
177 offset,
178 }
179 }
180
181 pub fn from_scale(scale: default::Vector2D<f32>) -> Self {
182 ScaleOffset {
183 scale,
184 offset: Vector2D::new(0.0, 0.0),
185 }
186 }
187
188 pub fn inverse(&self) -> Self {
189 if self.scale.x.approx_eq(&0.0) || self.scale.y.approx_eq(&0.0) {
194 return ScaleOffset::new(0.0, 0.0, 0.0, 0.0);
195 }
196
197 ScaleOffset {
198 scale: Vector2D::new(
199 1.0 / self.scale.x,
200 1.0 / self.scale.y,
201 ),
202 offset: Vector2D::new(
203 -self.offset.x / self.scale.x,
204 -self.offset.y / self.scale.y,
205 ),
206 }
207 }
208
209 pub fn pre_offset(&self, offset: default::Vector2D<f32>) -> Self {
210 self.pre_transform(
211 &ScaleOffset {
212 scale: Vector2D::new(1.0, 1.0),
213 offset,
214 }
215 )
216 }
217
218 pub fn pre_scale(&self, scale: f32) -> Self {
219 ScaleOffset {
220 scale: self.scale * scale,
221 offset: self.offset,
222 }
223 }
224
225 pub fn then_scale(&self, scale: f32) -> Self {
226 ScaleOffset {
227 scale: self.scale * scale,
228 offset: self.offset * scale,
229 }
230 }
231
232 pub fn pre_transform(&self, other: &ScaleOffset) -> Self {
236 ScaleOffset {
237 scale: Vector2D::new(
238 self.scale.x * other.scale.x,
239 self.scale.y * other.scale.y,
240 ),
241 offset: Vector2D::new(
242 self.offset.x + self.scale.x * other.offset.x,
243 self.offset.y + self.scale.y * other.offset.y,
244 ),
245 }
246 }
247
248 #[allow(unused)]
252 pub fn then(&self, other: &ScaleOffset) -> Self {
253 ScaleOffset {
254 scale: Vector2D::new(
255 self.scale.x * other.scale.x,
256 self.scale.y * other.scale.y,
257 ),
258 offset: Vector2D::new(
259 other.scale.x * self.offset.x + other.offset.x,
260 other.scale.y * self.offset.y + other.offset.y,
261 ),
262 }
263 }
264
265
266 pub fn map_rect<F, T>(&self, rect: &Box2D<f32, F>) -> Box2D<f32, T> {
267 let x0 = rect.min.x * self.scale.x + self.offset.x;
268 let y0 = rect.min.y * self.scale.y + self.offset.y;
269 let x1 = rect.min.x.max(rect.max.x) * self.scale.x + self.offset.x;
274 let y1 = rect.min.y.max(rect.max.y) * self.scale.y + self.offset.y;
275
276 Box2D::new(
277 Point2D::new(x0.min(x1), y0.min(y1)),
278 Point2D::new(x0.max(x1), y0.max(y1)),
279 )
280 }
281
282 pub fn unmap_rect<F, T>(&self, rect: &Box2D<f32, F>) -> Box2D<f32, T> {
283 let x0 = (rect.min.x - self.offset.x) / self.scale.x;
284 let y0 = (rect.min.y - self.offset.y) / self.scale.y;
285 let x1 = (rect.min.x.max(rect.max.x) - self.offset.x) / self.scale.x;
290 let y1 = (rect.min.y.max(rect.max.y) - self.offset.y) / self.scale.y;
291
292 Box2D::new(
293 Point2D::new(x0.min(x1), y0.min(y1)),
294 Point2D::new(x0.max(x1), y0.max(y1)),
295 )
296 }
297
298 pub fn map_vector<F, T>(&self, vector: &Vector2D<f32, F>) -> Vector2D<f32, T> {
299 Vector2D::new(
300 vector.x * self.scale.x,
301 vector.y * self.scale.y,
302 )
303 }
304
305 pub fn map_size<F, T>(&self, size: &Size2D<f32, F>) -> Size2D<f32, T> {
306 Size2D::new(
307 size.width * self.scale.x,
308 size.height * self.scale.y,
309 )
310 }
311
312 pub fn unmap_vector<F, T>(&self, vector: &Vector2D<f32, F>) -> Vector2D<f32, T> {
313 Vector2D::new(
314 vector.x / self.scale.x,
315 vector.y / self.scale.y,
316 )
317 }
318
319 pub fn map_point<F, T>(&self, point: &Point2D<f32, F>) -> Point2D<f32, T> {
320 Point2D::new(
321 point.x * self.scale.x + self.offset.x,
322 point.y * self.scale.y + self.offset.y,
323 )
324 }
325
326 pub fn unmap_point<F, T>(&self, point: &Point2D<f32, F>) -> Point2D<f32, T> {
327 Point2D::new(
328 (point.x - self.offset.x) / self.scale.x,
329 (point.y - self.offset.y) / self.scale.y,
330 )
331 }
332
333 pub fn to_transform<F, T>(&self) -> Transform3D<f32, F, T> {
334 Transform3D::new(
335 self.scale.x,
336 0.0,
337 0.0,
338 0.0,
339
340 0.0,
341 self.scale.y,
342 0.0,
343 0.0,
344
345 0.0,
346 0.0,
347 1.0,
348 0.0,
349
350 self.offset.x,
351 self.offset.y,
352 0.0,
353 1.0,
354 )
355 }
356
357 pub fn is_identity(&self) -> bool {
358 self.scale.x == 1.0 &&
359 self.scale.y == 1.0 &&
360 self.offset.x == 0.0 &&
361 self.offset.y == 0.0
362 }
363
364 pub fn is_reflection(&self) -> bool {
365 self.scale.x < 0.0 ||
366 self.scale.y < 0.0
367 }
368}
369
370pub trait MatrixHelpers<Src, Dst> {
372 fn preserves_2d_axis_alignment(&self) -> bool;
375 fn has_perspective_component(&self) -> bool;
376 fn coplanar_scale_factors(&self) -> Option<(f32, f32)>;
386 fn has_2d_inverse(&self) -> bool;
387 fn exceeds_2d_scale(&self, limit: f64) -> bool;
390 fn inverse_project(&self, target: &Point2D<f32, Dst>) -> Option<Point2D<f32, Src>>;
391 fn inverse_rect_footprint(&self, rect: &Box2D<f32, Dst>) -> Option<Box2D<f32, Src>>;
392 fn is_simple_translation(&self) -> bool;
393 fn is_simple_2d_translation(&self) -> bool;
394 fn is_2d_scale_translation(&self) -> bool;
395 fn determinant_2d(&self) -> f32;
397 fn flatten_z_output(&mut self);
400
401 fn cast_unit<NewSrc, NewDst>(&self) -> Transform3D<f32, NewSrc, NewDst>;
402}
403
404impl<Src, Dst> MatrixHelpers<Src, Dst> for Transform3D<f32, Src, Dst> {
405 fn preserves_2d_axis_alignment(&self) -> bool {
406 if self.m14 != 0.0 || self.m24 != 0.0 {
407 return false;
408 }
409
410 let mut col0 = 0;
411 let mut col1 = 0;
412 let mut row0 = 0;
413 let mut row1 = 0;
414
415 if self.m11.abs() > NEARLY_ZERO {
416 col0 += 1;
417 row0 += 1;
418 }
419 if self.m12.abs() > NEARLY_ZERO {
420 col1 += 1;
421 row0 += 1;
422 }
423 if self.m21.abs() > NEARLY_ZERO {
424 col0 += 1;
425 row1 += 1;
426 }
427 if self.m22.abs() > NEARLY_ZERO {
428 col1 += 1;
429 row1 += 1;
430 }
431
432 col0 < 2 && col1 < 2 && row0 < 2 && row1 < 2
433 }
434
435 fn has_perspective_component(&self) -> bool {
436 self.m14.abs() > NEARLY_ZERO ||
437 self.m24.abs() > NEARLY_ZERO ||
438 self.m34.abs() > NEARLY_ZERO ||
439 (self.m44 - 1.0).abs() > NEARLY_ZERO
440 }
441
442 fn coplanar_scale_factors(&self) -> Option<(f32, f32)> {
443 if self.m14.abs() > NEARLY_ZERO ||
445 self.m24.abs() > NEARLY_ZERO {
446 return None;
447 }
448
449 if self.m44 < NEARLY_ZERO {
453 return None;
454 }
455
456 let (major, minor) = scale_factors(self);
457
458 Some((major / self.m44, minor / self.m44))
459 }
460
461 fn has_2d_inverse(&self) -> bool {
462 self.determinant_2d() != 0.0
463 }
464
465 fn exceeds_2d_scale(&self, limit: f64) -> bool {
466 let limit2 = (limit * limit) as f32;
467 self.m11 * self.m11 + self.m12 * self.m12 > limit2 ||
468 self.m21 * self.m21 + self.m22 * self.m22 > limit2
469 }
470
471 fn inverse_project(&self, target: &Point2D<f32, Dst>) -> Option<Point2D<f32, Src>> {
473 let m = Transform2D::<f32, Src, Dst>::new(
475 self.m11 - target.x * self.m14, self.m12 - target.y * self.m14,
476 self.m21 - target.x * self.m24, self.m22 - target.y * self.m24,
477 self.m41 - target.x * self.m44, self.m42 - target.y * self.m44,
478 );
479 let inv = m.inverse()?;
480 if inv.m31 * self.m14 + inv.m32 * self.m24 + self.m44 > 0.0 {
482 Some(Point2D::new(inv.m31, inv.m32))
483 } else {
484 None
485 }
486 }
487
488 fn inverse_rect_footprint(&self, rect: &Box2D<f32, Dst>) -> Option<Box2D<f32, Src>> {
489 Some(Box2D::from_points(&[
490 self.inverse_project(&rect.top_left())?,
491 self.inverse_project(&rect.top_right())?,
492 self.inverse_project(&rect.bottom_left())?,
493 self.inverse_project(&rect.bottom_right())?,
494 ]))
495 }
496
497 fn is_simple_translation(&self) -> bool {
498 if (self.m11 - 1.0).abs() > NEARLY_ZERO ||
499 (self.m22 - 1.0).abs() > NEARLY_ZERO ||
500 (self.m33 - 1.0).abs() > NEARLY_ZERO ||
501 (self.m44 - 1.0).abs() > NEARLY_ZERO {
502 return false;
503 }
504
505 self.m12.abs() < NEARLY_ZERO && self.m13.abs() < NEARLY_ZERO &&
506 self.m14.abs() < NEARLY_ZERO && self.m21.abs() < NEARLY_ZERO &&
507 self.m23.abs() < NEARLY_ZERO && self.m24.abs() < NEARLY_ZERO &&
508 self.m31.abs() < NEARLY_ZERO && self.m32.abs() < NEARLY_ZERO &&
509 self.m34.abs() < NEARLY_ZERO
510 }
511
512 fn is_simple_2d_translation(&self) -> bool {
513 if !self.is_simple_translation() {
514 return false;
515 }
516
517 self.m43.abs() < NEARLY_ZERO
518 }
519
520 fn is_2d_scale_translation(&self) -> bool {
527 (self.m33 - 1.0).abs() < NEARLY_ZERO &&
528 (self.m44 - 1.0).abs() < NEARLY_ZERO &&
529 self.m12.abs() < NEARLY_ZERO && self.m13.abs() < NEARLY_ZERO && self.m14.abs() < NEARLY_ZERO &&
530 self.m21.abs() < NEARLY_ZERO && self.m23.abs() < NEARLY_ZERO && self.m24.abs() < NEARLY_ZERO &&
531 self.m31.abs() < NEARLY_ZERO && self.m32.abs() < NEARLY_ZERO && self.m34.abs() < NEARLY_ZERO &&
532 self.m43.abs() < NEARLY_ZERO
533 }
534
535 fn determinant_2d(&self) -> f32 {
536 self.m11 * self.m22 - self.m12 * self.m21
537 }
538
539 fn flatten_z_output(&mut self) {
540 self.m13 = 0.0;
541 self.m23 = 0.0;
542 self.m33 = 1.0;
543 self.m43 = 0.0;
544 }
546
547 fn cast_unit<NewSrc, NewDst>(&self) -> Transform3D<f32, NewSrc, NewDst> {
548 Transform3D::new(
549 self.m11, self.m12, self.m13, self.m14,
550 self.m21, self.m22, self.m23, self.m24,
551 self.m31, self.m32, self.m33, self.m34,
552 self.m41, self.m42, self.m43, self.m44,
553 )
554 }
555}
556
557pub trait PointHelpers<U>
558where
559 Self: Sized,
560{
561 fn snap(&self) -> Self;
562}
563
564impl<U> PointHelpers<U> for Point2D<f32, U> {
565 fn snap(&self) -> Self {
566 Point2D::new(
567 self.x.round(),
568 self.y.round(),
569 )
570 }
571}
572
573pub trait VectorHelpers<U>
574where
575 Self: Sized,
576{
577 fn snap(&self) -> Self;
578}
579
580impl<U> VectorHelpers<U> for Vector2D<f32, U> {
581 fn snap(&self) -> Self {
582 Vector2D::new(
583 self.x.round(),
584 self.y.round(),
585 )
586 }
587}
588
589pub trait RectHelpers<U>
590where
591 Self: Sized,
592{
593 fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self;
594 fn snap(&self) -> Self;
595}
596
597impl<U> RectHelpers<U> for Rect<f32, U> {
598 fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self {
599 Rect::new(
600 Point2D::new(x0, y0),
601 Size2D::new(x1 - x0, y1 - y0),
602 )
603 }
604
605 fn snap(&self) -> Self {
606 let origin = Point2D::new(
607 (self.origin.x + 0.5).floor(),
608 (self.origin.y + 0.5).floor(),
609 );
610 Rect::new(
611 origin,
612 Size2D::new(
613 (self.origin.x + self.size.width + 0.5).floor() - origin.x,
614 (self.origin.y + self.size.height + 0.5).floor() - origin.y,
615 ),
616 )
617 }
618}
619
620impl<U> RectHelpers<U> for Box2D<f32, U> {
621 fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self {
622 Box2D {
623 min: Point2D::new(x0, y0),
624 max: Point2D::new(x1, y1),
625 }
626 }
627
628 fn snap(&self) -> Self {
629 self.round()
630 }
631}
632
633pub fn lerp(a: f32, b: f32, t: f32) -> f32 {
634 (b - a) * t + a
635}
636
637#[repr(u32)]
638#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
639#[cfg_attr(feature = "capture", derive(Serialize))]
640#[cfg_attr(feature = "replay", derive(Deserialize))]
641pub enum TransformedRectKind {
642 AxisAligned = 0,
643 Complex = 1,
644}
645
646#[inline(always)]
647pub fn pack_as_float(value: u32) -> f32 {
648 value as f32 + 0.5
649}
650
651#[inline]
652fn extract_inner_rect_impl<U>(
653 rect: &Box2D<f32, U>,
654 radii: &BorderRadius,
655 k: f32,
656) -> Option<Box2D<f32, U>> {
657 let xl = (k * radii.top_left.width.max(radii.bottom_left.width)).ceil();
662 let xr = (rect.width() - k * radii.top_right.width.max(radii.bottom_right.width)).floor();
663 let yt = (k * radii.top_left.height.max(radii.top_right.height)).ceil();
664 let yb =
665 (rect.height() - k * radii.bottom_left.height.max(radii.bottom_right.height)).floor();
666
667 if xl <= xr && yt <= yb {
668 Some(Box2D::from_origin_and_size(
669 Point2D::new(rect.min.x + xl, rect.min.y + yt),
670 Size2D::new(xr - xl, yb - yt),
671 ))
672 } else {
673 None
674 }
675}
676
677pub fn extract_inner_rect_safe<U>(
680 rect: &Box2D<f32, U>,
681 radii: &BorderRadius,
682) -> Option<Box2D<f32, U>> {
683 extract_inner_rect_impl(rect, radii, 1.0)
686}
687
688pub fn extract_inner_rect_k<U>(
692 rect: &Box2D<f32, U>,
693 radii: &BorderRadius,
694 k: f32,
695) -> Option<Box2D<f32, U>> {
696 extract_inner_rect_impl(rect, radii, k)
697}
698
699#[cfg(test)]
700use euclid::vec3;
701
702#[cfg(test)]
703pub mod test {
704 use super::*;
705 use euclid::default::{Box2D, Point2D, Size2D, Transform3D};
706 use euclid::{Angle, approxeq::ApproxEq};
707 use std::f32::consts::PI;
708 use crate::clip::{is_left_of_line, polygon_contains_point};
709 use crate::prim_store::PolygonKey;
710 use api::FillRule;
711
712 #[test]
713 fn inverse_project() {
714 let m0 = Transform3D::identity();
715 let p0 = Point2D::new(1.0, 2.0);
716 assert_eq!(m0.inverse_project(&p0), Some(p0));
718 let m1 = Transform3D::rotation(0.0, 1.0, 0.0, Angle::radians(-PI / 3.0));
719 assert_eq!(m1.inverse_project(&p0), Some(Point2D::new(2.0, 2.0)));
721 }
722
723 #[test]
724 fn inverse_project_footprint() {
725 let m = Transform3D::new(
726 0.477499992, 0.135000005, -1.0, 0.000624999986,
727 -0.642787635, 0.766044438, 0.0, 0.0,
728 0.766044438, 0.642787635, 0.0, 0.0,
729 1137.10986, 113.71286, 402.0, 0.748749971,
730 );
731 let r = Box2D::from_size(Size2D::new(804.0, 804.0));
732 {
733 let points = &[
734 r.top_left(),
735 r.top_right(),
736 r.bottom_left(),
737 r.bottom_right(),
738 ];
739 let mi = m.inverse().unwrap();
740 info!("Points:");
744 for p in points {
745 let pp = m.transform_point2d_homogeneous(*p);
746 let p3 = pp.to_point3d().unwrap();
747 let pi = mi.transform_point3d_homogeneous(p3);
748 let px = pi.to_point2d().unwrap();
749 let py = m.inverse_project(&pp.to_point2d().unwrap()).unwrap();
750 info!("\t{:?} -> {:?} -> {:?} -> ({:?} -> {:?}, {:?})", p, pp, p3, pi, px, py);
751 assert!(px.approx_eq_eps(p, &Point2D::new(0.001, 0.001)));
752 assert!(py.approx_eq_eps(p, &Point2D::new(0.001, 0.001)));
753 }
754 }
755 let rp = project_rect(&m, &r, &Box2D::from_size(Size2D::new(1000.0, 1000.0))).unwrap();
757 info!("Projected {:?}", rp);
758 assert_eq!(m.inverse_project(&rp.min), None);
760 if let Some(ri) = m.inverse_rect_footprint(&rp) {
762 assert!(ri.contains_box(&r), "Inverse {:?}", ri);
764 }
765 }
766
767 fn validate_convert(xref: &LayoutTransform) {
768 let so = ScaleOffset::from_transform(xref).unwrap();
769 let xf = so.to_transform();
770 assert!(xref.approx_eq(&xf));
771 }
772
773 #[test]
774 fn negative_scale_map_unmap() {
775 let xref = LayoutTransform::scale(1.0, -1.0, 1.0)
776 .pre_translate(LayoutVector3D::new(124.0, 38.0, 0.0));
777 let so = ScaleOffset::from_transform(&xref).unwrap();
778 let local_rect = LayoutRect {
779 min: LayoutPoint::new(50.0, -100.0),
780 max: LayoutPoint::new(250.0, 300.0),
781 };
782
783 let mapped_rect = so.map_rect::<LayoutPixel, DevicePixel>(&local_rect);
784 let xf_rect = project_rect(
785 &xref,
786 &local_rect,
787 &LayoutRect::max_rect(),
788 ).unwrap();
789
790 assert!(mapped_rect.min.x.approx_eq(&xf_rect.min.x));
791 assert!(mapped_rect.min.y.approx_eq(&xf_rect.min.y));
792 assert!(mapped_rect.max.x.approx_eq(&xf_rect.max.x));
793 assert!(mapped_rect.max.y.approx_eq(&xf_rect.max.y));
794
795 let unmapped_rect = so.unmap_rect::<DevicePixel, LayoutPixel>(&mapped_rect);
796 assert!(unmapped_rect.min.x.approx_eq(&local_rect.min.x));
797 assert!(unmapped_rect.min.y.approx_eq(&local_rect.min.y));
798 assert!(unmapped_rect.max.x.approx_eq(&local_rect.max.x));
799 assert!(unmapped_rect.max.y.approx_eq(&local_rect.max.y));
800 }
801
802 #[test]
803 fn scale_offset_convert() {
804 let xref = LayoutTransform::translation(130.0, 200.0, 0.0);
805 validate_convert(&xref);
806
807 let xref = LayoutTransform::scale(13.0, 8.0, 1.0);
808 validate_convert(&xref);
809
810 let xref = LayoutTransform::scale(0.5, 0.5, 1.0)
811 .pre_translate(LayoutVector3D::new(124.0, 38.0, 0.0));
812 validate_convert(&xref);
813
814 let xref = LayoutTransform::scale(30.0, 11.0, 1.0)
815 .then_translate(vec3(50.0, 240.0, 0.0));
816 validate_convert(&xref);
817 }
818
819 fn validate_inverse(xref: &LayoutTransform) {
820 let s0 = ScaleOffset::from_transform(xref).unwrap();
821 let s1 = s0.inverse().pre_transform(&s0);
822 assert!((s1.scale.x - 1.0).abs() < NEARLY_ZERO &&
823 (s1.scale.y - 1.0).abs() < NEARLY_ZERO &&
824 s1.offset.x.abs() < NEARLY_ZERO &&
825 s1.offset.y.abs() < NEARLY_ZERO,
826 "{:?}",
827 s1);
828 }
829
830 #[test]
831 fn scale_offset_inverse() {
832 let xref = LayoutTransform::translation(130.0, 200.0, 0.0);
833 validate_inverse(&xref);
834
835 let xref = LayoutTransform::scale(13.0, 8.0, 1.0);
836 validate_inverse(&xref);
837
838 let xref = LayoutTransform::translation(124.0, 38.0, 0.0).
839 then_scale(0.5, 0.5, 1.0);
840
841 validate_inverse(&xref);
842
843 let xref = LayoutTransform::scale(30.0, 11.0, 1.0)
844 .then_translate(vec3(50.0, 240.0, 0.0));
845 validate_inverse(&xref);
846 }
847
848 fn validate_accumulate(x0: &LayoutTransform, x1: &LayoutTransform) {
849 let x = x1.then(&x0);
850
851 let s0 = ScaleOffset::from_transform(x0).unwrap();
852 let s1 = ScaleOffset::from_transform(x1).unwrap();
853
854 let s = s0.pre_transform(&s1).to_transform();
855
856 assert!(x.approx_eq(&s), "{:?}\n{:?}", x, s);
857 }
858
859 #[test]
860 fn scale_offset_accumulate() {
861 let x0 = LayoutTransform::translation(130.0, 200.0, 0.0);
862 let x1 = LayoutTransform::scale(7.0, 3.0, 1.0);
863
864 validate_accumulate(&x0, &x1);
865 }
866
867 #[test]
868 fn scale_offset_invalid_scale() {
869 let s0 = ScaleOffset::new(0.0, 1.0, 10.0, 20.0);
870 let i0 = s0.inverse();
871 assert_eq!(i0, ScaleOffset::new(0.0, 0.0, 0.0, 0.0));
872
873 let s1 = ScaleOffset::new(1.0, 0.0, 10.0, 20.0);
874 let i1 = s1.inverse();
875 assert_eq!(i1, ScaleOffset::new(0.0, 0.0, 0.0, 0.0));
876 }
877
878 #[test]
879 fn polygon_clip_is_left_of_point() {
880 let p0_x = 1.0;
886 let p0_y = -3.0;
887 let p1_x = -2.0;
888 let p1_y = 6.0;
889
890 assert!(is_left_of_line(-9.0, 0.0, p0_x, p0_y, p1_x, p1_y) > 0.0);
892 assert!(is_left_of_line(-1.0, 1.0, p0_x, p0_y, p1_x, p1_y) > 0.0);
893 assert!(is_left_of_line(1.0, -4.0, p0_x, p0_y, p1_x, p1_y) > 0.0);
894
895 assert!(is_left_of_line(-3.0, 9.0, p0_x, p0_y, p1_x, p1_y) == 0.0);
897 assert!(is_left_of_line(0.0, 0.0, p0_x, p0_y, p1_x, p1_y) == 0.0);
898 assert!(is_left_of_line(100.0, -300.0, p0_x, p0_y, p1_x, p1_y) == 0.0);
899
900 assert!(is_left_of_line(0.0, 1.0, p0_x, p0_y, p1_x, p1_y) < 0.0);
902 assert!(is_left_of_line(-4.0, 13.0, p0_x, p0_y, p1_x, p1_y) < 0.0);
903 assert!(is_left_of_line(5.0, -12.0, p0_x, p0_y, p1_x, p1_y) < 0.0);
904 }
905
906 #[test]
907 fn polygon_clip_contains_point() {
908 let p0 = LayoutPoint::new(4.0, 4.0);
911 let p1 = LayoutPoint::new(6.0, 4.0);
912 let p2 = LayoutPoint::new(4.0, 7.0);
913 let p3 = LayoutPoint::new(2.0, 1.0);
914 let p4 = LayoutPoint::new(8.0, 1.0);
915 let p5 = LayoutPoint::new(6.0, 7.0);
916
917 let poly_clockwise_nonzero = PolygonKey::new(
918 &[p5, p4, p3, p2, p1, p0].to_vec(), FillRule::Nonzero
919 );
920 let poly_clockwise_evenodd = PolygonKey::new(
921 &[p5, p4, p3, p2, p1, p0].to_vec(), FillRule::Evenodd
922 );
923 let poly_counter_clockwise_nonzero = PolygonKey::new(
924 &[p0, p1, p2, p3, p4, p5].to_vec(), FillRule::Nonzero
925 );
926 let poly_counter_clockwise_evenodd = PolygonKey::new(
927 &[p0, p1, p2, p3, p4, p5].to_vec(), FillRule::Evenodd
928 );
929
930 let rect = LayoutRect::from_size(LayoutSize::new(10.0, 10.0));
933
934 let p_inside_once = LayoutPoint::new(5.0, 3.0);
936 let p_inside_twice = LayoutPoint::new(5.0, 5.0);
937 let p_outside = LayoutPoint::new(9.0, 9.0);
938
939 for poly_nonzero in vec![poly_clockwise_nonzero, poly_counter_clockwise_nonzero].iter() {
943 assert_eq!(polygon_contains_point(&p_inside_once, &rect, &poly_nonzero), true);
944 assert_eq!(polygon_contains_point(&p_inside_twice, &rect, &poly_nonzero), true);
945 assert_eq!(polygon_contains_point(&p_outside, &rect, &poly_nonzero), false);
946 }
947 for poly_evenodd in vec![poly_clockwise_evenodd, poly_counter_clockwise_evenodd].iter() {
949 assert_eq!(polygon_contains_point(&p_inside_once, &rect, &poly_evenodd), true);
950 assert_eq!(polygon_contains_point(&p_inside_twice, &rect, &poly_evenodd), false);
951 assert_eq!(polygon_contains_point(&p_outside, &rect, &poly_evenodd), false);
952 }
953 }
954
955 #[test]
958 fn map_unmap_negative_size() {
959 let scale_offset = ScaleOffset::new(2.0, 2.0, 1.0, 1.0);
960 let rect = Box2D::new(Point2D::new(5.0, 5.0), Point2D::new(0.0, 0.0));
961 let mapped_rect: Box2D<f32> = scale_offset.map_rect(&rect);
962 assert_eq!(mapped_rect, Box2D::new(Point2D::new(11.0, 11.0), Point2D::new(11.0, 11.0)));
963
964 let unmapped_rect: Box2D<f32> = scale_offset.unmap_rect(&rect);
965 assert_eq!(unmapped_rect, Box2D::new(Point2D::new(2.0, 2.0), Point2D::new(2.0, 2.0)));
966 }
967
968 #[test]
971 fn map_unmap_adjoining_rects() {
972 let so = ScaleOffset::new(0.3, 0.3, 0.0, 0.0);
973 let p1 = Point2D::new(15.0, 15.0);
974 let p2 = Point2D::new(45.0, 45.0);
975 let p3 = Point2D::new(75.0, 75.0);
976
977 let rect_1 = Box2D::new(p1, p2);
978 let rect_2 = Box2D::new(p2, p3);
979
980 let mapped_rect_1: Box2D<f32> = so.map_rect(&rect_1);
981 let mapped_rect_2: Box2D<f32> = so.map_rect(&rect_2);
982 assert_eq!(mapped_rect_1.max, mapped_rect_2.min);
983
984 let unmapped_rect_1: Box2D<f32> = so.unmap_rect(&rect_1);
985 let unmapped_rect_2: Box2D<f32> = so.unmap_rect(&rect_2);
986 assert_eq!(unmapped_rect_1.max, unmapped_rect_2.min);
987 }
988}
989
990pub trait MaxRect {
991 fn max_rect() -> Self;
992}
993
994impl MaxRect for DeviceIntRect {
995 fn max_rect() -> Self {
996 DeviceIntRect::from_origin_and_size(
997 DeviceIntPoint::new(i32::MIN / 2, i32::MIN / 2),
998 DeviceIntSize::new(i32::MAX, i32::MAX),
999 )
1000 }
1001}
1002
1003impl<U> MaxRect for Rect<f32, U> {
1004 fn max_rect() -> Self {
1005 const MAX_COORD: f32 = 1.0e9;
1012
1013 Rect::new(
1014 Point2D::new(-MAX_COORD, -MAX_COORD),
1015 Size2D::new(2.0 * MAX_COORD, 2.0 * MAX_COORD),
1016 )
1017 }
1018}
1019
1020impl<U> MaxRect for Box2D<f32, U> {
1021 fn max_rect() -> Self {
1022 const MAX_COORD: f32 = 1.0e9;
1029
1030 Box2D::new(
1031 Point2D::new(-MAX_COORD, -MAX_COORD),
1032 Point2D::new(MAX_COORD, MAX_COORD),
1033 )
1034 }
1035}
1036
1037#[derive(Debug, MallocSizeOf)]
1040#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1041pub enum FastTransform<Src, Dst> {
1042 Offset(Vector2D<f32, Src>),
1044
1045 Transform {
1047 transform: Transform3D<f32, Src, Dst>,
1048 inverse: Option<Transform3D<f32, Dst, Src>>,
1049 is_2d: bool,
1050 },
1051}
1052
1053impl<Src, Dst> Clone for FastTransform<Src, Dst> {
1054 fn clone(&self) -> Self {
1055 *self
1056 }
1057}
1058
1059impl<Src, Dst> Copy for FastTransform<Src, Dst> { }
1060
1061impl<Src, Dst> Default for FastTransform<Src, Dst> {
1062 fn default() -> Self {
1063 Self::identity()
1064 }
1065}
1066
1067impl<Src, Dst> FastTransform<Src, Dst> {
1068 pub fn identity() -> Self {
1069 FastTransform::Offset(Vector2D::zero())
1070 }
1071
1072 pub fn with_vector(offset: Vector2D<f32, Src>) -> Self {
1073 FastTransform::Offset(offset)
1074 }
1075
1076 pub fn with_scale_offset(scale_offset: ScaleOffset) -> Self {
1077 if scale_offset.scale == Vector2D::new(1.0, 1.0) {
1078 FastTransform::Offset(Vector2D::from_untyped(scale_offset.offset))
1079 } else {
1080 FastTransform::Transform {
1081 transform: scale_offset.to_transform(),
1082 inverse: Some(scale_offset.inverse().to_transform()),
1083 is_2d: true,
1084 }
1085 }
1086 }
1087
1088 #[inline(always)]
1089 pub fn with_transform(transform: Transform3D<f32, Src, Dst>) -> Self {
1090 if transform.is_simple_2d_translation() {
1091 return FastTransform::Offset(Vector2D::new(transform.m41, transform.m42));
1092 }
1093 let inverse = transform.inverse();
1094 let is_2d = transform.is_2d();
1095 FastTransform::Transform { transform, inverse, is_2d}
1096 }
1097
1098 pub fn to_transform(&self) -> Cow<Transform3D<f32, Src, Dst>> {
1099 match *self {
1100 FastTransform::Offset(offset) => Cow::Owned(
1101 Transform3D::translation(offset.x, offset.y, 0.0)
1102 ),
1103 FastTransform::Transform { ref transform, .. } => Cow::Borrowed(transform),
1104 }
1105 }
1106
1107 #[allow(unused)]
1109 pub fn is_identity(&self)-> bool {
1110 match *self {
1111 FastTransform::Offset(offset) => {
1112 offset == Vector2D::zero()
1113 }
1114 FastTransform::Transform { ref transform, .. } => {
1115 *transform == Transform3D::identity()
1116 }
1117 }
1118 }
1119
1120 pub fn then<NewDst>(&self, other: &FastTransform<Dst, NewDst>) -> FastTransform<Src, NewDst> {
1121 match *self {
1122 FastTransform::Offset(offset) => match *other {
1123 FastTransform::Offset(other_offset) => {
1124 FastTransform::Offset(offset + other_offset * Scale::<_, _, Src>::new(1.0))
1125 }
1126 FastTransform::Transform { transform: ref other_transform, .. } => {
1127 FastTransform::with_transform(
1128 other_transform
1129 .with_source::<Src>()
1130 .pre_translate(offset.to_3d())
1131 )
1132 }
1133 }
1134 FastTransform::Transform { ref transform, ref inverse, is_2d } => match *other {
1135 FastTransform::Offset(other_offset) => {
1136 FastTransform::with_transform(
1137 transform
1138 .then_translate(other_offset.to_3d())
1139 .with_destination::<NewDst>()
1140 )
1141 }
1142 FastTransform::Transform { transform: ref other_transform, inverse: ref other_inverse, is_2d: other_is_2d } => {
1143 FastTransform::Transform {
1144 transform: transform.then(other_transform),
1145 inverse: inverse.as_ref().and_then(|self_inv|
1146 other_inverse.as_ref().map(|other_inv| other_inv.then(self_inv))
1147 ),
1148 is_2d: is_2d & other_is_2d,
1149 }
1150 }
1151 }
1152 }
1153 }
1154
1155 pub fn pre_transform<NewSrc>(
1156 &self,
1157 other: &FastTransform<NewSrc, Src>
1158 ) -> FastTransform<NewSrc, Dst> {
1159 other.then(self)
1160 }
1161
1162 pub fn pre_translate(&self, other_offset: Vector2D<f32, Src>) -> Self {
1163 match *self {
1164 FastTransform::Offset(offset) =>
1165 FastTransform::Offset(offset + other_offset),
1166 FastTransform::Transform { transform, .. } =>
1167 FastTransform::with_transform(transform.pre_translate(other_offset.to_3d()))
1168 }
1169 }
1170
1171 pub fn then_translate(&self, other_offset: Vector2D<f32, Dst>) -> Self {
1172 match *self {
1173 FastTransform::Offset(offset) => {
1174 FastTransform::Offset(offset + other_offset * Scale::<_, _, Src>::new(1.0))
1175 }
1176 FastTransform::Transform { ref transform, .. } => {
1177 let transform = transform.then_translate(other_offset.to_3d());
1178 FastTransform::with_transform(transform)
1179 }
1180 }
1181 }
1182
1183 #[inline(always)]
1184 pub fn is_backface_visible(&self) -> bool {
1185 match *self {
1186 FastTransform::Offset(..) => false,
1187 FastTransform::Transform { inverse: None, .. } => false,
1188 FastTransform::Transform { inverse: Some(ref inverse), .. } => inverse.m33 < 0.0,
1191 }
1192 }
1193
1194 #[inline(always)]
1195 pub fn transform_point2d(&self, point: Point2D<f32, Src>) -> Option<Point2D<f32, Dst>> {
1196 match *self {
1197 FastTransform::Offset(offset) => {
1198 let new_point = point + offset;
1199 Some(Point2D::from_untyped(new_point.to_untyped()))
1200 }
1201 FastTransform::Transform { ref transform, .. } => transform.transform_point2d(point),
1202 }
1203 }
1204
1205 #[inline(always)]
1206 pub fn project_point2d(&self, point: Point2D<f32, Src>) -> Option<Point2D<f32, Dst>> {
1207 match* self {
1208 FastTransform::Offset(..) => self.transform_point2d(point),
1209 FastTransform::Transform{ref transform, ..} => {
1210 let z = -(point.x * transform.m13 + point.y * transform.m23 + transform.m43) / transform.m33;
1217
1218 transform.transform_point3d(point3(point.x, point.y, z)).map(| p3 | point2(p3.x, p3.y))
1219 }
1220 }
1221 }
1222
1223 #[inline(always)]
1224 pub fn inverse(&self) -> Option<FastTransform<Dst, Src>> {
1225 match *self {
1226 FastTransform::Offset(offset) =>
1227 Some(FastTransform::Offset(Vector2D::new(-offset.x, -offset.y))),
1228 FastTransform::Transform { transform, inverse: Some(inverse), is_2d, } =>
1229 Some(FastTransform::Transform {
1230 transform: inverse,
1231 inverse: Some(transform),
1232 is_2d
1233 }),
1234 FastTransform::Transform { inverse: None, .. } => None,
1235
1236 }
1237 }
1238}
1239
1240impl<Src, Dst> From<Transform3D<f32, Src, Dst>> for FastTransform<Src, Dst> {
1241 fn from(transform: Transform3D<f32, Src, Dst>) -> Self {
1242 FastTransform::with_transform(transform)
1243 }
1244}
1245
1246impl<Src, Dst> From<Vector2D<f32, Src>> for FastTransform<Src, Dst> {
1247 fn from(vector: Vector2D<f32, Src>) -> Self {
1248 FastTransform::with_vector(vector)
1249 }
1250}
1251
1252pub type LayoutFastTransform = FastTransform<LayoutPixel, LayoutPixel>;
1253pub type LayoutToWorldFastTransform = FastTransform<LayoutPixel, WorldPixel>;
1254
1255pub fn project_rect<F, T>(
1256 transform: &Transform3D<f32, F, T>,
1257 rect: &Box2D<f32, F>,
1258 bounds: &Box2D<f32, T>,
1259) -> Option<Box2D<f32, T>>
1260 where F: fmt::Debug
1261{
1262 let homogens = [
1263 transform.transform_point2d_homogeneous(rect.top_left()),
1264 transform.transform_point2d_homogeneous(rect.top_right()),
1265 transform.transform_point2d_homogeneous(rect.bottom_left()),
1266 transform.transform_point2d_homogeneous(rect.bottom_right()),
1267 ];
1268
1269 if homogens.iter().any(|h| h.w <= 0.0 || h.w.is_nan()) {
1272 let mut clipper = Clipper::new();
1273 let polygon = Polygon::from_rect(rect.to_rect().cast().cast_unit(), 1);
1274
1275 let planes = match Clipper::<usize>::frustum_planes(
1276 &transform.cast_unit().cast(),
1277 Some(bounds.to_rect().cast_unit().to_f64()),
1278 ) {
1279 Ok(planes) => planes,
1280 Err(..) => return None,
1281 };
1282
1283 for plane in planes {
1284 clipper.add(plane);
1285 }
1286
1287 let results = clipper.clip(polygon);
1288 if results.is_empty() {
1289 return None
1290 }
1291
1292 Some(Box2D::from_points(results
1293 .into_iter()
1294 .flat_map(|poly| &poly.points)
1296 .map(|p| {
1297 let mut homo = transform.transform_point2d_homogeneous(p.to_2d().to_f32().cast_unit());
1298 homo.w = homo.w.max(0.00000001); homo.to_point2d().unwrap()
1300 })
1301 ))
1302 } else {
1303 Some(Box2D::from_points(&[
1305 homogens[0].to_point2d().unwrap(),
1306 homogens[1].to_point2d().unwrap(),
1307 homogens[2].to_point2d().unwrap(),
1308 homogens[3].to_point2d().unwrap(),
1309 ]))
1310 }
1311}
1312
1313pub fn drain_filter<T, Filter, Action>(
1355 vec: &mut Vec<T>,
1356 mut filter: Filter,
1357 mut action: Action,
1358)
1359where
1360 Filter: FnMut(&mut T) -> bool,
1361 Action: FnMut(T)
1362{
1363 let mut i = 0;
1364 while i != vec.len() {
1365 if filter(&mut vec[i]) {
1366 action(vec.remove(i));
1367 } else {
1368 i += 1;
1369 }
1370 }
1371}
1372
1373
1374#[derive(Debug)]
1375pub struct Recycler {
1376 pub num_allocations: usize,
1377}
1378
1379impl Recycler {
1380 const MAX_EXTRA_CAPACITY_PERCENT: usize = 200;
1383 const MIN_EXTRA_CAPACITY_PERCENT: usize = 20;
1385 const MIN_VECTOR_LENGTH: usize = 16;
1387
1388 pub fn new() -> Self {
1389 Recycler {
1390 num_allocations: 0,
1391 }
1392 }
1393
1394 pub fn recycle_vec<T>(&mut self, vec: &mut Vec<T>) {
1397 let extra_capacity = (vec.capacity() - vec.len()) * 100 / vec.len().max(Self::MIN_VECTOR_LENGTH);
1398
1399 if extra_capacity > Self::MAX_EXTRA_CAPACITY_PERCENT {
1400 *vec = Vec::with_capacity(vec.len() + vec.len() * Self::MIN_EXTRA_CAPACITY_PERCENT / 100);
1405 self.num_allocations += 1;
1406 } else {
1407 vec.clear();
1408 }
1409 }
1410}
1411
1412#[derive(Copy, Clone, Debug)]
1415pub struct Preallocator {
1416 size: usize,
1417}
1418
1419impl Preallocator {
1420 pub fn new(initial_size: usize) -> Self {
1421 Preallocator {
1422 size: initial_size,
1423 }
1424 }
1425
1426 pub fn record_vec<T>(&mut self, vec: &[T]) {
1428 let len = vec.len();
1429 if len > self.size {
1430 self.size = len;
1431 } else {
1432 self.size = (self.size + len) / 2;
1433 }
1434 }
1435
1436 pub fn preallocation_size(&self) -> usize {
1438 (self.size + 15) & !15
1441 }
1442
1443 pub fn preallocate_vec<T>(&self, vec: &mut Vec<T>) {
1448 let len = vec.len();
1449 let cap = self.preallocation_size();
1450 if len < cap {
1451 vec.reserve(cap - len);
1452 }
1453 }
1454
1455 pub fn preallocate_framevec<T>(&self, vec: &mut FrameVec<T>) {
1460 let len = vec.len();
1461 let cap = self.preallocation_size();
1462 if len < cap {
1463 vec.reserve(cap - len);
1464 }
1465 }
1466}
1467
1468impl Default for Preallocator {
1469 fn default() -> Self {
1470 Self::new(0)
1471 }
1472}
1473
1474pub fn scale_factors<Src, Dst>(
1483 mat: &Transform3D<f32, Src, Dst>
1484) -> (f32, f32) {
1485 let m11 = mat.m11 as f64;
1486 let m12 = mat.m12 as f64;
1487 let det = m11 * mat.m22 as f64 - m12 * mat.m21 as f64;
1489 if det == 0.0 {
1490 return (0.0, 0.0);
1491 }
1492
1493 let det = det.abs();
1495
1496 let major = (m11 * m11 + m12 * m12).sqrt();
1497 let minor = if major != 0.0 { det / major } else { 0.0 };
1498
1499 (major as f32, minor as f32)
1500}
1501
1502#[test]
1503fn scale_factors_large() {
1504 let mat = Transform3D::<f32, (), ()>::new(
1506 1.6534229920333123e27, 3.673100922561787e27, 0.0, 0.0,
1507 -3.673100922561787e27, 1.6534229920333123e27, 0.0, 0.0,
1508 0.0, 0.0, 1.0, 0.0,
1509 -828140552192.0, -1771307401216.0, 0.0, 1.0,
1510 );
1511 let (major, minor) = scale_factors(&mat);
1512 assert!(major.is_normal() && minor.is_normal());
1513}
1514
1515pub fn clamp_to_scale_factor(val: f32, round_down: bool) -> f32 {
1522 const SCALE_RESOLUTION: f32 = 2.0;
1526
1527 let val = val.abs();
1530
1531 let (val, inverse) = if val < 1.0 {
1532 (1.0 / val, true)
1533 } else {
1534 (val, false)
1535 };
1536
1537 let power = val.log2() / SCALE_RESOLUTION.log2();
1538
1539 let power = if (power - power.round()).abs() < 1e-5 {
1543 power.round()
1544 } else if inverse != round_down {
1545 power.floor()
1548 } else {
1549 power.ceil()
1552 };
1553
1554 let scale = SCALE_RESOLUTION.powf(power);
1555
1556 if inverse {
1557 1.0 / scale
1558 } else {
1559 scale
1560 }
1561}
1562
1563pub fn round_up_to_multiple(val: usize, mul: NonZeroUsize) -> usize {
1565 match val % mul.get() {
1566 0 => val,
1567 rem => val - rem + mul.get(),
1568 }
1569}
1570
1571
1572#[macro_export]
1573macro_rules! c_str {
1574 ($lit:expr) => {
1575 unsafe {
1576 std::ffi::CStr::from_ptr(concat!($lit, "\0").as_ptr()
1577 as *const std::os::raw::c_char)
1578 }
1579 }
1580}
1581
1582pub struct WeakTable {
1585 inner: Vec<std::sync::Weak<Vec<u8>>>
1586}
1587
1588impl WeakTable {
1589 pub fn new() -> WeakTable {
1590 WeakTable { inner: Vec::new() }
1591 }
1592 pub fn insert(&mut self, x: std::sync::Weak<Vec<u8>>) {
1593 if self.inner.len() == self.inner.capacity() {
1594 self.remove_expired();
1595
1596 if self.inner.len() * 3 < self.inner.capacity() {
1600 self.inner.shrink_to_fit();
1604 } else {
1605 self.inner.reserve(self.inner.len())
1607 }
1608 }
1609 self.inner.push(x);
1610 }
1611
1612 fn remove_expired(&mut self) {
1613 self.inner.retain(|x| x.strong_count() > 0)
1614 }
1615
1616 pub fn iter(&self) -> impl Iterator<Item = Arc<Vec<u8>>> + '_ {
1617 self.inner.iter().filter_map(|x| x.upgrade())
1618 }
1619}
1620
1621#[test]
1622fn weak_table() {
1623 let mut tbl = WeakTable::new();
1624 let mut things = Vec::new();
1625 let target_count = 50;
1626 for _ in 0..target_count {
1627 things.push(Arc::new(vec![4]));
1628 }
1629 for i in &things {
1630 tbl.insert(Arc::downgrade(i))
1631 }
1632 assert_eq!(tbl.inner.len(), target_count);
1633 drop(things);
1634 assert_eq!(tbl.iter().count(), 0);
1635
1636 for _ in 0..target_count*2 {
1639 tbl.insert(Arc::downgrade(&Arc::new(vec![5])))
1640 }
1641 assert!(tbl.inner.capacity() <= 4);
1642}
1643
1644#[test]
1645fn scale_offset_pre_post() {
1646 let a = ScaleOffset::new(1.0, 2.0, 3.0, 4.0);
1647 let b = ScaleOffset::new(5.0, 6.0, 7.0, 8.0);
1648
1649 assert_eq!(a.then(&b), b.pre_transform(&a));
1650 assert_eq!(a.then_scale(10.0), a.then(&ScaleOffset::from_scale(Vector2D::new(10.0, 10.0))));
1651 assert_eq!(a.pre_scale(10.0), a.pre_transform(&ScaleOffset::from_scale(Vector2D::new(10.0, 10.0))));
1652}