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

Expose a few more glyph apis from ui.Paragraph #47698

Merged
merged 15 commits into from
Nov 22, 2023

Conversation

LongCatIsLooong
Copy link
Contributor

@LongCatIsLooong LongCatIsLooong commented Nov 6, 2023

Add 2 methods for querying glyph-related metrics

  GlyphInfo? getClosestGlyphInfoForOffset(Offset offset); 
  GlyphInfo? getGlyphInfoAt(int codeUnitOffset);

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide and the C++, Objective-C, Java style guides.
  • I listed at least one issue that this PR fixes in the description above.
  • I added new tests to check the change I am making or feature I am adding, or the PR is test-exempt. See testing the engine for instructions on writing and running engine tests.
  • I updated/added relevant documentation (doc comments with ///).
  • I signed the CLA.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@github-actions github-actions bot added the platform-web Code specifically for the web engine label Nov 6, 2023
@LongCatIsLooong LongCatIsLooong force-pushed the paragraph-api-glyph branch 3 times, most recently from 960e92b to 2de2458 Compare November 6, 2023 02:57
@LongCatIsLooong LongCatIsLooong force-pushed the paragraph-api-glyph branch 3 times, most recently from 100db12 to 581c2fa Compare November 6, 2023 07:04
@LongCatIsLooong LongCatIsLooong marked this pull request as ready for review November 6, 2023 08:26
@LongCatIsLooong LongCatIsLooong requested review from eyebrowsoffire, mdebbar and jason-simmons and removed request for mdebbar November 6, 2023 08:27
Copy link
Contributor

@eyebrowsoffire eyebrowsoffire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! I'd like to request a couple minor adjustments to the types along the C boundary in skwasm, if you don't mind. Thanks!

SkScalar offsetX,
SkScalar offsetY,
SkScalar* graphemeLayoutBounds,
size_t* garphemeCodeUnitRange,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a typo in this name

Also, could you just put a comment next to the argument that explains it is an array of length two that represents the start and end.

SkScalar offsetY,
SkScalar* graphemeLayoutBounds,
size_t* garphemeCodeUnitRange,
bool* booleanFlags) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of returning a boolean here, you can directly return a skia::textlayout::TextDirection, and we use that to index into the enum on the dart side. Check out textBoxList_getBoxAtIndex as an example of this.

Copy link
Contributor Author

@LongCatIsLooong LongCatIsLooong Nov 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return value currently indicates whether the out parameters are valid. To add TextDirection information to it I think we'd need to return a tristate value (LTR, RTL, invalid)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, to clarify, my suggestion is to return it by reference as you're doing, but instead of using a bool just return a TextDirection by reference. You can leave the actual return value as a normal boolean, indicating success/failure of the overall API call.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I just realized the parameters are called "booleanFlags" because there are a few more booleans I'd like to expose after this (e.g., isPlaceholder, isEllipsis) that I'd like to pack together. Would it be ok to keep this a bool* for now?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with leaving it as-is for now. I think longer term maybe what we should be doing is actually declaring the C structs themselves on the dart side using ffi constructs and then actually just passing one struct (right by value or by reference) across the boundary. I have been meaning to experiment with that with these bindings but haven't really had much of a chance.

Paragraph* paragraph,
SkScalar offsetX,
SkScalar offsetY,
SkScalar* graphemeLayoutBounds,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think just making this a SkRect *, returning a single rect is a little more expressive. SkRect is a plain old data struct with four floats, it's pretty safe to assume the memory layout. (We already do this for SkRect objects in several places).

external bool paragraphGetClosestGlyphInfoAtCoordinate(
ParagraphHandle handle,
double offsetX, double offsetY,
Pointer<Float> graphemeLayoutBounds, // 4 floats, [LTRB]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can do Pointer<RawRect> here, which is the same type but it's just a little more expressive.

final Pointer<Bool> outBooleanFlags = scope.allocBoolArray(1);
return paragraphGetGlyphInfoAt(handle, codeUnitOffset, outRect, outRange, outBooleanFlags)
? ui.GlyphInfo(
ui.Rect.fromLTRB(outRect[0], outRect[1], outRect[2], outRect[3]),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a scope.convertRectFromNative helper you can use here.

Copy link
Contributor

@eyebrowsoffire eyebrowsoffire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skwasm stuff looks good to me.

Dart_Handle Paragraph::getWordBoundary(unsigned offset) {
txt::Paragraph::Range<size_t> point = m_paragraph->GetWordBoundary(offset);
Dart_Handle glyphInfoFrom(Dart_Handle constructor,
skia::textlayout::Paragraph::GlyphInfo& glyphInfo) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pass this as a const reference

@LongCatIsLooong
Copy link
Contributor Author

hi @mdebbar could you take a look and see if the web implementation makes sense?

lib/web_ui/lib/src/engine/text/layout_fragmenter.dart Outdated Show resolved Hide resolved
if (lineNumber == null) {
return null;
}
final List<LayoutFragment> lineFragments = lines[lineNumber].fragments;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if it's a good idea to calculate grapheme clusters only inside a single fragment. A grapheme cluster could start in one fragment, and end in another.

Here's an idea and let me know what you think:

  1. Calculate grapheme clusters on the entire paragraph.
  2. Find the grapheme cluster that contains codeUnitOffset.
  3. Find the subset of fragments that intersect with that cluster (using overlapsWith(...)).
  4. For each of these fragments, do fragment.toTextBox(start: graphemeStart, end: graphemeEnd).toRect().
  5. Calculate the union (?) of all the produced rects (using Rect.expandToInclude(...) maybe?).
  6. For the direction, you can just use the direction from any of the intersecting fragments (I think all of them must have the same direction, because a grapheme cluster can't have multiple direction inside of it, right?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A grapheme cluster could start in one fragment, and end in another.

Ah interesting. When would this happen (so I can write a test for it)? When the codeunits that belong to the same grapheme are split into different TextSpans?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the codeunits that belong to the same grapheme are split into different TextSpans?

Yes, that's the one possibility I could think of. Not sure if there are others.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright I ended up doing grapheme breaks per line (all breaks within a grapheme cluster are prohibited so grapheme clusters won't be broken into different lines I think). PTAL.

Copy link
Contributor

@mdebbar mdebbar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks for making the changes to make this more robust.

@LongCatIsLooong LongCatIsLooong added the autosubmit Merge PR when tree becomes green via auto submit App label Nov 22, 2023
@auto-submit auto-submit bot merged commit 8194c23 into flutter:main Nov 22, 2023
29 checks passed
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 22, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 22, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 22, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 22, 2023
@LongCatIsLooong LongCatIsLooong deleted the paragraph-api-glyph branch November 22, 2023 22:05
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Nov 22, 2023
…ions) (#138918)

Manual roll requested by [email protected]

flutter/engine@342fb00...f331e0a

2023-11-22 98614782+auto-submit[bot]@users.noreply.github.com Reverts "[Impeller] pass const ref to binding helpers." (flutter/engine#48330)
2023-11-22 [email protected] Revert "Manual roll Dart SDK from f1fd14505782 to df958dc1ca7b (6 revisions)" (flutter/engine#48325)
2023-11-22 [email protected] [Impeller] cache render target properties on Render Pass. (flutter/engine#48323)
2023-11-22 [email protected] [Impeller] pass const ref to binding helpers. (flutter/engine#48318)
2023-11-22 [email protected] Roll Skia from 994558cd1fae to 30ecaac60b47 (1 revision) (flutter/engine#48324)
2023-11-22 [email protected] Roll Skia from 9086788fc341 to 994558cd1fae (1 revision) (flutter/engine#48322)
2023-11-22 [email protected] Expose a few more glyph apis from `ui.Paragraph` (flutter/engine#47698)
2023-11-22 [email protected] Roll Skia from efdec1f459ce to 9086788fc341 (2 revisions) (flutter/engine#48317)
2023-11-22 [email protected] Manual roll Dart SDK from f1fd14505782 to df958dc1ca7b (6 revisions) (flutter/engine#48316)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC [email protected],[email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
caseycrogers pushed a commit to caseycrogers/flutter that referenced this pull request Dec 29, 2023
…ions) (flutter#138918)

Manual roll requested by [email protected]

flutter/engine@342fb00...f331e0a

2023-11-22 98614782+auto-submit[bot]@users.noreply.github.com Reverts "[Impeller] pass const ref to binding helpers." (flutter/engine#48330)
2023-11-22 [email protected] Revert "Manual roll Dart SDK from f1fd14505782 to df958dc1ca7b (6 revisions)" (flutter/engine#48325)
2023-11-22 [email protected] [Impeller] cache render target properties on Render Pass. (flutter/engine#48323)
2023-11-22 [email protected] [Impeller] pass const ref to binding helpers. (flutter/engine#48318)
2023-11-22 [email protected] Roll Skia from 994558cd1fae to 30ecaac60b47 (1 revision) (flutter/engine#48324)
2023-11-22 [email protected] Roll Skia from 9086788fc341 to 994558cd1fae (1 revision) (flutter/engine#48322)
2023-11-22 [email protected] Expose a few more glyph apis from `ui.Paragraph` (flutter/engine#47698)
2023-11-22 [email protected] Roll Skia from efdec1f459ce to 9086788fc341 (2 revisions) (flutter/engine#48317)
2023-11-22 [email protected] Manual roll Dart SDK from f1fd14505782 to df958dc1ca7b (6 revisions) (flutter/engine#48316)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC [email protected],[email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autosubmit Merge PR when tree becomes green via auto submit App platform-web Code specifically for the web engine
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants