mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-11-11 13:10:45 +00:00
Codechange: Store both left and right glyph positions in a run.
This also allows the end of a run to be known without using an extra position entry.
This commit is contained in:
parent
80ddcb9d7d
commit
5cd81a980e
@ -349,10 +349,10 @@ struct IConsoleWindow : Window
|
||||
{
|
||||
int delta = std::min<int>(this->width - this->line_offset - _iconsole_cmdline.pixels - ICON_RIGHT_BORDERWIDTH, 0);
|
||||
|
||||
Point p1 = GetCharPosInString(_iconsole_cmdline.buf, from, FS_NORMAL);
|
||||
Point p2 = from != to ? GetCharPosInString(_iconsole_cmdline.buf, to, FS_NORMAL) : p1;
|
||||
const auto p1 = GetCharPosInString(_iconsole_cmdline.buf, from, FS_NORMAL);
|
||||
const auto p2 = from != to ? GetCharPosInString(_iconsole_cmdline.buf, to, FS_NORMAL) : p1;
|
||||
|
||||
Rect r = {this->line_offset + delta + p1.x, this->height - this->line_height, this->line_offset + delta + p2.x, this->height};
|
||||
Rect r = {this->line_offset + delta + p1.left, this->height - this->line_height, this->line_offset + delta + p2.right, this->height};
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -605,9 +605,9 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
|
||||
/* Not a valid glyph (empty) */
|
||||
if (glyph == 0xFFFF) continue;
|
||||
|
||||
int begin_x = positions[i].x + left - offset_x;
|
||||
int end_x = positions[i + 1].x + left - offset_x - 1;
|
||||
int top = positions[i].y + y;
|
||||
int begin_x = positions[i].left + left - offset_x;
|
||||
int end_x = positions[i].right + left - offset_x;
|
||||
int top = positions[i].top + y;
|
||||
|
||||
/* Truncated away. */
|
||||
if (truncation && (begin_x < min_x || end_x > max_x)) continue;
|
||||
|
@ -225,7 +225,7 @@ static bool IsConsumedFormattingCode(char32_t ch)
|
||||
* @return Upper left corner of the character relative to the start of the string.
|
||||
* @note Will only work right for single-line strings.
|
||||
*/
|
||||
Point Layouter::GetCharPosition(std::string_view::const_iterator ch) const
|
||||
ParagraphLayouter::Position Layouter::GetCharPosition(std::string_view::const_iterator ch) const
|
||||
{
|
||||
const auto &line = this->front();
|
||||
|
||||
@ -245,8 +245,8 @@ Point Layouter::GetCharPosition(std::string_view::const_iterator ch) const
|
||||
}
|
||||
|
||||
/* Initial position, returned if character not found. */
|
||||
const Point initial_position = {_current_text_dir == TD_LTR ? 0 : line->GetWidth(), 0};
|
||||
const Point *position = &initial_position;
|
||||
const ParagraphLayouter::Position initial_position = Point{_current_text_dir == TD_LTR ? 0 : line->GetWidth(), 0};
|
||||
const ParagraphLayouter::Position *position = &initial_position;
|
||||
|
||||
/* We couldn't find the code point index. */
|
||||
if (str != ch) return *position;
|
||||
@ -303,8 +303,8 @@ ptrdiff_t Layouter::GetCharAtPosition(int x, size_t line_index) const
|
||||
/* Not a valid glyph (empty). */
|
||||
if (glyphs[i] == 0xFFFF) continue;
|
||||
|
||||
int begin_x = positions[i].x;
|
||||
int end_x = positions[i + 1].x;
|
||||
int begin_x = positions[i].left;
|
||||
int end_x = positions[i].right + 1;
|
||||
|
||||
if (IsInsideMM(x, begin_x, end_x)) {
|
||||
/* Found our glyph, now convert to UTF-8 string index. */
|
||||
@ -418,7 +418,7 @@ void Layouter::ReduceLineCache()
|
||||
* @param start_fontsize Font size to start the text with.
|
||||
* @return Upper left corner of the glyph associated with the character.
|
||||
*/
|
||||
Point GetCharPosInString(std::string_view str, const char *ch, FontSize start_fontsize)
|
||||
ParagraphLayouter::Position GetCharPosInString(std::string_view str, const char *ch, FontSize start_fontsize)
|
||||
{
|
||||
/* Ensure "ch" is inside "str" or at the exact end. */
|
||||
assert(ch >= str.data() && (ch - str.data()) <= static_cast<ptrdiff_t>(str.size()));
|
||||
|
@ -90,6 +90,19 @@ class ParagraphLayouter {
|
||||
public:
|
||||
virtual ~ParagraphLayouter() = default;
|
||||
|
||||
/** Position of a glyph within a VisualRun. */
|
||||
class Position {
|
||||
public:
|
||||
int16_t left; ///< Left-most position of glyph.
|
||||
int16_t right; ///< Right-most position of glyph.
|
||||
int16_t top; ///< Top-most position of glyph.
|
||||
|
||||
constexpr inline Position(int16_t left, int16_t right, int16_t top) : left(left), right(right), top(top) { }
|
||||
|
||||
/** Conversion from a single point to a Position. */
|
||||
constexpr inline Position(const Point &pt) : left(pt.x), right(pt.x), top(pt.y) { }
|
||||
};
|
||||
|
||||
/** Visual run contains data about the bit of text with the same font. */
|
||||
class VisualRun {
|
||||
public:
|
||||
@ -97,7 +110,7 @@ public:
|
||||
virtual const Font *GetFont() const = 0;
|
||||
virtual int GetGlyphCount() const = 0;
|
||||
virtual std::span<const GlyphID> GetGlyphs() const = 0;
|
||||
virtual std::span<const Point> GetPositions() const = 0;
|
||||
virtual std::span<const Position> GetPositions() const = 0;
|
||||
virtual int GetLeading() const = 0;
|
||||
virtual std::span<const int> GetGlyphToCharMap() const = 0;
|
||||
};
|
||||
@ -176,7 +189,7 @@ public:
|
||||
|
||||
Layouter(std::string_view str, int maxw = INT32_MAX, FontSize fontsize = FS_NORMAL);
|
||||
Dimension GetBounds();
|
||||
Point GetCharPosition(std::string_view::const_iterator ch) const;
|
||||
ParagraphLayouter::Position GetCharPosition(std::string_view::const_iterator ch) const;
|
||||
ptrdiff_t GetCharAtPosition(int x, size_t line_index) const;
|
||||
|
||||
static void Initialize();
|
||||
@ -185,7 +198,7 @@ public:
|
||||
static void ReduceLineCache();
|
||||
};
|
||||
|
||||
Point GetCharPosInString(std::string_view str, const char *ch, FontSize start_fontsize = FS_NORMAL);
|
||||
ParagraphLayouter::Position GetCharPosInString(std::string_view str, const char *ch, FontSize start_fontsize = FS_NORMAL);
|
||||
ptrdiff_t GetCharAtPosition(std::string_view str, int x, FontSize start_fontsize = FS_NORMAL);
|
||||
|
||||
#endif /* GFX_LAYOUT_H */
|
||||
|
@ -40,7 +40,7 @@ public:
|
||||
/** Visual run contains data about the bit of text with the same font. */
|
||||
class FallbackVisualRun : public ParagraphLayouter::VisualRun {
|
||||
std::vector<GlyphID> glyphs; ///< The glyphs we're drawing.
|
||||
std::vector<Point> positions; ///< The positions of the glyphs.
|
||||
std::vector<Position> positions; ///< The positions of the glyphs.
|
||||
std::vector<int> glyph_to_char; ///< The char index of the glyphs.
|
||||
|
||||
Font *font; ///< The font used to layout these.
|
||||
@ -50,7 +50,7 @@ public:
|
||||
const Font *GetFont() const override { return this->font; }
|
||||
int GetGlyphCount() const override { return static_cast<int>(this->glyphs.size()); }
|
||||
std::span<const GlyphID> GetGlyphs() const override { return this->glyphs; }
|
||||
std::span<const Point> GetPositions() const override { return this->positions; }
|
||||
std::span<const Position> GetPositions() const override { return this->positions; }
|
||||
int GetLeading() const override { return this->GetFont()->fc->GetHeight(); }
|
||||
std::span<const int> GetGlyphToCharMap() const override { return this->glyph_to_char; }
|
||||
};
|
||||
@ -116,25 +116,22 @@ FallbackParagraphLayout::FallbackVisualRun::FallbackVisualRun(Font *font, const
|
||||
|
||||
this->glyphs.reserve(char_count);
|
||||
this->glyph_to_char.reserve(char_count);
|
||||
|
||||
/* Positions contains the location of the begin of each of the glyphs, and the end of the last one. */
|
||||
this->positions.reserve(char_count + 1);
|
||||
this->positions.reserve(char_count);
|
||||
|
||||
int advance = x;
|
||||
for (int i = 0; i < char_count; i++) {
|
||||
const GlyphID &glyph_id = this->glyphs.emplace_back(font->fc->MapCharToGlyph(chars[i]));
|
||||
int x_advance = font->fc->GetGlyphWidth(glyph_id);
|
||||
if (isbuiltin) {
|
||||
this->positions.emplace_back(advance, font->fc->GetAscender()); // Apply sprite font's ascender.
|
||||
this->positions.emplace_back(advance, advance + x_advance - 1, font->fc->GetAscender()); // Apply sprite font's ascender.
|
||||
} else if (chars[i] >= SCC_SPRITE_START && chars[i] <= SCC_SPRITE_END) {
|
||||
this->positions.emplace_back(advance, (font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(font->fc->GetSize()))) / 2); // Align sprite font to centre
|
||||
this->positions.emplace_back(advance, advance + x_advance - 1, (font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(font->fc->GetSize()))) / 2); // Align sprite font to centre
|
||||
} else {
|
||||
this->positions.emplace_back(advance, 0); // No ascender adjustment.
|
||||
this->positions.emplace_back(advance, advance + x_advance - 1, 0); // No ascender adjustment.
|
||||
}
|
||||
advance += font->fc->GetGlyphWidth(glyph_id);
|
||||
advance += x_advance;
|
||||
this->glyph_to_char.push_back(char_offset + i);
|
||||
}
|
||||
/* End-of-run position. */
|
||||
this->positions.emplace_back(advance, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -165,7 +162,9 @@ int FallbackParagraphLayout::FallbackLine::GetWidth() const
|
||||
* the last run gives us the end of the line and thus the width.
|
||||
*/
|
||||
const auto &run = this->GetVisualRun(this->CountRuns() - 1);
|
||||
return run.GetPositions().back().x;
|
||||
const auto &positions = run.GetPositions();
|
||||
if (positions.empty()) return 0;
|
||||
return positions.back().right + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,7 +45,7 @@ public:
|
||||
std::vector<GlyphID> glyphs; ///< The glyphs of the run. Valid after Shape() is called.
|
||||
std::vector<int> advance; ///< The advance (width) of the glyphs. Valid after Shape() is called.
|
||||
std::vector<int> glyph_to_char; ///< The mapping from glyphs to characters. Valid after Shape() is called.
|
||||
std::vector<Point> positions; ///< The positions of the glyphs. Valid after Shape() is called.
|
||||
std::vector<ParagraphLayouter::Position> positions; ///< The positions of the glyphs. Valid after Shape() is called.
|
||||
int total_advance = 0; ///< The total advance of the run. Valid after Shape() is called.
|
||||
|
||||
ICURun(int start, int length, UBiDiLevel level, UScriptCode script = USCRIPT_UNKNOWN, Font *font = nullptr) : start(start), length(length), level(level), script(script), font(font) {}
|
||||
@ -62,7 +62,7 @@ public:
|
||||
class ICUVisualRun : public ParagraphLayouter::VisualRun {
|
||||
private:
|
||||
std::vector<GlyphID> glyphs;
|
||||
std::vector<Point> positions;
|
||||
std::vector<Position> positions;
|
||||
std::vector<int> glyph_to_char;
|
||||
|
||||
int total_advance;
|
||||
@ -72,7 +72,7 @@ public:
|
||||
ICUVisualRun(const ICURun &run, int x);
|
||||
|
||||
std::span<const GlyphID> GetGlyphs() const override { return this->glyphs; }
|
||||
std::span<const Point> GetPositions() const override { return this->positions; }
|
||||
std::span<const Position> GetPositions() const override { return this->positions; }
|
||||
std::span<const int> GetGlyphToCharMap() const override { return this->glyph_to_char; }
|
||||
|
||||
const Font *GetFont() const override { return this->font; }
|
||||
@ -136,8 +136,8 @@ ICUParagraphLayout::ICUVisualRun::ICUVisualRun(const ICURun &run, int x) :
|
||||
this->positions.reserve(run.positions.size());
|
||||
|
||||
/* Copy positions, moving x coordinate by x offset. */
|
||||
for (const Point &pt : run.positions) {
|
||||
this->positions.emplace_back(pt.x + x, pt.y);
|
||||
for (const auto &pos : run.positions) {
|
||||
this->positions.emplace_back(pos.left + x, pos.right + x, pos.top);
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,7 +179,7 @@ void ICURun::Shape(UChar *buff, size_t buff_length)
|
||||
/* Reserve space, as we already know the size. */
|
||||
this->glyphs.reserve(glyph_count);
|
||||
this->glyph_to_char.reserve(glyph_count);
|
||||
this->positions.reserve(glyph_count + 1);
|
||||
this->positions.reserve(glyph_count);
|
||||
this->advance.reserve(glyph_count);
|
||||
|
||||
/* Prepare the glyphs/position. ICUVisualRun will give the position an offset if needed. */
|
||||
@ -189,14 +189,13 @@ void ICURun::Shape(UChar *buff, size_t buff_length)
|
||||
|
||||
if (buff[glyph_info[i].cluster] >= SCC_SPRITE_START && buff[glyph_info[i].cluster] <= SCC_SPRITE_END && glyph_info[i].codepoint == 0) {
|
||||
auto glyph = this->font->fc->MapCharToGlyph(buff[glyph_info[i].cluster]);
|
||||
|
||||
this->glyphs.push_back(glyph);
|
||||
this->positions.emplace_back(advance, (this->font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(this->font->fc->GetSize()))) / 2); // Align sprite font to centre
|
||||
x_advance = this->font->fc->GetGlyphWidth(glyph);
|
||||
this->glyphs.push_back(glyph);
|
||||
this->positions.emplace_back(advance, advance + x_advance - 1, (this->font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(this->font->fc->GetSize()))) / 2); // Align sprite font to centre
|
||||
} else {
|
||||
this->glyphs.push_back(glyph_info[i].codepoint);
|
||||
this->positions.emplace_back(glyph_pos[i].x_offset / FONT_SCALE + advance, glyph_pos[i].y_offset / FONT_SCALE);
|
||||
x_advance = glyph_pos[i].x_advance / FONT_SCALE;
|
||||
this->glyphs.push_back(glyph_info[i].codepoint);
|
||||
this->positions.emplace_back(glyph_pos[i].x_offset / FONT_SCALE + advance, glyph_pos[i].x_offset / FONT_SCALE + advance + x_advance - 1, glyph_pos[i].y_offset / FONT_SCALE);
|
||||
}
|
||||
|
||||
this->glyph_to_char.push_back(glyph_info[i].cluster);
|
||||
@ -204,9 +203,6 @@ void ICURun::Shape(UChar *buff, size_t buff_length)
|
||||
advance += x_advance;
|
||||
}
|
||||
|
||||
/* End-of-run position. */
|
||||
this->positions.emplace_back(advance, 0);
|
||||
|
||||
/* Track the total advancement we made. */
|
||||
this->total_advance = advance;
|
||||
|
||||
|
@ -902,10 +902,10 @@ Rect QueryString::GetBoundingRect(const Window *w, WidgetID wid, const char *fro
|
||||
r = ScrollEditBoxTextRect(r, *tb);
|
||||
|
||||
/* Get location of first and last character. */
|
||||
Point p1 = GetCharPosInString(tb->buf, from, FS_NORMAL);
|
||||
Point p2 = from != to ? GetCharPosInString(tb->buf, to, FS_NORMAL) : p1;
|
||||
const auto p1 = GetCharPosInString(tb->buf, from, FS_NORMAL);
|
||||
const auto p2 = from != to ? GetCharPosInString(tb->buf, to, FS_NORMAL) : p1;
|
||||
|
||||
return { Clamp(r.left + p1.x, r.left, r.right), r.top, Clamp(r.left + p2.x, r.left, r.right), r.bottom };
|
||||
return { Clamp(r.left + p1.left, r.left, r.right), r.top, Clamp(r.left + p2.right, r.left, r.right), r.bottom };
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,7 +71,7 @@ public:
|
||||
class CoreTextVisualRun : public ParagraphLayouter::VisualRun {
|
||||
private:
|
||||
std::vector<GlyphID> glyphs;
|
||||
std::vector<Point> positions;
|
||||
std::vector<Position> positions;
|
||||
std::vector<int> glyph_to_char;
|
||||
|
||||
int total_advance = 0;
|
||||
@ -82,7 +82,7 @@ public:
|
||||
CoreTextVisualRun(CoreTextVisualRun &&other) = default;
|
||||
|
||||
std::span<const GlyphID> GetGlyphs() const override { return this->glyphs; }
|
||||
std::span<const Point> GetPositions() const override { return this->positions; }
|
||||
std::span<const Position> GetPositions() const override { return this->positions; }
|
||||
std::span<const int> GetGlyphToCharMap() const override { return this->glyph_to_char; }
|
||||
|
||||
const Font *GetFont() const override { return this->font; }
|
||||
@ -241,7 +241,9 @@ CoreTextParagraphLayout::CoreTextVisualRun::CoreTextVisualRun(CTRunRef run, Font
|
||||
|
||||
CGPoint pts[this->glyphs.size()];
|
||||
CTRunGetPositions(run, CFRangeMake(0, 0), pts);
|
||||
this->positions.reserve(this->glyphs.size() + 1);
|
||||
CGSize advs[this->glyphs.size()];
|
||||
CTRunGetAdvances(run, CFRangeMake(0, 0), advs);
|
||||
this->positions.reserve(this->glyphs.size());
|
||||
|
||||
/* Convert glyph array to our data type. At the same time, substitute
|
||||
* the proper glyphs for our private sprite glyphs. */
|
||||
@ -251,15 +253,13 @@ CoreTextParagraphLayout::CoreTextVisualRun::CoreTextVisualRun(CTRunRef run, Font
|
||||
if (buff[this->glyph_to_char[i]] >= SCC_SPRITE_START && buff[this->glyph_to_char[i]] <= SCC_SPRITE_END && (gl[i] == 0 || gl[i] == 3)) {
|
||||
/* A glyph of 0 indidicates not found, while apparently 3 is what char 0xFFFC maps to. */
|
||||
this->glyphs[i] = font->fc->MapCharToGlyph(buff[this->glyph_to_char[i]]);
|
||||
this->positions.emplace_back(pts[i].x, (font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(font->fc->GetSize()))) / 2); // Align sprite font to centre
|
||||
this->positions.emplace_back(pts[i].x, pts[i].x + advs[i].width - 1, (font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(font->fc->GetSize()))) / 2); // Align sprite font to centre
|
||||
} else {
|
||||
this->glyphs[i] = gl[i];
|
||||
this->positions.emplace_back(pts[i].x, pts[i].y);
|
||||
this->positions.emplace_back(pts[i].x, pts[i].x + advs[i].width - 1, pts[i].y);
|
||||
}
|
||||
}
|
||||
this->total_advance = (int)std::ceil(CTRunGetTypographicBounds(run, CFRangeMake(0, 0), nullptr, nullptr, nullptr));
|
||||
/* End-of-run position. */
|
||||
this->positions.emplace_back(this->positions.front().x + this->total_advance, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,7 +74,7 @@ public:
|
||||
class UniscribeVisualRun : public ParagraphLayouter::VisualRun {
|
||||
private:
|
||||
std::vector<GlyphID> glyphs;
|
||||
std::vector<Point> positions;
|
||||
std::vector<Position> positions;
|
||||
std::vector<WORD> char_to_glyph;
|
||||
|
||||
int start_pos;
|
||||
@ -89,7 +89,7 @@ public:
|
||||
UniscribeVisualRun(UniscribeVisualRun &&other) noexcept;
|
||||
|
||||
std::span<const GlyphID> GetGlyphs() const override { return this->glyphs; }
|
||||
std::span<const Point> GetPositions() const override { return this->positions; }
|
||||
std::span<const Position> GetPositions() const override { return this->positions; }
|
||||
std::span<const int> GetGlyphToCharMap() const override;
|
||||
|
||||
const Font *GetFont() const override { return this->font; }
|
||||
@ -474,16 +474,15 @@ int UniscribeParagraphLayout::UniscribeLine::GetWidth() const
|
||||
UniscribeParagraphLayout::UniscribeVisualRun::UniscribeVisualRun(const UniscribeRun &range, int x) : glyphs(range.ft_glyphs), char_to_glyph(range.char_to_glyph), start_pos(range.pos), total_advance(range.total_advance), font(range.font)
|
||||
{
|
||||
this->num_glyphs = (int)glyphs.size();
|
||||
this->positions.reserve(this->num_glyphs + 1);
|
||||
this->positions.reserve(this->num_glyphs);
|
||||
|
||||
int advance = x;
|
||||
for (int i = 0; i < this->num_glyphs; i++) {
|
||||
this->positions.emplace_back(range.offsets[i].du + advance, range.offsets[i].dv);
|
||||
int x_advance = range.advances[i];
|
||||
this->positions.emplace_back(range.offsets[i].du + advance - 1, range.offsets[i].du + advance + x_advance, range.offsets[i].dv);
|
||||
|
||||
advance += range.advances[i];
|
||||
advance += x_advance;
|
||||
}
|
||||
/* End-of-run position. */
|
||||
this->positions.emplace_back(advance, 0);
|
||||
}
|
||||
|
||||
UniscribeParagraphLayout::UniscribeVisualRun::UniscribeVisualRun(UniscribeVisualRun&& other) noexcept
|
||||
|
@ -309,15 +309,15 @@ void Textbuf::UpdateWidth()
|
||||
/** Update pixel position of the caret. */
|
||||
void Textbuf::UpdateCaretPosition()
|
||||
{
|
||||
this->caretxoffs = this->chars > 1 ? GetCharPosInString(this->buf, this->buf + this->caretpos, FS_NORMAL).x : 0;
|
||||
this->caretxoffs = this->chars > 1 ? GetCharPosInString(this->buf, this->buf + this->caretpos, FS_NORMAL).left : 0;
|
||||
}
|
||||
|
||||
/** Update pixel positions of the marked text area. */
|
||||
void Textbuf::UpdateMarkedText()
|
||||
{
|
||||
if (this->markend != 0) {
|
||||
this->markxoffs = GetCharPosInString(this->buf, this->buf + this->markpos, FS_NORMAL).x;
|
||||
this->marklength = GetCharPosInString(this->buf, this->buf + this->markend, FS_NORMAL).x - this->markxoffs;
|
||||
this->markxoffs = GetCharPosInString(this->buf, this->buf + this->markpos, FS_NORMAL).left;
|
||||
this->marklength = GetCharPosInString(this->buf, this->buf + this->markend, FS_NORMAL).left - this->markxoffs;
|
||||
} else {
|
||||
this->markxoffs = this->marklength = 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user