Skip to content

layout: Integrate more details into FontAndScriptInfo#43974

Merged
mrobinson merged 1 commit into
servo:mainfrom
mrobinson:integrate-more-details-into-info
Apr 8, 2026
Merged

layout: Integrate more details into FontAndScriptInfo#43974
mrobinson merged 1 commit into
servo:mainfrom
mrobinson:integrate-more-details-into-info

Conversation

@mrobinson

Copy link
Copy Markdown
Member

This will be needed for ensuring that shaped text is valid during
relayout. It duplicates some information, but the hope is that when all
of these change are done, there will be many fewer individual shaped
segments of text.

Testing: This should not really change observable behavior so is covered by existing tests.

@mrobinson mrobinson requested a review from Loirooriol as a code owner April 6, 2026 12:55
@servo-highfive servo-highfive added the S-awaiting-review There is new code that needs to be reviewed. label Apr 6, 2026
language,
bidi_level: Level::ltr(),
letter_spacing,
word_spacing: None,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why pass the actual letter_spacing, but not the actual word_spacing?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I was thinking that this would only be reached when the segment is entirely control characters and white space, but to be safe I'll pass a real word_spacing here.

let mut results = Vec::new();

let lang = parent_style.get_font()._x_lang.clone();
let lang_attribute = parent_style.get_font()._x_lang.clone();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Currently we are only using -x-lang for the attribute, but e.g. Firefox also sets it on <math>, so I wouldn't name the variable this way.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Okay. I'll rename it.

