Bug 1221947 - part 1: add BYTOUCH flag to nsIFocusManager, r=jaws,smaug
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Thu, 12 Nov 2015 16:35:20 +0000
changeset 272868 e5bc99e6f928b4e0cd08e259adad09c1dfe1fa38
parent 272867 ac86f7cbd322753d6dbeaccc438c066392ab0b97
child 272869 5af628d4e296a898e2efbd8529878857113e6291
push id29686
push usercbook@mozilla.com
push dateTue, 17 Nov 2015 11:27:19 +0000
treeherdermozilla-central@f8b569906e4c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws, smaug
bugs1221947
milestone45.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1221947 - part 1: add BYTOUCH flag to nsIFocusManager, r=jaws,smaug IGNORE IDL
browser/components/search/content/search.xml
dom/events/EventStateManager.cpp
dom/html/HTMLButtonElement.cpp
dom/html/HTMLLabelElement.cpp
dom/interfaces/base/nsIFocusManager.idl
dom/xul/nsXULPopupListener.cpp
dom/xul/nsXULPopupListener.h
--- a/browser/components/search/content/search.xml
+++ b/browser/components/search/content/search.xml
@@ -483,17 +483,17 @@
         }
 
         // Don't open the suggestions if there is no text in the textbox.
         if (!this._textbox.value)
           return;
 
         // Don't open the suggestions if the mouse was used to focus the
         // textbox, that will be taken care of in the click handler.
