mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 20:15:17 +00:00
LibWeb: Don't lose change events on MediaQueryList internal state change
MediaQueryList will now remember if a state change occurred when evaluating its match state. This memory can then be used by the document later on when it's updating all queries, to ensure that we don't forget to fire at least one change event. This also required plumbing the system visibility state to initial about:blank documents, since otherwise they would be stuck in "hidden" state indefinitely and never evaluate their media queries.
This commit is contained in:
parent
6fd24c2a68
commit
c9cd795257
Notes:
github-actions[bot]
2025-02-13 19:53:28 +00:00
Author: https://github.com/awesomekling Commit: https://github.com/LadybirdBrowser/ladybird/commit/c9cd7952572 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3558 Reviewed-by: https://github.com/AtkinsSJ ✅
7 changed files with 78 additions and 23 deletions
|
@ -54,6 +54,14 @@ bool MediaQueryList::matches() const
|
|||
if (m_media.is_empty())
|
||||
return true;
|
||||
|
||||
bool did_match = false;
|
||||
for (auto const& media : m_media) {
|
||||
if (media->matches()) {
|
||||
did_match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: If our document is inside a frame, we need to update layout
|
||||
// since that may cause our frame (and thus viewport) to resize.
|
||||
if (auto container_document = m_document->container_document()) {
|
||||
|
@ -61,12 +69,18 @@ bool MediaQueryList::matches() const
|
|||
const_cast<MediaQueryList*>(this)->evaluate();
|
||||
}
|
||||
|
||||
bool now_matches = false;
|
||||
for (auto& media : m_media) {
|
||||
if (media->matches())
|
||||
return true;
|
||||
if (media->matches()) {
|
||||
now_matches = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
if (did_match != now_matches)
|
||||
m_has_changed_state = true;
|
||||
|
||||
return now_matches;
|
||||
}
|
||||
|
||||
bool MediaQueryList::evaluate()
|
||||
|
|
|
@ -32,6 +32,9 @@ public:
|
|||
void set_onchange(WebIDL::CallbackType*);
|
||||
WebIDL::CallbackType* onchange();
|
||||
|
||||
[[nodiscard]] Optional<bool> const& has_changed_state() const { return m_has_changed_state; }
|
||||
void set_has_changed_state(bool has_changed_state) { m_has_changed_state = has_changed_state; }
|
||||
|
||||
private:
|
||||
MediaQueryList(DOM::Document&, Vector<NonnullRefPtr<MediaQuery>>&&);
|
||||
|
||||
|
@ -40,6 +43,8 @@ private:
|
|||
|
||||
GC::Ref<DOM::Document> m_document;
|
||||
Vector<NonnullRefPtr<MediaQuery>> m_media;
|
||||
|
||||
mutable Optional<bool> m_has_changed_state { false };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -3293,7 +3293,10 @@ void Document::evaluate_media_queries_and_report_changes()
|
|||
bool did_match = media_query_list->matches();
|
||||
bool now_matches = media_query_list->evaluate();
|
||||
|
||||
if (did_match != now_matches) {
|
||||
auto did_change_internally = media_query_list->has_changed_state();
|
||||
media_query_list->set_has_changed_state(false);
|
||||
|
||||
if (did_change_internally == true || did_match != now_matches) {
|
||||
CSS::MediaQueryListEventInit init;
|
||||
init.media = media_query_list->media();
|
||||
init.matches = now_matches;
|
||||
|
|
|
@ -109,6 +109,9 @@ WebIDL::ExceptionOr<void> NavigableContainer::create_new_child_navigable(GC::Ptr
|
|||
// 11. Let traversable be parentNavigable's traversable navigable.
|
||||
auto traversable = parent_navigable->traversable_navigable();
|
||||
|
||||
// AD-HOC: Let the initial about:blank document inherit the system visibility state from traversable.
|
||||
document->update_the_visibility_state(traversable->system_visibility_state());
|
||||
|
||||
// 12. Append the following session history traversal steps to traversable:
|
||||
traversable->append_session_history_traversal_steps(GC::create_function(heap(), [traversable, navigable, parent_navigable, history_entry, after_session_history_update] {
|
||||
// 1. Let parentDocState be parentNavigable's active session history entry's document state.
|
||||
|
|
|
@ -13,16 +13,46 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
|
|||
frag 7 from NavigableContainerViewport start: 0, length: 0, rect: [18,228 10x10] baseline: 30
|
||||
frag 8 from NavigableContainerViewport start: 0, length: 0, rect: [18,258 10x10] baseline: 30
|
||||
frag 9 from NavigableContainerViewport start: 0, length: 0, rect: [18,288 10x10] baseline: 30
|
||||
NavigableContainerViewport <iframe> at (18,18) content-size 10x10 children: not-inline (url: about:blank)
|
||||
NavigableContainerViewport <iframe> at (18,48) content-size 10x10 children: not-inline (url: about:blank)
|
||||
NavigableContainerViewport <iframe> at (18,78) content-size 10x10 children: not-inline (url: about:blank)
|
||||
NavigableContainerViewport <iframe> at (18,108) content-size 10x10 children: not-inline (url: about:blank)
|
||||
NavigableContainerViewport <iframe> at (18,138) content-size 10x10 children: not-inline (url: about:blank)
|
||||
NavigableContainerViewport <iframe> at (18,168) content-size 10x10 children: not-inline (url: about:blank)
|
||||
NavigableContainerViewport <iframe> at (18,198) content-size 10x10 children: not-inline (url: about:blank)
|
||||
NavigableContainerViewport <iframe> at (18,228) content-size 10x10 children: not-inline (url: about:blank)
|
||||
NavigableContainerViewport <iframe> at (18,258) content-size 10x10 children: not-inline (url: about:blank)
|
||||
NavigableContainerViewport <iframe> at (18,288) content-size 10x10 children: not-inline (url: about:blank)
|
||||
NavigableContainerViewport <iframe> at (18,18) content-size 10x10 children: not-inline (url: about:blank) Viewport <#document> at (0,0) content-size 10x10 children: not-inline
|
||||
BlockContainer <html> at (0,0) content-size 10x16 [BFC] children: not-inline
|
||||
BlockContainer <body> at (8,8) content-size 0x0 children: not-inline
|
||||
|
||||
NavigableContainerViewport <iframe> at (18,48) content-size 10x10 children: not-inline (url: about:blank) Viewport <#document> at (0,0) content-size 10x10 children: not-inline
|
||||
BlockContainer <html> at (0,0) content-size 10x16 [BFC] children: not-inline
|
||||
BlockContainer <body> at (8,8) content-size 0x0 children: not-inline
|
||||
|
||||
NavigableContainerViewport <iframe> at (18,78) content-size 10x10 children: not-inline (url: about:blank) Viewport <#document> at (0,0) content-size 10x10 children: not-inline
|
||||
BlockContainer <html> at (0,0) content-size 10x16 [BFC] children: not-inline
|
||||
BlockContainer <body> at (8,8) content-size 0x0 children: not-inline
|
||||
|
||||
NavigableContainerViewport <iframe> at (18,108) content-size 10x10 children: not-inline (url: about:blank) Viewport <#document> at (0,0) content-size 10x10 children: not-inline
|
||||
BlockContainer <html> at (0,0) content-size 10x16 [BFC] children: not-inline
|
||||
BlockContainer <body> at (8,8) content-size 0x0 children: not-inline
|
||||
|
||||
NavigableContainerViewport <iframe> at (18,138) content-size 10x10 children: not-inline (url: about:blank) Viewport <#document> at (0,0) content-size 10x10 children: not-inline
|
||||
BlockContainer <html> at (0,0) content-size 10x16 [BFC] children: not-inline
|
||||
BlockContainer <body> at (8,8) content-size 0x0 children: not-inline
|
||||
|
||||
NavigableContainerViewport <iframe> at (18,168) content-size 10x10 children: not-inline (url: about:blank) Viewport <#document> at (0,0) content-size 10x10 children: not-inline
|
||||
BlockContainer <html> at (0,0) content-size 10x16 [BFC] children: not-inline
|
||||
BlockContainer <body> at (8,8) content-size 0x0 children: not-inline
|
||||
|
||||
NavigableContainerViewport <iframe> at (18,198) content-size 10x10 children: not-inline (url: about:blank) Viewport <#document> at (0,0) content-size 10x10 children: not-inline
|
||||
BlockContainer <html> at (0,0) content-size 10x16 [BFC] children: not-inline
|
||||
BlockContainer <body> at (8,8) content-size 0x0 children: not-inline
|
||||
|
||||
NavigableContainerViewport <iframe> at (18,228) content-size 10x10 children: not-inline (url: about:blank) Viewport <#document> at (0,0) content-size 10x10 children: not-inline
|
||||
BlockContainer <html> at (0,0) content-size 10x16 [BFC] children: not-inline
|
||||
BlockContainer <body> at (8,8) content-size 0x0 children: not-inline
|
||||
|
||||
NavigableContainerViewport <iframe> at (18,258) content-size 10x10 children: not-inline (url: about:blank) Viewport <#document> at (0,0) content-size 10x10 children: not-inline
|
||||
BlockContainer <html> at (0,0) content-size 10x16 [BFC] children: not-inline
|
||||
BlockContainer <body> at (8,8) content-size 0x0 children: not-inline
|
||||
|
||||
NavigableContainerViewport <iframe> at (18,288) content-size 10x10 children: not-inline (url: about:blank) Viewport <#document> at (0,0) content-size 10x10 children: not-inline
|
||||
BlockContainer <html> at (0,0) content-size 10x16 [BFC] children: not-inline
|
||||
BlockContainer <body> at (8,8) content-size 0x0 children: not-inline
|
||||
|
||||
|
||||
ViewportPaintable (Viewport<#document>) [0,0 800x600]
|
||||
PaintableWithLines (BlockContainer<HTML>) [0,0 800x16]
|
||||
|
|
|
@ -2,5 +2,5 @@ Harness status: OK
|
|||
|
||||
Found 1 tests
|
||||
|
||||
1 Fail
|
||||
Fail MediaQueryList.changed is correct for all lists in the document even during a change event handler
|
||||
1 Pass
|
||||
Pass MediaQueryList.changed is correct for all lists in the document even during a change event handler
|
|
@ -2,8 +2,8 @@ Harness status: OK
|
|||
|
||||
Found 22 tests
|
||||
|
||||
12 Pass
|
||||
10 Fail
|
||||
17 Pass
|
||||
5 Fail
|
||||
Pass matchMedia('(max-width: 150px)').matches should update immediately
|
||||
Pass matchMedia('(width: 100px)').matches should update immediately
|
||||
Pass matchMedia('(orientation: portrait)').matches should update immediately
|
||||
|
@ -16,11 +16,11 @@ Pass matchMedia('(min-height: 150px)').matches should update immediately
|
|||
Pass matchMedia('(aspect-ratio: 1/2)').matches should update immediately
|
||||
Pass matchMedia('(min-width: 150px)').matches should update immediately
|
||||
Pass matchMedia('(min-aspect-ratio: 4/3)').matches should update immediately
|
||||
Fail matchMedia('(max-width: 150px)') should not receive a change event until update the rendering step of HTML5 event loop
|
||||
Fail matchMedia('(width: 100px)') should not receive a change event until update the rendering step of HTML5 event loop
|
||||
Fail matchMedia('(orientation: portrait)') should not receive a change event until update the rendering step of HTML5 event loop
|
||||
Fail matchMedia('(aspect-ratio: 1/1)') should not receive a change event until update the rendering step of HTML5 event loop
|
||||
Fail matchMedia('(max-aspect-ratio: 4/3)') should not receive a change event until update the rendering step of HTML5 event loop
|
||||
Pass matchMedia('(max-width: 150px)') should not receive a change event until update the rendering step of HTML5 event loop
|
||||
Pass matchMedia('(width: 100px)') should not receive a change event until update the rendering step of HTML5 event loop
|
||||
Pass matchMedia('(orientation: portrait)') should not receive a change event until update the rendering step of HTML5 event loop
|
||||
Pass matchMedia('(aspect-ratio: 1/1)') should not receive a change event until update the rendering step of HTML5 event loop
|
||||
Pass matchMedia('(max-aspect-ratio: 4/3)') should not receive a change event until update the rendering step of HTML5 event loop
|
||||
Fail matchMedia('(max-width: 150px)') should receive a change event after resize event on the window but before a requestAnimationFrame callback is called
|
||||
Fail matchMedia('(width: 100px)') should receive a change event after resize event on the window but before a requestAnimationFrame callback is called
|
||||
Fail matchMedia('(orientation: portrait)') should receive a change event after resize event on the window but before a requestAnimationFrame callback is called
|
||||
|
|
Loading…
Add table
Reference in a new issue