tor-browser

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

space.rs (9499B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 
      6 //! Utilities to deal with coordinate spaces.
      7 
      8 use std::fmt;
      9 
     10 use euclid::{Transform3D, Box2D, Point2D, Vector2D};
     11 
     12 use api::units::*;
     13 use crate::spatial_tree::{SpatialTree, CoordinateSpaceMapping, SpatialNodeIndex, VisibleFace, SpatialNodeContainer};
     14 use crate::util::project_rect;
     15 use crate::util::{MatrixHelpers, ScaleOffset, RectHelpers, PointHelpers};
     16 
     17 
     18 #[derive(Debug, Clone)]
     19 pub struct SpaceMapper<F, T> {
     20    kind: CoordinateSpaceMapping<F, T>,
     21    pub ref_spatial_node_index: SpatialNodeIndex,
     22    pub current_target_spatial_node_index: SpatialNodeIndex,
     23    pub bounds: Box2D<f32, T>,
     24    visible_face: VisibleFace,
     25 }
     26 
     27 impl<F, T> SpaceMapper<F, T> where F: fmt::Debug {
     28    pub fn new(
     29        ref_spatial_node_index: SpatialNodeIndex,
     30        bounds: Box2D<f32, T>,
     31    ) -> Self {
     32        SpaceMapper {
     33            kind: CoordinateSpaceMapping::Local,
     34            ref_spatial_node_index,
     35            current_target_spatial_node_index: ref_spatial_node_index,
     36            bounds,
     37            visible_face: VisibleFace::Front,
     38        }
     39    }
     40 
     41    pub fn new_with_target(
     42        ref_spatial_node_index: SpatialNodeIndex,
     43        target_node_index: SpatialNodeIndex,
     44        bounds: Box2D<f32, T>,
     45        spatial_tree: &SpatialTree,
     46    ) -> Self {
     47        let mut mapper = Self::new(ref_spatial_node_index, bounds);
     48        mapper.set_target_spatial_node(target_node_index, spatial_tree);
     49        mapper
     50    }
     51 
     52    pub fn set_target_spatial_node(
     53        &mut self,
     54        target_node_index: SpatialNodeIndex,
     55        spatial_tree: &SpatialTree,
     56    ) {
     57        if target_node_index == self.current_target_spatial_node_index {
     58            return
     59        }
     60 
     61        let ref_spatial_node = spatial_tree.get_spatial_node(self.ref_spatial_node_index);
     62        let target_spatial_node = spatial_tree.get_spatial_node(target_node_index);
     63        self.visible_face = VisibleFace::Front;
     64 
     65        self.kind = if self.ref_spatial_node_index == target_node_index {
     66            CoordinateSpaceMapping::Local
     67        } else if ref_spatial_node.coordinate_system_id == target_spatial_node.coordinate_system_id {
     68            let scale_offset = target_spatial_node.content_transform
     69                .then(&ref_spatial_node.content_transform.inverse());
     70            CoordinateSpaceMapping::ScaleOffset(scale_offset)
     71        } else {
     72            let transform = spatial_tree
     73                .get_relative_transform_with_face(
     74                    target_node_index,
     75                    self.ref_spatial_node_index,
     76                    Some(&mut self.visible_face),
     77                )
     78                .into_transform()
     79                .with_source::<F>()
     80                .with_destination::<T>();
     81            CoordinateSpaceMapping::Transform(transform)
     82        };
     83 
     84        self.current_target_spatial_node_index = target_node_index;
     85    }
     86 
     87    pub fn get_transform(&self) -> Transform3D<f32, F, T> {
     88        match self.kind {
     89            CoordinateSpaceMapping::Local => {
     90                Transform3D::identity()
     91            }
     92            CoordinateSpaceMapping::ScaleOffset(ref scale_offset) => {
     93                scale_offset.to_transform()
     94            }
     95            CoordinateSpaceMapping::Transform(transform) => {
     96                transform
     97            }
     98        }
     99    }
    100 
    101    pub fn unmap(&self, rect: &Box2D<f32, T>) -> Option<Box2D<f32, F>> {
    102        match self.kind {
    103            CoordinateSpaceMapping::Local => {
    104                Some(rect.cast_unit())
    105            }
    106            CoordinateSpaceMapping::ScaleOffset(ref scale_offset) => {
    107                Some(scale_offset.unmap_rect(rect))
    108            }
    109            CoordinateSpaceMapping::Transform(ref transform) => {
    110                transform.inverse_rect_footprint(rect)
    111            }
    112        }
    113    }
    114 
    115    pub fn map(&self, rect: &Box2D<f32, F>) -> Option<Box2D<f32, T>> {
    116        match self.kind {
    117            CoordinateSpaceMapping::Local => {
    118                Some(rect.cast_unit())
    119            }
    120            CoordinateSpaceMapping::ScaleOffset(ref scale_offset) => {
    121                Some(scale_offset.map_rect(rect))
    122            }
    123            CoordinateSpaceMapping::Transform(ref transform) => {
    124                match project_rect(transform, rect, &self.bounds) {
    125                    Some(bounds) => {
    126                        Some(bounds)
    127                    }
    128                    None => {
    129                        warn!("parent relative transform can't transform the primitive rect for {:?}", rect);
    130                        None
    131                    }
    132                }
    133            }
    134        }
    135    }
    136 
    137    // Attempt to return a rect that is contained in the mapped rect.
    138    pub fn map_inner_bounds(&self, rect: &Box2D<f32, F>) -> Option<Box2D<f32, T>> {
    139        match self.kind {
    140            CoordinateSpaceMapping::Local => {
    141                Some(rect.cast_unit())
    142            }
    143            CoordinateSpaceMapping::ScaleOffset(ref scale_offset) => {
    144                Some(scale_offset.map_rect(rect))
    145            }
    146            CoordinateSpaceMapping::Transform(..) => {
    147                // We could figure out a rect that is contained in the transformed rect but
    148                // for now we do the simple thing here and bail out.
    149                return None;
    150            }
    151        }
    152    }
    153 
    154    // Map a local space point to the target coordinate space
    155    pub fn map_point(&self, p: Point2D<f32, F>) -> Option<Point2D<f32, T>> {
    156        match self.kind {
    157            CoordinateSpaceMapping::Local => {
    158                Some(p.cast_unit())
    159            }
    160            CoordinateSpaceMapping::ScaleOffset(ref scale_offset) => {
    161                Some(scale_offset.map_point(&p))
    162            }
    163            CoordinateSpaceMapping::Transform(ref transform) => {
    164                transform.transform_point2d(p)
    165            }
    166        }
    167    }
    168 
    169    pub fn map_vector(&self, v: Vector2D<f32, F>) -> Vector2D<f32, T> {
    170        match self.kind {
    171            CoordinateSpaceMapping::Local => {
    172                v.cast_unit()
    173            }
    174            CoordinateSpaceMapping::ScaleOffset(ref scale_offset) => {
    175                scale_offset.map_vector(&v)
    176            }
    177            CoordinateSpaceMapping::Transform(ref transform) => {
    178                transform.transform_vector2d(v)
    179            }
    180        }
    181    }
    182 }
    183 
    184 
    185 #[derive(Clone, Debug)]
    186 pub struct SpaceSnapper {
    187    ref_spatial_node_index: SpatialNodeIndex,
    188    current_target_spatial_node_index: SpatialNodeIndex,
    189    snapping_transform: Option<ScaleOffset>,
    190    raster_pixel_scale: RasterPixelScale,
    191 }
    192 
    193 impl SpaceSnapper {
    194    pub fn new(
    195        ref_spatial_node_index: SpatialNodeIndex,
    196        raster_pixel_scale: RasterPixelScale,
    197    ) -> Self {
    198        SpaceSnapper {
    199            ref_spatial_node_index,
    200            current_target_spatial_node_index: SpatialNodeIndex::INVALID,
    201            snapping_transform: None,
    202            raster_pixel_scale,
    203        }
    204    }
    205 
    206    pub fn new_with_target<S: SpatialNodeContainer>(
    207        ref_spatial_node_index: SpatialNodeIndex,
    208        target_node_index: SpatialNodeIndex,
    209        raster_pixel_scale: RasterPixelScale,
    210        spatial_tree: &S,
    211    ) -> Self {
    212        let mut snapper = SpaceSnapper {
    213            ref_spatial_node_index,
    214            current_target_spatial_node_index: SpatialNodeIndex::INVALID,
    215            snapping_transform: None,
    216            raster_pixel_scale,
    217        };
    218 
    219        snapper.set_target_spatial_node(target_node_index, spatial_tree);
    220        snapper
    221    }
    222 
    223    pub fn set_target_spatial_node<S: SpatialNodeContainer>(
    224        &mut self,
    225        target_node_index: SpatialNodeIndex,
    226        spatial_tree: &S,
    227    ) {
    228        if target_node_index == self.current_target_spatial_node_index {
    229            return
    230        }
    231 
    232        let ref_snap = spatial_tree.get_node_info(self.ref_spatial_node_index).snapping_transform;
    233        let target_snap = spatial_tree.get_node_info(target_node_index).snapping_transform;
    234 
    235        self.current_target_spatial_node_index = target_node_index;
    236        self.snapping_transform = match (ref_snap, target_snap) {
    237            (Some(ref ref_scale_offset), Some(ref target_scale_offset)) => {
    238                Some(target_scale_offset
    239                    .pre_scale(self.raster_pixel_scale.0)
    240                    .then(&ref_scale_offset.inverse())
    241                )
    242            }
    243            _ => None,
    244        };
    245    }
    246 
    247    pub fn snap_rect<F>(&self, rect: &Box2D<f32, F>) -> Box2D<f32, F> where F: fmt::Debug {
    248        debug_assert!(self.current_target_spatial_node_index != SpatialNodeIndex::INVALID);
    249        match self.snapping_transform {
    250            Some(ref scale_offset) => {
    251                let snapped_device_rect: DeviceRect = scale_offset.map_rect(rect).snap();
    252                scale_offset.unmap_rect(&snapped_device_rect)
    253            }
    254            None => *rect,
    255        }
    256    }
    257 
    258    pub fn snap_point<F>(&self, point: &Point2D<f32, F>) -> Point2D<f32, F> where F: fmt::Debug {
    259        debug_assert!(self.current_target_spatial_node_index != SpatialNodeIndex::INVALID);
    260        match self.snapping_transform {
    261            Some(ref scale_offset) => {
    262                let snapped_device_vector : DevicePoint = scale_offset.map_point(point).snap();
    263                scale_offset.unmap_point(&snapped_device_vector)
    264            }
    265            None => *point,
    266        }
    267    }
    268 }