Skip to content

Conversation

j-piasecki
Copy link
Contributor

@j-piasecki j-piasecki commented Apr 25, 2024

Summary:

Paddings are not applied to inline views in text, this PR fixes that.

Closes #42099

Changelog:

[GENERAL] [FIXED] - Fixed padding not being applied to inline views in text

Test Plan:

A simple test case
      <Text style={{paddingHorizontal: 40, paddingVertical: 40, backgroundColor: 'green', width: 300 }}>
        <View style={{backgroundColor: 'red', width: 50, height: 50}} />
        foobar foobar
        <View style={{backgroundColor: 'red', width: 50, height: 50}} />
      </Text>
iOS before iOS after Android before Android after
Screenshot 2024-04-25 at 17 17 50 Screenshot 2024-04-25 at 17 15 56 Screenshot 2024-04-26 at 11 18 17 Screenshot 2024-04-26 at 11 17 11

@facebook-github-bot facebook-github-bot added CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Software Mansion Partner: Software Mansion Partner labels Apr 25, 2024
@analysis-bot
Copy link

analysis-bot commented Apr 25, 2024

Platform Engine Arch Size (bytes) Diff
android hermes arm64-v8a 19,460,041 +14,284
android hermes armeabi-v7a n/a --
android hermes x86 n/a --
android hermes x86_64 n/a --
android jsc arm64-v8a 22,833,515 +15,224
android jsc armeabi-v7a n/a --
android jsc x86 n/a --
android jsc x86_64 n/a --

Base commit: c96c893
Branch: main

@NickGerleman
Copy link
Contributor

NickGerleman commented Apr 26, 2024

First things that come to mind:

  1. Android and iOS will separately set frame in their own versions of TextLayoutManager. So, before making changes at this specific layer, it would be good to check if iOS does the same thing. Though I can see we are only passing the content frame (frame minus border and padding) as layoutConstraints when measuring string, so I would guess everything is relative to this frame.
  2. If we are not offsetting by padding, we are also likely missing space taken by paragraph border as well (also part of the contentFrame insets)
  3. We should be reading Fabric LayoutMetrics (see above in same function) instead of from Yoga Node directly. It has contentInsets set which is I think what we're looking for

@j-piasecki
Copy link
Contributor Author

Android and iOS will separately set frame in their own versions of TextLayoutManager. So, before making changes at this specific layer, it would be good to check if iOS does the same thing. Though I can see we are only passing the content frame (frame minus border and padding) as layoutConstraints when measuring string, so I would guess everything is relative to this frame.

It seems like it, though the exact mechanism differs between Android and iOS. Both pass layoutConstraints to the relevant measure methods, which are then passed on to the platform-specific code.

On iOS, the text storage with the maximum width is created and used to measure text:

CGSize maximumSize = CGSize{layoutConstraints.maximumSize.width, CGFLOAT_MAX};
NSTextStorage *textStorage = [self _textStorageAndLayoutManagerWithAttributesString:attributedString
paragraphAttributes:paragraphAttributes
size:maximumSize];
return [self _measureTextStorage:textStorage];

On Android, the min/max size is passed to the java measure method:

auto size = yogaMeassureToSize(measure(
fabricUIManager,
rootTag,
componentNameRef.get(),
localDataMap.get(),
propsMap.get(),
nullptr,
minWidth,
maxWidth,
minHeight,
maxHeight,
attachmentPositions));
and then the max width is used to calculate the text layout:
Layout layout =
createLayout(
text,
boring,
width,
widthYogaMeasureMode,
includeFontPadding,
textBreakStrategy,
hyphenationFrequency);

When it comes to drawing, iOS uses the content frame directly:

CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());

On Android the insets are passed on to the native view as padding:

public void setPadding(ReactTextView view, int left, int top, int right, int bottom) {
view.setPadding(left, top, right, bottom);
}

But in both cases, the measurement logic itself is unaware of the padding.

@j-piasecki
Copy link
Contributor Author

If we are not offsetting by padding, we are also likely missing space taken by paragraph border as well (also part of the contentFrame insets)
We should be reading Fabric LayoutMetrics (see above in same function) instead of from Yoga Node directly. It has contentInsets set which is I think what we're looking for

Yes, and yes. Before I saw that the padding itself is not passed to the measurement I tried to access the padding in the measureContent where layoutMetrics are not yet initialized. Then I copied it without updating 🤦.

Using contentInsets also addresses the second point since it includes borders.

@j-piasecki
Copy link
Contributor Author

@NickGerleman Friendly ping in case you missed the response.

@NickGerleman
Copy link
Contributor

@j-piasecki yeah I think the only change needed here is just moving to content insets

@j-piasecki j-piasecki marked this pull request as ready for review April 30, 2024 20:04
@facebook-github-bot
Copy link
Contributor

@NickGerleman has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@facebook-github-bot
Copy link
Contributor

@NickGerleman merged this pull request in 12aef32.

@facebook-github-bot facebook-github-bot added the Merged This PR has been merged. label May 1, 2024
Copy link

github-actions bot commented May 1, 2024

This pull request was successfully merged by @j-piasecki in 12aef32.

When will my fix make it into a release? | How to file a pick request?

kosmydel pushed a commit to kosmydel/react-native that referenced this pull request May 6, 2024
Summary:
Paddings are not applied to inline views in text, this PR fixes that.

Closes facebook#42099

## Changelog:

[GENERAL] [FIXED] - Fixed padding not being applied to inline views in text

Pull Request resolved: facebook#44258

Test Plan:
<details>
<summary>A simple test case</summary>

```jsx
      <Text style={{paddingHorizontal: 40, paddingVertical: 40, backgroundColor: 'green', width: 300 }}>
        <View style={{backgroundColor: 'red', width: 50, height: 50}} />
        foobar foobar
        <View style={{backgroundColor: 'red', width: 50, height: 50}} />
      </Text>
```

|iOS before|iOS after|Android before|Android after|
|-|-|-|-|
|<img width="502" alt="Screenshot 2024-04-25 at 17 17 50" src="https://github.com/facebook/react-native/assets/21055725/e6981de0-6714-4bb0-a006-547b30374b8a">|<img width="546" alt="Screenshot 2024-04-25 at 17 15 56" src="https://github.com/facebook/react-native/assets/21055725/51e8458b-ad4e-4755-865c-664414bfee55">|<img width="457" alt="Screenshot 2024-04-26 at 11 18 17" src="https://github.com/facebook/react-native/assets/21055725/ac351eff-6d24-40a0-bf7e-0cf3782e9368">|<img width="457" alt="Screenshot 2024-04-26 at 11 17 11" src="https://github.com/facebook/react-native/assets/21055725/3284a79a-157d-43ea-b080-849520e2ee7d">|

</details>

Reviewed By: christophpurrer

Differential Revision: D56789213

Pulled By: NickGerleman

fbshipit-source-id: 2dd0e4bf291e20b3e4c4d73f58079d1abafc3f8e
kosmydel pushed a commit to kosmydel/react-native that referenced this pull request Jun 11, 2024
Summary:
Paddings are not applied to inline views in text, this PR fixes that.

Closes facebook#42099

## Changelog:

[GENERAL] [FIXED] - Fixed padding not being applied to inline views in text

Pull Request resolved: facebook#44258

Test Plan:
<details>
<summary>A simple test case</summary>

```jsx
      <Text style={{paddingHorizontal: 40, paddingVertical: 40, backgroundColor: 'green', width: 300 }}>
        <View style={{backgroundColor: 'red', width: 50, height: 50}} />
        foobar foobar
        <View style={{backgroundColor: 'red', width: 50, height: 50}} />
      </Text>
```

|iOS before|iOS after|Android before|Android after|
|-|-|-|-|
|<img width="502" alt="Screenshot 2024-04-25 at 17 17 50" src="https://github.com/facebook/react-native/assets/21055725/e6981de0-6714-4bb0-a006-547b30374b8a">|<img width="546" alt="Screenshot 2024-04-25 at 17 15 56" src="https://github.com/facebook/react-native/assets/21055725/51e8458b-ad4e-4755-865c-664414bfee55">|<img width="457" alt="Screenshot 2024-04-26 at 11 18 17" src="https://github.com/facebook/react-native/assets/21055725/ac351eff-6d24-40a0-bf7e-0cf3782e9368">|<img width="457" alt="Screenshot 2024-04-26 at 11 17 11" src="https://github.com/facebook/react-native/assets/21055725/3284a79a-157d-43ea-b080-849520e2ee7d">|

</details>

Reviewed By: christophpurrer

Differential Revision: D56789213

Pulled By: NickGerleman

fbshipit-source-id: 2dd0e4bf291e20b3e4c4d73f58079d1abafc3f8e
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. p: Software Mansion Partner: Software Mansion Partner
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Text's padding doesn't affect views inside Text component
4 participants