Bug 1490401 - MatchMedia should work inside display: none iframes. r=heycam
authorEmilio Cobos Álvarez <emilio@crisal.io>
Thu, 04 Apr 2019 11:25:31 +0000
changeset 467972 f98617ff7cf585b77a60e90f9ba3f191d09ec653
parent 467971 a0adda35967e606236d485d2be5ff2825dffec59
child 467973 ba71816514eb515f0a7c29de61ddeca9d2939551
push id112667
push useraiakab@mozilla.com
push dateThu, 04 Apr 2019 16:12:45 +0000
treeherdermozilla-inbound@230bb363f2f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1490401
milestone68.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 1490401 - MatchMedia should work inside display: none iframes. r=heycam Differential Revision: https://phabricator.services.mozilla.com/D25926
Cargo.lock
dom/html/HTMLLinkElement.cpp
dom/html/HTMLSourceElement.cpp
layout/style/Loader.cpp
layout/style/MediaList.cpp
layout/style/MediaList.h
layout/style/MediaQueryList.cpp
layout/style/test/test_media_query_list.html
testing/web-platform/tests/css/cssom-view/matchMedia-display-none-iframe.html
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,9 +1,11 @@
-[[package]]
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
 name = "Inflector"
 version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
--- a/dom/html/HTMLLinkElement.cpp
+++ b/dom/html/HTMLLinkElement.cpp
@@ -496,21 +496,17 @@ bool HTMLLinkElement::CheckPreloadAttrs(
   nsContentPolicyType policyType = Link::AsValueToContentPolicy(aAs);
   if (policyType == nsIContentPolicy::TYPE_INVALID) {
     return false;
   }
 
   // Check if media attribute is valid.
   if (!aMedia.IsEmpty()) {
     RefPtr<MediaList> mediaList = MediaList::Create(aMedia);
-    nsPresContext* presContext = aDocument->GetPresContext();
-    if (!presContext) {
-      return false;
-    }
-    if (!mediaList->Matches(presContext)) {
+    if (!mediaList->Matches(*aDocument)) {
       return false;
     }
   }
 
   if (aType.IsEmpty()) {
     return true;
   }
 
--- a/dom/html/HTMLSourceElement.cpp
+++ b/dom/html/HTMLSourceElement.cpp
@@ -35,35 +35,32 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLS
 
 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(HTMLSourceElement,
                                                nsGenericHTMLElement)
 
 NS_IMPL_ELEMENT_CLONE(HTMLSourceElement)
 
 bool HTMLSourceElement::MatchesCurrentMedia() {
   if (mMediaList) {
-    nsPresContext* pctx = OwnerDoc()->GetPresContext();
-    return pctx && mMediaList->Matches(pctx);
+    return mMediaList->Matches(*OwnerDoc());
   }
 
   // No media specified
   return true;
 }
 
 /* static */
 bool HTMLSourceElement::WouldMatchMediaForDocument(const nsAString& aMedia,
                                                    const Document* aDocument) {
   if (aMedia.IsEmpty()) {
     return true;
   }
 
-  nsPresContext* pctx = aDocument->GetPresContext();
-
   RefPtr<MediaList> mediaList = MediaList::Create(aMedia);
-  return pctx && mediaList->Matches(pctx);
+  return mediaList->Matches(*aDocument);
 }
 
 void HTMLSourceElement::UpdateMediaList(const nsAttrValue* aValue) {
   mMediaList = nullptr;
   nsString mediaStr;
   if (!aValue || (mediaStr = aValue->GetStringValue()).IsEmpty()) {
     return;
   }
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -1071,23 +1071,17 @@ nsresult Loader::CreateSheet(nsIURI* aUR
 }
 
 static Loader::MediaMatched MediaListMatches(const MediaList* aMediaList,
                                              const Document* aDocument) {
   if (!aMediaList || !aDocument) {
     return Loader::MediaMatched::Yes;
   }
 
-  nsPresContext* pc = aDocument->GetPresContext();
-  if (!pc) {
-    // Conservatively assume a match.
-    return Loader::MediaMatched::Yes;
-  }
-
-  if (aMediaList->Matches(pc)) {
+  if (aMediaList->Matches(*aDocument)) {
     return Loader::MediaMatched::Yes;
   }
 
   return Loader::MediaMatched::No;
 }
 
 /**
  * PrepareSheet() handles setting the media and title on the sheet, as
--- a/layout/style/MediaList.cpp
+++ b/layout/style/MediaList.cpp
@@ -4,22 +4,21 @@
  * 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/. */
 
 /* base class for representation of media lists */
 
 #include "mozilla/dom/MediaList.h"
 
 #include "mozAutoDocUpdate.h"
+#include "mozilla/dom/Document.h"
 #include "mozilla/dom/MediaListBinding.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/StyleSheetInlines.h"
-#include "nsPresContext.h"
-#include "nsPresContextInlines.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
@@ -110,18 +109,19 @@ void MediaList::IndexedGetter(uint32_t a
 nsresult MediaList::Delete(const nsAString& aOldMedium) {
   NS_ConvertUTF16toUTF8 oldMedium(aOldMedium);
   if (Servo_MediaList_DeleteMedium(mRawList, &oldMedium)) {
     return NS_OK;
   }
   return NS_ERROR_DOM_NOT_FOUND_ERR;
 }
 
-bool MediaList::Matches(nsPresContext* aPresContext) const {
-  const RawServoStyleSet* rawSet = aPresContext->StyleSet()->RawSet();
+bool MediaList::Matches(const Document& aDocument) const {
+  const RawServoStyleSet* rawSet =
+    aDocument.StyleSetForPresShellOrMediaQueryEvaluation()->RawSet();
   MOZ_ASSERT(rawSet, "The RawServoStyleSet should be valid!");
   return Servo_MediaList_Matches(mRawList, rawSet);
 }
 
 nsresult MediaList::Append(const nsAString& aNewMedium) {
   if (aNewMedium.IsEmpty()) {
     return NS_ERROR_DOM_NOT_FOUND_ERR;
   }
--- a/layout/style/MediaList.h
+++ b/layout/style/MediaList.h
@@ -11,24 +11,25 @@
 
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/ServoBindingTypes.h"
 #include "mozilla/ServoUtils.h"
 
 #include "nsWrapperCache.h"
 
-class nsPresContext;
 class nsMediaQueryResultCacheKey;
 
 namespace mozilla {
 class StyleSheet;
 
 namespace dom {
 
+class Document;
+
 class MediaList final : public nsISupports, public nsWrapperCache {
  public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaList)
 
   // Needed for CSSOM, but please don't use it outside of that :)
   explicit MediaList(already_AddRefed<RawServoMediaList> aRawList)
       : mRawList(aRawList) {}
@@ -38,17 +39,17 @@ class MediaList final : public nsISuppor
 
   already_AddRefed<MediaList> Clone();
 
   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) final;
   nsISupports* GetParentObject() const { return nullptr; }
 
   void GetText(nsAString& aMediaText);
   void SetText(const nsAString& aMediaText);
-  bool Matches(nsPresContext* aPresContext) const;
+  bool Matches(const Document&) const;
 
   void SetStyleSheet(StyleSheet* aSheet);
 
   // WebIDL
   void Stringify(nsAString& aString) { GetMediaText(aString); }
   void GetMediaText(nsAString& aMediaText);
   void SetMediaText(const nsAString& aMediaText);
   uint32_t Length();
--- a/layout/style/MediaQueryList.cpp
+++ b/layout/style/MediaQueryList.cpp
@@ -113,38 +113,17 @@ void MediaQueryList::Disconnect() {
 
 void MediaQueryList::RecomputeMatches() {
   mMatches = false;
 
   if (!mDocument) {
     return;
   }
 
-  // FIXME(emilio, bug 1490401): We shouldn't need a pres context to evaluate
-  // media queries.
-  nsPresContext* presContext = mDocument->GetPresContext();
-  if (!presContext && mDocument->GetParentDocument()) {
-    // Flush frames on the parent so our prescontext will get
-    // created if needed.
-    mDocument->GetParentDocument()->FlushPendingNotifications(
-        FlushType::Frames);
-    // That might have killed our document, so recheck that.
-    if (!mDocument) {
-      return;
-    }
-
-    presContext = mDocument->GetPresContext();
-  }
-
-  if (!presContext) {
-    // XXXbz What's the right behavior here?  Spec doesn't say.
-    return;
-  }
-
-  mMatches = mMediaList->Matches(presContext);
+  mMatches = mMediaList->Matches(*mDocument);
   mMatchesValid = true;
 }
 
 nsISupports* MediaQueryList::GetParentObject() const {
   return ToSupports(mDocument);
 }
 
 JSObject* MediaQueryList::WrapObject(JSContext* aCx,
--- a/layout/style/test/test_media_query_list.html
+++ b/layout/style/test/test_media_query_list.html
@@ -264,20 +264,25 @@ function run() {
        "notification order (removal tests)");
   })();
 
   /* Bug 753777: test that things work in a freshly-created iframe */
   (function() {
     var iframe = document.createElement("iframe");
     document.body.appendChild(iframe);
 
-    is(iframe.contentWindow.matchMedia("(min-width: 1px)").matches, true,
-       "(min-width: 1px) should match in newly-created iframe");
-    is(iframe.contentWindow.matchMedia("(max-width: 1px)").matches, false,
-       "(max-width: 1px) should not match in newly-created iframe");
+    is(iframe.contentWindow.matchMedia("all").matches, true,
+       "matchMedia should work in newly-created iframe");
+    // FIXME(emilio): All browsers fail this test right now. Probably should
+    // pass, see https://github.com/w3c/csswg-drafts/issues/3101, bug 1458816,
+    // and bug 1011468.
+    todo_is(iframe.contentWindow.matchMedia("(min-width: 1px)").matches, true,
+            "(min-width: 1px) should match in newly-created iframe");
+    todo_is(iframe.contentWindow.matchMedia("(max-width: 1px)").matches, false,
+            "(max-width: 1px) should not match in newly-created iframe");
 
     document.body.removeChild(iframe);
   })();
 
   /* Bug 716751: listeners lost due to GC */
   var gc_received = [];
   (function() {
     var received = [];
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/cssom-view/matchMedia-display-none-iframe.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>CSS Test: matchMedia works on display: none iframes</title>
+<link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-window-matchmedia">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+  function frameLoaded(frame) {
+    test(function() {
+      assert_true(frame.contentWindow.matchMedia("all").matches);
+    }, "matchMedia should work in display: none iframes");
+    test(function() {
+      assert_true(frame.contentWindow.matchMedia("(min-width: 0)").matches);
+      assert_true(!frame.contentWindow.matchMedia("(min-width: 1px)").matches);
+    }, "matchMedia should assume a 0x0 viewport in display: none iframes");
+  }
+</script>
+<iframe style="display: none" onload="frameLoaded(this)"></iframe>