Bug 1291457 - Call nsIWidget::SetIsArrowPanel for panels with type="arrow", and supply the computed value of the transform-origin CSS property as the panel's arrow tip location. draft
authorMarkus Stange <mstange@themasta.com>
Tue, 02 Aug 2016 16:32:09 -0400
changeset 395777 d9a03f20423fc20774d6d3de7458426326211c8f
parent 395776 ca3c88de268845bb4d1fc47ff186cbe4f5e52123
child 395778 7667b4d4af2449cdeb26807f6c78c68c3008de94
push id24844
push usermstange@themasta.com
push dateTue, 02 Aug 2016 21:27:11 +0000
bugs1291457
milestone51.0a1
Bug 1291457 - Call nsIWidget::SetIsArrowPanel for panels with type="arrow", and supply the computed value of the transform-origin CSS property as the panel's arrow tip location. This does not work for the bookmarks popup because that popup is not type="arrow" and reimplements a bunch of arrowpanel stuff itself. MozReview-Commit-ID: 2IG8YOPcNV7
layout/base/nsDisplayList.cpp
layout/xul/nsMenuPopupFrame.cpp
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -5531,24 +5531,33 @@ nsDisplayTransform::nsDisplayTransform(n
  * called off the main thread.
  */
 /* static */ Point3D
 nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame,
                                               float aAppUnitsPerPixel,
                                               const nsRect* aBoundsOverride)
 {
   NS_PRECONDITION(aFrame, "Can't get delta for a null frame!");
-  NS_PRECONDITION(aFrame->IsTransformed() ||
-                  aFrame->BackfaceIsHidden() ||
-                  aFrame->Combines3DTransformWithAncestors(),
-                  "Shouldn't get a delta for an untransformed frame!");
-
-  if (!aFrame->IsTransformed()) {
-    return Point3D();
-  }
+
+  // Disable this stuff because nsMenuPopupFrame::LayoutPopup wants to know the
+  // value of transform-origin for a frame that is not transformed.
+  // Disabling these checks is not right. What we should do instead is create
+  // a wrapper function that has these checks and is called in the existing
+  // places where this function used to be called, and then the inner function
+  // (without the checks) should be the one that is only called by
+  // nsMenuPopupFrame::LayoutPopup (and by the new wrapper function).
+
+  // NS_PRECONDITION(aFrame->IsTransformed() ||
+  //                 aFrame->BackfaceIsHidden() ||
+  //                 aFrame->Combines3DTransformWithAncestors(),
+  //                 "Shouldn't get a delta for an untransformed frame!");
+
+  // if (!aFrame->IsTransformed()) {
+  //   return Point3D();
+  // }
 
   /* For both of the coordinates, if the value of transform is a
    * percentage, it's relative to the size of the frame.  Otherwise, if it's
    * a distance, it's already computed for us!
    */
   const nsStyleDisplay* display = aFrame->StyleDisplay();
   // We don't use aBoundsOverride for SVG since we need to account for
   // refBox.X/Y(). This happens to work because ReflowSVG sets the frame's
--- a/layout/xul/nsMenuPopupFrame.cpp
+++ b/layout/xul/nsMenuPopupFrame.cpp
@@ -502,35 +502,44 @@ nsMenuPopupFrame::LayoutPopup(nsBoxLayou
         SetPopupPosition(aAnchor, false, aSizedToPopup);
         needCallback = true;
       }
     }
   }
 
   nsPresContext* pc = PresContext();
   nsView* view = GetView();
+  nsIWidget* widget = view->GetWidget();
 
-  if (sizeChanged) {
+  if (sizeChanged && widget) {
     // If the size of the popup changed, apply any size constraints.
-    nsIWidget* widget = view->GetWidget();
-    if (widget) {
-      SetSizeConstraints(pc, widget, minSize, maxSize);
-    }
+    SetSizeConstraints(pc, widget, minSize, maxSize);
   }
 
   if (isOpen) {
     nsViewManager* viewManager = view->GetViewManager();
     nsRect rect = GetRect();
     rect.x = rect.y = 0;
     viewManager->ResizeView(view, rect);
 
     if (mPopupState == ePopupOpening) {
       mPopupState = ePopupVisible;
     }
 
+    if (widget) {
+      if (mPopupType == ePopupTypePanel &&
+          mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
+                                nsGkAtoms::arrow, eIgnoreCase)) {
+        mozilla::gfx::Point3D transformOrigin = nsDisplayTransform::GetDeltaToTransformOrigin(this, pc->AppUnitsPerDevPixel(), nullptr);
+        widget->SetIsArrowPanel(true, LayoutDeviceIntPoint((int32_t)transformOrigin.x, (int32_t)transformOrigin.y));
+      } else {
+        widget->SetIsArrowPanel(false, LayoutDeviceIntPoint());
+      }
+    }
+
     viewManager->SetViewVisibility(view, nsViewVisibility_kShow);
     nsContainerFrame::SyncFrameViewProperties(pc, this, nullptr, view, 0);
   }
 
   // finally, if the popup just opened, send a popupshown event
   if (mIsOpenChanged) {
     mIsOpenChanged = false;