forked from facebook/react-native
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use CALayers to draw text (facebook#24387)
Summary: The current technique we use to draw text uses linear memory, which means that when text is too long the UIView layer is unable to draw it. This causes the issue described [here](facebook#19453). On an iOS simulator the bug happens at around 500 lines which is quite annoying. It can also happen on a real device but requires a lot more text. To be more specific the amount of text doesn't actually matter, it is the size of the UIView that we use to draw the text. When we use `[drawRect:]` the view creates a bitmap to send to the gpu to render, if that bitmap is too big it cannot render. To fix this we can use `CATiledLayer` which will split drawing into smaller parts, that gets executed when the content is about to be visible. This drawing is also async which means the text can seem to appear during scroll. See https://developer.apple.com/documentation/quartzcore/calayer?language=objc. `CATiledLayer` also adds some overhead that we don't want when rendering small amount of text. To fix this we can use either a regular `CALayer` or a `CATiledLayer` depending on the size of the view containing the text. I picked 1024 as the threshold which is about 1 screen and a half, and is still smaller than the height needed for the bug to occur when using a regular `CALayer` on a iOS simulator. Also found this which addresses the problem in a similar manner and took some inspiration from the code linked there GitHawkApp/StyledTextKit#14 (comment) Fixes facebook#19453 ## Changelog [iOS] [Fixed] - Use CALayers to draw text, fixes rendering for long text Pull Request resolved: facebook#24387 Test Plan: - Added the example I was using to verify the fix to RNTester. - Made sure all other examples are still rendering properly. - Tested text selection Reviewed By: shergin Differential Revision: D15918277 Pulled By: sammy-SC fbshipit-source-id: c45409a8413e6e3ad272be39ba527a4e8d349e28
- Loading branch information
1 parent
49713d2
commit 1998995
Showing
6 changed files
with
222 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/** | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
#import <UIKit/UIKit.h> | ||
|
||
NS_ASSUME_NONNULL_BEGIN | ||
|
||
/** | ||
* Used by text layers to render text. Note that UIKit crashes if this delegate is implemented | ||
* directly on a UIView subclass since it already implements it for the view's root | ||
* layer. This is why this is implemented in a separate class. | ||
*/ | ||
@interface RCTTextRenderer : NSObject <CALayerDelegate> | ||
|
||
- (void)setTextStorage:(NSTextStorage *)textStorage contentFrame:(CGRect)contentFrame; | ||
|
||
@end | ||
|
||
NS_ASSUME_NONNULL_END |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/** | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
#import "RCTTextRenderer.h" | ||
|
||
#import "RCTTextAttributes.h" | ||
|
||
@implementation RCTTextRenderer | ||
{ | ||
NSTextStorage *_Nullable _textStorage; | ||
CGRect _contentFrame; | ||
} | ||
|
||
- (void)setTextStorage:(NSTextStorage *)textStorage | ||
contentFrame:(CGRect)contentFrame | ||
{ | ||
_textStorage = textStorage; | ||
_contentFrame = contentFrame; | ||
} | ||
|
||
- (void)drawLayer:(CALayer *)layer | ||
inContext:(CGContextRef)ctx; | ||
{ | ||
if (!_textStorage) { | ||
return; | ||
} | ||
|
||
CGRect boundingBox = CGContextGetClipBoundingBox(ctx); | ||
CGContextSaveGState(ctx); | ||
UIGraphicsPushContext(ctx); | ||
|
||
NSLayoutManager *layoutManager = _textStorage.layoutManagers.firstObject; | ||
NSTextContainer *textContainer = layoutManager.textContainers.firstObject; | ||
|
||
NSRange glyphRange = | ||
[layoutManager glyphRangeForBoundingRect:boundingBox | ||
inTextContainer:textContainer]; | ||
|
||
[layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:_contentFrame.origin]; | ||
[layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:_contentFrame.origin]; | ||
|
||
UIGraphicsPopContext(); | ||
CGContextRestoreGState(ctx); | ||
} | ||
|
||
- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event | ||
{ | ||
// Disable all implicit animations. | ||
return (id)[NSNull null]; | ||
} | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file modified
BIN
-166 Bytes
(100%)
...ests/ReferenceImages/RNTester-js-RNTesterApp.ios/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters