Skip to content

Fix text clipping (#57408) - #57408

Closed
sbuggay wants to merge 2 commits into
react:mainfrom
sbuggay:export-D110430304
Closed

sbuggay wants to merge 2 commits into
react:mainfrom
sbuggay:export-D110430304

Conversation

@sbuggay

@sbuggay sbuggay commented Jul 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary:

Gate the iOS compressed text adjustment behind a runtime gate, expand the paragraph text drawing frame when compressed glyph bounds exceed the view bounds, and center glyph drawing for explicit line heights shorter than the font metrics.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D110430304

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jul 2, 2026
@facebook-github-tools facebook-github-tools Bot added p: Facebook Partner: Facebook Partner labels Jul 2, 2026
@meta-codesync

meta-codesync Bot commented Jul 2, 2026

Copy link
Copy Markdown

@sbuggay has exported this pull request. If you are a Meta employee, you can view the originating Diff in D110430304.

@sbuggay
sbuggay force-pushed the export-D110430304 branch from 6ad3898 to 52a1b24 Compare July 2, 2026 08:26
sbuggay added a commit to sbuggay/react-native that referenced this pull request Jul 2, 2026
Summary:
Pull Request resolved: react#57408

Gate the iOS compressed text adjustment behind `enableIOSCompressedTextFrameAdjustment`, expand the paragraph text drawing frame when compressed glyph bounds exceed the view bounds, and center glyph drawing for explicit line heights shorter than the font metrics.

Changelog: [internal]

Differential Revision: D110430304
@meta-codesync meta-codesync Bot changed the title Fix text clipping Fix text clipping (#57408) Jul 2, 2026
@sbuggay
sbuggay force-pushed the export-D110430304 branch from 52a1b24 to b933442 Compare July 2, 2026 08:30
sbuggay added 2 commits July 2, 2026 11:06
Summary:

Add the generated React Native feature flag plumbing for `enableIOSCompressedTextFrameAdjustment`. The flag gates an iOS `Text` rendering adjustment that expands and recenters compressed explicit `lineHeight` drawing when font glyph bounds exceed the drawing frame.

Changelog:
[iOS][Added] - Add `enableIOSCompressedTextFrameAdjustment` feature flag for `Text` rendering adjustments.

Differential Revision: D110430299
Summary:

Gate the iOS compressed text adjustment behind a runtime gate, expand the paragraph text drawing frame when compressed glyph bounds exceed the view bounds, and center glyph drawing for explicit line heights shorter than the font metrics.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D110430304
@sbuggay
sbuggay force-pushed the export-D110430304 branch from b933442 to 5bb7c71 Compare July 2, 2026 18:07
@meta-codesync meta-codesync Bot closed this in 3d9cc50 Jul 2, 2026
@meta-codesync

meta-codesync Bot commented Jul 2, 2026

Copy link
Copy Markdown

This pull request has been merged in 3d9cc50.

@meta-codesync meta-codesync Bot added the Merged This PR has been merged. label Jul 2, 2026
meta-codesync Bot pushed a commit that referenced this pull request Oct 7, 2026
…ews (#58632)

Summary:
`RCTParagraphComponentView` derives the text view's frame and drawing frame in `layoutSubviews`, requested with `setNeedsLayout` from `updateState` and `updateLayoutMetrics`. The layout pass itself dates from #46081, but until #57408 `drawRect:` read the content frame straight from `_layoutMetrics`, which is always current; #57408 moved drawing onto a `drawingFrame` computed in `layoutSubviews`, so drawing now assumes a layout pass will run before the view is displayed. It does not when the mount itself happens inside Core Animation's display phase — which is where `AppleEventBeat` processes a synchronous event requested during layout (#58530). This transaction's layout pass is already over, so the text view displays the new attributed string in the previous drawing frame and the text is cut off at the old width. The queued `layoutSubviews` updates the frame in the next transaction, but `drawingFrame` is a plain property that does not invalidate the display, so the clipped drawing stays until something else redraws the view.

Nothing on `main` emits a synchronous event from layout yet, so this is latent today; #58109 is the first thing that does (`layoutSubviews` reporting safe area insets on rotation) and it hits this on every rotation.

The frames are now computed in `finalizeUpdates:`, which the mounting manager calls [once per view after all of a mutation's `update*` calls](https://github.com/react/react-native/blob/f03f6c2b856e7d923f8af13d7ef452eb4bb21cd4/packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm#L108-L134). That coalesces state and layout-metrics changes the same way the layout pass did — one computation per mount, as before — without depending on a layout pass that may already have happened, and it removes the extra layout pass altogether. The `layoutSubviews` override goes away; `updateState` and `updateLayoutMetrics` keep their `setNeedsDisplay`.

## Changelog:

[IOS] [FIXED] - Text no longer renders clipped when mounted from a synchronous event during layout

Pull Request resolved: #58632

Test Plan:
Reproduced with #58109 on top of this branch, RNTester "Safe area insets" example, iPhone 17 Pro simulator: present the padded modal, apply insets, rotate. The readout text is re-rendered synchronously from the rotation's layout pass.

| Before | After |
|:---:|:---:|
| <img src="https://github.com/user-attachments/assets/092b162b-1b28-4b02-b584-4c28d66a96b5" width="440" /> | <img src="https://github.com/user-attachments/assets/52ae2ce8-75c7-4b2c-9e90-006e68b2588e" width="440" /> |

Before: `top: 0, right: 62, bottom: 19.99996` — the accessibility label carries the full `…9482421875, left: 62`, and the layout box is the right size; only the drawing is cut at the previous width. The paragraph under it overflows on one line for the same reason. After: both render at their new width. Rotating back to portrait renders correctly too, and ordinary text throughout RNTester (normal asynchronous mounts) is unchanged.

 ---

Found while testing #58109, which hits this on every rotation; standalone, that stack does not include this change.

Reviewed By: andrewdacenko, javache

Differential Revision: D121209981

Pulled By: Abbondanzo

fbshipit-source-id: 6fda49771b08d489623e2bb35c5b59ec46ac03da
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged This PR has been merged. meta-exported p: Facebook Partner: Facebook Partner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant