Bug 1325850 - part 1: Create ScriptableContentIterator to make each concrete class of nsIContentIterator scriptable r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 03 Jan 2019 22:19:04 +0000
changeset 509782 7cf2438bcd343bcd530e8e9f8e8e9c4cc92942e4
parent 509781 eb6cf8333a9aac70bddfa87b670dbce922fbe058
child 509783 1541218476834334f1e5af8b22671ff75b4c54b0
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1325850
milestone66.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 1325850 - part 1: Create ScriptableContentIterator to make each concrete class of nsIContentIterator scriptable r=smaug The concrete classes of nsIContentIterator are enough complicated, but they are not tested simply. Therefore, it's dangerous to touch them even if we meed bugs of them. Additionally, it's used in some hot paths, therefore, I'd like to keep them simple as far as possible. Therefore, this patch creates a mediator class between script and each nsIContentIterator instance. So, this change shouldn't affect any of actual behavior nor performance. Differential Revision: https://phabricator.services.mozilla.com/D15285
dom/base/ScriptableContentIterator.cpp
dom/base/ScriptableContentIterator.h
dom/base/moz.build
dom/base/nsIScriptableContentIterator.idl
layout/build/nsLayoutModule.cpp
new file mode 100644
--- /dev/null
+++ b/dom/base/ScriptableContentIterator.cpp
@@ -0,0 +1,145 @@
+/* -*- 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/. */
+
+#include "ScriptableContentIterator.h"
+#include "nsINode.h"
+#include "nsRange.h"
+
+namespace mozilla {
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(ScriptableContentIterator)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptableContentIterator)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScriptableContentIterator)
+  NS_INTERFACE_MAP_ENTRY(nsIScriptableContentIterator)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTION(ScriptableContentIterator, mContentIterator)
+
+ScriptableContentIterator::ScriptableContentIterator()
+    : mIteratorType(NOT_INITIALIZED) {}
+
+void ScriptableContentIterator::EnsureContentIterator() {
+  if (mContentIterator) {
+    return;
+  }
+  switch (mIteratorType) {
+    case POST_ORDER_ITERATOR:
+    default:
+      mContentIterator = NS_NewContentIterator();
+      break;
+    case PRE_ORDER_ITERATOR:
+      mContentIterator = NS_NewPreContentIterator();
+      break;
+    case SUBTREE_ITERATOR:
+      mContentIterator = NS_NewContentSubtreeIterator();
+      break;
+  }
+}
+
+NS_IMETHODIMP
+ScriptableContentIterator::InitWithRootNode(IteratorType aType,
+                                            nsINode* aRoot) {
+  if (aType == NOT_INITIALIZED ||
+      (mIteratorType != NOT_INITIALIZED && aType != mIteratorType)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+  mIteratorType = aType;
+  EnsureContentIterator();
+  return mContentIterator->Init(aRoot);
+}
+
+NS_IMETHODIMP
+ScriptableContentIterator::InitWithRange(IteratorType aType, nsRange* aRange) {
+  if (aType == NOT_INITIALIZED ||
+      (mIteratorType != NOT_INITIALIZED && aType != mIteratorType)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+  mIteratorType = aType;
+  EnsureContentIterator();
+  return mContentIterator->Init(aRange);
+}
+
+NS_IMETHODIMP
+ScriptableContentIterator::InitWithPositions(IteratorType aType,
+                                             nsINode* aStartContainer,
+                                             uint32_t aStartOffset,
+                                             nsINode* aEndContainer,
+                                             uint32_t aEndOffset) {
+  if (aType == NOT_INITIALIZED ||
+      (mIteratorType != NOT_INITIALIZED && aType != mIteratorType)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+  mIteratorType = aType;
+  EnsureContentIterator();
+  return mContentIterator->Init(aStartContainer, aStartOffset, aEndContainer,
+                                aEndOffset);
+}
+
+NS_IMETHODIMP
+ScriptableContentIterator::First() {
+  if (!mContentIterator) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+  mContentIterator->First();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ScriptableContentIterator::Last() {
+  if (!mContentIterator) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+  mContentIterator->Last();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ScriptableContentIterator::Next() {
+  if (!mContentIterator) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+  mContentIterator->Next();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ScriptableContentIterator::Prev() {
+  if (!mContentIterator) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+  mContentIterator->Prev();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ScriptableContentIterator::GetCurrentNode(nsINode** aNode) {
+  if (!mContentIterator) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+  NS_IF_ADDREF(*aNode = mContentIterator->GetCurrentNode());
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ScriptableContentIterator::GetIsDone(bool* aIsDone) {
+  if (!mContentIterator) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+  *aIsDone = mContentIterator->IsDone();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ScriptableContentIterator::PositionAt(nsINode* aNode) {
+  if (!mContentIterator) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+  return mContentIterator->PositionAt(aNode);
+}
+
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/base/ScriptableContentIterator.h
@@ -0,0 +1,34 @@
+/* -*- 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_scriptablecontentiterator_h
+#define mozilla_scriptablecontentiterator_h
+
+#include "mozilla/Attributes.h"
+#include "nsCOMPtr.h"
+#include "nsIContentIterator.h"
+#include "nsIScriptableContentIterator.h"
+
+namespace mozilla {
+
+class ScriptableContentIterator final : public nsIScriptableContentIterator {
+ public:
+  ScriptableContentIterator();
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(ScriptableContentIterator)
+  NS_DECL_NSISCRIPTABLECONTENTITERATOR
+
+ protected:
+  virtual ~ScriptableContentIterator() = default;
+  void EnsureContentIterator();
+
+  IteratorType mIteratorType;
+  nsCOMPtr<nsIContentIterator> mContentIterator;
+};
+
+}  // namespace mozilla
+
+#endif  // #ifndef mozilla_scriptablecontentiterator_h
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -18,16 +18,17 @@ XPIDL_SOURCES += [
     'nsIDocumentEncoder.idl',
     'nsIDOMRequestService.idl',
     'nsIDroppedLinkHandler.idl',
     'nsIFrameLoaderOwner.idl',
     'nsIImageLoadingContent.idl',
     'nsIMessageManager.idl',
     'nsIObjectLoadingContent.idl',
     'nsIRemoteWindowContext.idl',
+    'nsIScriptableContentIterator.idl',
     'nsIScriptChannel.idl',
     'nsISelectionController.idl',
     'nsISelectionDisplay.idl',
     'nsISelectionListener.idl',
     'nsISlowScriptDebug.idl',
 ]
 
 XPIDL_MODULE = 'dom'
@@ -124,16 +125,17 @@ if CONFIG['MOZ_WEBRTC']:
         'nsDOMDataChannelDeclarations.h',
     ]
 
 EXPORTS.mozilla += [
     'CORSMode.h',
     'FlushType.h',
     'FullscreenChange.h',
     'RangeBoundary.h',
+    'ScriptableContentIterator.h',
     'SelectionChangeEventDispatcher.h',
     'TextInputProcessor.h',
     'UseCounter.h',
 ]
 
 EXPORTS.mozilla.dom += [
     '!UseCounterList.h',
     'AnonymousContent.h',
@@ -370,16 +372,17 @@ UNIFIED_SOURCES += [
     'Pose.cpp',
     'PostMessageEvent.cpp',
     'ProcessMessageManager.cpp',
     'RemoteOuterWindowProxy.cpp',
     'ResponsiveImageSelector.cpp',
     'SameProcessMessageQueue.cpp',
     'ScreenLuminance.cpp',
     'ScreenOrientation.cpp',
+    'ScriptableContentIterator.cpp',
     'Selection.cpp',
     'SelectionChangeEventDispatcher.cpp',
     'ShadowRoot.cpp',
     'StorageAccessPermissionRequest.cpp',
     'StructuredCloneBlob.cpp',
     'StructuredCloneHolder.cpp',
     'StructuredCloneTester.cpp',
     'StyleSheetList.cpp',
new file mode 100644
--- /dev/null
+++ b/dom/base/nsIScriptableContentIterator.idl
@@ -0,0 +1,74 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "nsISupports.idl"
+
+webidl Node;
+webidl Range;
+
+/**
+ * nsIScriptableContentIterator is designed to testing concrete classes of
+ * nsIContentIterator.
+ */
+[scriptable, builtinclass, uuid(9f25fb2a-265f-44f9-a122-62bbf443239e)]
+interface nsIScriptableContentIterator : nsISupports
+{
+  cenum IteratorType : 8 {
+    NOT_INITIALIZED,
+    POST_ORDER_ITERATOR,
+    PRE_ORDER_ITERATOR,
+    SUBTREE_ITERATOR
+  };
+
+  /**
+   * You need to call initWith*() first.  Then, the instance of this interface
+   * decides the type of iterator with its aType argument.  You can call
+   * initWith*() multiple times, but you need to keep setting same type as
+   * previous call.  If you set different type, these method with throw an
+   * exception.
+   */
+
+  // See nsIContentIterator::Init(nsINode*)
+  void initWithRootNode(in nsIScriptableContentIterator_IteratorType aType,
+                        in Node aRoot);
+
+  // See nsIContentIterator::Init(nsRange*)
+  void initWithRange(in nsIScriptableContentIterator_IteratorType aType,
+                     in Range aRange);
+
+  // See nsIContentIterator::Init(nsINode*, uint32_t, nsINode*, uint32_t)
+  void initWithPositions(in nsIScriptableContentIterator_IteratorType aType,
+                         in Node aStartContainer, in unsigned long aStartOffset,
+                         in Node aEndContainer, in unsigned long aEndOffset);
+
+  // See nsIContentIterator::First()
+  void first();
+
+  // See nsIContentIterator::Last()
+  void last();
+
+  // See nsIContentIterator::Next()
+  void next();
+
+  // See nsIContentIterator::Prev()
+  void prev();
+
+  // See nsIContentIterator::GetCurrentNode()
+  readonly attribute Node currentNode;
+
+  // See nsIContentIterator::IsDone()
+  readonly attribute bool isDone;
+
+  // See nsIContentIterator::PositionAt(nsINode*)
+  void positionAt(in Node aNode);
+};
+
+%{C++
+#define SCRIPTABLE_CONTENT_ITERATOR_CID \
+  { 0xf68037ec, 0x2790, 0x44c5, \
+    { 0x8e, 0x5f, 0xdf, 0x5d, 0xa5, 0x8b, 0x93, 0xa7 } }
+#define SCRIPTABLE_CONTENT_ITERATOR_CONTRACTID \
+  "@mozilla.org/scriptable-content-iterator;1"
+%}
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -143,16 +143,17 @@ static void Shutdown();
 #include "mozilla/dom/PresentationDeviceManager.h"
 #include "mozilla/dom/PresentationTCPSessionTransport.h"
 
 #include "nsScriptError.h"
 #include "nsBaseCommandController.h"
 #include "nsControllerCommandTable.h"
 
 #include "mozilla/TextInputProcessor.h"
+#include "mozilla/ScriptableContentIterator.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::net;
 using mozilla::dom::power::PowerManagerService;
 using mozilla::dom::quota::QuotaManagerService;
 using mozilla::gmp::GeckoMediaPluginService;
 
@@ -215,16 +216,17 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR
                                          MediaManager::GetInstance)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PresentationDeviceManager)
 NS_GENERIC_FACTORY_CONSTRUCTOR(TextInputProcessor)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIPresentationService,
                                          NS_CreatePresentationService)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PresentationTCPSessionTransport)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NotificationTelemetryService, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PushNotifier)
+NS_GENERIC_FACTORY_CONSTRUCTOR(ScriptableContentIterator)
 
 //-----------------------------------------------------------------------------
 
 static bool gInitialized = false;
 
 // Perform our one-time intialization for this module
 
 void nsLayoutModuleInitialize() {
@@ -514,16 +516,18 @@ NS_DEFINE_NAMED_CID(GECKO_MEDIA_PLUGIN_S
 NS_DEFINE_NAMED_CID(PRESENTATION_SERVICE_CID);
 NS_DEFINE_NAMED_CID(PRESENTATION_DEVICE_MANAGER_CID);
 NS_DEFINE_NAMED_CID(PRESENTATION_TCP_SESSION_TRANSPORT_CID);
 
 NS_DEFINE_NAMED_CID(TEXT_INPUT_PROCESSOR_CID);
 
 NS_DEFINE_NAMED_CID(NS_SCRIPTERROR_CID);
 
+NS_DEFINE_NAMED_CID(SCRIPTABLE_CONTENT_ITERATOR_CID);
+
 static nsresult LocalStorageManagerConstructor(nsISupports* aOuter,
                                                REFNSIID aIID, void** aResult) {
   if (NextGenLocalStorageEnabled()) {
     RefPtr<LocalStorageManager2> manager = new LocalStorageManager2();
     return manager->QueryInterface(aIID, aResult);
   }
 
   RefPtr<LocalStorageManager> manager = new LocalStorageManager();
@@ -599,16 +603,17 @@ static const mozilla::Module::CIDEntry k
 #ifdef ACCESSIBILITY
   { &kNS_ACCESSIBILITY_SERVICE_CID, false, nullptr, CreateA11yService },
 #endif
   { &kPRESENTATION_SERVICE_CID, false, nullptr, nsIPresentationServiceConstructor },
   { &kPRESENTATION_DEVICE_MANAGER_CID, false, nullptr, PresentationDeviceManagerConstructor },
   { &kPRESENTATION_TCP_SESSION_TRANSPORT_CID, false, nullptr, PresentationTCPSessionTransportConstructor },
   { &kTEXT_INPUT_PROCESSOR_CID, false, nullptr, TextInputProcessorConstructor },
   { &kNS_SCRIPTERROR_CID, false, nullptr, nsScriptErrorConstructor },
+  { &kSCRIPTABLE_CONTENT_ITERATOR_CID, false, nullptr, ScriptableContentIteratorConstructor },
   { nullptr }
     // clang-format on
 };
 
 static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
     // clang-format off
   XPCONNECT_CONTRACTS
   { "@mozilla.org/inspector/deep-tree-walker;1", &kIN_DEEPTREEWALKER_CID },
@@ -671,16 +676,17 @@ static const mozilla::Module::ContractID
   { "@mozilla.org/accessibilityService;1", &kNS_ACCESSIBILITY_SERVICE_CID },
 #endif
   { "@mozilla.org/gecko-media-plugin-service;1",  &kGECKO_MEDIA_PLUGIN_SERVICE_CID },
   { PRESENTATION_SERVICE_CONTRACTID, &kPRESENTATION_SERVICE_CID },
   { PRESENTATION_DEVICE_MANAGER_CONTRACTID, &kPRESENTATION_DEVICE_MANAGER_CID },
   { PRESENTATION_TCP_SESSION_TRANSPORT_CONTRACTID, &kPRESENTATION_TCP_SESSION_TRANSPORT_CID },
   { "@mozilla.org/text-input-processor;1", &kTEXT_INPUT_PROCESSOR_CID },
   { NS_SCRIPTERROR_CONTRACTID, &kNS_SCRIPTERROR_CID },
+  { "@mozilla.org/scriptable-content-iterator;1", &kSCRIPTABLE_CONTENT_ITERATOR_CID },
   { nullptr }
 };
 
 static const mozilla::Module::CategoryEntry kLayoutCategories[] = {
   { "content-policy", NS_DATADOCUMENTCONTENTPOLICY_CONTRACTID, NS_DATADOCUMENTCONTENTPOLICY_CONTRACTID },
   { "content-policy", NS_NODATAPROTOCOLCONTENTPOLICY_CONTRACTID, NS_NODATAPROTOCOLCONTENTPOLICY_CONTRACTID },
   { "content-policy", "CSPService", CSPSERVICE_CONTRACTID },
   { "content-policy", NS_MIXEDCONTENTBLOCKER_CONTRACTID, NS_MIXEDCONTENTBLOCKER_CONTRACTID },