Fix hairline borders not visible
This commit is contained in:
committed by
Samuel Newman
parent
a086a2ebe0
commit
d52b760852
@@ -403,3 +403,25 @@ index 3e48dabc6fffc246fd0517ef5f3f2b7721115511..ea4ba5fdf359c513a5ca4f0e94492fac
|
|||||||
- }
|
- }
|
||||||
+ auto rootShadowNodeHolder = shadowTree.getCurrentRevision().rootShadowNode;
|
+ auto rootShadowNodeHolder = shadowTree.getCurrentRevision().rootShadowNode;
|
||||||
+ const auto* rootShadowNode = rootShadowNodeHolder.get();
|
+ const auto* rootShadowNode = rootShadowNodeHolder.get();
|
||||||
|
diff --git a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm
|
||||||
|
--- a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm
|
||||||
|
+++ b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm
|
||||||
|
@@ -827,9 +827,17 @@
|
||||||
|
} else {
|
||||||
|
CGSize imageSize = image.size;
|
||||||
|
UIEdgeInsets imageCapInsets = image.capInsets;
|
||||||
|
+ // The stretchable middle is whatever lies between the cap insets. The image
|
||||||
|
+ // may be larger than capInsets + 1 (its size is ceil'd to whole points), so
|
||||||
|
+ // deriving the middle from the caps rather than assuming a 1pt band keeps
|
||||||
|
+ // the bottom/right caps at their true size. A phantom cap here makes the
|
||||||
|
+ // caps overflow sub-pixel-sized layers (e.g. hairline borders), and the
|
||||||
|
+ // squeezed mesh + nearest-neighbor filtering drops the stroke entirely.
|
||||||
|
CGRect contentsCenter = CGRect{
|
||||||
|
CGPoint{imageCapInsets.left / imageSize.width, imageCapInsets.top / imageSize.height},
|
||||||
|
- CGSize{(CGFloat)1.0 / imageSize.width, (CGFloat)1.0 / imageSize.height}};
|
||||||
|
+ CGSize{
|
||||||
|
+ (imageSize.width - imageCapInsets.left - imageCapInsets.right) / imageSize.width,
|
||||||
|
+ (imageSize.height - imageCapInsets.top - imageCapInsets.bottom) / imageSize.height}};
|
||||||
|
layer.contents = (id)image.CGImage;
|
||||||
|
layer.contentsScale = image.scale;
|
||||||
|
|
||||||
|
|||||||
@@ -159,3 +159,22 @@ PR: https://github.com/facebook/react-native/pull/57483
|
|||||||
|
|
||||||
Issue: https://github.com/react/react-native/issues/53450#issuecomment-3298157830
|
Issue: https://github.com/react/react-native/issues/53450#issuecomment-3298157830
|
||||||
Bandaid fix taken from: https://github.com/react/react-native/commit/581d643a9e59fd88f93757f80194e1efd11bd0e5
|
Bandaid fix taken from: https://github.com/react/react-native/commit/581d643a9e59fd88f93757f80194e1efd11bd0e5
|
||||||
|
|
||||||
|
## RCTViewComponentView.mm Patch - Hairline border strokes dropped at certain subpixel Y offsets on New Arch
|
||||||
|
|
||||||
|
Symptom: dividers built as `borderTopWidth: hairlineWidth` vanish on some screens and not
|
||||||
|
others, deterministically by the view's absolute subpixel Y. A background fill of the same
|
||||||
|
geometry always renders.
|
||||||
|
|
||||||
|
Cause: Fabric draws borders as a stretched 9-slice image. The consumer
|
||||||
|
(`RCTAddContourEffectToLayer`) hardcodes the stretchable middle as a 1pt band, which matched
|
||||||
|
the image the producer built until RN 0.81. facebook/react-native#54237 changed the image
|
||||||
|
size to `ceil(insets) + 1 + ceil(insets)` without updating that formula, so for fractional
|
||||||
|
(hairline) insets the labels no longer match the image: transparent filler is treated as a
|
||||||
|
rigid cap, and when squeezed into a one-pixel-tall layer the sampling can land on it instead
|
||||||
|
of the stroke - no line.
|
||||||
|
|
||||||
|
Fix: compute the middle from the cap insets (`size - caps`) instead of assuming 1pt.
|
||||||
|
|
||||||
|
Upstream issue: https://github.com/react/react-native/issues/58054 (repro:
|
||||||
|
https://github.com/abulenok/HairlineBorderRepro, fails identically on 0.86.0 and 0.87.0).
|
||||||
|
|||||||
Generated
+326
-326
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,6 @@ import {createContext, useContext, useMemo} from 'react'
|
|||||||
import {
|
import {
|
||||||
type GestureResponderEvent,
|
type GestureResponderEvent,
|
||||||
type StyleProp,
|
type StyleProp,
|
||||||
StyleSheet,
|
|
||||||
View,
|
View,
|
||||||
type ViewStyle,
|
type ViewStyle,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
@@ -255,10 +254,10 @@ export function Divider({style}: ViewStyleProp) {
|
|||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
|
a.border_t,
|
||||||
|
t.atoms.border_contrast_low,
|
||||||
a.w_full,
|
a.w_full,
|
||||||
a.my_sm,
|
a.my_sm,
|
||||||
{height: StyleSheet.hairlineWidth},
|
|
||||||
t.atoms.bg_contrast_100,
|
|
||||||
style,
|
style,
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user