MediaQueryList.cpp (4724B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* implements DOM interface for querying and observing media queries */ 8 9 #include "mozilla/dom/MediaQueryList.h" 10 11 #include "mozilla/dom/Document.h" 12 #include "mozilla/dom/EventTarget.h" 13 #include "mozilla/dom/EventTargetBinding.h" 14 #include "mozilla/dom/MediaList.h" 15 #include "mozilla/dom/MediaQueryListEvent.h" 16 #include "nsPresContext.h" 17 18 namespace mozilla::dom { 19 20 MediaQueryList::MediaQueryList(Document* aDocument, 21 const nsACString& aMediaQueryList, 22 CallerType aCallerType) 23 : DOMEventTargetHelper(aDocument->GetInnerWindow()), 24 mDocument(aDocument), 25 mMediaList(MediaList::Create(aMediaQueryList, aCallerType)), 26 mViewportDependent(mMediaList->IsViewportDependent()), 27 mMatches(mMediaList->Matches(*aDocument)), 28 mMatchesOnRenderingUpdate(mMatches) { 29 KeepAliveIfHasListenersFor(nsGkAtoms::onchange); 30 } 31 32 MediaQueryList::~MediaQueryList() = default; 33 34 NS_IMPL_CYCLE_COLLECTION_CLASS(MediaQueryList) 35 36 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MediaQueryList, 37 DOMEventTargetHelper) 38 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument) 39 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 40 41 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MediaQueryList, 42 DOMEventTargetHelper) 43 if (tmp->mDocument) { 44 static_cast<LinkedListElement<MediaQueryList>*>(tmp)->remove(); 45 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument) 46 } 47 tmp->Disconnect(); 48 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 49 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 50 51 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaQueryList) 52 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) 53 54 NS_IMPL_ADDREF_INHERITED(MediaQueryList, DOMEventTargetHelper) 55 NS_IMPL_RELEASE_INHERITED(MediaQueryList, DOMEventTargetHelper) 56 57 void MediaQueryList::GetMedia(nsACString& aMedia) const { 58 mMediaList->GetText(aMedia); 59 } 60 61 bool MediaQueryList::Matches() { 62 if (mViewportDependent && 63 mDocument->StyleOrLayoutObservablyDependsOnParentDocumentLayout()) { 64 RefPtr<Document> doc = mDocument; 65 // This is enough to trigger media query updates in the current doc, and 66 // will flush the parent document layout if appropriate. 67 doc->FlushPendingNotifications(FlushType::Layout); 68 } 69 return mMatches; 70 } 71 72 void MediaQueryList::AddListener(EventListener* aListener) { 73 if (!aListener) { 74 return; 75 } 76 77 AddEventListenerOptionsOrBoolean options; 78 options.SetAsBoolean() = false; 79 80 AddEventListener(u"change"_ns, aListener, options, Nullable<bool>()); 81 } 82 83 void MediaQueryList::RemoveListener(EventListener* aListener) { 84 if (!aListener) { 85 return; 86 } 87 88 EventListenerOptionsOrBoolean options; 89 options.SetAsBoolean() = false; 90 91 RemoveEventListener(u"change"_ns, aListener, options); 92 } 93 94 bool MediaQueryList::HasListeners() const { 95 return HasListenersFor(nsGkAtoms::onchange); 96 } 97 98 void MediaQueryList::Disconnect() { 99 DisconnectFromOwner(); 100 IgnoreKeepAliveIfHasListenersFor(nsGkAtoms::onchange); 101 } 102 103 nsISupports* MediaQueryList::GetParentObject() const { 104 return ToSupports(mDocument); 105 } 106 107 JSObject* MediaQueryList::WrapObject(JSContext* aCx, 108 JS::Handle<JSObject*> aGivenProto) { 109 return MediaQueryList_Binding::Wrap(aCx, this, aGivenProto); 110 } 111 112 void MediaQueryList::MediaFeatureValuesChanged() { 113 mMatches = mDocument && mMediaList->Matches(*mDocument); 114 // Note that mMatchesOnRenderingUpdate remains with the old value here. 115 // That gets updated in EvaluateOnRenderingUpdate(). 116 } 117 118 bool MediaQueryList::EvaluateOnRenderingUpdate() { 119 if (mMatches == mMatchesOnRenderingUpdate) { 120 return false; 121 } 122 mMatchesOnRenderingUpdate = mMatches; 123 return HasListeners(); 124 } 125 126 void MediaQueryList::FireChangeEvent() { 127 MediaQueryListEventInit init; 128 init.mBubbles = false; 129 init.mCancelable = false; 130 init.mMatches = mMatches; 131 mMediaList->GetText(init.mMedia); 132 133 RefPtr<MediaQueryListEvent> event = 134 MediaQueryListEvent::Constructor(this, u"change"_ns, init); 135 event->SetTrusted(true); 136 DispatchEvent(*event); 137 } 138 139 size_t MediaQueryList::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { 140 size_t n = 0; 141 // mMediaList is reference counted, but it's created and primarily owned 142 // by this MediaQueryList object. 143 n += mMediaList->SizeOfIncludingThis(aMallocSizeOf); 144 return n; 145 } 146 147 } // namespace mozilla::dom