Bug 1396414 - Only animate cancelled popups, using a temporary result attribute. draft
authorSam Foster <sfoster@mozilla.com>
Fri, 29 Sep 2017 14:32:07 -0700
changeset 672997 081ee581d1773bd16d78ec57cffd55483afa3837
parent 672978 57f68296c350469d73d788eb3695a898947b4acb
child 733974 0cfda9152ba591a9c2e3094ff39ba0b535103b8b
push id82431
push userbmo:sfoster@mozilla.com
push dateFri, 29 Sep 2017 23:56:42 +0000
bugs1396414
milestone58.0a1
Bug 1396414 - Only animate cancelled popups, using a temporary result attribute. * Add temp. result attribute when hiding a popup, to communicate when a popup is being cancelled (no action taken) vs. not. * Refactor arrowpanel transition properties to be clearer about what animates, when. * Add some debug logging MozReview-Commit-ID: A9zqyC1z3VW
browser/base/content/browser.css
layout/xul/nsXULPopupManager.cpp
toolkit/content/widgets/popup.xml
toolkit/content/xul.css
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -1180,63 +1180,65 @@ toolbarpaletteitem[place="palette"] > #d
    shadow, and they don't affect the window's "shape", so the system doesn't
    have to recompute the shadow shape during the animation. This makes them a
    lot faster. In fact, Gecko no longer triggers shadow shape recomputations
    for repaints.
    These properties are not implemented on other platforms. */
 #BMB_bookmarksPopup:not([animate="false"]) {
   -moz-window-opacity: 0;
   -moz-window-transform: translateY(-70px);
-  transition-property: -moz-window-transform, -moz-window-opacity;
-  transition-duration: 0.18s, 0.18s;
-  transition-timing-function:
-    var(--animation-easing-function), ease-out;
+  transition-property: none;
 }
 
 #BMB_bookmarksPopup[side="bottom"]:not([animate="false"]) {
   -moz-window-transform: translateY(70px);
 }
 
 #BMB_bookmarksPopup[side][animate="open"] {
   -moz-window-opacity: 1.0;
+  -moz-window-transform: none;
+  transition-property: -moz-window-transform, -moz-window-opacity;
   transition-duration: 0.18s, 0.18s;
-  -moz-window-transform: none;
   transition-timing-function:
     var(--animation-easing-function), ease-in-out;
 }
 
 #BMB_bookmarksPopup[animate="cancel"] {
   -moz-window-transform: none;
+  transition-property: -moz-window-opacity;
+  transition-duration: 0.18s;
+  transition-timing-function: ease-out;
 }
 
 %elifndef MOZ_WIDGET_GTK
 
 #BMB_bookmarksPopup:not([animate="false"]) {
   opacity: 0;
   transform: translateY(-70px);
-  transition-property: transform, opacity;
-  transition-duration: 0.18s, 0.18s;
-  transition-timing-function:
-    var(--animation-easing-function), ease-out;
+  transition-property: none;
 }
 
 #BMB_bookmarksPopup[side="bottom"]:not([animate="false"]) {
   transform: translateY(70px);
 }
 
 #BMB_bookmarksPopup[side][animate="open"] {
   opacity: 1.0;
+  transform: none;
+  transition-property: transform, opacity;
   transition-duration: 0.18s, 0.18s;
-  transform: none;
   transition-timing-function:
     var(--animation-easing-function), ease-in-out;
 }
 
 #BMB_bookmarksPopup[animate="cancel"] {
   transform: none;
+  transition-property: opacity;
+  transition-duration: 0.18s;
+  transition-timing-function: ease-out;
 }
 %endif
 
 /* Customize mode */
 #PanelUI-contents > .panel-customization-placeholder > .panel-customization-placeholder-child {
   list-style-image: none;
 }
 
