1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/MediaQueryList.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,187 @@ 1.4 +/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* implements DOM interface for querying and observing media queries */ 1.10 + 1.11 +#include "mozilla/dom/MediaQueryList.h" 1.12 +#include "nsPresContext.h" 1.13 +#include "nsIMediaList.h" 1.14 +#include "nsCSSParser.h" 1.15 +#include "nsIDocument.h" 1.16 + 1.17 +namespace mozilla { 1.18 +namespace dom { 1.19 + 1.20 +MediaQueryList::MediaQueryList(nsPresContext *aPresContext, 1.21 + const nsAString &aMediaQueryList) 1.22 + : mPresContext(aPresContext), 1.23 + mMediaList(new nsMediaList), 1.24 + mMatchesValid(false) 1.25 +{ 1.26 + PR_INIT_CLIST(this); 1.27 + 1.28 + SetIsDOMBinding(); 1.29 + 1.30 + nsCSSParser parser; 1.31 + parser.ParseMediaList(aMediaQueryList, nullptr, 0, mMediaList, false); 1.32 +} 1.33 + 1.34 +MediaQueryList::~MediaQueryList() 1.35 +{ 1.36 + if (mPresContext) { 1.37 + PR_REMOVE_LINK(this); 1.38 + } 1.39 +} 1.40 + 1.41 +NS_IMPL_CYCLE_COLLECTION_CLASS(MediaQueryList) 1.42 + 1.43 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(MediaQueryList) 1.44 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext) 1.45 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallbacks) 1.46 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS 1.47 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.48 + 1.49 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MediaQueryList) 1.50 + if (tmp->mPresContext) { 1.51 + PR_REMOVE_LINK(tmp); 1.52 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mPresContext) 1.53 + } 1.54 + tmp->RemoveAllListeners(); 1.55 + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 1.56 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.57 + 1.58 +NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(MediaQueryList) 1.59 + 1.60 +NS_INTERFACE_MAP_BEGIN(MediaQueryList) 1.61 + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 1.62 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.63 + NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(MediaQueryList) 1.64 +NS_INTERFACE_MAP_END 1.65 + 1.66 +NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaQueryList) 1.67 +NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaQueryList) 1.68 + 1.69 +void 1.70 +MediaQueryList::GetMedia(nsAString &aMedia) 1.71 +{ 1.72 + mMediaList->GetText(aMedia); 1.73 +} 1.74 + 1.75 +bool 1.76 +MediaQueryList::Matches() 1.77 +{ 1.78 + if (!mMatchesValid) { 1.79 + NS_ABORT_IF_FALSE(!HasListeners(), 1.80 + "when listeners present, must keep mMatches current"); 1.81 + RecomputeMatches(); 1.82 + } 1.83 + 1.84 + return mMatches; 1.85 +} 1.86 + 1.87 +void 1.88 +MediaQueryList::AddListener(MediaQueryListListener& aListener) 1.89 +{ 1.90 + if (!HasListeners()) { 1.91 + // When we have listeners, the pres context owns a reference to 1.92 + // this. This is a cyclic reference that can only be broken by 1.93 + // cycle collection. 1.94 + NS_ADDREF_THIS(); 1.95 + } 1.96 + 1.97 + if (!mMatchesValid) { 1.98 + NS_ABORT_IF_FALSE(!HasListeners(), 1.99 + "when listeners present, must keep mMatches current"); 1.100 + RecomputeMatches(); 1.101 + } 1.102 + 1.103 + for (uint32_t i = 0; i < mCallbacks.Length(); ++i) { 1.104 + if (aListener == *mCallbacks[i]) { 1.105 + // Already registered 1.106 + return; 1.107 + } 1.108 + } 1.109 + 1.110 + mCallbacks.AppendElement(&aListener); 1.111 + if (!HasListeners()) { 1.112 + // Append failed; undo the AddRef above. 1.113 + NS_RELEASE_THIS(); 1.114 + } 1.115 +} 1.116 + 1.117 +void 1.118 +MediaQueryList::RemoveListener(MediaQueryListListener& aListener) 1.119 +{ 1.120 + for (uint32_t i = 0; i < mCallbacks.Length(); ++i) { 1.121 + if (aListener == *mCallbacks[i]) { 1.122 + mCallbacks.RemoveElementAt(i); 1.123 + if (!HasListeners()) { 1.124 + // See NS_ADDREF_THIS() in AddListener. 1.125 + NS_RELEASE_THIS(); 1.126 + } 1.127 + break; 1.128 + } 1.129 + } 1.130 +} 1.131 + 1.132 +void 1.133 +MediaQueryList::RemoveAllListeners() 1.134 +{ 1.135 + bool hadListeners = HasListeners(); 1.136 + mCallbacks.Clear(); 1.137 + if (hadListeners) { 1.138 + // See NS_ADDREF_THIS() in AddListener. 1.139 + NS_RELEASE_THIS(); 1.140 + } 1.141 +} 1.142 + 1.143 +void 1.144 +MediaQueryList::RecomputeMatches() 1.145 +{ 1.146 + if (!mPresContext) { 1.147 + return; 1.148 + } 1.149 + 1.150 + mMatches = mMediaList->Matches(mPresContext, nullptr); 1.151 + mMatchesValid = true; 1.152 +} 1.153 + 1.154 +void 1.155 +MediaQueryList::MediumFeaturesChanged(NotifyList &aListenersToNotify) 1.156 +{ 1.157 + mMatchesValid = false; 1.158 + 1.159 + if (HasListeners()) { 1.160 + bool oldMatches = mMatches; 1.161 + RecomputeMatches(); 1.162 + if (mMatches != oldMatches) { 1.163 + for (uint32_t i = 0, i_end = mCallbacks.Length(); i != i_end; ++i) { 1.164 + HandleChangeData *d = aListenersToNotify.AppendElement(); 1.165 + if (d) { 1.166 + d->mql = this; 1.167 + d->callback = mCallbacks[i]; 1.168 + } 1.169 + } 1.170 + } 1.171 + } 1.172 +} 1.173 + 1.174 +nsISupports* 1.175 +MediaQueryList::GetParentObject() const 1.176 +{ 1.177 + if (!mPresContext) { 1.178 + return nullptr; 1.179 + } 1.180 + return mPresContext->Document(); 1.181 +} 1.182 + 1.183 +JSObject* 1.184 +MediaQueryList::WrapObject(JSContext* aCx) 1.185 +{ 1.186 + return MediaQueryListBinding::Wrap(aCx, this); 1.187 +} 1.188 + 1.189 +} // namespace dom 1.190 +} // namespace mozilla