Bug 1419091: Switch to a compiled C++ table for html key bindings for browser and editor. r=masayuki
☠☠ backed out by 1bd4af34fe10 ☠ ☠
authorDave Townsend <dtownsend@oxymoronical.com>
Mon, 08 Oct 2018 11:09:31 -0700
changeset 442321 ac56492b6ed6f03cd61389db83a73e0fdf970089
parent 442320 72ccc94449163738199ec04886f2f5513bce5122
child 442322 2224ee809328bf70ded5648d0a2896d507def220
push id109151
push userdtownsend@mozilla.com
push dateMon, 22 Oct 2018 16:40:28 +0000
treeherdermozilla-inbound@15811bce212a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmasayuki
bugs1419091
milestone64.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 1419091: Switch to a compiled C++ table for html key bindings for browser and editor. r=masayuki Rather than loading an XBL binding for <browser> and <editor> elements this generates the handlers from static C arrays. Differential Revision: https://phabricator.services.mozilla.com/D6181
dom/xbl/builtin/ShortcutKeys.cpp
dom/xbl/builtin/ShortcutKeys.h
dom/xbl/builtin/moz.build
dom/xbl/nsXBLPrototypeHandler.cpp
dom/xbl/nsXBLPrototypeHandler.h
dom/xbl/nsXBLWindowKeyHandler.cpp
dom/xbl/nsXBLWindowKeyHandler.h
new file mode 100644
--- /dev/null
+++ b/dom/xbl/builtin/ShortcutKeys.cpp
@@ -0,0 +1,94 @@
+#include "mozilla/ShortcutKeys.h"
+#include "../nsXBLPrototypeHandler.h"
+#include "nsContentUtils.h"
+
+namespace mozilla {
+
+NS_IMPL_ISUPPORTS(ShortcutKeys, nsIObserver);
+
+StaticRefPtr<ShortcutKeys> ShortcutKeys::sInstance;
+
+ShortcutKeys::ShortcutKeys()
+  : mBrowserHandlers(nullptr)
+  , mEditorHandlers(nullptr)
+  , mInputHandlers(nullptr)
+  , mTextAreaHandlers(nullptr)
+{
+  MOZ_ASSERT(!sInstance, "Attempt to instantiate a second ShortcutKeys.");
+  nsContentUtils::RegisterShutdownObserver(this);
+}
+
+ShortcutKeys::~ShortcutKeys()
+{
+  delete mBrowserHandlers;
+  delete mEditorHandlers;
+  delete mInputHandlers;
+  delete mTextAreaHandlers;
+}
+
+nsresult
+ShortcutKeys::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
+{
+  // Clear our strong reference so we can clean up.
+  sInstance = nullptr;
+  return NS_OK;
+}
+
+/* static */ nsXBLPrototypeHandler*
+ShortcutKeys::GetHandlers(HandlerType aType)
+{
+  if (!sInstance) {
+    sInstance = new ShortcutKeys();
+  }
+
+  return sInstance->EnsureHandlers(aType);
+}
+
+nsXBLPrototypeHandler*
+ShortcutKeys::EnsureHandlers(HandlerType aType)
+{
+  ShortcutKeyData* keyData;
+  nsXBLPrototypeHandler** cache;
+
+  switch (aType) {
+    case HandlerType::eBrowser:
+      keyData = &sBrowserHandlers[0];
+      cache = &mBrowserHandlers;
+      break;
+    case HandlerType::eEditor:
+      keyData = &sEditorHandlers[0];
+      cache = &mEditorHandlers;
+      break;
+    case HandlerType::eInput:
+      keyData = &sInputHandlers[0];
+      cache = &mInputHandlers;
+      break;
+    case HandlerType::eTextArea:
+      keyData = &sTextAreaHandlers[0];
+      cache = &mTextAreaHandlers;
+      break;
+    default:
+      MOZ_ASSERT(false, "Unknown handler type requested.");
+  }
+
+  if (*cache) {
+    return *cache;
+  }
+
+  nsXBLPrototypeHandler* lastHandler = nullptr;
+  while (keyData->event) {
+    nsXBLPrototypeHandler* handler =
+      new nsXBLPrototypeHandler(keyData);
+    if (lastHandler) {
+      lastHandler->SetNextHandler(handler);
+    } else {
+      *cache = handler;
+    }
+    lastHandler = handler;
+    keyData++;
+  }
+
+  return *cache;
+}
+
+} // namespace mozilla
--- a/dom/xbl/builtin/ShortcutKeys.h
+++ b/dom/xbl/builtin/ShortcutKeys.h
@@ -1,30 +1,65 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_ShortcutKeys_h
 #define mozilla_dom_ShortcutKeys_h
 
