* Get the character that is at a pixel position in the first line of the layouted text. * @param x Position in the string. * @param line_index Which line of the layout to search * @return String offset of the position (bytes) or -1 if no character is at the position. */
| 301 | * @return String offset of the position (bytes) or -1 if no character is at the position. |
| 302 | */ |
| 303 | ptrdiff_t Layouter::GetCharAtPosition(int x, size_t line_index) const |
| 304 | { |
| 305 | if (line_index >= this->size()) return -1; |
| 306 | |
| 307 | const auto &line = this->at(line_index); |
| 308 | |
| 309 | for (int run_index = 0; run_index < line->CountRuns(); run_index++) { |
| 310 | const ParagraphLayouter::VisualRun &run = line->GetVisualRun(run_index); |
| 311 | const auto &glyphs = run.GetGlyphs(); |
| 312 | const auto &positions = run.GetPositions(); |
| 313 | const auto &charmap = run.GetGlyphToCharMap(); |
| 314 | |
| 315 | for (int i = 0; i < run.GetGlyphCount(); i++) { |
| 316 | /* Not a valid glyph (empty). */ |
| 317 | if (glyphs[i] == 0xFFFF) continue; |
| 318 | |
| 319 | int begin_x = positions[i].left; |
| 320 | int end_x = positions[i].right + 1; |
| 321 | |
| 322 | if (IsInsideMM(x, begin_x, end_x)) { |
| 323 | /* Found our glyph, now convert to UTF-8 string index. */ |
| 324 | size_t index = charmap[i]; |
| 325 | |
| 326 | size_t cur_idx = 0; |
| 327 | Utf8View view(this->string); |
| 328 | for (auto it = view.begin(), end = view.end(); it != end; ++it) { |
| 329 | if (cur_idx == index) return it.GetByteOffset(); |
| 330 | |
| 331 | char32_t c = *it; |
| 332 | if (!IsConsumedFormattingCode(c)) cur_idx += line->GetInternalCharLength(c); |
| 333 | } |
| 334 | } |
| 335 | } |
| 336 | } |
| 337 | |
| 338 | return -1; |
| 339 | } |
| 340 | |
| 341 | /** |
| 342 | * Get a static font instance. |
no test coverage detected