Skip to content

layout: Allow same ScriptThread <iframe>s to be resized synchronously#34656

Merged
mrobinson merged 1 commit intoservo:mainfrom
mrobinson:synchronous-iframe-sizing
Dec 17, 2024
Merged

layout: Allow same ScriptThread <iframe>s to be resized synchronously#34656
mrobinson merged 1 commit intoservo:mainfrom
mrobinson:synchronous-iframe-sizing

Conversation

@mrobinson
Copy link
Member

Post layout, when a Window has all of the new <iframe> sizes, size
any Windows for Pipelines in the same ScriptThread synchronously.
This ensures that when laying out from the outermost frame to the
innermost frames, the frames sizes are set properly.

There is still an issue where a non-same-ScriptThread <iframe> sits
in between two <iframe>s of the same origin. According to the
specification these frames should all be synchrnously laid out --
something quite difficult in Servo. This is issue #34655.

This is the first change in a series of changes to improve the
consistency of <iframe> loading and sizing.

Fixes #14719.
Fixes #24569.
Fixes #24571.
Fixes #25269.
Fixes #25275.
Fixes #25285.
Fixes #30571.

Signed-off-by: Martin Robinson mrobinson@igalia.com


  • ./mach build -d does not report any errors
  • ./mach test-tidy does not report any errors
  • There are tests for these changes.

@mrobinson mrobinson requested a review from gterzian as a code owner December 16, 2024 19:41
@mrobinson mrobinson added the T-linux-wpt Do a try run of the WPT label Dec 16, 2024
@github-actions github-actions bot removed the T-linux-wpt Do a try run of the WPT label Dec 16, 2024
@github-actions
Copy link

