servo: Merge #12841 - Fix hit testing to take into account nested stacking contexts #12777 (from emilio:hit-test); r=pcwalton
authorEmilio Cobos Álvarez <ecoal95@gmail.com>
Thu, 25 Aug 2016 13:44:27 -0500
changeset 368601 24fe39332dec9f935f3070ef5f1ac82f6204fe05
parent 368600 0a908d343078cd91dfe69724f3dec99609e99a7d
child 368602 622700a312cbeb52c0cbeaf07798315df7f30a2e
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspcwalton
servo: Merge #12841 - Fix hit testing to take into account nested stacking contexts #12777 (from emilio:hit-test); r=pcwalton <!-- Please describe your changes on the following line: --> Fixes #12833. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #12833 (github issue number if applicable). <!-- Either: --> - [x] There are tests for these changes OR <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 9b4713f5366aa43ac0db6a8f1d96f33b2f527978
servo/components/gfx/display_list/mod.rs
--- a/servo/components/gfx/display_list/mod.rs
+++ b/servo/components/gfx/display_list/mod.rs
@@ -714,64 +714,69 @@ impl StackingContext {
                                             .pre_mul(&self.transform);
         let transform_2d = transform.to_2d();
 
         let overflow = geometry::au_rect_to_f32_rect(self.overflow);
         let overflow = transform_2d.transform_rect(&overflow);
         geometry::f32_rect_to_au_rect(overflow)
     }
 
-    pub fn hit_test<'a>(&self,
-                        traversal: &mut DisplayListTraversal<'a>,
-                        translated_point: &Point2D<Au>,
-                        client_point: &Point2D<Au>,
-                        scroll_offsets: &ScrollOffsetMap,
-                        result: &mut Vec<DisplayItemMetadata>) {
+    fn hit_test<'a>(&self,
+                    traversal: &mut DisplayListTraversal<'a>,
+                    translated_point: &Point2D<Au>,
+                    client_point: &Point2D<Au>,
+                    scroll_offsets: &ScrollOffsetMap,
+                    result: &mut Vec<DisplayItemMetadata>) {
         let is_fixed = match self.layer_info {
             Some(ref layer_info) => layer_info.scroll_policy == ScrollPolicy::FixedPosition,
             None => false,
         };
 
-        let effective_point = if is_fixed { client_point } else { translated_point };
-
-        // Convert the point into stacking context local transform space.
-        let mut point = if self.context_type == StackingContextType::Real {
-            let point = *effective_point - self.bounds.origin;
+        // Convert the parent translated point into stacking context local
+        // transform space if the stacking context isn't fixed.
+        //
+        // If it's fixed, we need to use the client point anyway, and if it's a
+        // pseudo-stacking context, our parent's is enough.
+        let mut translated_point = if is_fixed {
+            *client_point
+        } else if self.context_type == StackingContextType::Real {
+            let point = *translated_point - self.bounds.origin;
             let inv_transform = self.transform.inverse().unwrap();
             let frac_point = inv_transform.transform_point(&Point2D::new(point.x.to_f32_px(),
                                                                          point.y.to_f32_px()));
             Point2D::new(Au::from_f32_px(frac_point.x), Au::from_f32_px(frac_point.y))
         } else {
-            *effective_point
+            *translated_point
         };
 
         // Adjust the translated point to account for the scroll offset if
         // necessary. This can only happen when WebRender is in use.
         //
         // We don't perform this adjustment on the root stacking context because
         // the DOM-side code has already translated the point for us (e.g. in
         // `Window::hit_test_query()`) by now.
         if !is_fixed && self.id != StackingContextId::root() {
             if let Some(scroll_offset) = scroll_offsets.get(&self.id) {
-                point.x -= Au::from_f32_px(scroll_offset.x);
-                point.y -= Au::from_f32_px(scroll_offset.y);
+                translated_point.x -= Au::from_f32_px(scroll_offset.x);
+                translated_point.y -= Au::from_f32_px(scroll_offset.y);
             }
         }
 
         for child in self.children() {
             while let Some(item) = traversal.advance(self) {
-                if let Some(meta) = item.hit_test(point) {
+                if let Some(meta) = item.hit_test(translated_point) {
                     result.push(meta);
                 }
             }
-            child.hit_test(traversal, translated_point, client_point, scroll_offsets, result);
+            child.hit_test(traversal, &translated_point, client_point,
+                           scroll_offsets, result);
         }
 
         while let Some(item) = traversal.advance(self) {
-            if let Some(meta) = item.hit_test(point) {
+            if let Some(meta) = item.hit_test(translated_point) {
                 result.push(meta);
             }
         }
     }
 
     pub fn print_with_tree(&self, print_tree: &mut PrintTree) {
         print_tree.new_level(format!("{:?}", self));
         for kid in self.children() {