Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(iOS): displaying irregular borders on iOS Fabric #45973

Closed
wants to merge 5 commits into from

Conversation

coado
Copy link
Contributor

@coado coado commented Aug 12, 2024

Summary:

This PR solves issue with displaying irregular borders on Fabric. The same issue appears on the old architecture, but I am having a problems there, so I am pushing this fix for now.

The problem is solved by decoupling backgroundColor from borderLayer and setting zPosition on borderLayer to 1024.0f, so that the border is always in front of the layer. The zPosition is compared within a layer, so it shouldn't impact outside components. I would love to hear your opinion if there is a case in which this could break.

Changelog:

[IOS] [FIXED] - changed border display

Test Plan:

I've checked that on RNTester Images.

border-issues-screen

@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 Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. labels Aug 12, 2024
Copy link
Contributor

@cipolleschi cipolleschi left a comment

Choose a reason for hiding this comment

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

great job here...
I guess that that -1024 was definitely the main issue.

I think that this implementation is correct.

What problem are you facing with the old arch? Is fine to have a separate PR for that.

@facebook-github-bot
Copy link
Contributor

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

@coado
Copy link
Contributor Author

coado commented Aug 12, 2024

I am trying to replicate the same mechanism (creating a borderLayer and setting it as a sublayer of layer). Unfortunately, the zPosition makes the border come above children of the view. I am not sure why is that, but I am still working on it.

screen-issue

@@ -681,7 +681,7 @@ - (void)invalidateLayer
} else {
if (!_borderLayer) {
CALayer *borderLayer = [CALayer new];
borderLayer.zPosition = -1024.0f;
borderLayer.zPosition = 1024.0f;
Copy link
Contributor

Choose a reason for hiding this comment

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

Hi, maybe you can check the code history, and it introduce borderLayer is because CSS draws the border behind the content :) .

https://github.com/facebook/react-native/pull/45973/files#diff-fce237eeca8733cbef40d994a0c0a154026be79e681b103b4afde567dd42330bL659-L661

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, css draws a border behind the component's children. In the provided solution, the border is still drawn behind the inner content of the element. I think that layer's zPosition applies only within a layer, so it shouldn't have an impact outside of that. The above problem looks like this after the changes on Fabric:

image

Copy link
Contributor

Choose a reason for hiding this comment

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

Emm, zPosition also affects the view or layer for the same hierarchy, For example like below, setting border layer's zPosition to 1024 can cover the content of SubView1 I think.

View
---border layer
---SubView1
------Subview of SubView1

Copy link
Contributor

Choose a reason for hiding this comment

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

BTW, I'm trying to refactor the Text to support border, you can try #45972 and applied your code, you can see border is cover the text like below: :)

image

We hope to see this:
image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately, the iOS docs are not too descriptive about how the zPosition works 😕 I will try to think about other solution.

Copy link
Contributor

@cipolleschi cipolleschi left a comment

Choose a reason for hiding this comment

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

The approach is promising, but it breaks another use case: Animated-MovingView

BEFORE AFTER
before after
You can see that the blue background is not clipped and is present outside the rounded corners.

The suggested approach from @joevilches would be to take out the background color entirely from that method and implement the border drawing in CG correctly without it.
Also, we should test for dotted and dashed borders if possible.

Many thanks for working on this!

UIImage *image = RCTGetBorderImage(
RCTBorderStyleFromBorderStyle(borderMetrics.borderStyles.left),
layer.bounds.size,
RCTCornerRadiiFromBorderRadii(borderMetrics.borderRadii),
RCTUIEdgeInsetsFromEdgeInsets(borderMetrics.borderWidths),
borderColors,
backgroundColor,
transparentBackgroundColor,
Copy link
Contributor

Choose a reason for hiding this comment

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

Feedback @joevilches on this line:

I feel like we should just get rid of this param at this point. It's still used in the old arch but they are both relying on iOS graphics at that point so we should be able to refactor both of these.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am not sure if we can get rid of the background here. If we set the background in the layer instead of borderLayer, components that have clipsToBounds = false may not be drawn correctly. This causes the above-mentioned bug of not clipping the background.

@coado
Copy link
Contributor Author

coado commented Aug 13, 2024

The new approach clips the inner image separately (as this bug occurs for images only) according to its bounds and the border's corner insets. We keep the previous value of zPosition, so it should be drawn in the same way as css does.

@coado coado requested a review from cipolleschi August 13, 2024 14:35
@cipolleschi
Copy link
Contributor

@coado could you please resolve the merge conflict? 🙏

@joevilches
Copy link
Contributor

joevilches commented Aug 13, 2024

What do you think of this solution?

  • Set the zPosition of the contentView (which holds the image, among other things), to be less than the borderLayer
  • Refactor border drawing the be agnostic of the layer's background color (so resulting image is just the border, no pixels for background color). If we do not do this, the backgroundColor would now hide the contentView that is under this layer.
  • Introduce a layer that holds the background color and the appropriate shape using mask, if necessary. This layer would go under all other layers
    • If we are clipping for this view then we wouldn't need to do this, we could just set the mask on the current layer, but its a generalized solution for all cases. We could optimize fast paths if needed like those that currently exist for border rounding

Btw, this area has a ton of churn right now. There is this PR, @jorge-cab is working on asymmetrical border radius % in #46009, and I am prototyping how to get box shadows to work with clipping (which relates to borders and masks). I feel like we just need to clean this area up some, and have a good story for how each element of the background/border area works.

Lmk if the steps above would miss some edge case you have thought about

@joevilches
Copy link
Contributor

Hey @coado, was thinking about this more and the above refactor I mentioned would in theory fix some problem I am running across with trying to get outset box shadows to work with clipping, so I went ahead and started on some of that refactor (specifically the second bullet point). I think we can just land this as is, but I might refactor some of it in the coming days

@coado
Copy link
Contributor Author

coado commented Aug 14, 2024

Hey @coado, was thinking about this more and the above refactor I mentioned would in theory fix some problem I am running across with trying to get outset box shadows to work with clipping, so I went ahead and started on some of that refactor (specifically the second bullet point). I think we can just land this as is, but I might refactor some of it in the coming days

Hey, so I've resolved the merge conflicts. I was thinking about the solution that you provided, but I wasn't sure if we wanted to keep the border in front of the image. I think it will work, but I haven't tested it myself. Should I proceed with it or is it something that you want to implement in the future?

@facebook-github-bot
Copy link
Contributor

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

@facebook-github-bot facebook-github-bot added the Merged This PR has been merged. label Aug 14, 2024
@facebook-github-bot
Copy link
Contributor

@cipolleschi merged this pull request in 94407f5.

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 Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants