mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 06:38:10 +00:00
LibWeb: Fire MediaQueryListEvents when an MQL's match-state changes
The HTML event loop does a check for MQL match-state changes and dispatches the events. This requires us to keep a list of MQLs on the Document.
This commit is contained in:
parent
1c829e0417
commit
050823bea7
10 changed files with 122 additions and 2 deletions
|
@ -10,6 +10,7 @@
|
||||||
#include <LibWeb/Bindings/EventWrapper.h>
|
#include <LibWeb/Bindings/EventWrapper.h>
|
||||||
#include <LibWeb/Bindings/EventWrapperFactory.h>
|
#include <LibWeb/Bindings/EventWrapperFactory.h>
|
||||||
#include <LibWeb/Bindings/KeyboardEventWrapper.h>
|
#include <LibWeb/Bindings/KeyboardEventWrapper.h>
|
||||||
|
#include <LibWeb/Bindings/MediaQueryListEventWrapper.h>
|
||||||
#include <LibWeb/Bindings/MessageEventWrapper.h>
|
#include <LibWeb/Bindings/MessageEventWrapper.h>
|
||||||
#include <LibWeb/Bindings/MouseEventWrapper.h>
|
#include <LibWeb/Bindings/MouseEventWrapper.h>
|
||||||
#include <LibWeb/Bindings/PageTransitionEventWrapper.h>
|
#include <LibWeb/Bindings/PageTransitionEventWrapper.h>
|
||||||
|
@ -22,6 +23,8 @@ EventWrapper* wrap(JS::GlobalObject& global_object, DOM::Event& event)
|
||||||
{
|
{
|
||||||
if (is<DOM::CustomEvent>(event))
|
if (is<DOM::CustomEvent>(event))
|
||||||
return static_cast<CustomEventWrapper*>(wrap_impl(global_object, static_cast<DOM::CustomEvent&>(event)));
|
return static_cast<CustomEventWrapper*>(wrap_impl(global_object, static_cast<DOM::CustomEvent&>(event)));
|
||||||
|
if (is<CSS::MediaQueryListEvent>(event))
|
||||||
|
return static_cast<MediaQueryListEventWrapper*>(wrap_impl(global_object, static_cast<CSS::MediaQueryListEvent&>(event)));
|
||||||
if (is<HTML::CloseEvent>(event))
|
if (is<HTML::CloseEvent>(event))
|
||||||
return static_cast<CloseEventWrapper*>(wrap_impl(global_object, static_cast<HTML::CloseEvent&>(event)));
|
return static_cast<CloseEventWrapper*>(wrap_impl(global_object, static_cast<HTML::CloseEvent&>(event)));
|
||||||
if (is<HTML::MessageEvent>(event))
|
if (is<HTML::MessageEvent>(event))
|
||||||
|
|
|
@ -204,6 +204,8 @@
|
||||||
#include <LibWeb/Bindings/ImageDataConstructor.h>
|
#include <LibWeb/Bindings/ImageDataConstructor.h>
|
||||||
#include <LibWeb/Bindings/ImageDataPrototype.h>
|
#include <LibWeb/Bindings/ImageDataPrototype.h>
|
||||||
#include <LibWeb/Bindings/MediaQueryListConstructor.h>
|
#include <LibWeb/Bindings/MediaQueryListConstructor.h>
|
||||||
|
#include <LibWeb/Bindings/MediaQueryListEventConstructor.h>
|
||||||
|
#include <LibWeb/Bindings/MediaQueryListEventPrototype.h>
|
||||||
#include <LibWeb/Bindings/MediaQueryListPrototype.h>
|
#include <LibWeb/Bindings/MediaQueryListPrototype.h>
|
||||||
#include <LibWeb/Bindings/MessageChannelConstructor.h>
|
#include <LibWeb/Bindings/MessageChannelConstructor.h>
|
||||||
#include <LibWeb/Bindings/MessageChannelPrototype.h>
|
#include <LibWeb/Bindings/MessageChannelPrototype.h>
|
||||||
|
@ -371,6 +373,7 @@
|
||||||
ADD_WINDOW_OBJECT_INTERFACE(HTMLVideoElement) \
|
ADD_WINDOW_OBJECT_INTERFACE(HTMLVideoElement) \
|
||||||
ADD_WINDOW_OBJECT_INTERFACE(ImageData) \
|
ADD_WINDOW_OBJECT_INTERFACE(ImageData) \
|
||||||
ADD_WINDOW_OBJECT_INTERFACE(MediaQueryList) \
|
ADD_WINDOW_OBJECT_INTERFACE(MediaQueryList) \
|
||||||
|
ADD_WINDOW_OBJECT_INTERFACE(MediaQueryListEvent) \
|
||||||
ADD_WINDOW_OBJECT_INTERFACE(MessageChannel) \
|
ADD_WINDOW_OBJECT_INTERFACE(MessageChannel) \
|
||||||
ADD_WINDOW_OBJECT_INTERFACE(MessageEvent) \
|
ADD_WINDOW_OBJECT_INTERFACE(MessageEvent) \
|
||||||
ADD_WINDOW_OBJECT_INTERFACE(MouseEvent) \
|
ADD_WINDOW_OBJECT_INTERFACE(MouseEvent) \
|
||||||
|
|
|
@ -354,6 +354,7 @@ libweb_js_wrapper(CSS/CSSStyleDeclaration)
|
||||||
libweb_js_wrapper(CSS/CSSStyleRule)
|
libweb_js_wrapper(CSS/CSSStyleRule)
|
||||||
libweb_js_wrapper(CSS/CSSStyleSheet)
|
libweb_js_wrapper(CSS/CSSStyleSheet)
|
||||||
libweb_js_wrapper(CSS/MediaQueryList)
|
libweb_js_wrapper(CSS/MediaQueryList)
|
||||||
|
libweb_js_wrapper(CSS/MediaQueryListEvent)
|
||||||
libweb_js_wrapper(CSS/Screen)
|
libweb_js_wrapper(CSS/Screen)
|
||||||
libweb_js_wrapper(CSS/StyleSheet)
|
libweb_js_wrapper(CSS/StyleSheet)
|
||||||
libweb_js_wrapper(CSS/StyleSheetList)
|
libweb_js_wrapper(CSS/StyleSheetList)
|
||||||
|
|
47
Userland/Libraries/LibWeb/CSS/MediaQueryListEvent.h
Normal file
47
Userland/Libraries/LibWeb/CSS/MediaQueryListEvent.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibWeb/DOM/Event.h>
|
||||||
|
|
||||||
|
namespace Web::CSS {
|
||||||
|
|
||||||
|
struct MediaQueryListEventInit : public DOM::EventInit {
|
||||||
|
String media { "" };
|
||||||
|
bool matches { false };
|
||||||
|
};
|
||||||
|
|
||||||
|
class MediaQueryListEvent : public DOM::Event {
|
||||||
|
public:
|
||||||
|
using WrapperType = Bindings::MediaQueryListEventWrapper;
|
||||||
|
|
||||||
|
static NonnullRefPtr<MediaQueryListEvent> create(FlyString const& event_name, MediaQueryListEventInit const& event_init = {})
|
||||||
|
{
|
||||||
|
return adopt_ref(*new MediaQueryListEvent(event_name, event_init));
|
||||||
|
}
|
||||||
|
static NonnullRefPtr<MediaQueryListEvent> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, MediaQueryListEventInit const& event_init)
|
||||||
|
{
|
||||||
|
return MediaQueryListEvent::create(event_name, event_init);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~MediaQueryListEvent() override = default;
|
||||||
|
|
||||||
|
String const& media() const { return m_media; }
|
||||||
|
bool matches() const { return m_matches; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MediaQueryListEvent(FlyString const& event_name, MediaQueryListEventInit const& event_init)
|
||||||
|
: DOM::Event(event_name, event_init)
|
||||||
|
, m_media(event_init.media)
|
||||||
|
, m_matches(event_init.matches)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
String m_media;
|
||||||
|
bool m_matches;
|
||||||
|
};
|
||||||
|
}
|
13
Userland/Libraries/LibWeb/CSS/MediaQueryListEvent.idl
Normal file
13
Userland/Libraries/LibWeb/CSS/MediaQueryListEvent.idl
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#import <DOM/Event.idl>
|
||||||
|
|
||||||
|
interface MediaQueryListEvent : Event {
|
||||||
|
constructor(CSSOMString type, optional MediaQueryListEventInit eventInitDict = {});
|
||||||
|
|
||||||
|
readonly attribute CSSOMString media;
|
||||||
|
readonly attribute boolean matches;
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary MediaQueryListEventInit : EventInit {
|
||||||
|
CSSOMString media = "";
|
||||||
|
boolean matches = false;
|
||||||
|
};
|
|
@ -2,6 +2,7 @@
|
||||||
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
||||||
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||||
* Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
|
* Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
|
||||||
|
* Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -15,6 +16,7 @@
|
||||||
#include <LibJS/Runtime/FunctionObject.h>
|
#include <LibJS/Runtime/FunctionObject.h>
|
||||||
#include <LibWeb/Bindings/MainThreadVM.h>
|
#include <LibWeb/Bindings/MainThreadVM.h>
|
||||||
#include <LibWeb/Bindings/WindowObject.h>
|
#include <LibWeb/Bindings/WindowObject.h>
|
||||||
|
#include <LibWeb/CSS/MediaQueryListEvent.h>
|
||||||
#include <LibWeb/CSS/StyleComputer.h>
|
#include <LibWeb/CSS/StyleComputer.h>
|
||||||
#include <LibWeb/Cookie/ParsedCookie.h>
|
#include <LibWeb/Cookie/ParsedCookie.h>
|
||||||
#include <LibWeb/DOM/Comment.h>
|
#include <LibWeb/DOM/Comment.h>
|
||||||
|
@ -1105,4 +1107,42 @@ void Document::run_the_resize_steps()
|
||||||
update_layout();
|
update_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Document::add_media_query_list(NonnullRefPtr<CSS::MediaQueryList>& media_query_list)
|
||||||
|
{
|
||||||
|
m_media_query_lists.append(media_query_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/cssom-view/#evaluate-media-queries-and-report-changes
|
||||||
|
void Document::evaluate_media_queries_and_report_changes()
|
||||||
|
{
|
||||||
|
// NOTE: Not in the spec, but we take this opportunity to prune null WeakPtrs.
|
||||||
|
m_media_query_lists.remove_all_matching([](auto& it) {
|
||||||
|
return it.is_null();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 1. For each MediaQueryList object target that has doc as its document,
|
||||||
|
// in the order they were created, oldest first, run these substeps:
|
||||||
|
for (auto& media_query_list_ptr : m_media_query_lists) {
|
||||||
|
// 1.1. If target’s matches state has changed since the last time these steps
|
||||||
|
// were run, fire an event at target using the MediaQueryListEvent constructor,
|
||||||
|
// with its type attribute initialized to change, its isTrusted attribute
|
||||||
|
// initialized to true, its media attribute initialized to target’s media,
|
||||||
|
// and its matches attribute initialized to target’s matches state.
|
||||||
|
if (media_query_list_ptr.is_null())
|
||||||
|
continue;
|
||||||
|
auto media_query_list = media_query_list_ptr.strong_ref();
|
||||||
|
bool did_match = media_query_list->matches();
|
||||||
|
bool now_matches = media_query_list->evaluate();
|
||||||
|
|
||||||
|
if (did_match != now_matches) {
|
||||||
|
CSS::MediaQueryListEventInit init;
|
||||||
|
init.media = media_query_list->media();
|
||||||
|
init.matches = now_matches;
|
||||||
|
auto event = CSS::MediaQueryListEvent::create(HTML::EventNames::change, init);
|
||||||
|
event->set_is_trusted(true);
|
||||||
|
media_query_list->dispatch_event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -303,6 +303,9 @@ public:
|
||||||
|
|
||||||
void run_the_resize_steps();
|
void run_the_resize_steps();
|
||||||
|
|
||||||
|
void evaluate_media_queries_and_report_changes();
|
||||||
|
void add_media_query_list(NonnullRefPtr<CSS::MediaQueryList>&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Document(const AK::URL&);
|
explicit Document(const AK::URL&);
|
||||||
|
|
||||||
|
@ -393,6 +396,9 @@ private:
|
||||||
|
|
||||||
// Used by run_the_resize_steps().
|
// Used by run_the_resize_steps().
|
||||||
Gfx::IntSize m_last_viewport_size;
|
Gfx::IntSize m_last_viewport_size;
|
||||||
|
|
||||||
|
// Used by evaluate_media_queries_and_report_changes().
|
||||||
|
Vector<WeakPtr<CSS::MediaQueryList>> m_media_query_lists;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -285,7 +285,9 @@ NonnullRefPtr<CSS::CSSStyleDeclaration> Window::get_computed_style(DOM::Element&
|
||||||
|
|
||||||
NonnullRefPtr<CSS::MediaQueryList> Window::match_media(String media)
|
NonnullRefPtr<CSS::MediaQueryList> Window::match_media(String media)
|
||||||
{
|
{
|
||||||
return CSS::MediaQueryList::create(associated_document(), parse_media_query_list(CSS::ParsingContext(associated_document()), media));
|
auto media_query_list = CSS::MediaQueryList::create(associated_document(), parse_media_query_list(CSS::ParsingContext(associated_document()), media));
|
||||||
|
associated_document().add_media_query_list(media_query_list);
|
||||||
|
return media_query_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<CSS::StyleValue> Window::query_media_feature(FlyString const& name) const
|
RefPtr<CSS::StyleValue> Window::query_media_feature(FlyString const& name) const
|
||||||
|
|
|
@ -31,6 +31,7 @@ class Length;
|
||||||
class MediaList;
|
class MediaList;
|
||||||
class MediaQuery;
|
class MediaQuery;
|
||||||
class MediaQueryList;
|
class MediaQueryList;
|
||||||
|
class MediaQueryListEvent;
|
||||||
class PropertyOwningCSSStyleDeclaration;
|
class PropertyOwningCSSStyleDeclaration;
|
||||||
class Screen;
|
class Screen;
|
||||||
class Selector;
|
class Selector;
|
||||||
|
@ -375,6 +376,7 @@ class ImageDataWrapper;
|
||||||
class KeyboardEventWrapper;
|
class KeyboardEventWrapper;
|
||||||
class LocationObject;
|
class LocationObject;
|
||||||
class MediaQueryListWrapper;
|
class MediaQueryListWrapper;
|
||||||
|
class MediaQueryListEventWrapper;
|
||||||
class MessageChannelWrapper;
|
class MessageChannelWrapper;
|
||||||
class MessageEventWrapper;
|
class MessageEventWrapper;
|
||||||
class MessagePortWrapper;
|
class MessagePortWrapper;
|
||||||
|
|
|
@ -164,7 +164,10 @@ void EventLoop::process()
|
||||||
|
|
||||||
// FIXME: 8. For each fully active Document in docs, run the scroll steps for that Document, passing in now as the timestamp. [CSSOMVIEW]
|
// FIXME: 8. For each fully active Document in docs, run the scroll steps for that Document, passing in now as the timestamp. [CSSOMVIEW]
|
||||||
|
|
||||||
// FIXME: 9. For each fully active Document in docs, evaluate media queries and report changes for that Document, passing in now as the timestamp. [CSSOMVIEW]
|
// 9. For each fully active Document in docs, evaluate media queries and report changes for that Document, passing in now as the timestamp. [CSSOMVIEW]
|
||||||
|
for_each_fully_active_document_in_docs([&](DOM::Document& document) {
|
||||||
|
document.evaluate_media_queries_and_report_changes();
|
||||||
|
});
|
||||||
|
|
||||||
// FIXME: 10. For each fully active Document in docs, update animations and send events for that Document, passing in now as the timestamp. [WEBANIMATIONS]
|
// FIXME: 10. For each fully active Document in docs, update animations and send events for that Document, passing in now as the timestamp. [WEBANIMATIONS]
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue