Bug 1119609 part.3 Implement converting methods from key/code value to key/code name index r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 19 Feb 2015 15:50:19 +0900
changeset 256957 d7ef5a56b661bbabc20b0ef5ba09e5e8d3b9cba0
parent 256956 eb629fa95d06928dbf1cde8edbbd34893421daed
child 256958 4af5d66b1c0bd98d089d4f4ff3b3daa596ce0f37
push id4610
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:32:55 +0000
treeherdermozilla-beta@4df54044d9ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1119609
milestone38.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 1119609 part.3 Implement converting methods from key/code value to key/code name index r=smaug
dom/events/KeyboardEvent.cpp
widget/SharedWidgetUtils.cpp
widget/TextEvents.h
widget/WidgetEventImpl.cpp
widget/WidgetUtils.h
widget/android/nsWidgetFactory.cpp
widget/cocoa/nsWidgetFactory.mm
widget/gonk/nsWidgetFactory.cpp
widget/gtk/nsWidgetFactory.cpp
widget/qt/nsWidgetFactory.cpp
widget/windows/nsWidgetFactory.cpp
--- a/dom/events/KeyboardEvent.cpp
+++ b/dom/events/KeyboardEvent.cpp
@@ -262,20 +262,26 @@ KeyboardEvent::InitWithKeyboardEventInit
   mDetail = aParam.mDetail;
   mInitializedByCtor = true;
   mInitializedWhichValue = aParam.mWhich;
 
   WidgetKeyboardEvent* internalEvent = mEvent->AsKeyboardEvent();
   internalEvent->location = aParam.mLocation;
   internalEvent->mIsRepeat = aParam.mRepeat;
   internalEvent->mIsComposing = aParam.mIsComposing;
-  internalEvent->mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
-  internalEvent->mCodeNameIndex = CODE_NAME_INDEX_USE_STRING;
-  internalEvent->mKeyValue = aParam.mKey;
-  internalEvent->mCodeValue = aParam.mCode;
+  internalEvent->mKeyNameIndex =
+    WidgetKeyboardEvent::GetKeyNameIndex(aParam.mKey);
+  if (internalEvent->mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) {
+    internalEvent->mKeyValue = aParam.mKey;
+  }
+  internalEvent->mCodeNameIndex =
+    WidgetKeyboardEvent::GetCodeNameIndex(aParam.mCode);
+  if (internalEvent->mCodeNameIndex == CODE_NAME_INDEX_USE_STRING) {
+    internalEvent->mCodeValue = aParam.mCode;
+  }
 }
 
 NS_IMETHODIMP
 KeyboardEvent::InitKeyEvent(const nsAString& aType,
                             bool aCanBubble,
                             bool aCancelable,
                             nsIDOMWindow* aView,
                             bool aCtrlKey,
--- a/widget/SharedWidgetUtils.cpp
+++ b/widget/SharedWidgetUtils.cpp
@@ -11,17 +11,24 @@
 #include "nsIBaseWindow.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShell.h"
 #include "nsIInterfaceRequestorUtils.h"
 
 namespace mozilla {
 namespace widget {
 
-//static
+// static
+void
+WidgetUtils::Shutdown()
+{
+  WidgetKeyboardEvent::Shutdown();
+}
+
+// static
 already_AddRefed<nsIWidget>
 WidgetUtils::DOMWindowToWidget(nsIDOMWindow *aDOMWindow)
 {
   nsCOMPtr<nsIWidget> widget;
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aDOMWindow);
   if (window) {
     nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(window->GetDocShell()));
--- a/widget/TextEvents.h
+++ b/widget/TextEvents.h
@@ -16,16 +16,19 @@
 #include "nsCOMPtr.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsITransferable.h"
 #include "nsRect.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
 #include "WritingModes.h"
 
+class nsStringHashKey;
+template<class, class> class nsDataHashtable;
+
 /******************************************************************************
  * virtual keycode values
  ******************************************************************************/
 
 #define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) NS_##aDOMKeyName = aDOMKeyCode
 
 enum
 {
@@ -180,23 +183,28 @@ public:
   {
     if (mCodeNameIndex == CODE_NAME_INDEX_USE_STRING) {
       aCodeName = mCodeValue;
       return;
     }
     GetDOMCodeName(mCodeNameIndex, aCodeName);
   }
 
+  static void Shutdown();
+
   static uint32_t ComputeLocationFromCodeValue(CodeNameIndex aCodeNameIndex);
 
   static void GetDOMKeyName(KeyNameIndex aKeyNameIndex,
                             nsAString& aKeyName);
   static void GetDOMCodeName(CodeNameIndex aCodeNameIndex,
                              nsAString& aCodeName);
 
+  static KeyNameIndex GetKeyNameIndex(const nsAString& aKeyValue);
+  static CodeNameIndex GetCodeNameIndex(const nsAString& aCodeValue);
+
   static const char* GetCommandStr(Command aCommand);
 
   void AssignKeyEventData(const WidgetKeyboardEvent& aEvent, bool aCopyTargets)
   {
     AssignInputEventData(aEvent, aCopyTargets);
 
     keyCode = aEvent.keyCode;
     charCode = aEvent.charCode;
@@ -209,16 +217,26 @@ public:
     mCodeNameIndex = aEvent.mCodeNameIndex;
     mKeyValue = aEvent.mKeyValue;
     mCodeValue = aEvent.mCodeValue;
     // Don't copy mNativeKeyEvent because it may be referred after its instance
     // is destroyed.
     mNativeKeyEvent = nullptr;
     mUniqueId = aEvent.mUniqueId;
   }
+
+private:
+  static const char16_t* kKeyNames[];
+  static const char16_t* kCodeNames[];
+  typedef nsDataHashtable<nsStringHashKey,
+                          KeyNameIndex> KeyNameIndexHashtable;
+  typedef nsDataHashtable<nsStringHashKey,
+                          CodeNameIndex> CodeNameIndexHashtable;
+  static KeyNameIndexHashtable* sKeyNameIndexHashtable;
+  static CodeNameIndexHashtable* sCodeNameIndexHashtable;
 };
 
 
 /******************************************************************************
  * mozilla::InternalBeforeAfterKeyboardEvent
  *
  * This is extended from WidgetKeyboardEvent and is mapped to DOM event
  * "BeforeAfterKeyboardEvent".
--- a/widget/WidgetEventImpl.cpp
+++ b/widget/WidgetEventImpl.cpp
@@ -284,16 +284,34 @@ WidgetInputEvent::AccelModifier()
   }
   return sAccelModifier;
 }
 
 /******************************************************************************
  * mozilla::WidgetKeyboardEvent (TextEvents.h)
  ******************************************************************************/
 
+#define NS_DEFINE_KEYNAME(aCPPName, aDOMKeyName) MOZ_UTF16(aDOMKeyName),
+const char16_t* WidgetKeyboardEvent::kKeyNames[] = {
+#include "mozilla/KeyNameList.h"
+};
+#undef NS_DEFINE_KEYNAME
+
+#define NS_DEFINE_PHYSICAL_KEY_CODE_NAME(aCPPName, aDOMCodeName) \
+    MOZ_UTF16(aDOMCodeName),
+const char16_t* WidgetKeyboardEvent::kCodeNames[] = {
+#include "mozilla/PhysicalKeyCodeNameList.h"
+};
+#undef NS_DEFINE_PHYSICAL_KEY_CODE_NAME
+
+WidgetKeyboardEvent::KeyNameIndexHashtable*
+  WidgetKeyboardEvent::sKeyNameIndexHashtable = nullptr;
+WidgetKeyboardEvent::CodeNameIndexHashtable*
+  WidgetKeyboardEvent::sCodeNameIndexHashtable = nullptr;
+
 bool
 WidgetKeyboardEvent::ShouldCauseKeypressEvents() const
 {
   // Currently, we don't dispatch keypress events of modifier keys.
   switch (mKeyNameIndex) {
     case KEY_NAME_INDEX_Alt:
     case KEY_NAME_INDEX_AltGraph:
     case KEY_NAME_INDEX_CapsLock:
@@ -310,105 +328,87 @@ WidgetKeyboardEvent::ShouldCauseKeypress
     case KEY_NAME_INDEX_Symbol:
     // case KEY_NAME_INDEX_SymbolLock:
       return false;
     default:
       return true;
   }
 }
 
-/*static*/ void
+/* static */ void
+WidgetKeyboardEvent::Shutdown()
+{
+  delete sKeyNameIndexHashtable;
+  sKeyNameIndexHashtable = nullptr;
+  delete sCodeNameIndexHashtable;
+  sCodeNameIndexHashtable = nullptr;
+}
+
+/* static */ void
 WidgetKeyboardEvent::GetDOMKeyName(KeyNameIndex aKeyNameIndex,
                                    nsAString& aKeyName)
 {
-  // The expected way to implement this function would be to use a
-  // switch statement.  By using a table-based implementation, below, we
-  // ensure that this function executes in constant time in cases where
-  // compilers wouldn't be able to convert the switch statement to a
-  // jump table.  This table-based implementation also minimizes the
-  // space required by the code and data.
-#define KEY_STR_NUM_INTERNAL(line) key##line
-#define KEY_STR_NUM(line) KEY_STR_NUM_INTERNAL(line)
-
-  // Catch non-ASCII DOM key names in our key name list.
-#define NS_DEFINE_KEYNAME(aCPPName, aDOMKeyName)                      \
-  static_assert(sizeof(aDOMKeyName) == MOZ_ARRAY_LENGTH(aDOMKeyName), \
-                "Invalid DOM key name");
-#include "mozilla/KeyNameList.h"
-#undef NS_DEFINE_KEYNAME
-
-  struct KeyNameTable
-  {
-#define NS_DEFINE_KEYNAME(aCPPName, aDOMKeyName)          \
-    char16_t KEY_STR_NUM(__LINE__)[sizeof(aDOMKeyName)];
-#include "mozilla/KeyNameList.h"
-#undef NS_DEFINE_KEYNAME
-  };
-
-  static const KeyNameTable kKeyNameTable = {
-#define NS_DEFINE_KEYNAME(aCPPName, aDOMKeyName) MOZ_UTF16(aDOMKeyName),
-#include "mozilla/KeyNameList.h"
-#undef NS_DEFINE_KEYNAME
-  };
-
-  static const uint16_t kKeyNameOffsets[] = {
-#define NS_DEFINE_KEYNAME(aCPPName, aDOMKeyName)          \
-    offsetof(struct KeyNameTable, KEY_STR_NUM(__LINE__)) / sizeof(char16_t),
-#include "mozilla/KeyNameList.h"
-#undef NS_DEFINE_KEYNAME
-    // Include this entry so we can compute lengths easily.
-    sizeof(kKeyNameTable)
-  };
-
-  // Use the sizeof trick rather than MOZ_ARRAY_LENGTH to avoid problems
-  // with constexpr functions called inside static_assert with some
-  // compilers.
-  static_assert(KEY_NAME_INDEX_USE_STRING ==
-                (sizeof(kKeyNameOffsets)/sizeof(kKeyNameOffsets[0])) - 1,
-                "Invalid enumeration values!");
-
   if (aKeyNameIndex >= KEY_NAME_INDEX_USE_STRING) {
     aKeyName.Truncate();
     return;
   }
 
-  uint16_t offset = kKeyNameOffsets[aKeyNameIndex];
-  uint16_t nextOffset = kKeyNameOffsets[aKeyNameIndex + 1];
-  const char16_t* table = reinterpret_cast<const char16_t*>(&kKeyNameTable);
-
-  // Subtract off 1 for the null terminator.
-  aKeyName.Assign(table + offset, nextOffset - offset - 1);
-
-#undef KEY_STR_NUM
-#undef KEY_STR_NUM_INTERNAL
+  MOZ_RELEASE_ASSERT(static_cast<size_t>(aKeyNameIndex) <
+                       ArrayLength(kKeyNames),
+                     "Illegal key enumeration value");
+  aKeyName = kKeyNames[aKeyNameIndex];
 }
 
-/*static*/ void
+/* static */ void
 WidgetKeyboardEvent::GetDOMCodeName(CodeNameIndex aCodeNameIndex,
                                     nsAString& aCodeName)
 {
   if (aCodeNameIndex >= CODE_NAME_INDEX_USE_STRING) {
     aCodeName.Truncate();
     return;
   }
 
-#define NS_DEFINE_PHYSICAL_KEY_CODE_NAME(aCPPName, aDOMCodeName) \
-    MOZ_UTF16(aDOMCodeName),
-  static const char16_t* kCodeNames[] = {
-#include "mozilla/PhysicalKeyCodeNameList.h"
-    MOZ_UTF16("")
-  };
-#undef NS_DEFINE_PHYSICAL_KEY_CODE_NAME
-
   MOZ_RELEASE_ASSERT(static_cast<size_t>(aCodeNameIndex) <
                        ArrayLength(kCodeNames),
                      "Illegal physical code enumeration value");
   aCodeName = kCodeNames[aCodeNameIndex];
 }
 
+/* static */ KeyNameIndex
+WidgetKeyboardEvent::GetKeyNameIndex(const nsAString& aKeyValue)
+{
+  if (!sKeyNameIndexHashtable) {
+    sKeyNameIndexHashtable =
+      new KeyNameIndexHashtable(ArrayLength(kKeyNames));
+    for (size_t i = 0; i < ArrayLength(kKeyNames); i++) {
+      sKeyNameIndexHashtable->Put(nsDependentString(kKeyNames[i]),
+                                  static_cast<KeyNameIndex>(i));
+    }
+  }
+  KeyNameIndex result = KEY_NAME_INDEX_USE_STRING;
+  sKeyNameIndexHashtable->Get(aKeyValue, &result);
+  return result;
+}
+
+/* static */ CodeNameIndex
+WidgetKeyboardEvent::GetCodeNameIndex(const nsAString& aCodeValue)
+{
+  if (!sCodeNameIndexHashtable) {
+    sCodeNameIndexHashtable =
+      new CodeNameIndexHashtable(ArrayLength(kCodeNames));
+    for (size_t i = 0; i < ArrayLength(kCodeNames); i++) {
+      sCodeNameIndexHashtable->Put(nsDependentString(kCodeNames[i]),
+                                   static_cast<CodeNameIndex>(i));
+    }
+  }
+  CodeNameIndex result = CODE_NAME_INDEX_USE_STRING;
+  sCodeNameIndexHashtable->Get(aCodeValue, &result);
+  return result;
+}
+
 /* static */ const char*
 WidgetKeyboardEvent::GetCommandStr(Command aCommand)
 {
 #define NS_DEFINE_COMMAND(aName, aCommandStr) , #aCommandStr
   static const char* kCommands[] = {
     "" // CommandDoNothing
 #include "mozilla/CommandList.h"
   };
--- a/widget/WidgetUtils.h
+++ b/widget/WidgetUtils.h
@@ -38,16 +38,22 @@ nsIntRect RotateRect(nsIntRect aRect,
                      const nsIntRect& aBounds,
                      ScreenRotation aRotation);
 
 namespace widget {
 
 class WidgetUtils
 {
 public:
+  /**
+   * Shutdown() is called when "xpcom-will-shutdown" is notified.  This is
+   * useful when you need to observe the notification in XP level code under
+   * widget.
+   */
+  static void Shutdown();
 
   /**
    * Starting at the docshell item for the passed in DOM window this looks up
    * the docshell tree until it finds a docshell item that has a widget.
    */
   static already_AddRefed<nsIWidget> DOMWindowToWidget(nsIDOMWindow *aDOMWindow);
 
   /**
--- a/widget/android/nsWidgetFactory.cpp
+++ b/widget/android/nsWidgetFactory.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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/. */
 
 #include "mozilla/ModuleUtils.h"
+#include "mozilla/WidgetUtils.h"
 
 #include "nsCOMPtr.h"
 #include "nsWidgetsCID.h"
 #include "nsAppShell.h"
 #include "AndroidBridge.h"
 
 #include "nsWindow.h"
 #include "nsLookAndFeel.h"
@@ -104,16 +105,19 @@ static const mozilla::Module::ContractID
   { "@mozilla.org/android/bridge;1", &kNS_ANDROIDBRIDGE_CID },
   { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "android", &kNS_ANDROIDPROTOCOLHANDLER_CID },
   { nullptr }
 };
 
 static void
 nsWidgetAndroidModuleDtor()
 {
+    // Shutdown all XP level widget classes.
+    mozilla::widget::WidgetUtils::Shutdown();
+
     nsLookAndFeel::Shutdown();
     nsAppShellShutdown();
 }
 
 static const mozilla::Module kWidgetModule = {
     mozilla::Module::kVersion,
     kWidgetCIDs,
     kWidgetContracts,
--- a/widget/cocoa/nsWidgetFactory.mm
+++ b/widget/cocoa/nsWidgetFactory.mm
@@ -2,16 +2,17 @@
 /* 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/. */
 
 #include "nsIFactory.h"
 #include "nsISupports.h"
 #include "nsIComponentManager.h"
 #include "mozilla/ModuleUtils.h"
+#include "mozilla/WidgetUtils.h"
 
 #include "nsWidgetsCID.h"
 
 #include "nsChildView.h"
 #include "nsCocoaWindow.h"
 #include "nsAppShell.h"
 #include "nsAppShellSingleton.h"
 #include "nsFilePicker.h"
@@ -33,18 +34,16 @@
 
 #include "nsScreenManagerCocoa.h"
 #include "nsDeviceContextSpecX.h"
 #include "nsPrintOptionsX.h"
 #include "nsPrintDialogX.h"
 #include "nsPrintSession.h"
 #include "nsToolkitCompsCID.h"
 
-#include "mozilla/Module.h"
-
 using namespace mozilla;
 using namespace mozilla::widget;
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsCocoaWindow)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsChildView)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePicker)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsColorPicker)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSound)
@@ -190,16 +189,19 @@ static const mozilla::Module::ContractID
   { "@mozilla.org/widget/macsystemstatusbar;1", &kNS_MACSYSTEMSTATUSBAR_CID },
   { "@mozilla.org/gfx/info;1", &kNS_GFXINFO_CID },
   { NULL }
 };
 
 static void
 nsWidgetCocoaModuleDtor()
 {
+  // Shutdown all XP level widget classes.
+  WidgetUtils::Shutdown();
+
   NativeKeyBindings::Shutdown();
   nsLookAndFeel::Shutdown();
   nsToolkit::Shutdown();
   nsAppShellShutdown();
 }
 
 static const mozilla::Module kWidgetModule = {
   mozilla::Module::kVersion,
--- a/widget/gonk/nsWidgetFactory.cpp
+++ b/widget/gonk/nsWidgetFactory.cpp
@@ -12,16 +12,17 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "base/basictypes.h"
 
 #include "mozilla/ModuleUtils.h"
+#include "mozilla/WidgetUtils.h"
 
 #include "nsCOMPtr.h"
 #include "nsWidgetsCID.h"
 #include "nsAppShell.h"
 
 #include "nsWindow.h"
 #include "nsLookAndFeel.h"
 #include "nsAppShellSingleton.h"
@@ -102,16 +103,19 @@ static const mozilla::Module::ContractID
     { "@mozilla.org/widget/clipboard;1", &kNS_CLIPBOARD_CID },
     { "@mozilla.org/widget/clipboardhelper;1", &kNS_CLIPBOARDHELPER_CID },
     { nullptr }
 };
 
 static void
 nsWidgetGonkModuleDtor()
 {
+    // Shutdown all XP level widget classes.
+    WidgetUtils::Shutdown();
+
     nsLookAndFeel::Shutdown();
     nsAppShellShutdown();
 }
 
 static const mozilla::Module kWidgetModule = {
     mozilla::Module::kVersion,
     kWidgetCIDs,
     kWidgetContracts,
--- a/widget/gtk/nsWidgetFactory.cpp
+++ b/widget/gtk/nsWidgetFactory.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim:expandtab:shiftwidth=4:tabstop=4:
  */
 /* 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/. */
 
 #include "mozilla/ModuleUtils.h"
+#include "mozilla/WidgetUtils.h"
 #include "NativeKeyBindings.h"
 #include "nsWidgetsCID.h"
 #include "nsAppShell.h"
 #include "nsAppShellSingleton.h"
 #include "nsBaseWidget.h"
 #include "nsLookAndFeel.h"
 #include "nsWindow.h"
 #include "nsTransferable.h"
@@ -263,16 +264,19 @@ static const mozilla::Module::ContractID
     { "@mozilla.org/gfx/info;1", &kNS_GFXINFO_CID },
 #endif
     { nullptr }
 };
 
 static void
 nsWidgetGtk2ModuleDtor()
 {
+  // Shutdown all XP level widget classes.
+  WidgetUtils::Shutdown();
+
   NativeKeyBindings::Shutdown();
   nsLookAndFeel::Shutdown();
   nsFilePicker::Shutdown();
   nsSound::Shutdown();
   nsWindow::ReleaseGlobals();
   nsGTKToolkit::Shutdown();
   nsAppShellShutdown();
 #ifdef MOZ_ENABLE_DBUS
--- a/widget/qt/nsWidgetFactory.cpp
+++ b/widget/qt/nsWidgetFactory.cpp
@@ -12,16 +12,17 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "base/basictypes.h"
 
 #include "mozilla/ModuleUtils.h"
+#include "mozilla/WidgetUtils.h"
 
 #include "nsCOMPtr.h"
 #include "nsWidgetsCID.h"
 #include "nsAppShell.h"
 
 #include "nsWindow.h"
 #include "nsLookAndFeel.h"
 #include "nsAppShellSingleton.h"
@@ -142,16 +143,19 @@ static const mozilla::Module::ContractID
     { NS_PRINTDIALOGSERVICE_CONTRACTID, &kNS_PRINTDIALOGSERVICE_CID },
 #endif
     { nullptr }
 };
 
 static void
 nsWidgetQtModuleDtor()
 {
+    // Shutdown all XP level widget classes.
+    WidgetUtils::Shutdown();
+
     nsLookAndFeel::Shutdown();
     nsAppShellShutdown();
 }
 
 static const mozilla::Module kWidgetModule = {
     mozilla::Module::kVersion,
     kWidgetCIDs,
     kWidgetContracts,
--- a/widget/windows/nsWidgetFactory.cpp
+++ b/widget/windows/nsWidgetFactory.cpp
@@ -6,16 +6,17 @@
 
 #include "nsIFactory.h"
 #include "nsISupports.h"
 #include "nsdefs.h"
 #include "nsWidgetsCID.h"
 #include "nsAppShell.h"
 #include "nsAppShellSingleton.h"
 #include "mozilla/ModuleUtils.h"
+#include "mozilla/WidgetUtils.h"
 #include "nsIServiceManager.h"
 #include "nsIdleServiceWin.h"
 #include "nsLookAndFeel.h"
 #include "nsScreenManagerWin.h"
 #include "nsSound.h"
 #include "WinMouseScrollHandler.h"
 #include "KeyboardLayout.h"
 #include "GfxInfo.h"
@@ -51,18 +52,16 @@
 #include "JumpListItem.h"
 
 #ifdef NS_PRINTING
 #include "nsDeviceContextSpecWin.h"
 #include "nsPrintOptionsWin.h"
 #include "nsPrintSession.h"
 #endif
 
-#include "mozilla/Module.h"
-
 using namespace mozilla;
 using namespace mozilla::widget;
 
 static nsresult
 WindowConstructor(nsISupports *aOuter, REFNSIID aIID,
                   void **aResult)
 {
   *aResult = nullptr;
@@ -284,16 +283,19 @@ static const mozilla::Module::ContractID
   { "@mozilla.org/gfx/devicecontextspec;1", &kNS_DEVICE_CONTEXT_SPEC_CID },
 #endif
   { nullptr }
 };
 
 static void
 nsWidgetWindowsModuleDtor()
 {
+  // Shutdown all XP level widget classes.
+  WidgetUtils::Shutdown();
+
   KeyboardLayout::Shutdown();
   MouseScrollHandler::Shutdown();
   nsLookAndFeel::Shutdown();
   nsToolkit::Shutdown();
   nsAppShellShutdown();
 }
 
 static const mozilla::Module kWidgetModule = {