Add modern API for overriding the page's specified viewport configuration
[WebKit-https.git] / Source / WebCore / css / MediaQueryMatcher.cpp
index eef0b90..52a5589 100644 (file)
 #include "config.h"
 #include "MediaQueryMatcher.h"
 
-#include "CSSStyleSelector.h"
 #include "Document.h"
-#include "Element.h"
 #include "Frame.h"
 #include "FrameView.h"
+#include "Logging.h"
 #include "MediaList.h"
 #include "MediaQueryEvaluator.h"
 #include "MediaQueryList.h"
 #include "MediaQueryListListener.h"
+#include "MediaQueryParserContext.h"
+#include "NodeRenderStyle.h"
+#include "RenderElement.h"
+#include "StyleResolver.h"
+#include "StyleScope.h"
+#include <wtf/text/TextStream.h>
 
 namespace WebCore {
 
-MediaQueryMatcher::Listener::Listener(PassRefPtr<MediaQueryListListener> listener, PassRefPtr<MediaQueryList> query)
-    : m_listener(listener)
-    , m_query(query)
+MediaQueryMatcher::MediaQueryMatcher(Document& document)
+    : m_document(makeWeakPtr(document))
 {
 }
 
-MediaQueryMatcher::Listener::~Listener()
-{
-}
-
-void MediaQueryMatcher::Listener::evaluate(ScriptState* state, MediaQueryEvaluator* evaluator)
-{
-    bool notify;
-    m_query->evaluate(evaluator, notify);
-    if (notify)
-        m_listener->queryChanged(state, m_query.get());
-}
-
-MediaQueryMatcher::MediaQueryMatcher(Document* document)
-    : m_document(document)
-    , m_evaluationRound(1)
-{
-    ASSERT(m_document);
-}
-
-MediaQueryMatcher::~MediaQueryMatcher()
-{
-}
+MediaQueryMatcher::~MediaQueryMatcher() = default;
 
 void MediaQueryMatcher::documentDestroyed()
 {
     m_listeners.clear();
-    m_document = 0;
+    m_document = nullptr;
 }
 
 String MediaQueryMatcher::mediaType() const
@@ -75,83 +58,80 @@ String MediaQueryMatcher::mediaType() const
     return m_document->frame()->view()->mediaType();
 }
 
-PassOwnPtr<MediaQueryEvaluator> MediaQueryMatcher::prepareEvaluator() const
+std::unique_ptr<RenderStyle> MediaQueryMatcher::documentElementUserAgentStyle() const
 {
     if (!m_document || !m_document->frame())
         return nullptr;
 
-    Element* documentElement = m_document->documentElement();
+    auto* documentElement = m_document->documentElement();
     if (!documentElement)
         return nullptr;
 
-    StyleResolver* styleSelector = m_document->styleSelector();
-    if (!styleSelector)
-        return nullptr;
-
-    RefPtr<RenderStyle> rootStyle = styleSelector->styleForElement(documentElement, 0 /*defaultParent*/, DisallowStyleSharing, MatchOnlyUserAgentRules);
-
-    return adoptPtr(new MediaQueryEvaluator(mediaType(), m_document->frame(), rootStyle.get()));
+    return m_document->styleScope().resolver().styleForElement(*documentElement, m_document->renderStyle(), nullptr, RuleMatchingBehavior::MatchOnlyUserAgentRules).renderStyle;
 }
 
-bool MediaQueryMatcher::evaluate(const MediaQuerySet* media)
+bool MediaQueryMatcher::evaluate(const MediaQuerySet& media)
 {
-    if (!media)
+    auto style = documentElementUserAgentStyle();
+    if (!style)
         return false;
-
-    OwnPtr<MediaQueryEvaluator> evaluator(prepareEvaluator());
-    return evaluator && evaluator->eval(media);
+    return MediaQueryEvaluator { mediaType(), *m_document, style.get() }.evaluate(media);
 }
 
-PassRefPtr<MediaQueryList> MediaQueryMatcher::matchMedia(const String& query)
+RefPtr<MediaQueryList> MediaQueryMatcher::matchMedia(const String& query)
 {
     if (!m_document)
-        return 0;
+        return nullptr;
 
-    RefPtr<MediaQuerySet> media = MediaQuerySet::create(query);
-    return MediaQueryList::create(this, media, evaluate(media.get()));
+    auto media = MediaQuerySet::create(query, MediaQueryParserContext(*m_document));
+    reportMediaQueryWarningIfNeeded(m_document.get(), media.ptr());
+    bool result = evaluate(media.get());
+    return MediaQueryList::create(*this, WTFMove(media), result);
 }
 
-void MediaQueryMatcher::addListener(PassRefPtr<MediaQueryListListener> listener, PassRefPtr<MediaQueryList> query)
+void MediaQueryMatcher::addListener(Ref<MediaQueryListListener>&& listener, MediaQueryList& query)
 {
     if (!m_document)
         return;
 
-    for (size_t i = 0; i < m_listeners.size(); ++i) {
-        if (*m_listeners[i]->listener() == *listener && m_listeners[i]->query() == query)
+    for (auto& existingListener : m_listeners) {
+        if (existingListener.listener.get() == listener.get() && existingListener.query.ptr() == &query)
             return;
     }
 
-    m_listeners.append(adoptPtr(new Listener(listener, query)));
+    m_listeners.append(Listener { WTFMove(listener), query });
 }
 
-void MediaQueryMatcher::removeListener(MediaQueryListListener* listener, MediaQueryList* query)
+void MediaQueryMatcher::removeListener(MediaQueryListListener& listener, MediaQueryList& query)
 {
-    if (!m_document)
-        return;
-
-    for (size_t i = 0; i < m_listeners.size(); ++i) {
-        if (*m_listeners[i]->listener() == *listener && m_listeners[i]->query() == query) {
-            m_listeners.remove(i);
-            return;
-        }
-    }
+    m_listeners.removeFirstMatching([&listener, &query](auto& existingListener) {
+        return existingListener.listener.get() == listener && existingListener.query.ptr() == &query;
+    });
 }
 
-void MediaQueryMatcher::styleSelectorChanged()
+void MediaQueryMatcher::styleResolverChanged()
 {
     ASSERT(m_document);
 
-    ScriptState* scriptState = mainWorldScriptState(m_document->frame());
-    if (!scriptState)
-        return;
-
     ++m_evaluationRound;
-    OwnPtr<MediaQueryEvaluator> evaluator = prepareEvaluator();
-    if (!evaluator)
+
+    auto style = documentElementUserAgentStyle();
+    if (!style)
         return;
 
-    for (size_t i = 0; i < m_listeners.size(); ++i)
-        m_listeners[i]->evaluate(scriptState, evaluator.get());
+    LOG_WITH_STREAM(MediaQueries, stream << "MediaQueryMatcher::styleResolverChanged " << m_document->url());
+
+    MediaQueryEvaluator evaluator { mediaType(), *m_document, style.get() };
+    Vector<Listener> listeners;
+    listeners.reserveInitialCapacity(m_listeners.size());
+    for (auto& listener : m_listeners)
+        listeners.uncheckedAppend({ listener.listener.copyRef(), listener.query.copyRef() });
+    for (auto& listener : listeners) {
+        bool notify;
+        listener.query->evaluate(evaluator, notify);
+        if (notify)
+            listener.listener->handleEvent(listener.query);
+    }
 }
 
-}
+} // namespace WebCore