🔨 Triggering try run (#12362435585) for Linux WPT

@github-actions
Copy link

Test results for linux-wpt-layout-2020 from try job (#12362435585):

Flaky unexpected result (23)
  • FAIL [expected PASS] /_mozilla/css/iframe/hide_and_show.html (#15265)
  • TIMEOUT [expected OK] /_webgl/conformance/glsl/misc/shader-uniform-packing-restrictions.html (#28103)
  • TIMEOUT [expected OK] /_webgl/conformance/reading/read-pixels-test.html
  • TIMEOUT [expected OK] /_webgl/conformance/uniforms/out-of-bounds-uniform-array-access.html (#26225)
    • NOTRUN [expected PASS] subtest: Overall test
  • TIMEOUT [expected OK] /css/css-flexbox/abspos/position-absolute-013.html
  • OK /fetch/metadata/generated/css-font-face.https.sub.tentative.html (#32732)
    • PASS [expected FAIL] subtest: sec-fetch-site - Same-Site -&gt; Same Origin
  • OK /fetch/metadata/generated/css-font-face.sub.tentative.html (#34624)
    • PASS [expected FAIL] subtest: sec-fetch-storage-access - Not sent to non-trustworthy same-site destination
  • OK [expected TIMEOUT] /html/browsers/browsing-the-web/history-traversal/pagereveal/order-in-bfcache-restore.html
    • FAIL [expected TIMEOUT] subtest: pagereveal event fires and in correct order on restoration from BFCache

      assert_equals: expected "pageshow.persisted,pagereveal,rAF" but got "pageshow.persisted,rAF,rAF"
      

  • OK /html/browsers/browsing-the-web/navigating-across-documents/javascript-url-return-value-handling-dynamic.html (#28066)
    • FAIL [expected PASS] subtest: 0041 set in href="" targeting a frame and clicked

      assert_equals: expected "A" but got ""
      

    • FAIL [expected PASS] subtest: 0080 00FF set in href="" targeting a frame and clicked

      assert_equals: expected "�ÿ" but got ""
      

    • FAIL [expected PASS] subtest: 0080 00FF 0100 set in href="" targeting a frame and clicked

      assert_equals: expected "�ÿĀ" but got ""
      

    • FAIL [expected PASS] subtest: D83D DE0D set in href="" targeting a frame and clicked

      assert_equals: expected "😍" but got ""
      

    • FAIL [expected PASS] subtest: DE0D 0041 set in href="" targeting a frame and clicked

      assert_equals: expected "\ufffdA" but got ""
      

  • OK /html/browsers/browsing-the-web/navigating-across-documents/navigation-unload-same-origin.window.html (#29049)
    • PASS [expected FAIL] subtest: Same-origin navigation started from unload handler must be ignored
  • TIMEOUT [expected OK] /html/browsers/history/the-history-interface/traverse-during-unload.html (#28688)
    • TIMEOUT [expected PASS] subtest: Traversing the history during unload

      Test timed out
      

  • TIMEOUT [expected OK] /html/browsers/origin/cross-origin-objects/cross-origin-objects.html (#28569)
  • TIMEOUT [expected OK] /html/interaction/focus/the-autofocus-attribute/supported-elements.html (#24145)
    • TIMEOUT [expected FAIL] subtest: Element with tabindex should support autofocus

      Test timed out
      

    • NOTRUN [expected PASS] subtest: Non-HTMLElement should not support autofocus
    • NOTRUN [expected FAIL] subtest: Host element with delegatesFocus should support autofocus
    • NOTRUN [expected FAIL] subtest: Host element with delegatesFocus including no focusable descendants should be skipped
    • NOTRUN [expected FAIL] subtest: Area element should support autofocus
  • OK [expected TIMEOUT] /html/semantics/embedded-content/media-elements/playing-the-media-resource/loop-from-ended.tentative.html (#33778)
    • FAIL [expected TIMEOUT] subtest: play() with loop set to true after playback ended

      this argument is not a finite floating-point value
      

  • OK /html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-nav-form-submit.html (#32607)
    • FAIL [expected PASS] subtest: Navigating iframe loading='lazy' before it is loaded: form submit

      uncaught exception: Error: assert_equals: expected "http://web-platform.test:8000/html/semantics/embedded-content/the-iframe-element/support/blank.htm?" but got "http://web-platform.test:8000/html/semantics/embedded-content/the-iframe-element/support/blank.htm?src"
      

  • OK /html/semantics/forms/form-submission-0/form-data-set-usv.html
    • FAIL [expected PASS] subtest: Strings from form controls should be converted to Unicode scalar values in FormData

      Value is not an object.
      

  • OK /html/semantics/forms/form-submission-0/multipart-formdata.window.html (#28725)
    • PASS [expected FAIL] subtest: multipart/form-data: 0x00 in value (normal form)
  • CRASH [expected OK] /html/semantics/forms/the-fieldset-element/disabled-003.html (#31730)
  • OK /html/webappapis/dynamic-markup-insertion/document-write/module-delayed.html (#27659)
    • FAIL [expected PASS] subtest: async document.write in a module

      assert_true: onload must be called expected true got false
      

  • OK /html/webappapis/dynamic-markup-insertion/document-write/module-tla-delayed.html (#29137)
    • FAIL [expected PASS] subtest: document.write in an imported module

      assert_true: onload must be called expected true got false
      

  • TIMEOUT [expected OK] /html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events.html (#26371)
    • TIMEOUT [expected FAIL] subtest: delayed handling: delaying handling rejected promise created from createImageBitmap will cause both events to fire

      Test timed out
      

  • OK /resize-observer/eventloop.html (#33599)
    • FAIL [expected PASS] subtest: test0: multiple notifications inside same event loop

      assert_equals: new loop expected 1 but got 0
      

  • TIMEOUT [expected OK] /resource-timing/nested-context-navigations-iframe.html (#24311)
    • TIMEOUT [expected PASS] subtest: Test that cross-site iframe navigations are not observable by the parent, even after history navigations by the parent

      Test timed out
      

    • NOTRUN [expected PASS] subtest: Test that iframe navigations are not observable by the parent
    • NOTRUN [expected PASS] subtest: Test that crossorigin iframe navigations are not observable by the parent
    • NOTRUN [expected PASS] subtest: Test that cross-site iframe navigations are not observable by the parent
    • NOTRUN [expected PASS] subtest: Test that iframe refreshes are not observable by the parent
    • NOTRUN [expected PASS] subtest: Test that crossorigin iframe refreshes are not observable by the parent
    • NOTRUN [expected PASS] subtest: Test that cross-site iframe refreshes are not observable by the parent
Stable unexpected results that are known to be intermittent (13)
  • TIMEOUT /html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-src-aboutblank-navigate-immediately.html (#29048)
    • FAIL [expected PASS] subtest: Navigating to a different document with location.href

      assert_equals: expected "http://web-platform.test:8000/common/blank.html?1" but got "about:blank"
      

    • TIMEOUT [expected FAIL] subtest: Navigating to a different document with link click

      Test timed out
      

    • NOTRUN [expected TIMEOUT] subtest: Navigating to a different document with form submission
  • OK /html/browsers/browsing-the-web/navigating-across-documents/navigation-unload-same-origin-fragment.html (#20768)
    • FAIL [expected PASS] subtest: Tests that a fragment navigation in the unload handler will not block the initial navigation

      assert_equals: expected "" but got "#fragment"
      

  • OK [expected TIMEOUT] /html/browsers/history/the-history-interface/traverse_the_history_write_onload_1.html (#21581)
    • PASS [expected TIMEOUT] subtest: Traverse the history when a history entry is written in the load event
  • OK /html/browsers/windows/browsing-context-names/duplicate-name-order.html (#34623)
    • FAIL [expected PASS] subtest: Duplicate name lookup order

      assert_equals: subtree first expected "ChildA" but got "SiblingA"
      

  • OK /html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-nav-link-click.html (#32664)
    • FAIL [expected PASS] subtest: Navigating iframe loading='lazy' before it is loaded: link click

      uncaught exception: Error: assert_equals: expected "http://web-platform.test:8000/html/semantics/embedded-content/the-iframe-element/support/blank.htm?nav" but got "http://web-platform.test:8000/html/semantics/embedded-content/the-iframe-element/support/blank.htm?src"
      

  • OK /html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-location-reload.html (#32595)
    • FAIL [expected PASS] subtest: Reloading iframe loading='lazy' before it is loaded: location.reload

      uncaught exception: Error: assert_equals: expected "http://web-platform.test:8000/html/semantics/embedded-content/the-iframe-element/support/blank.htm?src" but got "about:blank"
      

  • TIMEOUT /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html (#22667)
    • TIMEOUT [expected FAIL] subtest: Check that popups from a sandboxed iframe escape the sandbox if allow-popups-to-escape-sandbox is used

      Test timed out
      

  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html (#24057)
    • FAIL [expected TIMEOUT] subtest: Check that popups from a sandboxed iframe escape the sandbox if allow-popups-to-escape-sandbox is used

      assert_equals: It came from a sandboxed iframe expected "null" but got "http://web-platform.test:8000"
      

  • TIMEOUT [expected CRASH] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html (#24066)
  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html (#24066)
    • FAIL [expected NOTRUN] subtest: Check that popups from a sandboxed iframe do not escape the sandbox

      assert_equals: It came from a sandboxed iframe expected "null" but got "http://web-platform.test:8000"
      

  • OK /html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html (#26243)
    • FAIL [expected PASS] subtest: document.write in an imported module

      assert_true: onload must be called expected true got false
      

  • OK /html/webappapis/update-rendering/child-document-raf-order.html (#33028)
    • PASS [expected FAIL] subtest: Ordering of steps in "Update the Rendering" - child document requestAnimationFrame order
  • OK [expected TIMEOUT] /webstorage/localstorage-about-blank-3P-iframe-opens-3P-window.partitioned.html (#29053)
    • PASS [expected TIMEOUT] subtest: StorageKey: test 3P about:blank window opened from a 3P iframe

@github-actions
Copy link

✨ Try run (#12362435585) succeeded.

Copy link
Member

@gterzian gterzian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with some comments

return;
}

// Send resize message to any local `Pipeline`s synchronously, so that the value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"synchronously" makes it sound like you are blocking on the sending of messages, so I think it's more precise to write that you are batching those messages locally for them to be handled at the next update the rendering(which is better than writing "layout", because the concept is more clearly defined across layout and script boundaries thanks to the html spec).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. I've reworded this a bit to be clearer.

);
}
});
// Send asynchronous updates to `Constellation.`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all of these will now result in receiving resize messages back from the constellation, in which case we need to write down somewhere what the proposed re-design is, which probably should include making a distinction between resizes that have already been batched locally at the script-thread(for same-origin iframes), and those that need to be propagated to other script-threads via the constellation. Describing this in an issue for a follow-up is a good idea I think.

Copy link
Member

@gterzian gterzian Dec 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also one last note on the topic of "According to the
specification these frames should all be synchrnously laid out", I think the way to do that in Servo would be to still first batch the resizes locally, but somehow only process them as part of an rendering update when the cross-origin resizes have been taken into account as well. So in other words, instead of batching them for the next udpate, they'd have to be batched for "an update in the future" conditioned on somehow haven taken into account the resizing of the cross-origin iframes, and this "transaction" across script-thread would have be to brokered by the constellation. I think it's also a good idea to start discussing in more details in an issue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a great idea to document the new design. This change fixes the issue in the majority of cases, but there are still some tricky cases where many resize events flooding the Constellation could lead to flashing layout. I hope to address those in a followup change, but the solution will affect the final design. Maybe I can have a section of the book ready with the design once I've worked through all of the issues.

Regarding whether or not we need synchronous layout of the entire frame tree (I'm not convinced we don't need it yet), I agree it's good to discuss more in #34655.

@mrobinson
Copy link
Member Author

Thanks for the review!

@mrobinson mrobinson force-pushed the synchronous-iframe-sizing branch from 70ab7e7 to 0b269bd Compare December 17, 2024 08:55
…usly

Post layout, when a `Window` has all of the new `<iframe>` sizes, size
any `Window`s for `Pipeline`s in the same `ScriptThread` synchronously.
This ensures that when laying out from the outermost frame to the
innermost frames, the frames sizes are set properly.

There is still an issue where a non-same-`ScriptThread` `<iframe>` sits
in between two `<iframe>`s of the same origin. According to the
specification these frames should all be synchrnously laid out --
something quite difficult in Servo. This is issue servo#34655.

This is the first change in a series of changes to improve the
consistency of `<iframe>` loading and sizing.

Fixes servo#14719.
Fixes servo#24569.
Fixes servo#24571.
Fixes servo#25269.
Fixes servo#25275.
Fixes servo#25285.
Fixes servo#30571.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
@mrobinson mrobinson force-pushed the synchronous-iframe-sizing branch from 0b269bd to 6b67a37 Compare December 17, 2024 09:00
@mrobinson mrobinson enabled auto-merge December 17, 2024 09:01
@mrobinson mrobinson added this pull request to the merge queue Dec 17, 2024
Merged via the queue into servo:main with commit 0a01d06 Dec 17, 2024
@mrobinson mrobinson deleted the synchronous-iframe-sizing branch December 17, 2024 10:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment