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

Add first_style() getter to Cluster #264

Merged
merged 1 commit into from
Feb 5, 2025

Conversation

nicoburns
Copy link
Contributor

This is useful for determining which node is currently being hovered in Blitz:

  • We are storing the the node ID in style.brush
  • We use Cluster::from_point to determine the cluster under the cursor

@nicoburns nicoburns added the enhancement New feature or request label Jan 31, 2025
@nicoburns nicoburns added this to the 0.3 Release milestone Jan 31, 2025
@dfrg
Copy link
Collaborator

dfrg commented Feb 1, 2025

This is only correct in cases where a cluster maps to a single glyph or where all glyphs share the same style. This is probably true in the common case but web browsers don’t make this guarantee and neither does parley (see the DIVERGENT_STYLES flag on Cluster).

@nicoburns
Copy link
Contributor Author

This is only correct in cases where a cluster maps to a single glyph or where all glyphs share the same style. This is probably true in the common case but web browsers don’t make this guarantee and neither does parley (see the DIVERGENT_STYLES flag on Cluster).

Hmm... could I maybe add this method but call it first_style or something?

I need this to access the node id from the cluster (my high-level goal here is to get the id of the node that is currently under the cursor)

Currently I'm doing:

Cluster::from_point(layout, x * scale, y * scale).and_then(|(cluster, _)| {
    let style_index = cluster.glyphs().next()?.style_index();
    let node_id = layout.styles()[style_index].brush.id;
    Some(HitResult { node_id, x, y })
})

But this is failing if the cluster contains no glyph (next() is returning None). So I think this method would be an improvement? Currently there's no public way to access the style_index on the Cluster...

@dfrg
Copy link
Collaborator

dfrg commented Feb 2, 2025

Ah, yes, I think it’s probably fine to call this first_style along with a doc comment noting that clusters may contain multiple glyphs with differing styles.

Signed-off-by: Nico Burns <nico@nicoburns.com>
@nicoburns
Copy link
Contributor Author

Renamed tofirst_style and added a doc comment :)

@nicoburns nicoburns changed the title Add style() getter to Cluster Add first_style() getter to Cluster Feb 2, 2025
@DJMcNab
Copy link
Member

DJMcNab commented Feb 3, 2025

I'm struggling to see where this would be semantically valid to use for that use case.
If there are multiple styles in the cluster, then surely some of the time using this method you'd get the wrong style?

In my mind, the question becomes why are there clusters with no glyphs? Is it because of whitespace?

@nicoburns
Copy link
Contributor Author

the question becomes why are there clusters with no glyphs? Is it because of whitespace?

I went back and tested the case that was panicking for me, and in that case yes. Specifically it was a newline (the text range of cluster contained "\n")

@DJMcNab
Copy link
Member

DJMcNab commented Feb 5, 2025

Hmm, so the correct way to handle this seems to be:

  1. Try to get the relevant glyph within the target cluster, based on the index of the cursor(?)
  2. If that fails (because there are no glyphs), use this method

Right? That seems very ugly

@nicoburns
Copy link
Contributor Author

Hmm, so the correct way to handle this seems to be:

  1. Try to get the relevant glyph within the target cluster, based on the index of the cursor(?)
  2. If that fails (because there are no glyphs), use this method

Right? That seems very ugly

Something like that is probably technically correct. But currently I have no way to determine which glyph within a cluster the cursor is over (and given that glyphs can be arbitrarily positioned relatively to each other by the shaper, I'm not sure even sure how possible this is to do well in general).

Just 2 is probably a 90% solution against non-adversarial inputs. Just 1 is probably not awful if it's only newlines that don't have an associated glyph.

@dfrg
Copy link
Collaborator

dfrg commented Feb 5, 2025

Ligature component clusters will also contain no glyphs.

Parley doesn’t really support hit testing against spans and doing so properly will require some work. This solution isn’t ideal but I think it’s the best we can do right now and I feel like it’s worth merging to support Blitz.

Copy link
Collaborator

@dfrg dfrg left a comment

Choose a reason for hiding this comment

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

Let’s revisit in the future but I’m fine with landing this as is to unblock hit testing in Blitz.

@nicoburns nicoburns added this pull request to the merge queue Feb 5, 2025
Merged via the queue into linebender:main with commit 6aa3876 Feb 5, 2025
21 checks passed
@nicoburns nicoburns deleted the cluster-style branch February 5, 2025 23:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants