Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Text anchoring is not calculated correctly if the line contains multiple TSpans #1205

Open
mjmasn opened this issue Nov 28, 2019 · 8 comments · May be fixed by #1206
Open

Text anchoring is not calculated correctly if the line contains multiple TSpans #1205

mjmasn opened this issue Nov 28, 2019 · 8 comments · May be fixed by #1206

Comments

@mjmasn
Copy link

mjmasn commented Nov 28, 2019

Bug

If a line of text with textAnchor="middle" comprises multiple <TSpan>s, each span is centred on itself (from the position it would have been in with textAnchor="start"), rather than as a whole line of text.

Probably easier to explain with a screenshot:

I'll push up a PR in a minute that solves this particular issue, however not being much of a Native Android/Java developer it's likely there's a better way to do this, and I can't be sure this hasn't broken something else.

Environment info

React native info output:

System:
    OS: macOS Mojave 10.14.5
    CPU: (4) x64 Intel(R) Core(TM) i5-4308U CPU @ 2.80GHz
    Memory: 57.91 MB / 16.00 GB
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 12.3.1 - ~/.nvm/versions/node/v12.3.1/bin/node
    Yarn: 1.16.0 - /usr/local/bin/yarn
    npm: 6.9.0 - ~/.nvm/versions/node/v12.3.1/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  SDKs:
    iOS SDK:
      Platforms: iOS 13.2, DriverKit 19.0, macOS 10.15, tvOS 13.2, watchOS 6.1
    Android SDK:
      API Levels: 23, 25, 26, 27, 28
      Build Tools: 23.0.1, 26.0.1, 26.0.2, 26.0.3, 27.0.3, 28.0.3
      System Images: android-23 | Intel x86 Atom_64, android-23 | Google APIs Intel x86 Atom_64, android-27 | Google APIs Intel x86 Atom, android-27 | Google Play Intel x86 Atom, android-28 | Google APIs Intel x86 Atom_64, android-28 | Google Play Intel x86 Atom_64
      Android NDK: 19.2.5345600
  IDEs:
    Android Studio: 3.4 AI-183.6156.11.34.5522156
    Xcode: 11.2/11B52 - /usr/bin/xcodebuild
  npmPackages:
    react: 16.9.0 => 16.9.0
    react-native: 0.61.5 => 0.61.5

Library version: 9.13.3

Steps To Reproduce

  1. Add a <Text textAnchor="middle"> element containing multiple <TSpan>s
  2. See only the first span on each line is aligned to the middle of the screen.

Describe what you expected to happen:

  1. The entire line should be aligned correctly

Reproducible sample code

https://github.com/mjmasn/TSpanIssue

@mjmasn mjmasn linked a pull request Nov 28, 2019 that will close this issue
6 tasks
@msand
Copy link
Collaborator

msand commented Dec 9, 2019

Interesting, have you tried running this code on the web? https://codesandbox.io/s/pypn6mn3y7
We should aim to render the same as the ever-green browsers. Haven't had time to look into this properly yet.

@mjmasn
Copy link
Author

mjmasn commented Dec 11, 2019

@msand yeah looks good with react-native-web (https://codesandbox.io/s/react-native-svg-test-0467e), and the code in my repro I converted to proper SVG and it worked fine in Google Chrome. I haven't done any testing with iOS but I can do that this evening.

@mjmasn
Copy link
Author

mjmasn commented Dec 11, 2019

Does #1206 look like a reasonable approach to solving this? I was hoping there would be a way without rebuilding all the FontData for every span but I couldn't get that working.

@msand
Copy link
Collaborator

msand commented Dec 11, 2019

I think it should be possible to achieve without that, i think that implementation is N^2 or even N^N in deeply nested situations, in the number of text children, rather than 2*N, not sure why this isn't working correctly to begin with, as I remember it, I made the getSubtreeTextChunksTotalAdvance specifically to be able to handle this use-case correctly. But, it's some time ago and haven't had time to look deeper into this again.

@mjmasn
Copy link
Author

mjmasn commented Dec 11, 2019

I guess getting the font from getTextRootGlyphContext would always return the same 'root' font for the group of TSpans, and that font is then passed to applyTextPropertiesToPaint(paint, font)? So while it is looping through all the children correctly, it's using the wrong font to calculate the advance. That's what I gathered from trying to debug it anyway.

I agree my method is inefficient though, maybe it's just a case of calculating and adding an mFontData property to the TSpanView class so that it's cached.

@msand
Copy link
Collaborator

msand commented Dec 11, 2019

We should probably make it a two pass algorithm, one to calculate the fonts and other text properties, glyph positions, advance etc. which can be cached, and then another pass to actually render based on that data. This way it wouldn't process a text node more than once. At least the advance should be calculated in what is essentially a layout step, and then use that for text alignment etc.

@stale
Copy link

stale bot commented Feb 9, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. You may also mark this issue as a "discussion" and I will leave this open.

@stale stale bot added the stale label Feb 9, 2020
@mjmasn
Copy link
Author

mjmasn commented Feb 9, 2020

Not stale but I don't have time to look at this at the moment. If anyone is interested in developing a more efficient fix for this please feel free!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants