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 229863 d7ef5a56b661bbabc20b0ef5ba09e5e8d3b9cba0
parent 229862 eb629fa95d06928dbf1cde8edbbd34893421daed
child 229864 4af5d66b1c0bd98d089d4f4ff3b3daa596ce0f37
push id11399
push userryanvm@gmail.com
push dateFri, 20 Feb 2015 00:03:38 +0000
treeherderfx-team@51458a066fda [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1119609
milestone38.0a1
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 = {