Bug 1328546 - stylo: Support ServoStyleSheets in nsIStyleSheetService::PreloadSheet and nsIDOMWindowUtils::AddSheet. r?bholley draft
authorCameron McCormack <cam@mcc.id.au>
Wed, 04 Jan 2017 13:27:13 +0800
changeset 456114 18406f75529285495fe51551bd6bfa664b6aeef7
parent 455592 fc0633f43b5bde982c04cdf3a1aea8d43a150636
child 541149 44ddd44457a80167c4c1160695641e11860e6c8d
push id40408
push userbmo:cam@mcc.id.au
push dateThu, 05 Jan 2017 02:34:14 +0000
reviewersbholley
bugs1328546
milestone53.0a1
Bug 1328546 - stylo: Support ServoStyleSheets in nsIStyleSheetService::PreloadSheet and nsIDOMWindowUtils::AddSheet. r?bholley MozReview-Commit-ID: 2KOMrnCf1Ag
dom/base/nsDOMWindowUtils.cpp
dom/interfaces/base/nsIDOMWindowUtils.idl
layout/base/moz.build
layout/base/nsIPreloadedStyleSheet.idl
layout/base/nsIStyleSheetService.idl
layout/base/nsStyleSheetService.cpp
layout/style/PreloadedStyleSheet.cpp
layout/style/PreloadedStyleSheet.h
layout/style/moz.build
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -108,16 +108,17 @@
 #include "nsDocument.h"
 #include "HTMLImageElement.h"
 #include "mozilla/css/ImageLoader.h"
 #include "mozilla/layers/APZCTreeManager.h" // for layers::ZoomToRectBehavior
 #include "mozilla/dom/Promise.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/dom/TimeoutManager.h"
+#include "mozilla/PreloadedStyleSheet.h"
 
 #ifdef XP_WIN
 #undef GetClassName
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
@@ -3445,33 +3446,40 @@ nsDOMWindowUtils::LoadSheetUsingURIStrin
   nsCOMPtr<nsIURI> uri;
   nsresult rv = NS_NewURI(getter_AddRefs(uri), aSheetURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return LoadSheet(uri, aSheetType);
 }
 
 NS_IMETHODIMP
-nsDOMWindowUtils::AddSheet(nsIDOMStyleSheet *aSheet, uint32_t aSheetType)
+nsDOMWindowUtils::AddSheet(nsIPreloadedStyleSheet* aSheet, uint32_t aSheetType)
 {
   NS_ENSURE_ARG_POINTER(aSheet);
   NS_ENSURE_ARG(aSheetType == AGENT_SHEET ||
                 aSheetType == USER_SHEET ||
                 aSheetType == AUTHOR_SHEET);
 
   nsCOMPtr<nsIDocument> doc = GetDocument();
   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
 
-  nsIDocument::additionalSheetType type = convertSheetType(aSheetType);
-  RefPtr<CSSStyleSheet> sheet = do_QueryObject(aSheet);
-  NS_ENSURE_TRUE(sheet, NS_ERROR_FAILURE);
-  if (sheet->GetOwningDocument()) {
+  auto preloadedSheet = static_cast<PreloadedStyleSheet*>(aSheet);
+
+  const PreloadedStyleSheet::SheetAndStatus& data =
+    preloadedSheet->GetSheet(doc->GetStyleBackendType());
+
+  NS_ENSURE_SUCCESS(data.mLoadStatus, data.mLoadStatus);
+  NS_ENSURE_TRUE(data.mSheet, NS_ERROR_FAILURE);
+
+  if (data.mSheet->GetOwningDocument()) {
     return NS_ERROR_INVALID_ARG;
   }
-  return doc->AddAdditionalStyleSheet(type, sheet);
+
+  nsIDocument::additionalSheetType type = convertSheetType(aSheetType);
+  return doc->AddAdditionalStyleSheet(type, data.mSheet);
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::RemoveSheet(nsIURI *aSheetURI, uint32_t aSheetType)
 {
   NS_ENSURE_ARG_POINTER(aSheetURI);
   NS_ENSURE_ARG(aSheetType == AGENT_SHEET ||
                 aSheetType == USER_SHEET ||
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -30,17 +30,17 @@ native nscolor(nscolor);
 typedef unsigned long long nsViewID;
 
 interface nsICycleCollectorListener;
 interface nsIDOMNode;
 interface nsIDOMNodeList;
 interface nsIDOMElement;
 interface nsIDOMHTMLCanvasElement;
 interface nsIDOMEvent;
-interface nsIDOMStyleSheet;
+interface nsIPreloadedStyleSheet;
 interface nsITransferable;
 interface nsIQueryContentEventResult;
 interface nsIDOMWindow;
 interface nsIFile;
 interface nsIDOMClientRect;
 interface nsIURI;
 interface nsIDOMEventTarget;
 interface nsIRunnable;
@@ -1739,17 +1739,17 @@ interface nsIDOMWindowUtils : nsISupport
 
   /**
    * Adds a style sheet to the list of additional style sheets of the document.
    *
    * Style sheets can be preloaded with nsIStyleSheetService.preloadSheet.
    *
    * Sheets added via this API take effect immediately on the document.
    */
-  void addSheet(in nsIDOMStyleSheet sheet, in unsigned long type);
+  void addSheet(in nsIPreloadedStyleSheet sheet, in unsigned long type);
 
   /**
    * Remove the document style sheet at |sheetURI| from the list of additional 
    * style sheets of the document.  The removal takes effect immediately.
    */
   void removeSheet(in nsIURI sheetURI, in unsigned long type);
 
   /**
--- a/layout/base/moz.build
+++ b/layout/base/moz.build
@@ -15,16 +15,17 @@ with Files('nsChangeHint.h'):
 
 with Files('nsBidi*'):
     BUG_COMPONENT = ('Core', 'Layout: Text')
 
 with Files('AccessibleCaret*'):
     BUG_COMPONENT = ('Core', 'Selection')
 
 XPIDL_SOURCES += [
+    'nsIPreloadedStyleSheet.idl',
     'nsIStyleSheetService.idl',
 ]
 
 if CONFIG['MOZ_DEBUG']:
     UNIFIED_SOURCES += [
         'nsAutoLayoutPhase.cpp',
     ]
 
new file mode 100644
--- /dev/null
+++ b/layout/base/nsIPreloadedStyleSheet.idl
@@ -0,0 +1,16 @@
+/* -*- 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"
+
+/**
+ * The nsIPreloadedStyleSheet interface is an opaque interface for
+ * style sheets returned by nsIStyleSheetService.preloadSheet, and
+ * which can be passed to nsIDOMWindowUtils.addSheet.
+ */
+[scriptable, builtinclass, uuid(2e2a84d0-2102-4b9e-9b78-1670623a582d)]
+interface nsIPreloadedStyleSheet : nsISupports
+{
+};
--- a/layout/base/nsIStyleSheetService.idl
+++ b/layout/base/nsIStyleSheetService.idl
@@ -2,18 +2,18 @@
 /* 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/. */
 
 /* interface for managing user and user-agent style sheets */
 
 #include "nsISupports.idl"
 
+interface nsIPreloadedStyleSheet;
 interface nsIURI;
-interface nsIDOMStyleSheet;
 
 /*
  * nsIStyleSheetService allows extensions or embeddors to add to the
  * built-in list of user or agent style sheets.
  */
 
 [scriptable, uuid(4de68896-e8eb-41de-8237-a797b570ac4a)]
 interface nsIStyleSheetService : nsISupports
@@ -46,17 +46,18 @@ interface nsIStyleSheetService : nsISupp
    * added to the list of style sheets specified by |type|.
    */
   boolean sheetRegistered(in nsIURI sheetURI, in unsigned long type);
 
   /**
    * Synchronously loads a style sheet from |sheetURI| and returns the
    * new style sheet object. Can be used with nsIDOMWindowUtils.addSheet.
    */
-  nsIDOMStyleSheet preloadSheet(in nsIURI sheetURI, in unsigned long type);
+  nsIPreloadedStyleSheet preloadSheet(in nsIURI sheetURI,
+                                      in unsigned long type);
 
   /**
    * Remove the style sheet at |sheetURI| from the list of style sheets
    * specified by |type|.  The removal takes effect immediately, even for
    * already-loaded documents.
    */
   void unregisterSheet(in nsIURI sheetURI, in unsigned long type);
 };
--- a/layout/base/nsStyleSheetService.cpp
+++ b/layout/base/nsStyleSheetService.cpp
@@ -4,16 +4,17 @@
  * 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/. */
 
 /* implementation of interface for managing user and user-agent style sheets */
 
 #include "nsStyleSheetService.h"
 #include "mozilla/CSSStyleSheet.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/PreloadedStyleSheet.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/Unused.h"
 #include "mozilla/css/Loader.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
@@ -257,18 +258,18 @@ nsStyleSheetService::SheetRegistered(nsI
   NS_PRECONDITION(_retval, "Null out param");
 
   *_retval = (FindSheetByURI(mSheets[aSheetType], sheetURI) >= 0);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsStyleSheetService::PreloadSheet(nsIURI *aSheetURI, uint32_t aSheetType,
-                                  nsIDOMStyleSheet **aSheet)
+nsStyleSheetService::PreloadSheet(nsIURI* aSheetURI, uint32_t aSheetType,
+                                  nsIPreloadedStyleSheet** aSheet)
 {
   NS_PRECONDITION(aSheet, "Null out param");
   NS_ENSURE_ARG_POINTER(aSheetURI);
   css::SheetParsingMode parsingMode;
   switch (aSheetType) {
     case AGENT_SHEET:
       parsingMode = css::eAgentSheetFeatures;
       break;
@@ -281,31 +282,26 @@ nsStyleSheetService::PreloadSheet(nsIURI
       parsingMode = css::eAuthorSheetFeatures;
       break;
 
     default:
       NS_WARNING("invalid sheet type argument");
       return NS_ERROR_INVALID_ARG;
   }
 
-  // XXXheycam PreloadSheet can't support ServoStyleSheets until they implement
-  // nsIDOMStyleSheet.
-
-  RefPtr<css::Loader> loader = new css::Loader(StyleBackendType::Gecko);
+  RefPtr<PreloadedStyleSheet> sheet =
+    new PreloadedStyleSheet(aSheetURI, parsingMode);
 
-  RefPtr<StyleSheet> sheet;
-  nsresult rv = loader->LoadSheetSync(aSheetURI, parsingMode, true, &sheet);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsresult rv = sheet->GetPreloadResult();
+  if (NS_FAILED(rv)) {
+    *aSheet = nullptr;
+    return rv;
+  }
 
-  MOZ_ASSERT(sheet->IsGecko(),
-             "stylo: didn't expect Loader to create a ServoStyleSheet");
-
-  RefPtr<CSSStyleSheet> cssSheet = sheet->AsGecko();
-  cssSheet.forget(aSheet);
-
+  sheet.forget(aSheet);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStyleSheetService::UnregisterSheet(nsIURI *aSheetURI, uint32_t aSheetType)
 {
   NS_ENSURE_ARG(aSheetType == AGENT_SHEET ||
                 aSheetType == USER_SHEET ||
new file mode 100644
--- /dev/null
+++ b/layout/style/PreloadedStyleSheet.cpp
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+// vim:cindent:tabstop=2:expandtab:shiftwidth=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/. */
+
+/* a CSS style sheet returned from nsIStyleSheetService.preloadSheet */
+
+#include "PreloadedStyleSheet.h"
+
+namespace mozilla {
+
+PreloadedStyleSheet::PreloadedStyleSheet(nsIURI* aURI,
+                                         css::SheetParsingMode aParsingMode)
+  : mURI(aURI)
+  , mParsingMode(aParsingMode)
+{
+  // The nsIStyleSheetService.preloadSheet API doesn't tell us which backend
+  // the sheet will be used with, and it seems wasteful to eagerly create
+  // both a CSSStyleSheet and a ServoStyleSheet.  So instead, we guess that
+  // the sheet type we will want matches the current value of the stylo pref,
+  // and preload a sheet of that type.
+  //
+  // If we guess wrong, we will re-load the sheet later with the requested type,
+  // and we won't really have front loaded the loading time as the name
+  // "preload" might suggest.  Also, in theory we could get different data from
+  // fetching the URL again, but for the usage patterns of this API this is
+  // unlikely, and it doesn't seem worth trying to store the contents of the URL
+  // and duplicating a bunch of css::Loader's logic.
+  GetSheet(nsLayoutUtils::StyloEnabled() ? StyleBackendType::Servo
+                                         : StyleBackendType::Gecko);
+}
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PreloadedStyleSheet)
+  NS_INTERFACE_MAP_ENTRY(nsIPreloadedStyleSheet)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(PreloadedStyleSheet)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(PreloadedStyleSheet)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(PreloadedStyleSheet)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(PreloadedStyleSheet)
+  if (tmp->mGecko) {
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGecko->mSheet);
+  }
+  if (tmp->mServo) {
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServo->mSheet);
+  }
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(PreloadedStyleSheet)
+  if (tmp->mGecko) {
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(mGecko->mSheet);
+  }
+  if (tmp->mServo) {
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(mServo->mSheet);
+  }
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+const PreloadedStyleSheet::SheetAndStatus&
+PreloadedStyleSheet::GetSheet(StyleBackendType aType)
+{
+  auto& data = aType == StyleBackendType::Gecko ? mGecko : mServo;
+
+  if (!data) {
+    RefPtr<css::Loader> loader = new css::Loader(aType);
+    data.emplace();
+    data->mLoadStatus =
+      loader->LoadSheetSync(mURI, mParsingMode, true, &data->mSheet);
+  }
+
+  return *data;
+}
+
+nsresult
+PreloadedStyleSheet::GetPreloadResult() const
+{
+  MOZ_ASSERT(mGecko.isSome() != mServo.isSome(),
+             "don't call GetPreloadResult after a second type of sheet has "
+             "been loaded");
+  if (mGecko.isSome()) {
+    return mGecko->mLoadStatus;
+  }
+  return mServo->mLoadStatus;
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/style/PreloadedStyleSheet.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+// vim:cindent:tabstop=2:expandtab:shiftwidth=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/. */
+
+/* a CSS style sheet returned from nsIStyleSheetService.preloadSheet */
+
+#ifndef mozilla_PreloadedStyleSheet_h
+#define mozilla_PreloadedStyleSheet_h
+
+#include "mozilla/css/SheetParsingMode.h"
+#include "mozilla/Maybe.h"
+#include "nsIPreloadedStyleSheet.h"
+
+namespace mozilla {
+
+class PreloadedStyleSheet : public nsIPreloadedStyleSheet
+{
+public:
+  struct SheetAndStatus
+  {
+    RefPtr<StyleSheet> mSheet;
+    nsresult mLoadStatus;
+  };
+
+  PreloadedStyleSheet(nsIURI* aURI, css::SheetParsingMode aParsingMode);
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(PreloadedStyleSheet)
+
+  nsresult GetPreloadResult() const;
+  const SheetAndStatus& GetSheet(StyleBackendType aType);
+
+protected:
+  virtual ~PreloadedStyleSheet() {}
+
+private:
+  Maybe<SheetAndStatus> mGecko;
+  Maybe<SheetAndStatus> mServo;
+
+  nsCOMPtr<nsIURI> mURI;
+  css::SheetParsingMode mParsingMode;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_PreloadedStyleSheet_h
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -87,16 +87,17 @@ EXPORTS.mozilla += [
     'CSSVariableResolver.h',
     'CSSVariableValues.h',
     'DeclarationBlock.h',
     'DeclarationBlockInlines.h',
     'DocumentStyleRootIterator.h',
     'HandleRefPtr.h',
     'IncrementalClearCOMRuleArray.h',
     'LayerAnimationInfo.h',
+    'PreloadedStyleSheet.h',
     'RuleNodeCacheConditions.h',
     'RuleProcessorCache.h',
     'ServoArcTypeList.h',
     'ServoBindingList.h',
     'ServoBindings.h',
     'ServoBindingTypes.h',
     'ServoCSSRuleList.h',
     'ServoDeclarationBlock.h',
@@ -193,16 +194,17 @@ UNIFIED_SOURCES += [
     'nsRuleNode.cpp',
     'nsStyleContext.cpp',
     'nsStyleCoord.cpp',
     'nsStyleSet.cpp',
     'nsStyleStruct.cpp',
     'nsStyleTransformMatrix.cpp',
     'nsStyleUtil.cpp',
     'nsTransitionManager.cpp',
+    'PreloadedStyleSheet.cpp',
     'RuleNodeCacheConditions.cpp',
     'RuleProcessorCache.cpp',
     'ServoBindings.cpp',
     'ServoCSSRuleList.cpp',
     'ServoDeclarationBlock.cpp',
     'ServoElementSnapshot.cpp',
     'ServoStyleRule.cpp',
     'ServoStyleSet.cpp',