+#include "nsIObserver.h"
+
+class nsXBLPrototypeHandler;
+
 namespace mozilla {
 
 typedef struct
 {
    const char16_t* event;
    const char16_t* keycode;
    const char16_t* key;
    const char16_t* modifiers;
    const char16_t* command;
 } ShortcutKeyData;
 
-class ShortcutKeys
+enum class HandlerType
+{
+  eInput,
+  eTextArea,
+  eBrowser,
+  eEditor,
+};
+
+class ShortcutKeys : public nsIObserver
 {
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+  // Returns a pointer to the first handler for the given type.
+  static nsXBLPrototypeHandler* GetHandlers(HandlerType aType);
+
 protected:
+  ShortcutKeys();
+  virtual ~ShortcutKeys();
+
+  // Returns a pointer to the first handler for the given type.
+  nsXBLPrototypeHandler* EnsureHandlers(HandlerType aType);
+
+  // Maintains a strong reference to the only instance.
+  static StaticRefPtr<ShortcutKeys> sInstance;
+
+  // Shortcut keys for different elements.
   static ShortcutKeyData sBrowserHandlers[];
   static ShortcutKeyData sEditorHandlers[];
   static ShortcutKeyData sInputHandlers[];
   static ShortcutKeyData sTextAreaHandlers[];
+
+  // Cached event handlers generated from the above data.
+  nsXBLPrototypeHandler* mBrowserHandlers;
+  nsXBLPrototypeHandler* mEditorHandlers;
+  nsXBLPrototypeHandler* mInputHandlers;
+  nsXBLPrototypeHandler* mTextAreaHandlers;
 };
 
 } // namespace mozilla
 
 #endif // #ifndef mozilla_dom_ShortcutKeys_h
--- a/dom/xbl/builtin/moz.build
+++ b/dom/xbl/builtin/moz.build
@@ -10,8 +10,13 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'co
     DIRS += ['mac']
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     DIRS += ['android']
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk3':
     DIRS += ['unix']
 else:
     DIRS += ['emacs']
 
+EXPORTS.mozilla += ['ShortcutKeys.h']
+
+SOURCES += ['ShortcutKeys.cpp']
+
+FINAL_LIBRARY = 'xul'
--- a/dom/xbl/nsXBLPrototypeHandler.cpp
+++ b/dom/xbl/nsXBLPrototypeHandler.cpp
@@ -101,26 +101,41 @@ nsXBLPrototypeHandler::nsXBLPrototypeHan
   Init();
 
   ConstructPrototype(nullptr, aEvent, aPhase, aAction, aCommand, aKeyCode,
                      aCharCode, aModifiers, aButton, aClickCount,
                      aGroup, aPreventDefault, aAllowUntrusted);
 }
 
 nsXBLPrototypeHandler::nsXBLPrototypeHandler(Element* aHandlerElement, XBLReservedKey aReserved)
