1/* 2 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 */ 19 20#include "config.h" 21#include "MediaQueryMatcher.h" 22 23#include "Document.h" 24#include "Element.h" 25#include "Frame.h" 26#include "FrameView.h" 27#include "MediaList.h" 28#include "MediaQueryEvaluator.h" 29#include "MediaQueryList.h" 30#include "MediaQueryListListener.h" 31#include "StyleResolver.h" 32 33namespace WebCore { 34 35MediaQueryMatcher::Listener::Listener(PassRefPtr<MediaQueryListListener> listener, PassRefPtr<MediaQueryList> query) 36 : m_listener(listener) 37 , m_query(query) 38{ 39} 40 41MediaQueryMatcher::Listener::~Listener() 42{ 43} 44 45void MediaQueryMatcher::Listener::evaluate(ScriptState* state, MediaQueryEvaluator* evaluator) 46{ 47 bool notify; 48 m_query->evaluate(evaluator, notify); 49 if (notify) 50 m_listener->queryChanged(state, m_query.get()); 51} 52 53MediaQueryMatcher::MediaQueryMatcher(Document* document) 54 : m_document(document) 55 , m_evaluationRound(1) 56{ 57 ASSERT(m_document); 58} 59 60MediaQueryMatcher::~MediaQueryMatcher() 61{ 62} 63 64void MediaQueryMatcher::documentDestroyed() 65{ 66 m_listeners.clear(); 67 m_document = 0; 68} 69 70String MediaQueryMatcher::mediaType() const 71{ 72 if (!m_document || !m_document->frame() || !m_document->frame()->view()) 73 return String(); 74 75 return m_document->frame()->view()->mediaType(); 76} 77 78PassOwnPtr<MediaQueryEvaluator> MediaQueryMatcher::prepareEvaluator() const 79{ 80 if (!m_document || !m_document->frame()) 81 return nullptr; 82 83 Element* documentElement = m_document->documentElement(); 84 if (!documentElement) 85 return nullptr; 86 87 StyleResolver* styleResolver = m_document->ensureStyleResolver(); 88 89 RefPtr<RenderStyle> rootStyle = styleResolver->styleForElement(documentElement, 0 /*defaultParent*/, DisallowStyleSharing, MatchOnlyUserAgentRules); 90 91 return adoptPtr(new MediaQueryEvaluator(mediaType(), m_document->frame(), rootStyle.get())); 92} 93 94bool MediaQueryMatcher::evaluate(const MediaQuerySet* media) 95{ 96 if (!media) 97 return false; 98 99 OwnPtr<MediaQueryEvaluator> evaluator(prepareEvaluator()); 100 return evaluator && evaluator->eval(media); 101} 102 103PassRefPtr<MediaQueryList> MediaQueryMatcher::matchMedia(const String& query) 104{ 105 if (!m_document) 106 return 0; 107 108 RefPtr<MediaQuerySet> media = MediaQuerySet::create(query); 109#if ENABLE(RESOLUTION_MEDIA_QUERY) 110 // Add warning message to inspector whenever dpi/dpcm values are used for "screen" media. 111 reportMediaQueryWarningIfNeeded(m_document, media.get()); 112#endif 113 return MediaQueryList::create(this, media, evaluate(media.get())); 114} 115 116void MediaQueryMatcher::addListener(PassRefPtr<MediaQueryListListener> listener, PassRefPtr<MediaQueryList> query) 117{ 118 if (!m_document) 119 return; 120 121 for (size_t i = 0; i < m_listeners.size(); ++i) { 122 if (*m_listeners[i]->listener() == *listener && m_listeners[i]->query() == query) 123 return; 124 } 125 126 m_listeners.append(adoptPtr(new Listener(listener, query))); 127} 128 129void MediaQueryMatcher::removeListener(MediaQueryListListener* listener, MediaQueryList* query) 130{ 131 if (!m_document) 132 return; 133 134 for (size_t i = 0; i < m_listeners.size(); ++i) { 135 if (*m_listeners[i]->listener() == *listener && m_listeners[i]->query() == query) { 136 m_listeners.remove(i); 137 return; 138 } 139 } 140} 141 142void MediaQueryMatcher::styleResolverChanged() 143{ 144 ASSERT(m_document); 145 146 ScriptState* scriptState = mainWorldScriptState(m_document->frame()); 147 if (!scriptState) 148 return; 149 150 ++m_evaluationRound; 151 OwnPtr<MediaQueryEvaluator> evaluator = prepareEvaluator(); 152 if (!evaluator) 153 return; 154 155 for (size_t i = 0; i < m_listeners.size(); ++i) 156 m_listeners[i]->evaluate(scriptState, evaluator.get()); 157} 158 159} 160