Bug 1301290 - Position resizer above own content but beneath overlapping content. r=mats
authorAlex Henrie <alexhenrie24@gmail.com>
Thu, 06 Oct 2016 08:44:00 -0600
changeset 421867 9a154874f694c3e5b54401d70034591b5861e71a
parent 421866 b5c1c15e0a74879178f610a6e663271a52ed2adc
child 421868 ccff388a7ef4eafbd2ea4ae969ed67415f9160f4
push id31622
push userbmo:kevin.m.wern@gmail.com
push dateFri, 07 Oct 2016 01:48:48 +0000
reviewersmats
bugs1301290
milestone52.0a1
Bug 1301290 - Position resizer above own content but beneath overlapping content. r=mats
layout/forms/test/mochitest.ini
layout/forms/test/test_bug1301290.html
layout/generic/nsGfxScrollFrame.cpp
--- a/layout/forms/test/mochitest.ini
+++ b/layout/forms/test/mochitest.ini
@@ -60,9 +60,11 @@ skip-if = (buildapp == 'b2g' && (toolkit
 [test_textarea_resize.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # b2g(resizing textarea not available in b2g) b2g-debug(resizing textarea not available in b2g) b2g-desktop(resizing textarea not available in b2g)
 [test_bug961363.html]
 skip-if = toolkit == 'android' # Bug 1021644 - Fails when pushed into a different chunk on Android
 [test_bug1111995.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g'
 [test_select_vertical.html]
 skip-if = e10s || buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # Bug 1170129 - vertical <select> popup not implemented for e10s # <select> elements don't use an in-page popup on B2G/Android
+[test_bug1301290.html]
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # b2g(resizing textarea not available in b2g) b2g-debug(resizing textarea not available in b2g) b2g-desktop(resizing textarea not available in b2g)
 [test_bug1305282.html]
new file mode 100644
--- /dev/null
+++ b/layout/forms/test/test_bug1301290.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Test for Bug 1301290</title>
+        <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+        <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+        <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+        <style type="text/css">
+            .blue, .green {
+                border: none;
+                box-sizing: border-box;
+                display: block;
+                width: 200px;
+                height: 100px;
+                overflow: scroll;
+                resize: both;
+            }
+
+            .blue {
+                background: blue;
+            }
+
+            .green {
+                background: green;
+                margin-top: -100px;
+            }
+        </style>
+    </head>
+    <body>
+        <div class="blue"></div>
+        <textarea class="green" id="textarea"></textarea>
+        <script type="application/javascript">
+            SimpleTest.waitForExplicitFinish();
+            addLoadEvent(() => SimpleTest.executeSoon(function() {
+                var textarea = $("textarea");
+                var rect = textarea.getBoundingClientRect();
+
+                synthesizeMouse(textarea, rect.width - 10, rect.height - 10, { type: "mousedown" });
+                synthesizeMouse(textarea, rect.width + 40, rect.height + 40, { type: "mousemove" });
+                synthesizeMouse(textarea, rect.width + 40, rect.height + 40, { type: "mouseup" });
+
+                var newrect = textarea.getBoundingClientRect();
+                ok(newrect.width > rect.width, "width did not increase");
+                ok(newrect.height > rect.height, "height did not increase");
+                SimpleTest.finish();
+            }));
+        </script>
+    </body>
+</html>
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -2932,17 +2932,17 @@ ScrollFrameHelper::ScrollToImpl(nsPoint 
   if (docShell) {
     docShell->NotifyScrollObservers();
   }
 }
 
 static int32_t
 MaxZIndexInList(nsDisplayList* aList, nsDisplayListBuilder* aBuilder)
 {
-  int32_t maxZIndex = 0;
+  int32_t maxZIndex = -1;
   for (nsDisplayItem* item = aList->GetBottom(); item; item = item->GetAbove()) {
     maxZIndex = std::max(maxZIndex, item->ZIndex());
   }
   return maxZIndex;
 }
 
 // Finds the max z-index of the items in aList that meet the following conditions
 //   1) have z-index auto or z-index >= 0.
@@ -2961,16 +2961,30 @@ MaxZIndexInListOfItemsContainedInFrame(n
     }
     if (nsLayoutUtils::IsProperAncestorFrame(aFrame, itemFrame)) {
       maxZIndex = std::max(maxZIndex, item->ZIndex());
     }
   }
   return maxZIndex;
 }
 
+template<class T>
+static void
+AppendInternalItemToTop(const nsDisplayListSet& aLists,
+                        T* aItem,
+                        int32_t aZIndex)
+{
+  if (aZIndex >= 0) {
+    aItem->SetOverrideZIndex(aZIndex);
+    aLists.PositionedDescendants()->AppendNewToTop(aItem);
+  } else {
+    aLists.Content()->AppendNewToTop(aItem);
+  }
+}
+
 static const uint32_t APPEND_OWN_LAYER = 0x1;
 static const uint32_t APPEND_POSITIONED = 0x2;
 static const uint32_t APPEND_SCROLLBAR_CONTAINER = 0x4;
 
 static void
 AppendToTop(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists,
             nsDisplayList* aSource, nsIFrame* aSourceFrame, uint32_t aFlags)
 {
@@ -2986,23 +3000,18 @@ AppendToTop(nsDisplayListBuilder* aBuild
   } else {
     newItem = new (aBuilder) nsDisplayWrapList(aBuilder, aSourceFrame, aSource);
   }
 
   if (aFlags & APPEND_POSITIONED) {
     // We want overlay scrollbars to always be on top of the scrolled content,
     // but we don't want them to unnecessarily cover overlapping elements from
     // outside our scroll frame.
-    nsDisplayList* positionedDescendants = aLists.PositionedDescendants();
-    if (!positionedDescendants->IsEmpty()) {
-      newItem->SetOverrideZIndex(MaxZIndexInList(positionedDescendants, aBuilder));
-      positionedDescendants->AppendNewToTop(newItem);
-    } else {
-      aLists.Outlines()->AppendNewToTop(newItem);
-    }
+    int32_t zIndex = MaxZIndexInList(aLists.PositionedDescendants(), aBuilder);
+    AppendInternalItemToTop(aLists, newItem, zIndex);
   } else {
     aLists.BorderBackground()->AppendNewToTop(newItem);
   }
 }
 
 struct HoveredStateComparator
 {
   bool Equals(nsIFrame* A, nsIFrame* B) const {
@@ -3568,27 +3577,19 @@ ScrollFrameHelper::BuildDisplayList(nsDi
         !mWillBuildScrollableLayer &&
         aBuilder->IsBuildingLayerEventRegions())
     {
       inactiveRegionItem = new (aBuilder) nsDisplayLayerEventRegions(aBuilder, mScrolledFrame);
       inactiveRegionItem->AddInactiveScrollPort(mScrollPort + aBuilder->ToReferenceFrame(mOuter));
     }
 
     if (inactiveRegionItem) {
-      nsDisplayList* positionedDescendants = scrolledContent.PositionedDescendants();
-      nsDisplayList* destinationList = nullptr;
-      int32_t zindex =
-        MaxZIndexInListOfItemsContainedInFrame(positionedDescendants, mOuter);
-      if (zindex >= 0) {
-        destinationList = positionedDescendants;
-        inactiveRegionItem->SetOverrideZIndex(zindex);
-      } else {
-        destinationList = scrolledContent.Outlines();
-      }
-      destinationList->AppendNewToTop(inactiveRegionItem);
+      int32_t zIndex =
+        MaxZIndexInListOfItemsContainedInFrame(scrolledContent.PositionedDescendants(), mOuter);
+      AppendInternalItemToTop(scrolledContent, inactiveRegionItem, zIndex);
     }
 
     if (aBuilder->ShouldBuildScrollInfoItemsForHoisting()) {
       aBuilder->AppendNewScrollInfoItemForHoisting(
         new (aBuilder) nsDisplayScrollInfoLayer(aBuilder, mScrolledFrame,
                                                 mOuter));
     }
   }