-  : mHandlerElement(nullptr),
+  : mHandlerElement(nullptr)
+  , mLineNumber(0)
+  , mReserved(aReserved)
+  , mNextHandler(nullptr)
+  , mPrototypeBinding(nullptr)
+{
+  Init();
+
+  // Make sure our prototype is initialized.
+  ConstructPrototype(aHandlerElement);
+}
+
+nsXBLPrototypeHandler::nsXBLPrototypeHandler(ShortcutKeyData* aKeyData)
+  : mHandlerText(nullptr),
     mLineNumber(0),
-    mReserved(aReserved),
+    mReserved(XBLReservedKey_False),
     mNextHandler(nullptr),
     mPrototypeBinding(nullptr)
 {
   Init();
 
-  // Make sure our prototype is initialized.
-  ConstructPrototype(aHandlerElement);
+  ConstructPrototype(nullptr, aKeyData->event, nullptr, nullptr,
+                     aKeyData->command, aKeyData->keycode, aKeyData->key,
+                     aKeyData->modifiers, nullptr, nullptr, nullptr, nullptr,
+                     nullptr);
 }
 
 nsXBLPrototypeHandler::nsXBLPrototypeHandler(nsXBLPrototypeBinding* aBinding)
   : mHandlerText(nullptr),
     mLineNumber(0),
     mPhase(0),
     mType(0),
     mMisc(0),
--- a/dom/xbl/nsXBLPrototypeHandler.h
+++ b/dom/xbl/nsXBLPrototypeHandler.h
@@ -13,16 +13,17 @@
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsIController.h"
 #include "nsAutoPtr.h"
 #include "nsXBLEventHandler.h"
 #include "nsIWeakReference.h"
 #include "nsCycleCollectionParticipant.h"
 #include "js/TypeDecls.h"
+#include "mozilla/ShortcutKeys.h"
 
 class nsIContent;
 class nsIObjectInputStream;
 class nsIObjectOutputStream;
 class nsXBLPrototypeBinding;
 
 namespace mozilla {
 
@@ -88,16 +89,20 @@ public:
                         const char16_t* aPreventDefault,
                         const char16_t* aAllowUntrusted,
                         nsXBLPrototypeBinding* aBinding,
                         uint32_t aLineNumber);
 
   // This constructor is used only by XUL key handlers (e.g., <key>)
   explicit nsXBLPrototypeHandler(mozilla::dom::Element* aKeyElement, XBLReservedKey aReserved);
 
+  // This constructor is used for keyboard handlers for browser, editor, input
+  // and textarea elements.
+  explicit nsXBLPrototypeHandler(mozilla::ShortcutKeyData* aKeyData);
+
   // This constructor is used for handlers loaded from the cache
   explicit nsXBLPrototypeHandler(nsXBLPrototypeBinding* aBinding);
 
   ~nsXBLPrototypeHandler();
 
   /**
    * Try and convert this XBL handler into an APZ KeyboardShortcut for handling
    * key events on the compositor thread. This only works for XBL handlers that
--- a/dom/xbl/nsXBLWindowKeyHandler.cpp
+++ b/dom/xbl/nsXBLWindowKeyHandler.cpp
@@ -29,141 +29,35 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/EventBinding.h"
 #include "mozilla/dom/KeyboardEvent.h"
 #include "mozilla/layers/KeyboardMap.h"
+#include "mozilla/ShortcutKeys.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 
-class nsXBLSpecialDocInfo : public nsIObserver
-{
-public:
-  RefPtr<nsXBLDocumentInfo> mHTMLBindings;
-
-  static const char sHTMLBindingStr[];
-  static const char sUserHTMLBindingStr[];
-
-  bool mInitialized;
-
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIOBSERVER
-
-  void LoadDocInfo();
-  void GetHandlers(const nsACString& aRef,
-                   nsXBLPrototypeHandler** handler);
-
-  nsXBLSpecialDocInfo() : mInitialized(false) {}
-
-protected:
-  virtual ~nsXBLSpecialDocInfo() {}
-
-};
-
-const char nsXBLSpecialDocInfo::sHTMLBindingStr[] =
-  "chrome://global/content/platformHTMLBindings.xml";
-
-NS_IMPL_ISUPPORTS(nsXBLSpecialDocInfo, nsIObserver)
-
-NS_IMETHODIMP
-nsXBLSpecialDocInfo::Observe(nsISupports* aSubject,
-                             const char* aTopic,
-                             const char16_t* aData)
-{
-  MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"), "wrong topic");
-
-  // On shutdown, clear our fields to avoid an extra cycle collection.
-  mHTMLBindings = nullptr;
-  mInitialized = false;
-  nsContentUtils::UnregisterShutdownObserver(this);
-
-  return NS_OK;
-}
-
-void nsXBLSpecialDocInfo::LoadDocInfo()
-{
-  if (mInitialized)
-    return;
-  mInitialized = true;
-  nsContentUtils::RegisterShutdownObserver(this);
-
-  nsXBLService* xblService = nsXBLService::GetInstance();
-  if (!xblService)
-    return;
-
-  // Obtain the platform doc info
-  nsCOMPtr<nsIURI> bindingURI;
-  NS_NewURI(getter_AddRefs(bindingURI), sHTMLBindingStr);
-  if (!bindingURI) {
-    return;
-  }
-  xblService->LoadBindingDocumentInfo(nullptr, nullptr,
-                                      bindingURI,
-                                      nullptr,
-                                      true,
-                                      getter_AddRefs(mHTMLBindings));
-}
-
-//
-// GetHandlers
-//
-//
-void
-nsXBLSpecialDocInfo::GetHandlers(const nsACString& aRef,
-                                 nsXBLPrototypeHandler** aHandler)
-{
-  if (mHTMLBindings) {
-    nsXBLPrototypeBinding* binding = mHTMLBindings->GetPrototypeBinding(aRef);
-
-    NS_ASSERTION(binding, "No binding found for the XBL window key handler.");
-    if (!binding)
-      return;
-
-    *aHandler = binding->GetPrototypeHandlers();
-  }
-}
-
-// Init statics
-static StaticRefPtr<nsXBLSpecialDocInfo> sXBLSpecialDocInfo;
-uint32_t nsXBLWindowKeyHandler::sRefCnt = 0;
-
-/* static */ void
-nsXBLWindowKeyHandler::EnsureSpecialDocInfo()
-{
-  if (!sXBLSpecialDocInfo) {
-    sXBLSpecialDocInfo = new nsXBLSpecialDocInfo();
-  }
-  sXBLSpecialDocInfo->LoadDocInfo();
-}
-
 nsXBLWindowKeyHandler::nsXBLWindowKeyHandler(Element* aElement,
                                              EventTarget* aTarget)
   : mTarget(aTarget),
     mHandler(nullptr)
 {
   mWeakPtrForElement = do_GetWeakReference(aElement);
-  ++sRefCnt;
 }
 
 nsXBLWindowKeyHandler::~nsXBLWindowKeyHandler()
 {
   // If mWeakPtrForElement is non-null, we created a prototype handler.
   if (mWeakPtrForElement)
     delete mHandler;
-
-  --sRefCnt;
-  if (!sRefCnt) {
-    sXBLSpecialDocInfo = nullptr;
-  }
 }
 
 NS_IMPL_ISUPPORTS(nsXBLWindowKeyHandler,
                   nsIDOMEventListener)
 
 static void
 BuildHandlerChain(nsIContent* aContent, nsXBLPrototypeHandler** aResult)
 {
@@ -225,24 +119,22 @@ nsXBLWindowKeyHandler::EnsureHandlers()
   NS_ENSURE_STATE(!mWeakPtrForElement || el);
   if (el) {
     // We are actually a XUL <keyset>.
     if (mHandler)
       return NS_OK;
 
     BuildHandlerChain(el, &mHandler);
   } else { // We are an XBL file of handlers.
-    EnsureSpecialDocInfo();
-
     // Now determine which handlers we should be using.
     if (IsHTMLEditableFieldFocused()) {
-      sXBLSpecialDocInfo->GetHandlers(NS_LITERAL_CSTRING("editor"), &mHandler);
+      mHandler = ShortcutKeys::GetHandlers(HandlerType::eEditor);
     }
     else {
-      sXBLSpecialDocInfo->GetHandlers(NS_LITERAL_CSTRING("browser"), &mHandler);
+      mHandler = ShortcutKeys::GetHandlers(HandlerType::eBrowser);
     }
   }
 
   return NS_OK;
 }
 
 nsresult
 nsXBLWindowKeyHandler::WalkHandlers(KeyboardEvent* aKeyEvent, nsAtom* aEventType)
