From 126133ead775fda064a6c23503e9a552a10dc2c5 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Sat, 22 Feb 2020 18:03:49 +0100
Subject: Fix `Clip` primitive intersection in `iced_wgpu`

---
 core/src/rectangle.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 wgpu/src/renderer.rs  | 29 +++++++++++------------------
 2 files changed, 61 insertions(+), 18 deletions(-)

diff --git a/core/src/rectangle.rs b/core/src/rectangle.rs
index ee1e3807..7ed3d2df 100644
--- a/core/src/rectangle.rs
+++ b/core/src/rectangle.rs
@@ -27,6 +27,34 @@ impl Rectangle<f32> {
             && self.y <= point.y
             && point.y <= self.y + self.height
     }
+
+    /// Computes the intersection with the given [`Rectangle`].
+    ///
+    /// [`Rectangle`]: struct.Rectangle.html
+    pub fn intersection(
+        &self,
+        other: &Rectangle<f32>,
+    ) -> Option<Rectangle<f32>> {
+        let x = self.x.max(other.x);
+        let y = self.y.max(other.y);
+
+        let lower_right_x = (self.x + self.width).min(other.x + other.width);
+        let lower_right_y = (self.y + self.height).min(other.y + other.height);
+
+        let width = lower_right_x - x;
+        let height = lower_right_y - y;
+
+        if width > 0.0 && height > 0.0 {
+            Some(Rectangle {
+                x,
+                y,
+                width,
+                height,
+            })
+        } else {
+            None
+        }
+    }
 }
 
 impl std::ops::Mul<f32> for Rectangle<u32> {
@@ -41,3 +69,25 @@ impl std::ops::Mul<f32> for Rectangle<u32> {
         }
     }
 }
+
+impl From<Rectangle<u32>> for Rectangle<f32> {
+    fn from(rectangle: Rectangle<u32>) -> Rectangle<f32> {
+        Rectangle {
+            x: rectangle.x as f32,
+            y: rectangle.y as f32,
+            width: rectangle.width as f32,
+            height: rectangle.height as f32,
+        }
+    }
+}
+
+impl From<Rectangle<f32>> for Rectangle<u32> {
+    fn from(rectangle: Rectangle<f32>) -> Rectangle<u32> {
+        Rectangle {
+            x: rectangle.x as u32,
+            y: rectangle.y as u32,
+            width: rectangle.width.ceil() as u32,
+            height: rectangle.height.ceil() as u32,
+        }
+    }
+}
diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs
index 29adcfb6..af61804e 100644
--- a/wgpu/src/renderer.rs
+++ b/wgpu/src/renderer.rs
@@ -240,25 +240,18 @@ impl Renderer {
                 offset,
                 content,
             } => {
-                let x = bounds.x - layer.offset.x as f32;
-                let y = bounds.y - layer.offset.y as f32;
-                let width = (bounds.width + x).min(bounds.width);
-                let height = (bounds.height + y).min(bounds.height);
-
-                // Only draw visible content on-screen
-                // TODO: Also, check for parent layer bounds to avoid further
-                // drawing in some circumstances.
-                if width > 0.0 && height > 0.0 {
-                    let clip_layer = Layer::new(
-                        Rectangle {
-                            x: x.max(0.0).floor() as u32,
-                            y: y.max(0.0).floor() as u32,
-                            width: width.ceil() as u32,
-                            height: height.ceil() as u32,
-                        },
-                        layer.offset + *offset,
-                    );
+                let layer_bounds: Rectangle<f32> = layer.bounds.into();
 
+                let clip = Rectangle {
+                    x: bounds.x - layer.offset.x as f32,
+                    y: bounds.y - layer.offset.y as f32,
+                    ..*bounds
+                };
+
+                // Only draw visible content
+                if let Some(clip_bounds) = layer_bounds.intersection(&clip) {
+                    let clip_layer =
+                        Layer::new(clip_bounds.into(), layer.offset + *offset);
                     let new_layer = Layer::new(layer.bounds, layer.offset);
 
                     layers.push(clip_layer);
-- 
cgit