MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches

◆ index_at()

MAYAFLUX_API size_t MayaFlux::Portal::Text::index_at ( std::string_view  text,
const LayoutResult &  layout,
GlyphAtlas &  atlas,
float  x,
float  y,
float  pen_x = 0.F,
float  pen_y = 0.F,
uint32_t  wrap_w = 0,
uint32_t  tab_width = 4 
)

Byte offset of the codepoint boundary nearest a screen-space point.

Scans layout.quads for the line whose quads sit closest to y, then within that line for the ink quad x falls into (resolving to its left or right half), or, failing that, for the two quads bracketing x. lay_out() never emits a quad for a space, tab, or newline, so a point landing in the gap between two quads - or before the first / after the last quad on a line - has no ink to test against directly: that gap is resolved exactly by walking its few codepoint boundaries through x_at() (same pen_x/pen_y/wrap_w/tab_width as the original lay_out() call) and keeping whichever pen position lands closest to x, rather than guessing from ink edges that were never meant to mark it.

A line with no quads at all (blank, or entirely whitespace) has nothing for the first scan to anchor on and is still not distinguishable from an adjacent line by this function - a real, if narrower, residual gap. Empty layout.quads (the whole text is blank or all-whitespace) returns 0.

Parameters
textSource UTF-8 string layout was produced from.
layoutLayoutResult to hit-test against.
atlasGlyphAtlas layout was produced with.
xScreen-space x coordinate, same space as layout's quads.
yScreen-space y coordinate, same space as layout's quads.
pen_xPen origin x, matching the original lay_out() call.
pen_yPen origin y, matching the original lay_out() call.
wrap_wWrap column, matching the original lay_out() call.
tab_widthTab stop width, matching the original lay_out() call.
Returns
Byte offset of the nearest codepoint boundary.

Definition at line 242 of file TypeSetter.cpp.

252{
253 if (layout.quads.empty()) {
254 return 0;
255 }
256
257 const auto line_h = static_cast<float>(atlas.line_height());
258
259 float line_y = layout.quads.front().y0;
260 float best_line_dy = abs_f(line_y - y);
261 for (const auto& q : layout.quads) {
262 const float dy = abs_f(q.y0 - y);
263 if (dy < best_line_dy) {
264 best_line_dy = dy;
265 line_y = q.y0;
266 }
267 }
268
269 const GlyphQuad* left = nullptr;
270 const GlyphQuad* right = nullptr;
271
272 for (const auto& q : layout.quads) {
273 if (abs_f(q.y0 - line_y) > line_h * 0.5F) {
274 continue;
275 }
276
277 if (x >= q.x0 && x <= q.x1) {
278 return x > (q.x0 + q.x1) * 0.5F
279 ? next_codepoint_offset(text, q.byte_offset)
280 : q.byte_offset;
281 }
282 if (q.x1 <= x && (!left || q.x1 > left->x1)) {
283 left = &q;
284 }
285 if (q.x0 >= x && (!right || q.x0 < right->x0)) {
286 right = &q;
287 }
288 }
289
290 const GlyphQuad* anchor = left ? left : right;
291 const float pen_line_y = x_at(text, atlas, anchor->byte_offset, pen_x, pen_y, wrap_w, tab_width).y;
292
293 const auto same_line = [&](size_t offset) {
294 return x_at(text, atlas, offset, pen_x, pen_y, wrap_w, tab_width).y == pen_line_y;
295 };
296
297 size_t bracket_start = 0;
298 if (left) {
299 bracket_start = next_codepoint_offset(text, left->byte_offset);
300 } else {
301 bracket_start = right->byte_offset;
302 while (bracket_start > 0) {
303 const size_t prev = previous_codepoint_offset(text, bracket_start);
304 if (!same_line(prev)) {
305 break;
306 }
307 bracket_start = prev;
308 }
309 }
310
311 size_t bracket_end = text.size();
312 if (right) {
313 bracket_end = right->byte_offset;
314 } else {
315 bracket_end = next_codepoint_offset(text, left->byte_offset);
316 while (bracket_end < text.size()) {
317 const size_t next = next_codepoint_offset(text, bracket_end);
318 if (!same_line(next)) {
319 break;
320 }
321 bracket_end = next;
322 }
323 }
324
325 if (bracket_start >= bracket_end) {
326 return bracket_start;
327 }
328
329 size_t best_offset = bracket_start;
330 float best_dx = abs_f(x_at(text, atlas, bracket_start, pen_x, pen_y, wrap_w, tab_width).x - x);
331
332 for (size_t off = bracket_start; off < bracket_end;) {
333 const size_t next = next_codepoint_offset(text, off);
334 const float dx = abs_f(x_at(text, atlas, next, pen_x, pen_y, wrap_w, tab_width).x - x);
335 if (dx < best_dx) {
336 best_dx = dx;
337 best_offset = next;
338 }
339 off = next;
340 }
341
342 return best_offset;
343}
uint64_t offset
Definition Composite.cpp:10
double q
uint32_t line_height() const
Line advance in pixels for this atlas's pixel_size.
size_t previous_codepoint_offset(std::string_view text, size_t byte_offset)
Byte offset of the codepoint boundary before byte_offset.
size_t next_codepoint_offset(std::string_view text, size_t byte_offset)
Byte offset of the codepoint boundary after byte_offset.
PenPosition x_at(std::string_view text, GlyphAtlas &atlas, size_t byte_offset, float pen_x, float pen_y, uint32_t wrap_w, uint32_t tab_width)
Pen position immediately before byte_offset, in lay_out()'s space.
std::vector< GlyphQuad > quads

References MayaFlux::Portal::Text::GlyphQuad::byte_offset, MayaFlux::Portal::Text::GlyphAtlas::line_height(), next_codepoint_offset(), offset, previous_codepoint_offset(), q, MayaFlux::Portal::Text::LayoutResult::quads, MayaFlux::Portal::Text::GlyphQuad::x0, MayaFlux::Portal::Text::GlyphQuad::x1, x_at(), and MayaFlux::Portal::Text::PenPosition::y.

Referenced by MayaFlux::Portal::Text::TextRun::index_at().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: