MCPcopy Create free account
hub / github.com/OpenTTD/OpenTTD / GetCharPosition

Method GetCharPosition

src/gfx_layout.cpp:237–295  ·  view source on GitHub ↗

* Get the position of a character in the layout. * @param ch Character to get the position of. Must be an iterator of the string passed to the constructor. * @return Upper left corner of the character relative to the start of the string. * @note Will only work right for single-line strings. */

Source from the content-addressed store, hash-verified

235 * @note Will only work right for single-line strings.
236 */
237ParagraphLayouter::Position Layouter::GetCharPosition(std::string_view::const_iterator ch) const
238{
239 const auto &line = this->front();
240
241 /* Pointer to the end-of-string marker? Return total line width. */
242 if (ch == this->string.end()) {
243 Point p = {_current_text_dir == TD_LTR ? line->GetWidth() : 0, 0};
244 return p;
245 }
246
247 /* Initial position, returned if character not found. */
248 const ParagraphLayouter::Position initial_position = Point{_current_text_dir == TD_LTR ? 0 : line->GetWidth(), 0};
249
250 /* Find the code point index which corresponds to the char
251 * pointer into our UTF-8 source string. */
252 size_t index = 0;
253 {
254 Utf8View view(this->string);
255 const size_t offset = ch - this->string.begin();
256 const auto pos = view.GetIterAtByte(offset);
257
258 /* We couldn't find the code point index. */
259 if (pos.GetByteOffset() != offset) return initial_position;
260
261 for (auto it = view.begin(); it < pos; ++it) {
262 char32_t c = *it;
263 if (!IsConsumedFormattingCode(c)) index += line->GetInternalCharLength(c);
264 }
265 }
266
267 const ParagraphLayouter::Position *position = &initial_position;
268
269 /* Scan all runs until we've found our code point index. */
270 size_t best_index = SIZE_MAX;
271 for (int run_index = 0; run_index < line->CountRuns(); run_index++) {
272 const ParagraphLayouter::VisualRun &run = line->GetVisualRun(run_index);
273 const auto &positions = run.GetPositions();
274 const auto &charmap = run.GetGlyphToCharMap();
275
276 auto itp = positions.begin();
277 for (auto it = charmap.begin(); it != charmap.end(); ++it, ++itp) {
278 const size_t cur_index = static_cast<size_t>(*it);
279 /* Found exact character match? */
280 if (cur_index == index) return *itp;
281
282 /* If the character we are looking for has been combined with other characters to form a ligature then
283 * we may not be able to find an exact match. We don't actually know if our character is part of a
284 * ligature. In this case we will aim to select the first character of the ligature instead, so the best
285 * index is the index nearest to but lower than the desired index. */
286 if (cur_index < index && (best_index < cur_index || best_index == SIZE_MAX)) {
287 best_index = cur_index;
288 position = &*itp;
289 }
290 }
291 }
292
293 /* At the end of the run but still didn't find our character so probably a trailing ligature, use the last found position. */
294 return *position;

Callers 1

GetCharPosInStringFunction · 0.80

Calls 10

IsConsumedFormattingCodeFunction · 0.85
GetIterAtByteMethod · 0.80
GetByteOffsetMethod · 0.80
endMethod · 0.45
GetWidthMethod · 0.45
beginMethod · 0.45
GetInternalCharLengthMethod · 0.45
CountRunsMethod · 0.45
GetPositionsMethod · 0.45
GetGlyphToCharMapMethod · 0.45

Tested by

no test coverage detected