<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use euclid::Point3D;
use geometry::ray_intersects_rect;
use spring::{DAMPING, STIFFNESS, Spring};
use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform};
use webrender_traits::{LayerToWorldTransform, PipelineId, ScrollEventPhase, ScrollLayerId};
use webrender_traits::{ScrollLayerRect, ScrollLocation, ScrollToWorldTransform, WorldPoint};
use webrender_traits::{WorldPoint4D};

#[cfg(target_os = "macos")]
const CAN_OVERSCROLL: bool = true;

#[cfg(not(target_os = "macos"))]
const CAN_OVERSCROLL: bool = false;


/// Contains scrolling and transform information stacking contexts.
#[derive(Clone)]
pub struct Layer {
    /// Manages scrolling offset, overscroll state etc.
    pub scrolling: ScrollingState,

    /// Size of the content inside the scroll region (in logical pixels)
    pub content_size: LayerSize,

    /// Viewing rectangle
    pub local_viewport_rect: LayerRect,

    /// Viewing rectangle clipped against parent layer(s)
    pub combined_local_viewport_rect: LayerRect,

    /// World transform for the viewport rect itself.
    pub world_viewport_transform: LayerToWorldTransform,

    /// World transform for content within this layer
    pub world_content_transform: LayerToWorldTransform,

    /// Transform for this layer, relative to parent scrollable layer.
    pub local_transform: LayerToScrollTransform,

    /// Pipeline that this layer belongs to
    pub pipeline_id: PipelineId,

    /// Child layers
    pub children: Vec<ScrollLayerId>,
}

impl Layer {
    pub fn new(local_viewport_rect: &LayerRect,
               content_size: LayerSize,
               local_transform: &LayerToScrollTransform,
               pipeline_id: PipelineId)
               -> Layer {
        Layer {
            scrolling: ScrollingState::new(),
            content_size: content_size,
            local_viewport_rect: *local_viewport_rect,
            combined_local_viewport_rect: *local_viewport_rect,
            world_viewport_transform: LayerToWorldTransform::identity(),
            world_content_transform: LayerToWorldTransform::identity(),
            local_transform: *local_transform,
            children: Vec::new(),
            pipeline_id: pipeline_id,
        }
    }

    pub fn add_child(&mut self, child: ScrollLayerId) {
        self.children.push(child);
    }

    pub fn finalize(&mut self, scrolling: &ScrollingState) {
        self.scrolling = *scrolling;
    }

    pub fn overscroll_amount(&self) -> LayerSize {
        let scrollable_width = self.scrollable_width();
        let overscroll_x = if self.scrolling.offset.x > 0.0 {
            -self.scrolling.offset.x
        } else if self.scrolling.offset.x < -scrollable_width {
            -scrollable_width - self.scrolling.offset.x
        } else {
            0.0
        };

        let scrollable_height = self.scrollable_height();
        let overscroll_y = if self.scrolling.offset.y > 0.0 {
            -self.scrolling.offset.y
        } else if self.scrolling.offset.y < -scrollable_height {
            -scrollable_height - self.scrolling.offset.y
        } else {
            0.0
        };

        LayerSize::new(overscroll_x, overscroll_y)
    }

    pub fn set_scroll_origin(&mut self, origin: &LayerPoint) -> bool {
        let scrollable_height = self.scrollable_height();
        let scrollable_width = self.scrollable_width();
        if scrollable_height <= 0. && scrollable_width <= 0. {
            return false;
        }

        let new_offset = LayerPoint::new((-origin.x).max(-scrollable_width).min(0.0).round(),
                                         (-origin.y).max(-scrollable_height).min(0.0).round());
        if new_offset == self.scrolling.offset {
            return false;
        }

        self.scrolling.offset = new_offset;
        self.scrolling.bouncing_back = false;
        self.scrolling.started_bouncing_back = false;
        return true;
    }

    pub fn update_transform(&mut self,
                            parent_world_transform: &ScrollToWorldTransform,
                            parent_viewport_rect: &ScrollLayerRect) {
        let inv_transform = self.local_transform.inverse().unwrap();
        let parent_viewport_rect_in_local_space = inv_transform.transform_rect(parent_viewport_rect)
                                                               .translate(&-self.scrolling.offset);
        let local_viewport_rect = self.local_viewport_rect.translate(&-self.scrolling.offset);
        let viewport_rect = parent_viewport_rect_in_local_space.intersection(&local_viewport_rect)
                                                               .unwrap_or(LayerRect::zero());

        self.combined_local_viewport_rect = viewport_rect;
        self.world_viewport_transform = parent_world_transform.pre_mul(&self.local_transform);
        self.world_content_transform = self.world_viewport_transform
                                                     .pre_translated(self.scrolling.offset.x,
                                                                     self.scrolling.offset.y,
                                                                     0.0);
    }
<commit_msg>Fix the panic when transform is non-invertible<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use euclid::Point3D;
use geometry::ray_intersects_rect;
use spring::{DAMPING, STIFFNESS, Spring};
use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform};
use webrender_traits::{LayerToWorldTransform, PipelineId, ScrollEventPhase, ScrollLayerId};
use webrender_traits::{ScrollLayerRect, ScrollLocation, ScrollToWorldTransform, WorldPoint};
use webrender_traits::{WorldPoint4D};

