Bug 1314707: Replace PDocAccessible::SendCOMProxy with new parameter to PDocAccessibleConstructor; r=tbsaunde draft
authorAaron Klotz <aklotz@mozilla.com>
Thu, 03 Nov 2016 13:36:20 -0600
changeset 433482 58e83cad970713ec59632b0d54153a60c00220c2
parent 433481 2fd096140370a618ad4e41a0f0fbe3d157798896
child 433483 f7a962376cc98c38f3539a72fcca24ac7eecab6b
push id34601
push useraklotz@mozilla.com
push dateThu, 03 Nov 2016 20:22:47 +0000
reviewerstbsaunde
bugs1314707
milestone52.0a1
Bug 1314707: Replace PDocAccessible::SendCOMProxy with new parameter to PDocAccessibleConstructor; r=tbsaunde MozReview-Commit-ID: 9xgSLor3OgB
accessible/base/DocManager.cpp
accessible/base/NotificationController.cpp
accessible/generic/DocAccessible-inl.h
accessible/generic/DocAccessible.h
accessible/ipc/DocAccessibleParent.cpp
accessible/ipc/DocAccessibleParent.h
accessible/ipc/IPCTypes.h
accessible/ipc/moz.build
accessible/ipc/other/DocAccessibleChild.h
accessible/ipc/win/DocAccessibleChild.cpp
accessible/ipc/win/DocAccessibleChild.h
accessible/ipc/win/PDocAccessible.ipdl
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
ipc/mscom/COMPtrHolder.h
--- a/accessible/base/DocManager.cpp
+++ b/accessible/base/DocManager.cpp
@@ -509,29 +509,29 @@ DocManager::CreateDocOrRootAccessible(ns
 
         // XXX We may need to handle the case that we don't have a tab child
         // differently.  It may be that this will cause us to fail to notify
         // the parent process about important accessible documents.
         if (tabChild) {
           DocAccessibleChild* ipcDoc = new DocAccessibleChild(docAcc);
           docAcc->SetIPCDoc(ipcDoc);
 
+#if defined(XP_WIN)
+          IAccessibleHolder holder(CreateHolderFromAccessible(docAcc));
+#endif
+
           static_cast<TabChild*>(tabChild.get())->
             SendPDocAccessibleConstructor(ipcDoc, nullptr, 0,
 #if defined(XP_WIN)
-                                          AccessibleWrap::GetChildIDFor(docAcc)
+                                          AccessibleWrap::GetChildIDFor(docAcc),
+                                          holder
 #else
-                                          0
+                                          0, 0
 #endif
                                           );
-
-#if defined(XP_WIN)
-          IAccessibleHolder holder(CreateHolderFromAccessible(docAcc));
-          ipcDoc->SendCOMProxy(holder);
-#endif
         }
       }
     }
   } else {
     parentDocAcc->BindChildDocument(docAcc);
   }
 
 #ifdef A11Y_LOG
--- a/accessible/base/NotificationController.cpp
+++ b/accessible/base/NotificationController.cpp
@@ -421,19 +421,20 @@ NotificationController::WillRefresh(mozi
       childDoc->SetIPCDoc(ipcDoc);
       nsCOMPtr<nsITabChild> tabChild =
         do_GetInterface(mDocument->DocumentNode()->GetDocShell());
       if (tabChild) {
         MOZ_ASSERT(parentIPCDoc);
         static_cast<TabChild*>(tabChild.get())->
           SendPDocAccessibleConstructor(ipcDoc, parentIPCDoc, id,
 #if defined(XP_WIN)
-                                        AccessibleWrap::GetChildIDFor(childDoc)
+                                        AccessibleWrap::GetChildIDFor(childDoc),
+                                        IAccessibleHolder()
 #else
-                                        0
+                                        0, 0
 #endif
                                         );
       }
     }
   }
 
   mObservingState = eRefreshObserving;
   if (!mDocument)
--- a/accessible/generic/DocAccessible-inl.h
+++ b/accessible/generic/DocAccessible-inl.h
@@ -3,16 +3,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/. */
 
 #ifndef mozilla_a11y_DocAccessible_inl_h_
 #define mozilla_a11y_DocAccessible_inl_h_
 
 #include "DocAccessible.h"
+#include "mozilla/a11y/DocAccessibleChild.h"
 #include "nsAccessibilityService.h"
 #include "nsAccessiblePivot.h"
 #include "NotificationController.h"
 #include "States.h"
 #include "nsIScrollableFrame.h"
 #include "nsIDocumentInlines.h"
 
 #ifdef A11Y_LOG
@@ -115,16 +116,23 @@ DocAccessible::RemoveScrollListener()
   nsIScrollableFrame* sf = mPresShell->GetRootScrollFrameAsScrollable();
   if (sf)
     sf->RemoveScrollPositionListener(this);
 }
 
 inline void
 DocAccessible::NotifyOfLoad(uint32_t aLoadEventType)
 {
+  // If this document is an e10s content document, we should not consider
+  // ourselves to be loaded until mIPCDoc is ready.
+  if (mIPCDoc && !mIPCDoc->IsReadyForNotifyOfLoad()) {
+    mIPCDoc->NotifyOfLoadWhenReady(aLoadEventType);
+    return;
+  }
+
   mLoadState |= eDOMLoaded;
   mLoadEventType = aLoadEventType;
 
   // If the document is loaded completely then network activity was presumingly
   // caused by file loading. Fire busy state change event.
   if (HasLoadState(eCompletelyLoaded) && IsLoadEventTarget()) {
     RefPtr<AccEvent> stateEvent =
       new AccStateChangeEvent(this, states::BUSY, false);
--- a/accessible/generic/DocAccessible.h
+++ b/accessible/generic/DocAccessible.h
@@ -392,16 +392,17 @@ protected:
   virtual nsresult RemoveEventListeners();
 
   /**
    * Marks this document as loaded or loading.
    */
   void NotifyOfLoad(uint32_t aLoadEventType);
   void NotifyOfLoading(bool aIsReloading);
 
+  friend class DocAccessibleChild;
   friend class DocManager;
   friend class ApplicationAccessible;
 
   /**
    * Perform initial update (create accessible tree).
    * Can be overridden by wrappers to prepare initialization work.
    */
   virtual void DoInitialUpdate();
--- a/accessible/ipc/DocAccessibleParent.cpp
+++ b/accessible/ipc/DocAccessibleParent.cpp
@@ -456,32 +456,31 @@ DocAccessibleParent::GetXPCAccessible(Pr
   MOZ_ASSERT(doc);
 
   return doc->GetXPCAccessible(aProxy);
 }
 
 #if defined(XP_WIN)
 /**
  * @param aCOMProxy COM Proxy to the document in the content process.
- * @param aParentCOMProxy COM Proxy to the OuterDocAccessible that is
- *        the parent of the document. The content process will use this
- *        proxy when traversing up across the content/chrome boundary.
  */
-bool
-DocAccessibleParent::RecvCOMProxy(const IAccessibleHolder& aCOMProxy,
-                                  IAccessibleHolder* aParentCOMProxy)
+void
+DocAccessibleParent::SetCOMInterface(const RefPtr<IAccessible>& aCOMProxy)
 {
-  RefPtr<IAccessible> ptr(aCOMProxy.Get());
-  SetCOMInterface(ptr);
+  ProxyAccessible::SetCOMInterface(aCOMProxy);
 
   Accessible* outerDoc = OuterDocOfRemoteBrowser();
+  MOZ_ASSERT(outerDoc);
+
   IAccessible* rawNative = nullptr;
   if (outerDoc) {
     outerDoc->GetNativeInterface((void**) &rawNative);
+    MOZ_ASSERT(rawNative);
   }
 
-  aParentCOMProxy->Set(IAccessibleHolder::COMPtrType(rawNative));
-  return true;
+  IAccessibleHolder::COMPtrType ptr(rawNative);
+  IAccessibleHolder holder(Move(ptr));
+  Unused << SendParentCOMProxy(holder);
 }
 #endif // defined(XP_WIN)
 
 } // a11y
 } // mozilla