character,
next_character,
lang.clone(),
lang_attribute.clone(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not necessarily in this PR, but might be good to pass the parsed language here?

@mrobinson mrobinson Apr 8, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I had the same thought actually. It needs a little investigation.

@servo-highfive servo-highfive removed the S-awaiting-review There is new code that needs to be reviewed. label Apr 8, 2026
@Loirooriol Loirooriol added the T-linux-wpt Do a try run of the WPT label Apr 8, 2026
@github-actions github-actions Bot removed the T-linux-wpt Do a try run of the WPT label Apr 8, 2026
@github-actions

github-actions Bot commented Apr 8, 2026

Copy link
Copy Markdown

🔨 Triggering try run (#24150662584) for Linux (WPT)

@github-actions

github-actions Bot commented Apr 8, 2026

Copy link
Copy Markdown

Test results for linux-wpt from try job (#24150662584):

Flaky unexpected result (42)
  • OK /_mozilla/mozilla/getBoundingClientRect.html (#39668)
    • FAIL [expected PASS] subtest: getBoundingClientRect 1

      assert_equals: expected 62 but got 60.35
      

  • CRASH [expected OK] /_mozilla/mozilla/img_find_non_sibling_map.html
  • OK /beacon/beacon-basic.https.window.html (#41723)
    • FAIL [expected PASS] subtest: Payload size restriction should be accumulated: type = blob

      assert_false: expected false got true
      

  • CRASH [expected OK] /content-security-policy/meta/sandbox-iframe.html (#43478)
  • FAIL [expected PASS] /css/css-backgrounds/background-size-042.html
  • OK /css/css-fonts/generic-family-keywords-002.html (#40929)
    • FAIL [expected PASS] subtest: font-family: -webkit-serif treated as &lt;font-family&gt;, not &lt;generic-name&gt;

      assert_equals: expected 30 but got 50
      

    • FAIL [expected PASS] subtest: font-family: -webkit-sans-serif treated as &lt;font-family&gt;, not &lt;generic-name&gt;

      assert_equals: expected 30 but got 50
      

    • FAIL [expected PASS] subtest: font-family: -webkit-cursive treated as &lt;font-family&gt;, not &lt;generic-name&gt;

      assert_equals: expected 30 but got 50
      

    • FAIL [expected PASS] subtest: font-family: -webkit-fantasy treated as &lt;font-family&gt;, not &lt;generic-name&gt;

      assert_equals: expected 30 but got 50
      

    • FAIL [expected PASS] subtest: font-family: -webkit-monospace treated as &lt;font-family&gt;, not &lt;generic-name&gt;

      assert_equals: expected 30 but got 50
      

    • FAIL [expected PASS] subtest: font-family: -webkit-system-ui treated as &lt;font-family&gt;, not &lt;generic-name&gt;

      assert_equals: expected 30 but got 50
      

    • FAIL [expected PASS] subtest: font-family: -webkit-math treated as &lt;font-family&gt;, not &lt;generic-name&gt;

      assert_equals: expected 30 but got 50
      

    • PASS [expected FAIL] subtest: font-family: -webkit-generic(fangsong) treated as &lt;font-family&gt;, not &lt;generic-name&gt;
    • PASS [expected FAIL] subtest: font-family: -webkit-generic(kai) treated as &lt;font-family&gt;, not &lt;generic-name&gt;
    • PASS [expected FAIL] subtest: font-family: -webkit-generic(khmer-mul) treated as &lt;font-family&gt;, not &lt;generic-name&gt;
    • And 12 more unexpected results...
  • FAIL [expected PASS] /css/css-ui/compute-kind-widget-generated/grouped-kind-of-widget-fallback-border-block-start-style-001.html
  • FAIL [expected PASS] /css/css-ui/webkit-appearance-meter-001.html
  • CRASH [expected OK] /fetch/api/headers/headers-combine.any.html
  • CRASH [expected OK] /fetch/api/policies/referrer-no-referrer.html
  • ERROR [expected OK] /fetch/fetch-later/quota/same-origin-iframe/multiple-iframes.https.window.html (#35176)
  • OK /fetch/metadata/generated/css-font-face.https.sub.tentative.html (#32732)
    • PASS [expected FAIL] subtest: sec-fetch-dest
    • FAIL [expected PASS] subtest: sec-fetch-user

      promise_test: Unhandled rejection with value: object "Error: Failed to query for recorded headers."
      

  • TIMEOUT /fetch/metadata/generated/css-images.https.sub.tentative.html (#42229)
    • PASS [expected FAIL] subtest: content sec-fetch-site - Same-Origin -&gt; Same Origin
  • ERROR [expected OK] /fetch/metadata/window-open.https.sub.html (#40339)
  • CRASH [expected TIMEOUT] /html/browsers/browsing-the-web/history-traversal/history-traversal-navigates-multiple-frames.html
  • ERROR [expected TIMEOUT] /html/browsers/browsing-the-web/history-traversal/pageswap/pageswap-initial-navigation.html (#40387)
  • CRASH [expected OK] /html/browsers/browsing-the-web/remote-context-helper-tests/addIframe-srcdoc-startOn.window.html
  • OK /html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/allow-scripts-flag-changing-1.html (#39694)
    • FAIL [expected PASS] subtest: Meta refresh is blocked by the allow-scripts sandbox flag at its creation time, not when refresh comes due

      uncaught exception: Error: assert_unreached: The iframe from which the meta came from must not refresh Reached unreachable code
      

  • OK /html/semantics/embedded-content/media-elements/media_fragment_seek.html (#24114)
    • FAIL [expected PASS] subtest: Video should seek to time specified in media fragment syntax

      assert_equals: expected 3 but got 0
      

  • OK [expected TIMEOUT] /html/semantics/embedded-content/media-elements/src_object_blob.html (#40340)
    • PASS [expected TIMEOUT] subtest: HTMLMediaElement.srcObject blob
  • TIMEOUT [expected OK] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_navigate_other_frame_popup.sub.html (#39702)
    • TIMEOUT [expected FAIL] subtest: Sandboxed iframe can not navigate other frame's popup

      Test timed out
      

  • OK /html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.worker-module.html (#43510)
    • FAIL [expected PASS] subtest: Revoking a blob URL immediately after calling import will not fail

      promise_test: Unhandled rejection with value: object "TypeError: Module fetching failed"
      

  • OK /html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.worker.html (#33909)
    • FAIL [expected PASS] subtest: Revoking a blob URL immediately after calling import will not fail

      promise_test: Unhandled rejection with value: object "TypeError: Module fetching failed"
      

  • TIMEOUT [expected OK] /html/user-activation/navigation-state-reset-sameorigin.html
    • TIMEOUT [expected PASS] subtest: Post-navigation state reset.

      Test timed out
      

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

      assert_true: onload must be called expected true got false
      

  • ERROR [expected OK] /intersection-observer/v2/animated-opacity.html (#40827)
  • TIMEOUT [expected OK] /pointerevents/compat/pointerevent_touch-action_two-finger_interaction.html
    • NOTRUN [expected PASS] subtest: touch two-finger pan on 'touch-action: pan-x pan-y'
    • NOTRUN [expected FAIL] subtest: touch two-finger pan on 'touch-action: pinch-zoom'
  • OK /resource-timing/buffer-full-add-then-clear.html (#40819)
    • FAIL [expected PASS] subtest: Test that if the buffer is cleared after entries were added to the secondary buffer, those entries make it into the primary one

      assert_equals: Number of entries does not match the expected value. expected 3 but got 0
      

  • OK [expected CRASH] /resource-timing/render-blocking-status-link.html (#41664)
  • OK /resource-timing/test_resource_timing.html (#25720)
    • PASS [expected FAIL] subtest: PerformanceEntry has correct name, initiatorType, startTime, and duration (iframe)
  • TIMEOUT [expected OK] /trusted-types/trusted-types-navigation.html?26-30 (#38807)
    • TIMEOUT [expected PASS] subtest: Navigate a window via form-submission with javascript:-urls in report-only mode.

      Test timed out
      

    • NOTRUN [expected PASS] subtest: Navigate a window via form-submission with javascript:-urls w/ default policy in report-only mode.
    • NOTRUN [expected PASS] subtest: Navigate a frame via form-submission with javascript:-urls in enforcing mode.
    • NOTRUN [expected PASS] subtest: Navigate a frame via form-submission with javascript:-urls w/ default policy in enforcing mode.
  • OK /visual-viewport/resize-event-order.html (#41981)
    • PASS [expected FAIL] subtest: Popup: DOMWindow resize fired before VisualViewport.
  • OK /webdriver/tests/classic/accept_alert/accept.py (#43194)
    • FAIL [expected PASS] subtest: test_null_response_value

      AssertionError: no such alert (404): No user prompt is currently active.
      

  • OK /webdriver/tests/classic/close_window/close.py
    • ERROR [expected PASS] subtest: test_no_top_browsing_context

      setup error: webdriver.error.NoSuchElementException: no such element (404)
      

  • OK /webdriver/tests/classic/dismiss_alert/dismiss.py (#39098)
    • FAIL [expected PASS] subtest: test_null_response_value

      AssertionError: no such alert (404): No user prompt is currently active.
      

    • FAIL [expected PASS] subtest: test_dismiss_in_popup_window

      AssertionError: no such alert (404): No user prompt is currently active.
      

  • OK /webdriver/tests/classic/execute_async_script/promise.py
    • FAIL [expected PASS] subtest: test_promise_resolve

      AssertionError: no such window (404): No such window
      

  • OK /webdriver/tests/classic/find_element_from_shadow_root/find.py
    • FAIL [expected PASS] subtest: test_null_parameter_value

      webdriver.error.NoSuchWindowException: no such window (404): No such window
      

  • OK /webdriver/tests/classic/get_element_attribute/get.py
    • ERROR [expected PASS] subtest: test_no_top_browsing_context

      setup error: webdriver.error.NoSuchElementException: no such element (404)
      

  • OK /webdriver/tests/classic/get_title/user_prompts.py
    • FAIL [expected PASS] subtest: test_accept[alert-None]

      webdriver.error.NoSuchWindowException: no such window (404)
      

  • CRASH [expected OK] /websockets/unload-a-document/003.html
  • OK /webxr/xrSession_features_deviceSupport.https.html (#24357)
    • FAIL [expected PASS] subtest: Immersive XRSession requests with no supported device should reject

      assert_unreached: Should have rejected: undefined Reached unreachable code
      

  • CRASH [expected OK] /webxr/xrSession_input_events_end.https.html
Stable unexpected results that are known to be intermittent (17)
  • TIMEOUT /FileAPI/url/url-in-tags-revoke.window.html (#19978)
    • PASS [expected TIMEOUT] subtest: Fetching a blob URL immediately before revoking it works in &lt;script&gt; tags.
  • OK /IndexedDB/idbdatabase_deleteObjectStore.any.worker.html (#43776)
    • PASS [expected FAIL] subtest: Deleted object store's name should be removed from database's list. Attempting to use a deleted IDBObjectStore should throw an InvalidStateError
  • FAIL [expected PASS] /_mozilla/mozilla/sslfail.html (#10760)
  • TIMEOUT [expected OK] /_mozilla/mozilla/window_resize_event.html (#36741)
    • TIMEOUT [expected PASS] subtest: Popup onresize event fires after resizeTo

      Test timed out
      

  • OK /_webgl/conformance/textures/misc/texture-upload-size.html (#21770)
    • FAIL [expected PASS] subtest: WebGL test #45

      assert_true: Texture was smaller than the expected size 2x2 expected true got false
      

    • FAIL [expected PASS] subtest: WebGL test #47

      assert_true: getError expected: INVALID_VALUE. Was NO_ERROR : when calling texSubImage2D with the same texture upload with offset 1, 1 expected true got false
      

    • FAIL [expected PASS] subtest: WebGL test #49

      assert_true: Texture was smaller than the expected size 2x2 expected true got false
      

    • FAIL [expected PASS] subtest: WebGL test #51

      assert_true: getError expected: INVALID_VALUE. Was NO_ERROR : when calling texSubImage2D with the same texture upload with offset 1, 1 expected true got false
      

    • PASS [expected FAIL] subtest: WebGL test #53
    • PASS [expected FAIL] subtest: WebGL test #55
    • PASS [expected FAIL] subtest: WebGL test #57
    • PASS [expected FAIL] subtest: WebGL test #59
    • FAIL [expected PASS] subtest: WebGL test #61

      assert_true: Texture was smaller than the expected size 2x2 expected true got false
      

    • FAIL [expected PASS] subtest: WebGL test #63

      assert_true: getError expected: INVALID_VALUE. Was NO_ERROR : when calling texSubImage2D with the same texture upload with offset 1, 1 expected true got false
      

    • And 6 more unexpected results...
  • OK /css/css-fonts/generic-family-keywords-001.html (#37467)
    • PASS [expected FAIL] subtest: @font-face matching for quoted and unquoted generic(fangsong)
    • FAIL [expected PASS] subtest: @font-face matching for quoted and unquoted generic(kai)

      assert_equals: quoted generic(kai) matches  @font-face rule expected 30 but got 50
      

    • FAIL [expected PASS] subtest: @font-face matching for quoted and unquoted generic(khmer-mul)

      assert_equals: quoted generic(khmer-mul) matches  @font-face rule expected 30 but got 50
      

    • FAIL [expected PASS] subtest: @font-face matching for quoted and unquoted generic(nastaliq)

      assert_equals: quoted generic(nastaliq) matches  @font-face rule expected 30 but got 50
      

  • OK /css/css-fonts/generic-family-keywords-003.html (#38994)
    • PASS [expected FAIL] subtest: @font-face matching for quoted and unquoted fantasy (drawing text in a canvas)
    • PASS [expected FAIL] subtest: @font-face matching for quoted and unquoted monospace (drawing text in a canvas)
    • PASS [expected FAIL] subtest: @font-face matching for quoted and unquoted system-ui (drawing text in a canvas)
    • PASS [expected FAIL] subtest: @font-face matching for quoted and unquoted generic(fangsong) (drawing text in a canvas)
    • FAIL [expected PASS] subtest: @font-face matching for quoted and unquoted generic(khmer-mul) (drawing text in a canvas)

      assert_equals: quoted generic(khmer-mul) matches  @font-face rule expected 125 but got 40
      

    • PASS [expected FAIL] subtest: @font-face matching for quoted and unquoted ui-serif (drawing text in a canvas)
  • OK [expected ERROR] /fetch/fetch-later/quota/same-origin-iframe/accumulated-oversized-payload.https.window.html (#41705)
  • 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 /html/browsers/browsing-the-web/navigating-across-documents/navigation-unload-same-origin-fragment.html (#20768)
    • PASS [expected FAIL] subtest: Tests that a fragment navigation in the unload handler will not block the initial navigation
  • OK /html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/a-click.html (#28697)
    • FAIL [expected PASS] subtest: aElement.click() before the load event must NOT replace

      assert_equals: expected "http://web-platform.test:8000/common/blank.html?thereplacement" but got "http://web-platform.test:8000/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/resources/code-injector.html?pipe=sub(none)&amp;code=%0A%20%20%20%20const%20a%20%3D%20document.createElement(%22a%22)%3B%0A%20%20%20%20a.href%20%3D%20%22%2Fcommon%2Fblank.html%3Fthereplacement%22%3B%0A%20%20%20%20document.currentScript.before(a)%3B%0A%20%20%20%20a.click()%3B%0A%20%20"
      

  • TIMEOUT /html/interaction/focus/the-autofocus-attribute/supported-elements.html (#24145)
    • TIMEOUT [expected PASS] subtest: Non-HTMLElement should not support autofocus

      Test timed out
      

  • OK /html/semantics/scripting-1/the-script-element/execution-timing/077.html (#22139)
    • FAIL [expected PASS] subtest: adding several types of scripts through the DOM and removing some of them confuses scheduler

      assert_array_equals: expected property 1 to be "Script #1 ran" but got "Script #3 ran" (expected array ["Script #2 ran", "Script #1 ran", "Script #3 ran", "Script #4 ran"] got ["Script #2 ran", "Script #3 ran", "Script #4 ran", "Script #1 ran"])
      

  • OK /html/webappapis/user-prompts/print-during-unload.html (#35944)
    • FAIL [expected PASS] subtest: print() during unload

      assert_array_equals: expected property 1 to be "destination" but got "error: window.print is not a function" (expected array ["start", "destination"] got ["start", "error: window.print is not a function"])
      

  • OK /mixed-content/tentative/autoupgrades/mixed-content-cors.https.sub.html (#41123)
    • PASS [expected FAIL] subtest: Cross-Origin video should get upgraded even if CORS is set
  • TIMEOUT /trusted-types/trusted-types-navigation.html?31-35 (#38034)
    • TIMEOUT [expected PASS] subtest: Navigate a frame via form-submission with javascript:-urls in report-only mode.

      Test timed out
      

    • NOTRUN [expected TIMEOUT] subtest: Navigate a frame via form-submission with javascript:-urls w/ default policy in report-only mode.
  • OK /trusted-types/trusted-types-reporting.html (#43737)
    • PASS [expected FAIL] subtest: Trusted Type violation report: creating a forbidden-but-not-reported policy.

@github-actions

github-actions Bot commented Apr 8, 2026

Copy link
Copy Markdown

✨ Try run (#24150662584) succeeded.

This will be needed for ensuring that shaped text is valid during
relayout. It duplicates some information, but the hope is that when all
of these change are done, there will be many fewer individual shaped
segments of text.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
@mrobinson mrobinson force-pushed the integrate-more-details-into-info branch from 9119355 to d150d17 Compare April 8, 2026 21:29
@servo-highfive servo-highfive added the S-awaiting-review There is new code that needs to be reviewed. label Apr 8, 2026
@mrobinson mrobinson enabled auto-merge April 8, 2026 21:29
@mrobinson mrobinson added this pull request to the merge queue Apr 8, 2026
@servo-highfive servo-highfive added the S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. label Apr 8, 2026
Merged via the queue into servo:main with commit b8ef264 Apr 8, 2026
33 checks passed
@mrobinson mrobinson deleted the integrate-more-details-into-info branch April 8, 2026 22:13
@servo-highfive servo-highfive removed the S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. label Apr 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-awaiting-review There is new code that needs to be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants