Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,34 @@
#import <react/renderer/textlayoutmanager/TextLayoutManager.h>
#import <react/utils/ManagedObjectWrapper.h>

#import <React/RCTUtils.h>
#import "RCTConversions.h"
#import "RCTFabricComponentsPlugins.h"

using namespace facebook::react;

/*
* The content frame with its height snapped back onto the pixel grid. Yoga
* rounds the frame to the grid but subtracts the two rounded edges as floats,
* so far from the origin the height can come out a float step under the grid
* value the paragraph was measured at: 43.9998 instead of 44 for two lines of
* lineHeight 22 at y = 2048 on a 3x screen. TextKit treats a container that
* short as too small for the last line and lays it out clipped. Anything else
* is rounded up, so the container is never made smaller.
* See https://github.com/facebook/react-native/issues/58970.
*/
static CGRect RCTParagraphTextFrame(const LayoutMetrics &layoutMetrics)
{
CGRect frame = RCTCGRectFromRect(layoutMetrics.getContentFrame());
CGFloat scale = RCTScreenScale();
if (scale > 0 && !isnan(frame.size.height)) {
CGFloat scaled = frame.size.height * scale;
CGFloat nearest = round(scaled);
frame.size.height = (fabs(scaled - nearest) < 0.01 ? nearest : ceil(scaled)) / scale;
}
return frame;
}

@interface RCTTextLayoutManager (RCTParagraphComponentViewPrivate)

- (CGRect)drawingFrameForAttributedString:(facebook::react::AttributedString)attributedString
Expand Down Expand Up @@ -178,7 +201,7 @@ - (void)prepareForRecycle
- (void)_updateTextViewFrame
{
CGRect textViewFrame = self.bounds;
CGRect drawingFrame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
CGRect drawingFrame = RCTParagraphTextFrame(_layoutMetrics);

if (ReactNativeFeatureFlags::enableIOSCompressedTextFrameAdjustment() && _textView.state &&
drawingFrame.size.height > 0) {
Expand Down Expand Up @@ -474,4 +497,4 @@ - (void)drawRect:(CGRect)rect
}];
}

@end
@end
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,31 @@
(layoutConstraints).maximumSize.height)

namespace facebook::react {

namespace {

/*
* Yoga rounds a node's frame to the pixel grid, but it subtracts the two
* rounded edges as floats, so far from the origin the height can come out a
* float step under the grid value the paragraph was measured at: 43.9998
* instead of 44 for two lines of lineHeight 22 at y = 2048 on a 3x screen.
* Laid out in a container that short, the last line does not fit and is
* drawn clipped. Snap such a height back onto the grid; anything else is
* rounded up, so a container is never made smaller.
* See https://github.com/facebook/react-native/issues/58970.
*/
Float snapHeightToPixelGrid(Float height, Float pointScaleFactor) {
if (pointScaleFactor <= 0 || std::isnan(height)) {
return height;
}
const auto scaled = height * pointScaleFactor;
const auto nearest = std::round(scaled);
const auto snapped =
std::abs(scaled - nearest) < 0.01f ? nearest : std::ceil(scaled);
return snapped / pointScaleFactor;
}

} // namespace
using Content = ParagraphShadowNode::Content;

// NOLINTNEXTLINE(facebook-hte-CArray, modernize-avoid-c-arrays)
Expand Down Expand Up @@ -305,6 +330,10 @@ void ParagraphShadowNode::layout(LayoutContext layoutContext) {
auto size = ReactNativeFeatureFlags::enablePreparedTextLayout()
? rawContentSize()
: layoutMetrics.getContentFrame().size;
if (!ReactNativeFeatureFlags::enablePreparedTextLayout()) {
size.height =
snapHeightToPixelGrid(size.height, layoutContext.pointScaleFactor);
}

LayoutConstraints layoutConstraints{
.minimumSize = size,
Expand Down Expand Up @@ -445,4 +474,4 @@ void ParagraphShadowNode::layout(LayoutContext layoutContext) {
}
}

} // namespace facebook::react
} // namespace facebook::react
Loading