#[cfg(target_os = "macos")]
const CAN_OVERSCROLL: bool = true;

#[cfg(not(target_os = "macos"))]
const CAN_OVERSCROLL: bool = false;


/// Contains scrolling and transform information stacking contexts.
#[derive(Clone)]
pub struct Layer {
    /// Manages scrolling offset, overscroll state etc.
    pub scrolling: ScrollingState,

    /// Size of the content inside the scroll region (in logical pixels)
    pub content_size: LayerSize,

    /// Viewing rectangle
    pub local_viewport_rect: LayerRect,

    /// Viewing rectangle clipped against parent layer(s)
    pub combined_local_viewport_rect: LayerRect,

    /// World transform for the viewport rect itself.
    pub world_viewport_transform: LayerToWorldTransform,

    /// World transform for content within this layer
    pub world_content_transform: LayerToWorldTransform,

    /// Transform for this layer, relative to parent scrollable layer.
    pub local_transform: LayerToScrollTransform,

    /// Pipeline that this layer belongs to
    pub pipeline_id: PipelineId,

    /// Child layers
    pub children: Vec<ScrollLayerId>,
}

impl Layer {
    pub fn new(local_viewport_rect: &LayerRect,
               content_size: LayerSize,
               local_transform: &LayerToScrollTransform,
               pipeline_id: PipelineId)
               -> Layer {
        Layer {
            scrolling: ScrollingState::new(),
            content_size: content_size,
            local_viewport_rect: *local_viewport_rect,
            combined_local_viewport_rect: *local_viewport_rect,
            world_viewport_transform: LayerToWorldTransform::identity(),
            world_content_transform: LayerToWorldTransform::identity(),
            local_transform: *local_transform,
            children: Vec::new(),
            pipeline_id: pipeline_id,
        }
    }

    pub fn add_child(&mut self, child: ScrollLayerId) {
        self.children.push(child);
    }

    pub fn finalize(&mut self, scrolling: &ScrollingState) {
        self.scrolling = *scrolling;
    }

    pub fn overscroll_amount(&self) -> LayerSize {
        let scrollable_width = self.scrollable_width();
        let overscroll_x = if self.scrolling.offset.x > 0.0 {
            -self.scrolling.offset.x
        } else if self.scrolling.offset.x < -scrollable_width {
            -scrollable_width - self.scrolling.offset.x
        } else {
            0.0
        };

        let scrollable_height = self.scrollable_height();
        let overscroll_y = if self.scrolling.offset.y > 0.0 {
            -self.scrolling.offset.y
        } else if self.scrolling.offset.y < -scrollable_height {
            -scrollable_height - self.scrolling.offset.y
        } else {
            0.0
        };

        LayerSize::new(overscroll_x, overscroll_y)
    }

    pub fn set_scroll_origin(&mut self, origin: &LayerPoint) -> bool {
        let scrollable_height = self.scrollable_height();
        let scrollable_width = self.scrollable_width();
        if scrollable_height <= 0. && scrollable_width <= 0. {
            return false;
        }

        let new_offset = LayerPoint::new((-origin.x).max(-scrollable_width).min(0.0).round(),
                                         (-origin.y).max(-scrollable_height).min(0.0).round());
        if new_offset == self.scrolling.offset {
            return false;
        }

        self.scrolling.offset = new_offset;
        self.scrolling.bouncing_back = false;
        self.scrolling.started_bouncing_back = false;
        return true;
    }

    pub fn update_transform(&mut self,
                            parent_world_transform: &ScrollToWorldTransform,
                            parent_viewport_rect: &ScrollLayerRect) {
        let inv_transform = match self.local_transform.inverse() {
            Some(transform) => transform,
            None => {
                // If a transform function causes the current transformation matrix of an object
                // to be non-invertible, the object and its content do not get displayed.
                self.combined_local_viewport_rect = LayerRect::zero();
                return;
            }
        };

        let parent_viewport_rect_in_local_space = inv_transform.transform_rect(parent_viewport_rect)
                                                               .translate(&-self.scrolling.offset);
        let local_viewport_rect = self.local_viewport_rect.translate(&-self.scrolling.offset);
        let viewport_rect = parent_viewport_rect_in_local_space.intersection(&local_viewport_rect)
                                                               .unwrap_or(LayerRect::zero());

        self.combined_local_viewport_rect = viewport_rect;
        self.world_viewport_transform = parent_world_transform.pre_mul(&self.local_transform);
        self.world_content_transform = self.world_viewport_transform
                                                     .pre_translated(self.scrolling.offset.x,
                                                                     self.scrolling.offset.y,
                                                                     0.0);
    }

{'fraction_non_alphanumeric': 0.08859060402684564, 'fraction_numerical': 0.003937360178970917, 'mean_word_length': 2.2535662299854438, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 28, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6164351', 'n_tokens_mistral': 3112, 'n_tokens_neox': 2970, 'n_words': 679}