--- a/layout/xul/nsXULPopupManager.cpp
+++ b/layout/xul/nsXULPopupManager.cpp
@@ -1425,16 +1425,20 @@ nsXULPopupManager::ExecuteMenu(nsIConten
 void
 nsXULPopupManager::FirePopupShowingEvent(nsIContent* aPopup,
                                          bool aIsContextMenu,
                                          bool aSelectFirstItem,
                                          nsIDOMEvent* aTriggerEvent)
 {
   nsCOMPtr<nsIContent> popup = aPopup; // keep a strong reference to the popup
 
+  if (aPopup->HasAttr(kNameSpaceID_None, nsGkAtoms::result)) {
+    aPopup->UnsetAttr(kNameSpaceID_None, nsGkAtoms::result, false);
+  }
+
   nsMenuPopupFrame* popupFrame = do_QueryFrame(aPopup->GetPrimaryFrame());
   if (!popupFrame)
     return;
 
   nsPresContext *presContext = popupFrame->PresContext();
   nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
   nsPopupType popupType = popupFrame->PopupType();
 
@@ -1553,16 +1557,22 @@ nsXULPopupManager::FirePopupHidingEvent(
                                         nsPresContext *aPresContext,
                                         nsPopupType aPopupType,
                                         bool aDeselectMenu,
                                         bool aIsCancel)
 {
   nsCOMPtr<nsIPresShell> presShell = aPresContext->PresShell();
   mozilla::Unused << presShell; // This presShell may be keeping things alive on non GTK platforms
 
+  // set a "result" attribute so the front-end can know if this popup is being
+  // cancelled (no action taken) or dismissed (action taken)
+  aPopup->SetAttr(kNameSpaceID_None, nsGkAtoms::result,
+      aIsCancel ? NS_LITERAL_STRING("cancel") : NS_LITERAL_STRING("true"),
+      false);
+
   nsEventStatus status = nsEventStatus_eIgnore;
   WidgetMouseEvent event(true, eXULPopupHiding, nullptr,
                          WidgetMouseEvent::eReal);
   EventDispatcher::Dispatch(aPopup, aPresContext, &event, nullptr, &status);
 
   // when a panel is closed, blur whatever has focus inside the popup
   if (aPopupType == ePopupTypePanel &&
       !aPopup->AttrValueIs(kNameSpaceID_None, nsGkAtoms::noautofocus,
--- a/toolkit/content/widgets/popup.xml
+++ b/toolkit/content/widgets/popup.xml
@@ -511,26 +511,41 @@
         } else {
           return;
         }
 
         this._fadeTimer = setTimeout(() => this.hidePopup(true), fadeDelay, this);
       ]]>
       </handler>
       <handler event="popuphiding" phase="target">
-        let animate = (this.getAttribute("animate") != "false");
-
+      <![CDATA[
+        let animate = this.getAttribute("animate");
+        let preventAnimate = (animate == "false");
+        let cancelling = this.getAttribute("result") == "cancel";
+        console.log(this.getAttribute("id") + ": popuphiding, animate: ", animate);
+        console.log(this.getAttribute("id") + ": popuphiding, cancelling: ", cancelling);
         if (this._fadeTimer) {
           clearTimeout(this._fadeTimer);
-          if (animate) {
+          if (!preventAnimate && animate) {
             this.setAttribute("animate", "fade");
           }
-        } else if (animate) {
-          this.setAttribute("animate", "cancel");
+        } else if (!preventAnimate) {
+          if (cancelling) {
+            this.setAttribute("animate", "cancel");
+          } else {
+            // panel is being dismissed
+            this.setAttribute("animate", "dismiss");
+          }
         }
+        console.log(this.getAttribute("id") + ": /popuphiding, animate: ", this.getAttribute("animate"));
+
+        let cs = getComputedStyle(this);
+        console.log(this.getAttribute("id") + ": /popuphiding, transition-property:", cs.getPropertyValue("transition-property"));
+        console.log(this.getAttribute("id") + ": /popuphiding, -moz-window-transform:", cs.getPropertyValue("-moz-window-transform"));
+      ]]>
       </handler>
       <handler event="popupshown" phase="target">
         this.removeAttribute("animating");
         this.setAttribute("panelopen", "true");
       </handler>
       <handler event="popuphidden" phase="target">
         this.removeAttribute("panelopen");
         if (this.getAttribute("animate") != "false") {
--- a/toolkit/content/xul.css
+++ b/toolkit/content/xul.css
@@ -449,63 +449,70 @@ panel[type="arrow"] {
    shadow, and they don't affect the window's "shape", so the system doesn't
    have to recompute the shadow shape during the animation. This makes them a
    lot faster. In fact, Gecko no longer triggers shadow shape recomputations
    for repaints.
    These properties are not implemented on other platforms. */
 panel[type="arrow"][side]:not([animate="false"]) {
   -moz-window-opacity: 0;
   -moz-window-transform: translateY(-70px);
-  transition-property: -moz-window-transform, -moz-window-opacity;
-  transition-duration: 0.18s, 0.18s;
-  transition-timing-function:
-    var(--animation-easing-function), ease-out;
+  transition-property: none;
 }
 
 panel[type="arrow"][side="bottom"]:not([animate="false"]) {
   -moz-window-transform: translateY(70px);
 }
 
 panel[type="arrow"][side][animate="open"] {
   -moz-window-opacity: 1.0;
+  -moz-window-transform: none;
+  transition-property: -moz-window-transform, -moz-window-opacity;
   transition-duration: 0.18s, 0.18s;
-  -moz-window-transform: none;
   transition-timing-function:
     var(--animation-easing-function), ease-in-out;
 }
 
 panel[type="arrow"][side][animate="cancel"] {
   -moz-window-transform: none;
+  transition-property: -moz-window-opacity;
+  transition-duration: 0.18s;
+  transition-timing-function: ease-out;
+}
+
+panel[type="arrow"][side][animate="dismiss"] {
+  /* wait until the popup is hidden before adjusting the transform */
+  -moz-window-transform: none;
 }
 
 %elifndef MOZ_WIDGET_GTK
 
 panel[type="arrow"][side]:not([animate="false"]) {
   opacity: 0;
   transform: translateY(-70px);
-  transition-property: transform, opacity;
-  transition-duration: 0.18s, 0.18s;
-  transition-timing-function:
-    var(--animation-easing-function), ease-out;
+  transition-property: none;
 }
 
 panel[type="arrow"][side="bottom"]:not([animate="false"]) {
   transform: translateY(70px);
 }
 
 panel[type="arrow"][side][animate="open"] {
   opacity: 1.0;
+  transform: none;
+  transition-property: transform, opacity;
   transition-duration: 0.18s, 0.18s;
-  transform: none;
   transition-timing-function:
     var(--animation-easing-function), ease-in-out;
 }
 
 panel[type="arrow"][side][animate="cancel"] {
   transform: none;
+  transition-property: opacity;
+  transition-duration: 0.18s;
+  transition-timing-function: ease-out;
 }
 
 %endif
 panel[type="arrow"][animating] {
   pointer-events: none;
 }
 
 %ifdef XP_MACOSX