-        if (Services.focus.getLastFocusMethod(window) == Services.focus.FLAG_BYMOUSE)
+        if (Services.focus.getLastFocusMethod(window) & Services.focus.FLAG_BYMOUSE)
           return;
 
         this.openSuggestionsPanel();
       ]]></handler>
 
       <handler event="mousedown" phase="capturing">
       <![CDATA[
         if (event.originalTarget.getAttribute("anonid") == "searchbar-search-button") {
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -2977,20 +2977,25 @@ EventStateManager::PostHandleEvent(nsPre
           // Another effect of mouse clicking, handled in nsSelection, is that
           // it should update the caret position to where the mouse was
           // clicked. Because the focus is cleared when clicking on a
           // non-focusable node, the next press of the tab key will cause
           // focus to be shifted from the caret position instead of the root.
           if (newFocus && currFrame) {
             // use the mouse flag and the noscroll flag so that the content
             // doesn't unexpectedly scroll when clicking an element that is
-            // only hald visible
+            // only half visible
+            uint32_t flags = nsIFocusManager::FLAG_BYMOUSE |
+                             nsIFocusManager::FLAG_NOSCROLL;
+            // If this was a touch-generated event, pass that information:
+            if (mouseEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
+              flags |= nsIFocusManager::FLAG_BYTOUCH;
+            }
             nsCOMPtr<nsIDOMElement> newFocusElement = do_QueryInterface(newFocus);
-            fm->SetFocus(newFocusElement, nsIFocusManager::FLAG_BYMOUSE |
-                                          nsIFocusManager::FLAG_NOSCROLL);
+            fm->SetFocus(newFocusElement, flags);
           }
           else if (!suppressBlur) {
             // clear the focus within the frame and then set it as the
             // focused frame
             EnsureDocument(mPresContext);
             if (mDocument) {
 #ifdef XP_MACOSX
               if (!activeContent || !activeContent->IsXULElement())
--- a/dom/html/HTMLButtonElement.cpp
+++ b/dom/html/HTMLButtonElement.cpp
@@ -312,19 +312,25 @@ HTMLButtonElement::PostHandleEvent(Event
           if (mouseEvent->button == WidgetMouseEvent::eLeftButton) {
             if (mouseEvent->mFlags.mIsTrusted) {
               EventStateManager* esm =
                 aVisitor.mPresContext->EventStateManager();
               EventStateManager::SetActiveManager(
                 static_cast<EventStateManager*>(esm), this);
             }
             nsIFocusManager* fm = nsFocusManager::GetFocusManager();
-            if (fm)
-              fm->SetFocus(this, nsIFocusManager::FLAG_BYMOUSE |
-                                 nsIFocusManager::FLAG_NOSCROLL);
+            if (fm) {
+              uint32_t flags = nsIFocusManager::FLAG_BYMOUSE |
+                               nsIFocusManager::FLAG_NOSCROLL;
+              // If this was a touch-generated event, pass that information:
+              if (mouseEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
+                flags |= nsIFocusManager::FLAG_BYTOUCH;
+              }
+              fm->SetFocus(this, flags);
+            }
             mouseEvent->mFlags.mMultipleActionsPrevented = true;
           } else if (mouseEvent->button == WidgetMouseEvent::eMiddleButton ||
                      mouseEvent->button == WidgetMouseEvent::eRightButton) {
             // cancel all of these events for buttons
             //XXXsmaug What to do with these events? Why these should be cancelled?
             if (aVisitor.mDOMEvent) {
               aVisitor.mDOMEvent->StopPropagation();
             }
--- a/dom/html/HTMLLabelElement.cpp
+++ b/dom/html/HTMLLabelElement.cpp
@@ -170,18 +170,20 @@ HTMLLabelElement::PostHandleEvent(EventC
               // flag is used and we want to select the text on label clicks as
               // well.
               // If the label has been clicked by the user, we also want to
               // pass FLAG_BYMOUSE so that we get correct focus ring behavior,
               // but we don't want to pass FLAG_BYMOUSE if this click event was
               // caused by the user pressing an accesskey.
               nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(content);
               bool byMouse = (mouseEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD);
+              bool byTouch = (mouseEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH);
               fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOVEFOCUS |
-                                 (byMouse ? nsIFocusManager::FLAG_BYMOUSE : 0));
+                                 (byMouse ? nsIFocusManager::FLAG_BYMOUSE : 0) |
+                                 (byTouch ? nsIFocusManager::FLAG_BYTOUCH : 0));
             }
           }
           // Dispatch a new click event to |content|
           //    (For compatibility with IE, we do only left click.  If
           //    we wanted to interpret the HTML spec very narrowly, we
           //    would do nothing.  If we wanted to do something
           //    sensible, we might send more events through like
           //    this.)  See bug 7554, bug 49897, and bug 96813.
--- a/dom/interfaces/base/nsIFocusManager.idl
+++ b/dom/interfaces/base/nsIFocusManager.idl
@@ -190,16 +190,22 @@ interface nsIFocusManager : nsISupports
   const unsigned long FLAG_BYMOVEFOCUS = 0x4000;
 
   /**
    * Always show the focus ring or other indicator of focus, regardless of
    * other state.
    */
   const unsigned long FLAG_SHOWRING = 0x100000;
 
+  /**
+   * Focus is changing due to a touch operation that generated a mouse event.
+   * Normally used in conjunction with FLAG_BYMOUSE.
+   */
+  const unsigned long FLAG_BYTOUCH = 0x200000;
+
   // these constants are used with the aType argument to MoveFocus
 
   /** move focus forward one element, used when pressing TAB */
   const unsigned long MOVEFOCUS_FORWARD = 1;
   /** move focus backward one element, used when pressing Shift+TAB */
   const unsigned long MOVEFOCUS_BACKWARD = 2;
   /** move focus forward to the next frame document, used when pressing F6 */
   const unsigned long MOVEFOCUS_FORWARDDOC = 3;
--- a/dom/xul/nsXULPopupListener.cpp
+++ b/dom/xul/nsXULPopupListener.cpp
@@ -190,19 +190,22 @@ nsXULPopupListener::HandleEvent(nsIDOMEv
   if (!mIsContext) {
     if (targetContent &&
         targetContent->IsAnyOfXULElements(nsGkAtoms::menu, nsGkAtoms::menuitem))
       return NS_OK;
   }
 
   if (mIsContext) {
 #ifndef NS_CONTEXT_MENU_IS_MOUSEUP
+    uint16_t inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
+    mouseEvent->GetMozInputSource(&inputSource);
+    bool isTouch = inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
     // If the context menu launches on mousedown,
     // we have to fire focus on the content we clicked on
-    FireFocusOnTargetContent(targetNode);
+    FireFocusOnTargetContent(targetNode, isTouch);
 #endif
   }
   else {
     // Only open popups when the left mouse button is down.
     mouseEvent->GetButton(&button);
     if (button != 0)
       return NS_OK;
   }
@@ -211,17 +214,17 @@ nsXULPopupListener::HandleEvent(nsIDOMEv
   // in the right situations.
   LaunchPopup(aEvent, targetContent);
 
   return NS_OK;
 }
 
 #ifndef NS_CONTEXT_MENU_IS_MOUSEUP
 nsresult
-nsXULPopupListener::FireFocusOnTargetContent(nsIDOMNode* aTargetNode)
+nsXULPopupListener::FireFocusOnTargetContent(nsIDOMNode* aTargetNode, bool aIsTouch)
 {
   nsresult rv;
   nsCOMPtr<nsIDOMDocument> domDoc;
   rv = aTargetNode->GetOwnerDocument(getter_AddRefs(domDoc));
   if(NS_SUCCEEDED(rv) && domDoc)
   {
     nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
 
@@ -257,18 +260,22 @@ nsXULPopupListener::FireFocusOnTargetCon
           }
         }
         currFrame = currFrame->GetParent();
     } 
 
     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
     if (fm) {
       if (element) {
-        fm->SetFocus(element, nsIFocusManager::FLAG_BYMOUSE |
-                              nsIFocusManager::FLAG_NOSCROLL);
+        uint32_t focusFlags = nsIFocusManager::FLAG_BYMOUSE |
+                              nsIFocusManager::FLAG_NOSCROLL;
+        if (aIsTouch) {
+          focusFlags |= nsIFocusManager::FLAG_BYTOUCH;
+        }
+        fm->SetFocus(element, focusFlags);
       } else if (!suppressBlur) {
         nsPIDOMWindow *window = doc->GetWindow();
         fm->ClearFocus(window);
       }
     }
 
     EventStateManager* esm = context->EventStateManager();
     nsCOMPtr<nsIContent> focusableContent = do_QueryInterface(element);
--- a/dom/xul/nsXULPopupListener.h
+++ b/dom/xul/nsXULPopupListener.h
@@ -40,17 +40,17 @@ protected:
     virtual nsresult LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent);
 
     // close the popup when the listener goes away
     virtual void ClosePopup();
 
 private:
 #ifndef NS_CONTEXT_MENU_IS_MOUSEUP
     // When a context menu is opened, focus the target of the contextmenu event.
-    nsresult FireFocusOnTargetContent(nsIDOMNode* aTargetNode);
+    nsresult FireFocusOnTargetContent(nsIDOMNode* aTargetNode, bool aIsTouch);
 #endif
 
     // |mElement| is the node to which this listener is attached.
     nsCOMPtr<mozilla::dom::Element> mElement;
 
     // The popup that is getting shown on top of mElement.
     nsCOMPtr<nsIContent> mPopupContent;