--- a/accessible/ipc/DocAccessibleParent.h
+++ b/accessible/ipc/DocAccessibleParent.h
@@ -139,18 +139,17 @@ public:
   const ProxyAccessible* GetAccessible(uintptr_t aID) const
     { return const_cast<DocAccessibleParent*>(this)->GetAccessible(aID); }
 
   size_t ChildDocCount() const { return mChildDocs.Length(); }
   const DocAccessibleParent* ChildDocAt(size_t aIdx) const
     { return mChildDocs[aIdx]; }
 
 #if defined(XP_WIN)
-  virtual bool RecvCOMProxy(const IAccessibleHolder& aCOMProxy,
-                            IAccessibleHolder* aParentCOMProxy) override;
+  void SetCOMInterface(const RefPtr<IAccessible>& aCOMProxy);
 #endif
 
 private:
 
   class ProxyEntry : public PLDHashEntryHdr
   {
   public:
     explicit ProxyEntry(const void*) : mProxy(nullptr) {}
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/IPCTypes.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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_a11y_IPCTypes_h
+#define mozilla_a11y_IPCTypes_h
+
+/**
+ * Since IPDL does not support preprocessing, this header file allows us to
+ * define types used by PDocAccessible differently depending on platform.
+ */
+
+#if defined(XP_WIN) && defined(ACCESSIBILITY)
+
+// So that we don't include a bunch of other Windows junk.
+#if !defined(COM_NO_WINDOWS_H)
+#define COM_NO_WINDOWS_H
+#endif // !defined(COM_NO_WINDOWS_H)
+
+// COM headers pull in MSXML which conflicts with our own XMLDocument class.
+// This define excludes those conflicting definitions.
+#if !defined(__XMLDocument_FWD_DEFINED__)
+#define __XMLDocument_FWD_DEFINED__
+#endif // !defined(__XMLDocument_FWD_DEFINED__)
+
+#include "mozilla/a11y/COMPtrTypes.h"
+
+// This define in rpcndr.h messes up our code, so we must undefine it after
+// COMPtrTypes.h has been included.
+#if defined(small)
+#undef small
+#endif // defined(small)
+
+#else
+
+namespace mozilla {
+namespace a11y {
+
+typedef uint32_t IAccessibleHolder;
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif // defined(XP_WIN) && defined(ACCESSIBILITY)
+
+#endif // mozilla_a11y_IPCTypes_h
+
--- a/accessible/ipc/moz.build
+++ b/accessible/ipc/moz.build
@@ -24,16 +24,20 @@ else:
         LOCAL_INCLUDES += [
             '/accessible/mac',
         ]
     else:
         LOCAL_INCLUDES += [
             '/accessible/other',
         ]
 
+EXPORTS.mozilla.a11y += [
+    'IPCTypes.h',
+]
+
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wno-error=shadow']
 
 if CONFIG['ACCESSIBILITY']:
     EXPORTS.mozilla.a11y += [
         'DocAccessibleChildBase.h',
         'DocAccessibleParent.h',
         'ProxyAccessibleBase.h',
--- a/accessible/ipc/other/DocAccessibleChild.h
+++ b/accessible/ipc/other/DocAccessibleChild.h
@@ -32,16 +32,24 @@ public:
     MOZ_COUNT_CTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
   }
 
   ~DocAccessibleChild()
   {
     MOZ_COUNT_DTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
   }
 
+  /**
+   * DocAccessible::NotifyOfLoad will not proceed unless this function returns
+   * true. If it returns false, DocAccessibleChild::NotifyOfLoadWhenReady will
+   * be called to defer the notification.
+   */
+  bool IsReadyForNotifyOfLoad() const { return true; }
+  void NotifyOfLoadWhenReady(uint32_t) {}
+
   /*
    * Return the state for the accessible with given ID.
    */
   virtual bool RecvState(const uint64_t& aID, uint64_t* aState) override;
 
   /*
    * Return the native state for the accessible with given ID.
    */
--- a/accessible/ipc/win/DocAccessibleChild.cpp
+++ b/accessible/ipc/win/DocAccessibleChild.cpp
@@ -12,32 +12,43 @@
 
 namespace mozilla {
 namespace a11y {
 
 static StaticAutoPtr<PlatformChild> sPlatformChild;
 
 DocAccessibleChild::DocAccessibleChild(DocAccessible* aDoc)
   : DocAccessibleChildBase(aDoc)
+  , mDeferredLoadEventType(0)
 {
   MOZ_COUNT_CTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
   if (!sPlatformChild) {
     sPlatformChild = new PlatformChild();
     ClearOnShutdown(&sPlatformChild, ShutdownPhase::Shutdown);
   }
 }
 
 DocAccessibleChild::~DocAccessibleChild()
 {
   MOZ_COUNT_DTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
 }
 
-void
-DocAccessibleChild::SendCOMProxy(const IAccessibleHolder& aProxy)
+bool
+DocAccessibleChild::RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy)
 {
-  IAccessibleHolder parentProxy;
-  PDocAccessibleChild::SendCOMProxy(aProxy, &parentProxy);
-  mParentProxy.reset(parentProxy.Release());
+  MOZ_ASSERT(!aParentCOMProxy.IsNull());
+  mParentProxy.reset(aParentCOMProxy.Release());
+  if (mDeferredLoadEventType) {
+    mDoc->NotifyOfLoad(mDeferredLoadEventType);
+  }
+  return true;
+}
+
+void
+DocAccessibleChild::NotifyOfLoadWhenReady(uint32_t aLoadEventType)
+{
+  MOZ_ASSERT(!mParentProxy && !mDeferredLoadEventType);
+  mDeferredLoadEventType = aLoadEventType;
 }
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/ipc/win/DocAccessibleChild.h
+++ b/accessible/ipc/win/DocAccessibleChild.h
@@ -19,19 +19,29 @@ namespace a11y {
  * and their lifetime is the same as the document they represent.
  */
 class DocAccessibleChild : public DocAccessibleChildBase
 {
 public:
   explicit DocAccessibleChild(DocAccessible* aDoc);
   ~DocAccessibleChild();
 
-  void SendCOMProxy(const IAccessibleHolder& aProxy);
+  bool RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy) override;
+
   IAccessible* GetParentIAccessible() const { return mParentProxy.get(); }
 
+  /**
+   * DocAccessible::NotifyOfLoad will not proceed unless this function returns
+   * true. If it returns false, DocAccessibleChild::NotifyOfLoadWhenReady will
+   * be called to defer the notification.
+   */
+  bool IsReadyForNotifyOfLoad() const { return !!mParentProxy; }
+  void NotifyOfLoadWhenReady(uint32_t aLoadEventType);
+
 private:
   mscom::ProxyUniquePtr<IAccessible> mParentProxy;
+  uint32_t mDeferredLoadEventType;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_DocAccessibleChild_h
--- a/accessible/ipc/win/PDocAccessible.ipdl
+++ b/accessible/ipc/win/PDocAccessible.ipdl
@@ -56,19 +56,16 @@ parent:
   async RoleChangedEvent(uint32_t aRole);
 
   /*
    * Tell the parent document to bind the existing document as a new child
    * document.
    */
   async BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
 
-  // For now we'll add the command to send the proxy here. This might move to
-  // PDocAccessible constructor in PBrowser.
-  sync COMProxy(IAccessibleHolder aDocCOMProxy)
-    returns(IAccessibleHolder aParentCOMProxy);
+child:
+  async ParentCOMProxy(IAccessibleHolder aParentCOMProxy);
 
-child:
   async __delete__();
 };
 
 }
 }
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -71,16 +71,17 @@ using class mozilla::dom::MessagePort fr
 using class mozilla::dom::ipc::StructuredCloneData from "mozilla/dom/ipc/StructuredCloneData.h";
 using mozilla::EventMessage from "mozilla/EventForwards.h";
 using nsEventStatus from "mozilla/EventForwards.h";
 using mozilla::Modifiers from "mozilla/EventForwards.h";
 using nsSizeMode from "nsIWidgetListener.h";
 using mozilla::widget::CandidateWindowPosition from "ipc/nsGUIEventIPC.h";
 using class mozilla::NativeEventData from "ipc/nsGUIEventIPC.h";
 using mozilla::FontRange from "ipc/nsGUIEventIPC.h";
+using mozilla::a11y::IAccessibleHolder from "mozilla/a11y/IPCTypes.h";
 
 namespace mozilla {
 namespace dom {
 
 struct NativeKeyBinding
 {
   CommandInt[] singleLineCommands;
   CommandInt[] multiLineCommands;
@@ -135,20 +136,21 @@ both:
     async PRenderFrame();
 
 parent:
     /**
      * Tell the parent process a new accessible document has been created.
      * aParentDoc is the accessible document it was created in if any, and
      * aParentAcc is the id of the accessible in that document the new document
      * is a child of. aMsaaID is the MSAA id for this content process, and
-     * is only valid on Windows. Set to 0 on other platforms.
+     * is only valid on Windows. Set to 0 on other platforms. aDocCOMProxy
+     * is also Windows-specific and should be set to 0 on other platforms.
      */
     async PDocAccessible(nullable PDocAccessible aParentDoc, uint64_t aParentAcc,
-                         uint32_t aMsaaID);
+                         uint32_t aMsaaID, IAccessibleHolder aDocCOMProxy);
 
     /*
      * Creates a new remoted nsIWidget connection for windowed plugins
      * in e10s mode. This is always initiated from the child in response
      * to windowed plugin creation.
      */
     sync PPluginWidget();
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1976,17 +1976,17 @@ TabChild::RecvPasteTransferable(const IP
 
   ourDocShell->DoCommandWithParams("cmd_pasteTransferable", params);
   return true;
 }
 
 
 a11y::PDocAccessibleChild*
 TabChild::AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&,
-                                   const uint32_t&)
+                                   const uint32_t&, const IAccessibleHolder&)
 {
   MOZ_ASSERT(false, "should never call this!");
   return nullptr;
 }
 
 bool
 TabChild::DeallocPDocAccessibleChild(a11y::PDocAccessibleChild* aChild)
 {
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -436,17 +436,17 @@ public:
                                 const IPC::Principal& aPrincipal,
                                 const ClonedMessageData& aData) override;
 
   virtual bool
   RecvSwappedWithOtherRemoteLoader(const IPCTabContext& aContext) override;
 
   virtual PDocAccessibleChild*
   AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&,
-                           const uint32_t&) override;
+                           const uint32_t&, const IAccessibleHolder&) override;
 
   virtual bool DeallocPDocAccessibleChild(PDocAccessibleChild*) override;
 
   virtual PDocumentRendererChild*
   AllocPDocumentRendererChild(const nsRect& aDocumentRect,
                               const gfx::Matrix& aTransform,
                               const nsString& aBggcolor,
                               const uint32_t& aRenderFlags,
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -895,17 +895,18 @@ TabParent::SetDocShell(nsIDocShell *aDoc
 {
   NS_ENSURE_ARG(aDocShell);
   NS_WARNING("No mDocShell member in TabParent so there is no docShell to set");
   return NS_OK;
 }
 
   a11y::PDocAccessibleParent*
 TabParent::AllocPDocAccessibleParent(PDocAccessibleParent* aParent,
-                                     const uint64_t&, const uint32_t&)
+                                     const uint64_t&, const uint32_t&,
+                                     const IAccessibleHolder&)
 {
 #ifdef ACCESSIBILITY
   return new a11y::DocAccessibleParent();
 #else
   return nullptr;
 #endif
 }
 
@@ -917,32 +918,34 @@ TabParent::DeallocPDocAccessibleParent(P
 #endif
   return true;
 }
 
 bool
 TabParent::RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc,
                                          PDocAccessibleParent* aParentDoc,
                                          const uint64_t& aParentID,
-                                         const uint32_t& aMsaaID)
+                                         const uint32_t& aMsaaID,
+                                         const IAccessibleHolder& aDocCOMProxy)
 {
 #ifdef ACCESSIBILITY
   auto doc = static_cast<a11y::DocAccessibleParent*>(aDoc);
   if (aParentDoc) {
     // A document should never directly be the parent of another document.
     // There should always be an outer doc accessible child of the outer
     // document containing the child.
     MOZ_ASSERT(aParentID);
     if (!aParentID) {
       return false;
     }
 
     auto parentDoc = static_cast<a11y::DocAccessibleParent*>(aParentDoc);
     bool added = parentDoc->AddChildDoc(doc, aParentID);
 #ifdef XP_WIN
+    MOZ_ASSERT(aDocCOMProxy.IsNull());
     if (added) {
       a11y::WrapperFor(doc)->SetID(aMsaaID);
     }
 #endif
     return added;
   } else {
     // null aParentDoc means this document is at the top level in the child
     // process.  That means it makes no sense to get an id for an accessible
@@ -951,16 +954,19 @@ TabParent::RecvPDocAccessibleConstructor
     if (aParentID) {
       return false;
     }
 
     doc->SetTopLevel();
     a11y::DocManager::RemoteDocAdded(doc);
 #ifdef XP_WIN
     a11y::WrapperFor(doc)->SetID(aMsaaID);
+    MOZ_ASSERT(!aDocCOMProxy.IsNull());
+    RefPtr<IAccessible> proxy(aDocCOMProxy.Get());
+    doc->SetCOMInterface(proxy);
 #endif
   }
 #endif
   return true;
 }
 
 a11y::DocAccessibleParent*
 TabParent::GetTopLevelDocAccessible() const
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -352,25 +352,26 @@ public:
   DeallocPColorPickerParent(PColorPickerParent* aColorPicker) override;
 
   virtual PDatePickerParent*
   AllocPDatePickerParent(const nsString& aTitle, const nsString& aInitialDate) override;
   virtual bool DeallocPDatePickerParent(PDatePickerParent* aDatePicker) override;
 
   virtual PDocAccessibleParent*
   AllocPDocAccessibleParent(PDocAccessibleParent*, const uint64_t&,
-                            const uint32_t&) override;
+                            const uint32_t&, const IAccessibleHolder&) override;
 
   virtual bool DeallocPDocAccessibleParent(PDocAccessibleParent*) override;
 
   virtual bool
   RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc,
                                 PDocAccessibleParent* aParentDoc,
                                 const uint64_t& aParentID,
-                                const uint32_t& aMsaaID) override;
+                                const uint32_t& aMsaaID,
+                                const IAccessibleHolder& aDocCOMProxy) override;
 
   /**
    * Return the top level doc accessible parent for this tab.
    */
   a11y::DocAccessibleParent* GetTopLevelDocAccessible() const;
 
   void LoadURL(nsIURI* aURI);
 
--- a/ipc/mscom/COMPtrHolder.h
+++ b/ipc/mscom/COMPtrHolder.h
@@ -33,17 +33,17 @@ public:
   {
   }
 
   Interface* Get() const
   {
     return mPtr.get();
   }
 
-  MOZ_MUST_USE Interface* Release()
+  MOZ_MUST_USE Interface* Release() const
   {
     return mPtr.release();
   }
 
   void Set(COMPtrType&& aPtr)
   {
     mPtr = Forward<COMPtrType>(aPtr);
   }