Skip to content

canvas: Support all Unicode variation selectors in text runs#43449

Merged
mrobinson merged 5 commits intoservo:mainfrom
yezhizhen:vello
Mar 25, 2026
Merged

canvas: Support all Unicode variation selectors in text runs#43449
mrobinson merged 5 commits intoservo:mainfrom
yezhizhen:vello

Conversation

@yezhizhen
Copy link
Copy Markdown
Member

@yezhizhen yezhizhen commented Mar 19, 2026

Initially I just want to update the legacy comment, since raqote backend is gone.

This also enforces other variation selectors properly: see anchor ⚓ below,
which ignored our text selector previously.

Fixes: #43448
Fixes: #43650
Testing: Added a test that all other browsers pass as well.

Before After
image image
image image

@yezhizhen yezhizhen requested a review from xiaochengh March 19, 2026 06:44
@yezhizhen yezhizhen requested a review from gterzian as a code owner March 19, 2026 06:44
@servo-highfive servo-highfive added the S-awaiting-review There is new code that needs to be reviewed. label Mar 19, 2026
@yezhizhen yezhizhen changed the title canvas: Support emoji variation selectors canvas: Support emoji variation selectors in text runs Mar 19, 2026
@yezhizhen yezhizhen changed the title canvas: Support emoji variation selectors in text runs canvas: Support more variation selectors in text runs Mar 19, 2026
@yezhizhen yezhizhen changed the title canvas: Support more variation selectors in text runs canvas: Support all unicode variation selectors in text runs Mar 19, 2026
@yezhizhen yezhizhen requested a review from nicoburns March 19, 2026 07:51
@yezhizhen yezhizhen changed the title canvas: Support all unicode variation selectors in text runs canvas: Support all Unicode variation selectors in text runs Mar 20, 2026
@yezhizhen yezhizhen added the T-linux-wpt Do a try run of the WPT label Mar 24, 2026
@github-actions github-actions Bot removed the T-linux-wpt Do a try run of the WPT label Mar 24, 2026
@github-actions
Copy link
Copy Markdown

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

@github-actions
Copy link
Copy Markdown

⚠️ Try run (#23483442693) cancelled.

Copy link
Copy Markdown
Member

@mrobinson mrobinson left a comment

Choose a reason for hiding this comment

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

Is it possible to write a test for this? I think you might find some ideas looking for other variation selector tests.

Comment thread components/script/dom/canvas/2d/canvas_state.rs Outdated
@servo-highfive servo-highfive added the S-needs-rebase There are merge conflict errors. label Mar 24, 2026
@yezhizhen yezhizhen marked this pull request as draft March 24, 2026 10:21
@yezhizhen yezhizhen added the T-linux-wpt Do a try run of the WPT label Mar 24, 2026
@yezhizhen yezhizhen marked this pull request as ready for review March 24, 2026 10:38
@servo-highfive servo-highfive removed the S-needs-rebase There are merge conflict errors. label Mar 24, 2026
@github-actions github-actions Bot removed the T-linux-wpt Do a try run of the WPT label Mar 24, 2026
@github-actions
Copy link
Copy Markdown

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

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

🤖 Opened new upstream WPT pull request (web-platform-tests/wpt#58708) with upstreamable changes.

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#58708).

@github-actions
Copy link
Copy Markdown

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

Flaky unexpected result (24)
  • TIMEOUT /FileAPI/url/url-in-tags-revoke.window.html (#19978)
    • PASS [expected TIMEOUT] subtest: Fetching a blob URL immediately before revoking it works in <script> tags.
  • OK /_mozilla/mozilla/getBoundingClientRect.html (#39668)
    • FAIL [expected PASS] subtest: getBoundingClientRect 1

      assert_equals: expected 62 but got 60.35
      

  • TIMEOUT [expected OK] /_mozilla/mozilla/window_resize_event.html (#36741)
    • TIMEOUT [expected PASS] subtest: Popup onresize event fires after resizeTo

      Test timed out
      

  • CRASH [expected PASS] /_mozilla/shadow-dom/move-element-with-ua-shadow-tree-crash.html (#39473)
  • CRASH [expected OK] /_webgl/conformance2/wasm/readpixels-2gb-in-4gb-wasm-memory.html
  • OK /content-security-policy/frame-ancestors/frame-ancestors-path-ignored.window.html (#36468)
    • PASS [expected FAIL] subtest: A 'frame-ancestors' CSP directive with a URL that includes a path should be ignored.
  • TIMEOUT [expected OK] /content-security-policy/inheritance/document-write-iframe.html (#41195)
    • TIMEOUT [expected PASS] subtest: document.open() keeps inherited CSPs on transient about:blank.

      Test timed out
      

  • FAIL [expected PASS] /css/css-backgrounds/background-size-042.html
  • CRASH [expected OK] /html/browsers/browsing-the-web/navigating-across-documents/anchor-fragment-form-submit-longfragment.html
  • OK /html/browsers/browsing-the-web/navigating-across-documents/refresh/same-document-refresh.html (#34597)
    • FAIL [expected PASS] subtest: Same-Document Referrer from Refresh

      assert_equals: original page loads expected "http://web-platform.test:8000/html/browsers/browsing-the-web/navigating-across-documents/refresh/resources/refresh-with-section.sub.html?url=%23section" but got "http://web-platform.test:8000/html/browsers/browsing-the-web/navigating-across-documents/refresh/resources/refresh-with-section.sub.html?url=%23section#section"
      

  • CRASH [expected OK] /html/browsers/browsing-the-web/unloading-documents/unload/002.html
  • CRASH [expected OK] /html/browsers/history/the-history-interface/combination_history_006.html
  • OK /html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/allow-scripts-flag-changing-1.html (#39694)
    • PASS [expected FAIL] subtest: Meta refresh is blocked by the allow-scripts sandbox flag at its creation time, not when refresh comes due
  • 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/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"])
      

  • TIMEOUT [expected OK] /preload/modulepreload-sri-importmap.html (#43354)
    • TIMEOUT [expected PASS] subtest: Script should not be loaded if modulepreload's integrity is invalid

      Test timed out
      

  • TIMEOUT /trusted-types/trusted-types-navigation.html?06-10 (#37920)
    • PASS [expected FAIL] subtest: Navigate a frame via anchor with javascript:-urls in report-only mode.
  • 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 /visual-viewport/resize-event-order.html (#41981)
    • PASS [expected FAIL] subtest: Popup: DOMWindow resize fired before VisualViewport.
  • OK /wasm/webapi/abort.any.html (#39966)
    • FAIL [expected PASS] subtest: compileStreaming() asynchronously racing with abort should succeed or reject with AbortError

      assert_equals: expected "AbortError" but got "CompileError"
      

  • CRASH [expected OK] /webaudio/the-audio-api/the-mediastreamaudiodestinationnode-interface/closed-audiocontext-construction.html
  • OK /webdriver/tests/classic/accept_alert/accept.py (#43194)
    • FAIL [expected PASS] subtest: test_accept_in_popup_window

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

  • 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
  • ERROR [expected OK] /workers/baseurl/alpha/sharedworker-in-worker.html (#21315)
Stable unexpected results that are known to be intermittent (17)
  • FAIL [expected PASS] /_mozilla/mozilla/sslfail.html (#10760)
  • 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)
  • OK /css/css-fonts/generic-family-keywords-003.html (#38994)
    • FAIL [expected PASS] subtest: @font-face matching for quoted and unquoted cursive (drawing text in a canvas)

      assert_equals: quoted cursive matches  @font-face rule expected 125 but got 40
      

    • FAIL [expected PASS] subtest: @font-face matching for quoted and unquoted fantasy (drawing text in a canvas)

      assert_equals: quoted fantasy matches  @font-face rule expected 125 but got 40
      

    • FAIL [expected PASS] subtest: @font-face matching for quoted and unquoted monospace (drawing text in a canvas)

      assert_equals: quoted monospace matches  @font-face rule expected 125 but got 40
      

    • PASS [expected FAIL] subtest: @font-face matching for quoted and unquoted generic(fangsong) (drawing text in a canvas)
    • PASS [expected FAIL] subtest: @font-face matching for quoted and unquoted generic(kai) (drawing text in a canvas)
    • FAIL [expected PASS] subtest: @font-face matching for quoted and unquoted generic(nastaliq) (drawing text in a canvas)

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

  • ERROR [expected OK] /fetch/fetch-later/quota/same-origin-iframe/accumulated-oversized-payload.https.window.html (#41705)
  • OK /fetch/metadata/generated/css-font-face.https.sub.tentative.html (#32732)
    • PASS [expected FAIL] subtest: sec-fetch-mode
  • TIMEOUT /fetch/metadata/generated/css-images.sub.tentative.html (#29047)
    • TIMEOUT [expected PASS] subtest: background-image sec-fetch-dest - Not sent to non-trustworthy cross-site destination

      Test timed out
      

  • OK /html/browsers/browsing-the-web/navigating-across-documents/005.html (#27062)
    • FAIL [expected PASS] subtest: Link with onclick navigation and href navigation

      assert_equals: expected "href" but got "click"
      

  • 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
  • TIMEOUT /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 TIMEOUT] subtest: Non-HTMLElement should not support autofocus
  • OK [expected TIMEOUT] /html/interaction/focus/the-autofocus-attribute/update-the-rendering.html (#24145)
    • FAIL [expected TIMEOUT] subtest: "Flush autofocus candidates" should be happen before a scroll event and animation frame callbacks

      assert_array_equals: animationFrame lengths differ, expected array ["autofocus", "scroll", "animationFrame"] length 3, got ["animationFrame"] length 1
      

  • OK /html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/allow-scripts-flag-changing-2.html (#39703)
    • FAIL [expected PASS] subtest: Meta refresh of the original iframe is not blocked if moved into a sandboxed iframe

      uncaught exception: Error: assert_unreached: The iframe into which the meta was moved must not refresh Reached unreachable code
      

  • OK /html/semantics/embedded-content/media-elements/audio_loop_seek_to_eos.html (#41226)
    • PASS [expected FAIL] subtest: seeking to the end of looping audio
  • 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
      

  • CRASH [expected OK] /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 (xmlhttprequest)
  • OK /touch-events/single-tap-when-touchend-listener-use-sync-xhr.html (#41175)
    • FAIL [expected PASS] subtest: Click event should be fired when touchend opens synchronous XHR

      assert_equals: expected "touchend@div, mousedown@div, mouseup@div, click@div" but got "touchend@div"
      

@github-actions
Copy link
Copy Markdown

✨ Try run (#23485185426) succeeded.

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

✍ Updated existing upstream WPT pull request (web-platform-tests/wpt#58708) title and body.

Copy link
Copy Markdown
Contributor

@xiaochengh xiaochengh left a comment

Choose a reason for hiding this comment

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

Impl change LGTM.

Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

✍ Updated existing upstream WPT pull request (web-platform-tests/wpt#58708) title and body.

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#58708).

@servo-highfive servo-highfive removed the S-awaiting-review There is new code that needs to be reviewed. label Mar 25, 2026
@mrobinson
Copy link
Copy Markdown
Member

@yezhizhen Nice work.

@mrobinson mrobinson enabled auto-merge March 25, 2026 14:47
Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
@servo-highfive servo-highfive added the S-awaiting-review There is new code that needs to be reviewed. label Mar 25, 2026
@yezhizhen
Copy link
Copy Markdown
Member Author

DCO was stuck. I also simplified the condition: previously it potentially allows VS to start new run if current_text_run is empty.
Try: https://github.com/servo/servo/actions/runs/23549038032

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#58708).

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

✍ Updated existing upstream WPT pull request (web-platform-tests/wpt#58708) title and body.

@mrobinson mrobinson added this pull request to the merge queue Mar 25, 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 Mar 25, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Mar 25, 2026
@servo-highfive servo-highfive added S-tests-failed The changes caused existing tests to fail. and removed S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. labels Mar 25, 2026
@mrobinson mrobinson added this pull request to the merge queue Mar 25, 2026
@servo-highfive servo-highfive added S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. and removed S-tests-failed The changes caused existing tests to fail. labels Mar 25, 2026
Merged via the queue into servo:main with commit 40d616c Mar 25, 2026
40 checks passed
@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 Mar 25, 2026
@yezhizhen yezhizhen deleted the vello branch March 26, 2026 01:31
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.

Panic with simple test regarding font canvas: Support variation selectors

5 participants