Summary:
Changelog:
[Internal] - Change the accessibilityRole from a string to an enum.
The change aims to save storage especially when scaling. Also, the enum makes it more difficult to input wrong because it gets checked when compiling.
Reviewed By: sammy-SC
Differential Revision: D22396351
fbshipit-source-id: b46ce0bd156c7705020ef5b061d8ac29e2cf3948
Summary:
Changelog:
[Internal] - Add `accessibilityRole` to `RCTAttributedTextUtils`. AccessibilityRole was in `TextAttributes` which is a Fabric's abstraction so cannot be detected when enumerating attributedString. Mapping accessibilityRole from `TextAttributes` to `NSAttributedString` could provide the attributeName when iterating over attributedString and then successfully find the range of the fragment whose `accessibilityRole` has value @"link".
Reviewed By: shergin
Differential Revision: D22286747
fbshipit-source-id: eb039d6a35e77d1860f86ba287391ccb56fbe7b5
Summary:
Changelog:
[iOS][Added] - `getRectWithAttributedString()` aims to get the rect of the fragment with embedded link, which is necessary when building the `accessibilityElement`. In this function, we first enumerate attributedString to find the range of fragments whose `accessibilityRole` is @"link". Then we calculate the rect of the fragment and send to the block and we would define what to do in the block in `RCTParagraphComponentAccessibilityProvider`.
Reviewed By: shergin
Differential Revision: D22286733
fbshipit-source-id: 4d11cb54375a4e9e72869e646fcb484de089b14b
Summary:
Changelog: [Internal]
Add support for dynamic font size.
New class `ThreadStorage` is introduced, which is used to pass LayoutContext to `YogaLayoutableShadowNode::yogaNodeMeasureCallbackConnector`.
## Shortcoming
This implementation doesn't cause re-render, if user changes font size and comes to the app without restarting it, it will show old font size. I believe this is fine for now as most people set their font size before they use the app and keep the same setting for a long time.
Reviewed By: shergin
Differential Revision: D22043728
fbshipit-source-id: 7453d165c280a2f4bcb73f4ee6daf9e64b637ded
Summary:
Changelog: [Internal]
Round calculated text size to closest larger pixel size.
In Paper we do this as well in https://fburl.com/diffusion/w2pj6ea0
Why do we need this?
For example, we calculate height of the text to be 16.707235, yoga takes this value and assigns text to have height 17 anyway.
I assume Yoga uses this extra 0.3 points of height to move other things around a little bit because Yoga doesn't deal with exact values.
Reviewed By: shergin
Differential Revision: D21999032
fbshipit-source-id: 73923dc3e27fa110adb3f76cfa635e0bfdc672d4
Summary:
While I was investigated the previous issue (T59430348) I found this place where we manipulate managed pointers manually. So, to make it error-prone this diff changes it to use `wrapManagedObject`.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: JoshuaGross
Differential Revision: D21943010
fbshipit-source-id: ecaeffb419ae8d4880187027ca7ec9563e0dfd46
Summary:
This diff changes API we use to measure text. Previously, a platform-specific measure infra returned just the size of the text, now it returns the size and an array of frames that describe where attachments are placed.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: sammy-SC
Differential Revision: D20268041
fbshipit-source-id: 7c065607b6af18a36318db0aab24dad0f171d33a
Summary:
Investigating a crash, I spend half of an hour staring at `__bridge`, `__bridge_retained`, `CFRelease` and etc trying to understand is there a bug or not. Even if I think there was no bug there, it should not be this way. We have a nice abstraction around that madness we should use to make the code obvious.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: sammy-SC
Differential Revision: D20260917
fbshipit-source-id: 2b511ebf46a78950c4720e749099134aed1dd890
Summary:
We are moving towards 100%-prettified files. That's the first step when we apply Clang Format for `ReactCommon`.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D20110895
fbshipit-source-id: 0a0ce4997cf1c3721b0b07ef78c1a57ce87d20f9
Summary:
With new logic we save one attributed string copy operation.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: sammy-SC
Differential Revision: D19844371
fbshipit-source-id: 62f6b0f9c8514a1b55224ccaa52c8fa89c06c9e7
Summary:
Fixes https://github.com/facebook/react-native/issues/27137
This PR fixes an issue on iOS where RCTTextView height is not calculated as it should for some fonts where font `leading` attributed is not equal to zero, which results in wrong baseline alignment behaviour.
The fix for this is by setting `usesFontLeading` property of `NSLayoutManager` to `NO`, which results is a layout behavior that is similar to `UILabel`
Probably the documentation for `usesFontLeading` describes why UILabel has a different (correct) layout behavior in that case
> // By default, a layout manager will use leading as specified by the font. However, this is not appropriate for most UI text, for which a fixed leading is usually specified by UI layout guidelines. These methods allow the use of the font's leading to be turned off.
## Changelog
[iOS] [Fixed] - Fix RCTTextView layout issue that happens on some font with `leading` attribute not equal to zero, which causes wrong base-alignment layout
Pull Request resolved: https://github.com/facebook/react-native/pull/27195
Test Plan:
Below are the test results before and after the change, and comparing that to native UILabel behavior.
The test is done with using system font and custom font (`GothamNarrow-Medium`) and font size 50
[GothamNarrow-Medium.otf.zip](https://github.com/facebook/react-native/files/3832143/GothamNarrow-Medium.otf.zip)
```js
const App: () => React$Node = () => {
return (
<View style={{flex: 1, margin: 40, flexDirection: 'row', justifyContent: 'center', alignItems: 'baseline'}}>
<View style={{width: 30, height: 30, backgroundColor: 'lightgray'}} />
<Text style={{fontSize: 50, backgroundColor: 'green', fontFamily: 'GothamNarrow-Medium'}}>{'Settings'}</Text>
</View>
);
};
```
-------
### Before the fix
<img width="962" alt="Screenshot 2019-11-11 at 16 53 26" src="https://user-images.githubusercontent.com/5355138/68601049-dd778780-04a3-11ea-879e-cc7b4eb2af95.png">
-----
### After the fix
<img width="944" alt="Screenshot 2019-11-11 at 16 55 11" src="https://user-images.githubusercontent.com/5355138/68601180-1d3e6f00-04a4-11ea-87bc-61c6fa2cdb18.png">
-----
### Using `UILabel`
<img width="805" alt="Screenshot 2019-11-11 at 16 59 28" src="https://user-images.githubusercontent.com/5355138/68601487-b2d9fe80-04a4-11ea-9a0f-c025c7753c24.png">
Differential Revision: D19576556
Pulled By: shergin
fbshipit-source-id: 4eaafdab963c3f53c461884c581e205e6426718a
Summary:
This is C++ part of the implementation of Fabric-compatible <TextInput> component on iOS.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: JoshuaGross
Differential Revision: D19169987
fbshipit-source-id: e2eac9beac6d1e124b5176b4a23676b8e05490c3
Summary:
It's nice to have those conversions between NSAttributedString and AttributedTextBox in some utils module because:
An empty string must be stored as an empty C++ string, not like an empty NSAttributedString. That allows deferring this property from the object without accessing Objective-C runtime;
It's nice to hide some tedious Objective-C object wrapping/unwrapping boilerplate.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: sammy-SC
Differential Revision: D18950430
fbshipit-source-id: 842c202f243da17c47bc5cca9df6722cdcec07c5
Summary:
We need to use that outside of this file, in Fabric's TextInputComponentView to build `defaultTextAttributes` from C++ text attributes.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: sammy-SC
Differential Revision: D18950433
fbshipit-source-id: c48155f4340b7e9780c35f86ba5155e54f160be1
Summary:
Same as D18048277 but for Fabric text infra.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: PeteTheHeat
Differential Revision: D18950415
fbshipit-source-id: 09701e261ecb871b3624260a36dd607fdb70e717
Summary:
Special thanks for Joshua Gross for flagging this problem!
This diff implements a custom evicting hash map designed specially to hold text measurement information. The key feature of this is custom equality checks and hashing functions.
They are designed around the following principals:
* Decorative text attributes (such as color, shadows, etc) has no effect on layout, therefore they should not be taking into account;
* `minimum height`, `minimum width`, and `maximum height` don't affect the measurement;
* the value of `layout metrics` are important only for `attachment` fragments.
After I redo all tests, I will enable this for Android-specific TextLayoutManager in separate diff.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: sammy-SC
Differential Revision: D18848583
fbshipit-source-id: 46c2fc445fbd1823afc5e7498e37de75381258b1
Summary:
In the previous diff, we noted that the maximum height is not really important for text measurement. That diff make is in code.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: sammy-SC
Differential Revision: D18848585
fbshipit-source-id: 5fe0ea8f76487a50baa8a2e024663a85afcd9861
Summary:
Here the deal with the clamp thing:
A layout engine asks nodes to measure their content providing layout constraints (min and max size) and that would be kind from nodes to return a result that in space of those constraints. Sometimes, satisfying that is an additional separate step of that operation, e.g. if we know that the intrinsic size of some node is `{100, 100}`, we need to clamp that to satisfy constraint `[min: {200, 200}, max: {inf, inf}]`.
In case when we need to cache measure information, it becomes tricky enough when we need to make the cache work most efficiently. For the case of measuring Text, we have an insight: the available maximum width is important, the rest three metrics (maximum height and minimum size) are not.
That means that any changes in those three metrics don't affect the actual measurement result but will affect the final value because the actual value will be clamped by constraints that didn't influence measuring in the first place.
That's why moving clamping outside of a cache is the first step into making it more efficient.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: sammy-SC
Differential Revision: D18848584
fbshipit-source-id: 8feeb3f1a9d0e9691abac8be43639487a626fec3
Summary:
Sometimes, very irregularly, measuring an empty string crashes/freezes iOS internal text infrastructure. This is our last line of defense.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: sammy-SC, mdvacca
Differential Revision: D18802308
fbshipit-source-id: addf523b31b78b0777be7eeaeee140ac8416393b
Summary:
Now RCTTextLayoutManager (and TextLayoutManager) not only accept `AttributedStringBox` but also is capable to measure such kind of string when it contains a pointer to NSAttributedString.
The same can be implemented for Android when/if needed.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: sammy-SC
Differential Revision: D18670791
fbshipit-source-id: f19089de64d00e1290767310a500ade4cede4685
Summary:
The diff implements a new class called `AttributedStringBox` that represents an object storing a shared `AttributedString` *or* a shared pointer to some opaque platform-specific object that can be used as an attributed string. The class serves two main purposes:
- Represent type-erased attributed string entity (which can be platform-specific or platform-independent);
- Represent a container that can be copied with constant complexity.
Why? Several reasons:
- Sometimes it makes sense to keep an attributed string as a shared resource. This way we don't need to pay for expensive copying and we also implement a copy-on-write semantics on top of that if needed.
- We need to extend a TextLayoutMeasure API to support measuring some platform-specific attributed string implementation to remove the necessity of converting a string back and forth between representations. That's especially important for TextInput because we will need to measure that very efficiently (and the source of measuring, in this case, is a platform attributed string).
In other words, we need something to store inside TextInputState to measure and update very efficiently. The source of this data might be a native TextInput control or a data from React, to represent that kinda object we need this data structure (and interfaces that deal with it).
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: sammy-SC
Differential Revision: D18670793
fbshipit-source-id: bc0164f801f28642f7c6da340af12acf33b85d24
Summary:
... because the original name made no sense.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: sammy-SC
Differential Revision: D18607834
fbshipit-source-id: bf32d2b61d1c3deccba0b599b303ede0b82e6dd6
Summary:
Before this change `AttributedString::Fragment` had two ShadowView objects (`shadowView` and `parentShadowView`). This diff unifies those two things into one. That allows us to save some CPU and memory and makes things a bit simpler. Besides that, now the length of NSAttributedString and AttributedString is now always the same (it's one Unicode character for an attachment for both).
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: JoshuaGross
Differential Revision: D18607658
fbshipit-source-id: 502ae244e98a52694adc0d646650f8ea0d7922ae
Summary:
We will have several consumers for the measure infra soon (TextInput will use the same TextLayoutManager). It makes sense to move the cache there.
In the future, iOS and Android implementations will probably use a bit different (platform-specific) cache implementations because we will implement the ability to measure "opaque"/platform-specific text containers alongside with normal AttributeStrings.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: mdvacca
Differential Revision: D18445855
fbshipit-source-id: 7b7a65152ac13c74525da695612ae034904e82bf
Summary: We need to have a weak semantic for the ManagedObjectWrapper, this diff implements that.
Reviewed By: sammy-SC
Differential Revision: D17773699
fbshipit-source-id: 978fa62191361c3b2c0e46c423240831ed1dd233
Summary:
We use `ViewManager.onMeasure` to perform measurements of Android views and pass the measured size back to Yoga. For Android in order to the report correct dimensions of a View, this View must be created using a Context that has a theme associated with it. Before, `onMeasure` only had ReactApplicationContext passed as the first parameter and ReactSwitch, for example, could not be measured correctly (because it uses the size of the thumb drawable, which is extracted from the current theme). This diff adds surfaceId as the first parameter of `FabricUIManager.measure`, so that we can retrieve ThemedReactContext and pass it to `ViewManager.onMeasure`.
The size of the Switch component is still incorrect, but at least the size reported back to Yoga is the same as in Paper. So there is more investigation necessary why this happens in Fabric. I will investigate and publish another diff with the fix.
Reviewed By: JoshuaGross, shergin
Differential Revision: D17625959
fbshipit-source-id: 48197a61240fb13042bef3e9f5d681acacc702fb
Summary:
Address Sanitizer told me that I have UB in `RCTUIFontWeightFromFloat` and it was right. After a short investigation, I find out that the original assumption that `UIFontWeight` values are practically numbers from 100 to 900 was incorrect. In my simulator, it's something like from `-1` to `+1` (irregularly!). So, the whole subsystem worked only by accident.
This diff fixes that; now we never assume which actual values `UIFontWeight` constants have.
I will publish code style fixes as a separate diff (otherwise it will be really hard to review).
Reviewed By: JoshuaGross
Differential Revision: D15756620
fbshipit-source-id: d7f888e85815d863487c6b68a960e39fd473e095
Summary:
Set `sizeMultiplier` to `1.0` if default value is `NAN`, otherwise, text cannot show properly.
## Changelog
[iOS] [Fixed] - Add NAN check for text font sizeMultiplier
Pull Request resolved: https://github.com/facebook/react-native/pull/24966
Differential Revision: D15466559
Pulled By: shergin
fbshipit-source-id: 6f8b47eb8e521cb120d7f351cba02dbf1c5411fd
Summary:
Creation NSAttributedString from attributedString is not so cheap process, so with this simple cache we hopefully can save a couple milliseconds.
The same string is used at least two times: first time for measuring and second for drawing.
Reviewed By: mdvacca
Differential Revision: D14296514
fbshipit-source-id: 6313aa2c6e9f63d873868131750f61c02d64d2de
Summary: Trivial diff that cleans up measure function in C++ and Android
Reviewed By: shergin
Differential Revision: D13200340
fbshipit-source-id: 6c0888439640241cdedf514898a1ba3dac231d6a
Summary:
That's generally better because:
* Avoids exposing ShadowNode to mounting layer;
* Enables hashing and comparing the AttributedString based on actual meaningful data (not on just a pointer to ShadowNode).
Reviewed By: mdvacca
Differential Revision: D13205230
fbshipit-source-id: 7b79c1aad97b10d81e3faa10408be61b74f815cf
Summary:
Previously, we stored a pointer to ShadowNode inside NSAttributedString's attributes to make possible retrieving an EventEmitter associated with some text fragment.
That worked fine besides only one caveat: the internal implementation of NSAttributedString is quite strange and that causes a memory leak. Because of some reason, NSAttributedString does not release stored attributes after own destruction (maybe OS uses some kind of caching).
So, now, instead of storing a strong pointer to ShadowNode inside NSAttributedString, we store a weak pointer to EventEmitter. Storing a weak pointer is okay because a desired lifetime of EventEmitter is guaranteed by LocalData stored inside a View. Storing a weak EventEmitter instead of weak ShadowNode will also help us with migration to ShadowView (we cannot store ShadowView weakly because it's a stack allocated object).
Reviewed By: sahrens
Differential Revision: D13196886
fbshipit-source-id: f8714e4b3709765629d6456edf0c635bf5f7c53b
Summary: We are moving to more stable APIs removing all mentiones of the effort name from the codebase.
Reviewed By: mdvacca
Differential Revision: D12912894
fbshipit-source-id: 4a0c6b9e7454b8b14e62d419e9e9311dc0c56e7a
Summary: This is the second and the final part of adopting clang-format.
Reviewed By: mdvacca
Differential Revision: D10229624
fbshipit-source-id: d97670b716800ea2488b84bd0aacaf54d8bd2e31
Summary: In this diff I added support to be able to measure C++ shadowNode in Android. As an example I implemented the measurement of TextViews
Reviewed By: shergin
Differential Revision: D9583972
fbshipit-source-id: 1344782d4c586c94a4576b18a4acfa4775e46952
Summary: This change drops the year from the copyright headers and the LICENSE file.
Reviewed By: yungsters
Differential Revision: D9727774
fbshipit-source-id: df4fc1e4390733fe774b1a160dd41b4a3d83302a
Summary:
When text nodes are nested, as below, `onPress` handlers need to be correctly invoked:
```
render() {
return (
<Text onPress={() => console.warn('hi')}>
hi
<Text onPress={() => console.warn('ramanpreet')}>ramanpreet</Text>
</Text>
);
}
```
In the above example, clicking on "hi" should warn "hi", and clicking on "ramanpreet" should warn "ramanpreet". This diff implements that behaviour.
Reviewed By: shergin
Differential Revision: D9696905
fbshipit-source-id: 2daf24e76c3b3c37aa36cd1540e54876a367faf7
Summary:
When a user clicks on some text, `RCTSurfaceTouchHandler` will call into a method on `RCTParagraphComponentView`. That method (i.e: `touchEventEmitter`) would be responsible for identifying the closest ancestral `<Text/>` component to which we should dispatch the `onPress` event, given the point where the user clicked. To answer this query, we'll use a data structure called `UIAttributedString`.
This data structure represents a string, and a corresponding mapping from sequences of its characters to some arbitrary data. In this attributed string, we'll map sequences of characters to their closest ancestral `ParagraphShadowNode` or `TextShadowNode`. That way, when we get a click event on `RCTParagraphComponentView`, we can just look at the character that was clicked, and use that information to do a lookup in the attributed string to find the shadow node who's EventEmitter is responsible for processing the click event.
Reviewed By: shergin
Differential Revision: D9696904
fbshipit-source-id: a199649981ad271afa85414ce4c3f056851348be
Summary:
@public
This diff consists of many interdependent changes which support one simple idea: YogaLayoutableShadowNode is now using YGNode children to iterate on them (it previously relied on `ShadowNode::getChildren()`). All other changes are just an unavoidable consequence of that. Hence we don't need to filter child nodes every single time when we do layout anymore! The logic around `clone callback` is also drastically simpler now.
The new approach also implies that `LayoutableShadowNode` and `YogaLayoutableShadowNode` don't use `shared_ptr`s to refer to ShadowNode objects because new relationship does not imply ownership. No more `SharedShadowNode` objects in those two classes.
Reviewed By: mdvacca
Differential Revision: D8796159
fbshipit-source-id: 6f52f92d1826f3eb13b2f8a132c3ea77de155d82
Summary:
@public
This compiles, but it works only on iOS for now.
Reviewed By: mdvacca
Differential Revision: D8655540
fbshipit-source-id: 7e9a73fadb317dd62298af6f347344ac4229a8a5