| 330 | } |
| 331 | |
| 332 | int32 Font::HitTestText(const StringView& text, const Float2& location, const TextLayoutOptions& layout) |
| 333 | { |
| 334 | // Check if there is no need to do anything |
| 335 | if (text.Length() <= 0) |
| 336 | return 0; |
| 337 | |
| 338 | // Process text |
| 339 | Array<FontLineCache, InlinedAllocation<8>> lines; |
| 340 | ProcessText(text, lines, layout); |
| 341 | ASSERT(lines.HasItems()); |
| 342 | float scale = layout.Scale / FontManager::FontScale; |
| 343 | float baseLinesDistance = static_cast<float>(_height) * layout.BaseLinesGapScale * scale; |
| 344 | |
| 345 | // Offset position to match lines origin space |
| 346 | Float2 testPoint = location - layout.Bounds.Location; |
| 347 | |
| 348 | // Get line which may intersect with the position (it's possible because lines have fixed height) |
| 349 | int32 lineIndex = Math::Clamp(Math::FloorToInt((testPoint.Y - lines.First().Location.Y) / baseLinesDistance), 0, lines.Count() - 1); |
| 350 | const FontLineCache& line = lines[lineIndex]; |
| 351 | float x = line.Location.X; |
| 352 | |
| 353 | // Check all characters in the line to find hit point |
| 354 | FontCharacterEntry previous; |
| 355 | FontCharacterEntry entry; |
| 356 | int32 smallestIndex = INVALID_INDEX; |
| 357 | float dst, smallestDst = MAX_float; |
| 358 | for (int32 currentIndex = line.FirstCharIndex; currentIndex <= line.LastCharIndex; currentIndex++) |
| 359 | { |
| 360 | // Cache current character |
| 361 | const Char currentChar = text[currentIndex]; |
| 362 | GetCharacter(currentChar, entry); |
| 363 | const bool isWhitespace = StringUtils::IsWhitespace(currentChar); |
| 364 | |
| 365 | // Apply kerning |
| 366 | if (!isWhitespace && previous.IsValid) |
| 367 | { |
| 368 | x += entry.Font->GetKerning(previous.Character, entry.Character); |
| 369 | } |
| 370 | previous = entry; |
| 371 | |
| 372 | // Test |
| 373 | dst = Math::Abs(testPoint.X - x); |
| 374 | if (dst < smallestDst) |
| 375 | { |
| 376 | // Found closer character |
| 377 | smallestIndex = currentIndex; |
| 378 | smallestDst = dst; |
| 379 | } |
| 380 | else if (dst > smallestDst) |
| 381 | { |
| 382 | // Current char is worse so return the best result |
| 383 | return smallestIndex; |
| 384 | } |
| 385 | |
| 386 | // Move |
| 387 | x += entry.AdvanceX * scale; |
| 388 | } |
| 389 |
nothing calls this directly
no test coverage detected