@@ -391,21 +283,17 @@ nsXBLWindowKeyHandler::RemoveKeyboardEve
   aEventListenerManager->RemoveEventListenerByType(
                            this, NS_LITERAL_STRING("mozkeyuponplugin"),
                            TrustedEventsAtSystemGroupBubble());
 }
 
 /* static */ KeyboardMap
 nsXBLWindowKeyHandler::CollectKeyboardShortcuts()
 {
-  // Load the XBL handlers
-  EnsureSpecialDocInfo();
-
-  nsXBLPrototypeHandler* handlers = nullptr;
-  sXBLSpecialDocInfo->GetHandlers(NS_LITERAL_CSTRING("browser"), &handlers);
+  nsXBLPrototypeHandler* handlers = ShortcutKeys::GetHandlers(HandlerType::eBrowser);
 
   // Convert the handlers into keyboard shortcuts, using an AutoTArray with
   // the maximum amount of shortcuts used on any platform to minimize allocations
   AutoTArray<KeyboardShortcut, 48> shortcuts;
 
   // Append keyboard shortcuts for hardcoded actions like tab
   KeyboardShortcut::AppendHardcodedShortcuts(shortcuts);
 
--- a/dom/xbl/nsXBLWindowKeyHandler.h
+++ b/dom/xbl/nsXBLWindowKeyHandler.h
@@ -83,19 +83,16 @@ protected:
                      nsXBLPrototypeHandler* aHandler);
 
   // Returns event type for matching between aWidgetKeyboardEvent and
   // shortcut key handlers.  This is used for calling WalkHandlers(),
   // WalkHandlersInternal() and WalkHandlersAndExecute().
   nsAtom* ConvertEventToDOMEventType(
              const mozilla::WidgetKeyboardEvent& aWidgetKeyboardEvent) const;
 
-  // lazily load the special doc info for loading handlers
-  static void EnsureSpecialDocInfo();
-
   // lazily load the handlers. Overridden to handle being attached
   // to a particular element rather than the document
   nsresult EnsureHandlers();
 
   // Is an HTML editable element focused
   bool IsHTMLEditableFieldFocused();
 
   // Returns the element which was passed as a parameter to the constructor,
@@ -121,21 +118,16 @@ protected:
    * Otherwise, false. aElement should be a command element or a key element.
    */
   bool IsExecutableElement(mozilla::dom::Element* aElement) const;
 
   // Using weak pointer to the DOM Element.
   nsWeakPtr              mWeakPtrForElement;
   mozilla::dom::EventTarget* mTarget; // weak ref
 
-  // these are not owning references; the prototype handlers are owned
-  // by the prototype bindings which are owned by the docinfo.
   nsXBLPrototypeHandler* mHandler;     // platform bindings
-
-  // holds reference count to document info about bindings
-  static uint32_t sRefCnt;
 };
 
 already_AddRefed<nsXBLWindowKeyHandler>
 NS_NewXBLWindowKeyHandler(mozilla::dom::Element* aElement,
                           mozilla::dom::EventTarget* aTarget);
 
 #endif