#include "core/css/MediaList.h"
#include "core/css/MediaQueryEvaluator.h"
#include "core/css/MediaQueryList.h"
+#include "core/css/MediaQueryListEvent.h"
#include "core/css/MediaQueryListListener.h"
#include "core/css/resolver/StyleResolver.h"
#include "core/dom/Document.h"
-#include "core/frame/Frame.h"
#include "core/frame/FrameView.h"
+#include "core/frame/LocalFrame.h"
+#include "wtf/Vector.h"
-namespace WebCore {
+namespace blink {
-MediaQueryMatcher::Listener::Listener(PassRefPtr<MediaQueryListListener> listener, PassRefPtr<MediaQueryList> query)
- : m_listener(listener)
- , m_query(query)
+PassRefPtrWillBeRawPtr<MediaQueryMatcher> MediaQueryMatcher::create(Document& document)
{
+ return adoptRefWillBeNoop(new MediaQueryMatcher(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)
+MediaQueryMatcher::MediaQueryMatcher(Document& document)
+ : m_document(&document)
{
ASSERT(m_document);
}
-MediaQueryMatcher::~MediaQueryMatcher()
-{
-}
-
-void MediaQueryMatcher::documentDestroyed()
-{
- m_listeners.clear();
- m_document = 0;
-}
+DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(MediaQueryMatcher)
-AtomicString MediaQueryMatcher::mediaType() const
+void MediaQueryMatcher::documentDetached()
{
- if (!m_document || !m_document->frame() || !m_document->frame()->view())
- return nullAtom;
-
- return m_document->frame()->view()->mediaType();
+ m_document = nullptr;
+ m_evaluator = nullptr;
}
-PassOwnPtr<MediaQueryEvaluator> MediaQueryMatcher::prepareEvaluator() const
+PassOwnPtr<MediaQueryEvaluator> MediaQueryMatcher::createEvaluator() const
{
if (!m_document || !m_document->frame())
return nullptr;
- Element* documentElement = m_document->documentElement();
- if (!documentElement)
- return nullptr;
-
- StyleResolver* styleResolver = m_document->styleResolver();
- if (!styleResolver)
- return nullptr;
-
- RefPtr<RenderStyle> rootStyle = styleResolver->styleForElement(documentElement, 0 /*defaultParent*/, DisallowStyleSharing, MatchOnlyUserAgentRules);
-
- return adoptPtr(new MediaQueryEvaluator(mediaType(), m_document->frame(), rootStyle.get()));
+ return adoptPtr(new MediaQueryEvaluator(m_document->frame()));
}
bool MediaQueryMatcher::evaluate(const MediaQuerySet* media)
{
+ ASSERT(!m_document || m_document->frame() || !m_evaluator);
+
if (!media)
return false;
- OwnPtr<MediaQueryEvaluator> evaluator(prepareEvaluator());
- return evaluator && evaluator->eval(media);
+ // Cache the evaluator to avoid allocating one per evaluation.
+ if (!m_evaluator)
+ m_evaluator = createEvaluator();
+
+ if (m_evaluator)
+ return m_evaluator->eval(media);
+
+ return false;
}
-PassRefPtr<MediaQueryList> MediaQueryMatcher::matchMedia(const String& query)
+PassRefPtrWillBeRawPtr<MediaQueryList> MediaQueryMatcher::matchMedia(const String& query)
{
if (!m_document)
- return 0;
+ return nullptr;
- RefPtr<MediaQuerySet> media = MediaQuerySet::create(query);
+ RefPtrWillBeRawPtr<MediaQuerySet> media = MediaQuerySet::create(query);
// Add warning message to inspector whenever dpi/dpcm values are used for "screen" media.
reportMediaQueryWarningIfNeeded(m_document, media.get());
- return MediaQueryList::create(this, media, evaluate(media.get()));
+ return MediaQueryList::create(m_document, this, media);
}
-void MediaQueryMatcher::addListener(PassRefPtr<MediaQueryListListener> listener, PassRefPtr<MediaQueryList> query)
+void MediaQueryMatcher::addMediaQueryList(MediaQueryList* query)
{
if (!m_document)
return;
+ m_mediaLists.add(query);
+}
- for (size_t i = 0; i < m_listeners.size(); ++i) {
- if (*m_listeners[i]->listener() == *listener && m_listeners[i]->query() == query)
- return;
- }
+void MediaQueryMatcher::removeMediaQueryList(MediaQueryList* query)
+{
+ if (!m_document)
+ return;
+ m_mediaLists.remove(query);
+}
- m_listeners.append(adoptPtr(new Listener(listener, query)));
+void MediaQueryMatcher::addViewportListener(PassRefPtrWillBeRawPtr<MediaQueryListListener> listener)
+{
+ if (!m_document)
+ return;
+ m_viewportListeners.add(listener);
}
-void MediaQueryMatcher::removeListener(MediaQueryListListener* listener, MediaQueryList* query)
+void MediaQueryMatcher::removeViewportListener(PassRefPtrWillBeRawPtr<MediaQueryListListener> listener)
+{
+ if (!m_document)
+ return;
+ m_viewportListeners.remove(listener);
+}
+
+void MediaQueryMatcher::mediaFeaturesChanged()
{
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;
+ WillBeHeapVector<RefPtrWillBeMember<MediaQueryListListener> > listenersToNotify;
+ for (const auto& list : m_mediaLists) {
+ if (list->mediaFeaturesChanged(&listenersToNotify)) {
+ RefPtrWillBeRawPtr<Event> event(MediaQueryListEvent::create(list));
+ event->setTarget(list);
+ m_document->enqueueUniqueAnimationFrameEvent(event);
}
}
+ m_document->enqueueMediaQueryChangeListeners(listenersToNotify);
}
-void MediaQueryMatcher::styleResolverChanged()
+void MediaQueryMatcher::viewportChanged()
{
if (!m_document)
return;
- ScriptState* scriptState = m_document->frame() ? mainWorldScriptState(m_document->frame()) : 0;
- if (!scriptState)
- return;
+ WillBeHeapVector<RefPtrWillBeMember<MediaQueryListListener> > listenersToNotify;
+ for (const auto& listener : m_viewportListeners)
+ listenersToNotify.append(listener);
- ++m_evaluationRound;
- OwnPtr<MediaQueryEvaluator> evaluator = prepareEvaluator();
- if (!evaluator)
- return;
+ m_document->enqueueMediaQueryChangeListeners(listenersToNotify);
+}
- for (size_t i = 0; i < m_listeners.size(); ++i)
- m_listeners[i]->evaluate(scriptState, evaluator.get());
+void MediaQueryMatcher::trace(Visitor* visitor)
+{
+#if ENABLE(OILPAN)
+ visitor->trace(m_document);
+ visitor->trace(m_mediaLists);
+ visitor->trace(m_viewportListeners);
+#endif
}
}