react-native-windows icon indicating copy to clipboard operation
react-native-windows copied to clipboard

Various bugs and crashes related to fast text workaround

Open rozele opened this issue 1 year ago • 0 comments

Problem Description

In TextViewManager, we special case a <Text> component with a single raw text (Run) child by setting the TextBlock::Text property directly, rather than adding an inline to allow XAML to perform optimized text rendering.

The current implementation has a few bugs:

  1. Prepending raw text at index 0 to a view that has other inline children drops all other inline children
  2. Attempting to unmount any other inline after prepending raw text at index 0 causes the app to crash due to the TextBlock::InlineCollection being empty / owned by the overwritten TextBlock::Text property
  3. Prepending virtual text (Span) at index 0 to a view that is optimized for fast text works, but when unmounting the prepended virtual text, it also removes the raw text.
  4. Prepending virtual text (Span) at index 0 to a view that is optimized for fast text works, but when unmounting the raw text then attempting to add a raw text node back at index 1, the app crashes.

Steps To Reproduce

Run the scenarios described above with the following example:

export default function App() {
  const [addRawText, setAddRawText] = useState(false);
  const [appendVirtualText, setAppendVirtualText] = useState(true);
  const [prependVirtualText, setPrependVirtualText] = useState(false);
  return (
    <View>
      <View>
        <Text>{prependVirtualText ? <Text>1{' '}</Text> : null}{addRawText ? "2 " : null}{appendVirtualText ? <Text>3</Text> : null}</Text>
      </View>
      <View onTouchEnd={() => setPrependVirtualText(!prependVirtualText)}>
        <Text>{prependVirtualText ? 'Remove Prepended' : 'Prepend'} Virtual Text {'(1)'}</Text>
      </View>
      <View onTouchEnd={() => setAddRawText(!addRawText)}>
        <Text>{addRawText ? 'Remove' : 'Insert'} Raw Text {'(2)'}</Text>
      </View>
      <View onTouchEnd={() => setAppendVirtualText(!appendVirtualText)}>
        <Text>{appendVirtualText ? 'Remove Appended' : 'Append'} Virtual Text {'(3)'}</Text>
      </View>
    </View>
  )
}

Expected Results

App should behave correctly when appending / prepending raw text / virtual text in the scenarios above. I.e.,

  1. Text should read "2 3"
  2. App should not crash and text should read "2"
  3. Text should read "2"
  4. App should not crash and text should read "1 2"

CLI version

npx react-native --version

Environment

npx react-native info

Target Platform Version

No response

Target Device(s)

No response

Visual Studio Version

No response

Build Configuration

No response

Snack, code example, screenshot, or link to a repository

No response

rozele avatar Aug 01 '22 16:08 rozele