Changeset - r28511:2d7264916867
[Not reviewed]
master
0 8 0
Peter Nelson - 11 months ago 2024-01-18 21:06:43
peter1138@openttd.org
Codechange: Store text run positions in vector of points.

This simplifies the interlaced vector of x/y positions.
8 files changed with 46 insertions and 53 deletions:
0 comments (0 inline, 0 general)
src/core/geometry_type.hpp
Show inline comments
 
@@ -18,12 +18,15 @@
 

	
 

	
 
/** Coordinates of a point in 2D */
 
struct Point {
 
	int x;
 
	int y;
 

	
 
	constexpr Point() : x(0), y(0) {}
 
	constexpr Point(int x, int y) : x(x), y(y) {}
 
};
 

	
 
/** Dimensions (a width and height) of a rectangle in 2D */
 
struct Dimension {
 
	uint width;
 
	uint height;
src/gfx.cpp
Show inline comments
 
@@ -596,15 +596,15 @@ static int DrawLayoutLine(const Paragrap
 
		for (int i = 0; i < run.GetGlyphCount(); i++) {
 
			GlyphID glyph = glyphs[i];
 

	
 
			/* Not a valid glyph (empty) */
 
			if (glyph == 0xFFFF) continue;
 

	
 
			int begin_x = (int)positions[i * 2]     + left - offset_x;
 
			int end_x   = (int)positions[i * 2 + 2] + left - offset_x  - 1;
 
			int top     = (int)positions[i * 2 + 1] + y;
 
			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;
 

	
 
			/* Truncated away. */
 
			if (truncation && (begin_x < min_x || end_x > max_x)) continue;
 

	
 
			const Sprite *sprite = fc->GetGlyph(glyph);
 
			/* Check clipping (the "+ 1" is for the shadow). */
src/gfx_layout.cpp
Show inline comments
 
@@ -257,14 +257,13 @@ Point Layouter::GetCharPosition(std::str
 
		const auto &positions = run.GetPositions();
 
		const auto &charmap = run.GetGlyphToCharMap();
 

	
 
		for (int i = 0; i < run.GetGlyphCount(); i++) {
 
			/* Matching glyph? Return position. */
 
			if ((size_t)charmap[i] == index) {
 
				Point p = { (int)positions[i * 2], (int)positions[i * 2 + 1] };
 
				return p;
 
				return positions[i];
 
			}
 
		}
 
	}
 

	
 
	NOT_REACHED();
 
}
 
@@ -288,14 +287,14 @@ ptrdiff_t Layouter::GetCharAtPosition(in
 
		const auto &charmap = run.GetGlyphToCharMap();
 

	
 
		for (int i = 0; i < run.GetGlyphCount(); i++) {
 
			/* Not a valid glyph (empty). */
 
			if (glyphs[i] == 0xFFFF) continue;
 

	
 
			int begin_x = (int)positions[i * 2];
 
			int end_x   = (int)positions[i * 2 + 2];
 
			int begin_x = positions[i].x;
 
			int end_x   = positions[i + 1].x;
 

	
 
			if (IsInsideMM(x, begin_x, end_x)) {
 
				/* Found our glyph, now convert to UTF-8 string index. */
 
				size_t index = charmap[i];
 

	
 
				size_t cur_idx = 0;
src/gfx_layout.h
Show inline comments
 
@@ -94,13 +94,13 @@ public:
 
	class VisualRun {
 
	public:
 
		virtual ~VisualRun() = default;
 
		virtual const Font *GetFont() const = 0;
 
		virtual int GetGlyphCount() const = 0;
 
		virtual const std::vector<GlyphID> &GetGlyphs() const = 0;
 
		virtual const std::vector<float> &GetPositions() const = 0;
 
		virtual const std::vector<Point> &GetPositions() const = 0;
 
		virtual int GetLeading() const = 0;
 
		virtual const std::vector<int> &GetGlyphToCharMap() const = 0;
 
	};
 

	
 
	/** A single line worth of VisualRuns. */
 
	class Line {
src/gfx_layout_fallback.cpp
Show inline comments
 
@@ -37,23 +37,23 @@
 
 */
 
class FallbackParagraphLayout : public ParagraphLayouter {
 
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<float> positions; ///< The positions of the glyphs.
 
		std::vector<Point> 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.
 

	
 
	public:
 
		FallbackVisualRun(Font *font, const char32_t *chars, int glyph_count, int char_offset, int x);
 
		const Font *GetFont() const override { return this->font; }
 
		int GetGlyphCount() const override { return static_cast<int>(this->glyphs.size()); }
 
		const std::vector<GlyphID> &GetGlyphs() const override { return this->glyphs; }
 
		const std::vector<float> &GetPositions() const override { return this->positions; }
 
		const std::vector<Point> &GetPositions() const override { return this->positions; }
 
		int GetLeading() const override { return this->GetFont()->fc->GetHeight(); }
 
		const std::vector<int> &GetGlyphToCharMap() const override { return this->glyph_to_char; }
 
	};
 

	
 
	/** A single line worth of VisualRuns. */
 
	class FallbackLine : public std::vector<FallbackVisualRun>, public ParagraphLayouter::Line {
 
@@ -115,27 +115,29 @@ FallbackParagraphLayout::FallbackVisualR
 
	const bool isbuiltin = font->fc->IsBuiltInFont();
 

	
 
	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.resize(char_count * 2 + 2);
 
	this->positions[0] = x;
 
	this->positions.reserve(char_count + 1);
 

	
 
	int advance = x;
 
	for (int i = 0; i < char_count; i++) {
 
		const GlyphID &glyph_id = this->glyphs.emplace_back(font->fc->MapCharToGlyph(chars[i]));
 
		if (isbuiltin) {
 
			this->positions[2 * i + 1] = font->fc->GetAscender(); // Apply sprite font's ascender.
 
			this->positions.emplace_back(advance, font->fc->GetAscender()); // Apply sprite font's ascender.
 
		} else if (chars[i] >= SCC_SPRITE_START && chars[i] <= SCC_SPRITE_END) {
 
			this->positions[2 * i + 1] = (font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(font->fc->GetSize()))) / 2; // Align sprite font to centre
 
			this->positions.emplace_back(advance, (font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(font->fc->GetSize()))) / 2); // Align sprite font to centre
 
		} else {
 
			this->positions[2 * i + 1] = 0;                       // No ascender adjustment.
 
			this->positions.emplace_back(advance, 0); // No ascender adjustment.
 
		}
 
		this->positions[2 * i + 2] = this->positions[2 * i] + font->fc->GetGlyphWidth(glyph_id);
 
		advance += font->fc->GetGlyphWidth(glyph_id);
 
		this->glyph_to_char.push_back(char_offset + i);
 
	}
 
	/* End-of-run position. */
 
	this->positions.emplace_back(advance, 0);
 
}
 

	
 
/**
 
 * Get the height of the line.
 
 * @return The maximum height of the line.
 
 */
 
@@ -160,13 +162,13 @@ int FallbackParagraphLayout::FallbackLin
 
	/*
 
	 * The last X position of a run contains is the end of that run.
 
	 * Since there is no left-to-right support, taking this value of
 
	 * the last run gives us the end of the line and thus the width.
 
	 */
 
	const auto &run = this->GetVisualRun(this->CountRuns() - 1);
 
	return (int)run.GetPositions()[run.GetGlyphCount() * 2];
 
	return run.GetPositions().back().x;
 
}
 

	
 
/**
 
 * Get the number of runs in this line.
 
 * @return The number of runs.
 
 */
src/gfx_layout_icu.cpp
Show inline comments
 
@@ -42,13 +42,13 @@ public:
 
	UScriptCode script; ///< Script of the run.
 
	Font *font; ///< Font of the run.
 

	
 
	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<float> positions; ///< The positions of the glyphs. Valid after Shape() is called.
 
	std::vector<Point> 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) {}
 

	
 
	void Shape(UChar *buff, size_t length);
 
};
 
@@ -59,23 +59,23 @@ public:
 
class ICUParagraphLayout : public ParagraphLayouter {
 
public:
 
	/** Visual run contains data about the bit of text with the same font. */
 
	class ICUVisualRun : public ParagraphLayouter::VisualRun {
 
	private:
 
		std::vector<GlyphID> glyphs;
 
		std::vector<float> positions;
 
		std::vector<Point> positions;
 
		std::vector<int> glyph_to_char;
 

	
 
		int total_advance;
 
		const Font *font;
 

	
 
	public:
 
		ICUVisualRun(const ICURun &run, int x);
 

	
 
		const std::vector<GlyphID> &GetGlyphs() const override { return this->glyphs; }
 
		const std::vector<float> &GetPositions() const override { return this->positions; }
 
		const std::vector<Point> &GetPositions() const override { return this->positions; }
 
		const std::vector<int> &GetGlyphToCharMap() const override { return this->glyph_to_char; }
 

	
 
		const Font *GetFont() const override { return this->font; }
 
		int GetLeading() const override { return this->font->fc->GetHeight(); }
 
		int GetGlyphCount() const override { return this->glyphs.size(); }
 
		int GetAdvance() const { return this->total_advance; }
 
@@ -132,22 +132,15 @@ ICUParagraphLayout::ICUVisualRun::ICUVis
 
	glyphs(run.glyphs), glyph_to_char(run.glyph_to_char), total_advance(run.total_advance), font(run.font)
 
{
 
	/* If there are no positions, the ICURun was not Shaped; that should never happen. */
 
	assert(!run.positions.empty());
 
	this->positions.reserve(run.positions.size());
 

	
 
	/* "positions" is an array of x/y. So we need to alternate. */
 
	bool is_x = true;
 
	for (auto &position : run.positions) {
 
		if (is_x) {
 
			this->positions.push_back(position + x);
 
		} else {
 
			this->positions.push_back(position);
 
		}
 

	
 
		is_x = !is_x;
 
	/* Copy positions, moving x coordinate by x offset. */
 
	for (const Point &pt : run.positions) {
 
		this->positions.emplace_back(pt.x + x, pt.y);
 
	}
 
}
 

	
 
/**
 
 * Shape a single run.
 
 *
 
@@ -183,42 +176,39 @@ void ICURun::Shape(UChar *buff, size_t b
 
	this->positions.clear();
 
	this->advance.clear();
 

	
 
	/* 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 * 2 + 2);
 
	this->positions.reserve(glyph_count + 1);
 
	this->advance.reserve(glyph_count);
 

	
 
	/* Prepare the glyphs/position. ICUVisualRun will give the position an offset if needed. */
 
	hb_position_t advance = 0;
 
	for (unsigned int i = 0; i < glyph_count; i++) {
 
		int x_advance;
 

	
 
		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.push_back(advance);
 
			this->positions.push_back((this->font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(this->font->fc->GetSize()))) / 2); // Align sprite font to centre
 
			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);
 
		} else {
 
			this->glyphs.push_back(glyph_info[i].codepoint);
 
			this->positions.push_back(glyph_pos[i].x_offset / FONT_SCALE + advance);
 
			this->positions.push_back(glyph_pos[i].y_offset / FONT_SCALE);
 
			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->glyph_to_char.push_back(glyph_info[i].cluster);
 
		this->advance.push_back(x_advance);
 
		advance += x_advance;
 
	}
 

	
 
	/* Position has one more element to close off the array. */
 
	this->positions.push_back(advance);
 
	this->positions.push_back(0);
 
	/* End-of-run position. */
 
	this->positions.emplace_back(advance, 0);
 

	
 
	/* Track the total advancement we made. */
 
	this->total_advance = advance;
 

	
 
	hb_buffer_destroy(hbbuf);
 
	hb_font_destroy(hbfont);
src/os/macosx/string_osx.cpp
Show inline comments
 
@@ -68,24 +68,24 @@ private:
 

	
 
public:
 
	/** Visual run contains data about the bit of text with the same font. */
 
	class CoreTextVisualRun : public ParagraphLayouter::VisualRun {
 
	private:
 
		std::vector<GlyphID> glyphs;
 
		std::vector<float> positions;
 
		std::vector<Point> positions;
 
		std::vector<int> glyph_to_char;
 

	
 
		int total_advance = 0;
 
		Font *font;
 

	
 
	public:
 
		CoreTextVisualRun(CTRunRef run, Font *font, const CoreTextParagraphLayoutFactory::CharType *buff);
 
		CoreTextVisualRun(CoreTextVisualRun &&other) = default;
 

	
 
		const std::vector<GlyphID> &GetGlyphs() const override { return this->glyphs; }
 
		const std::vector<float> &GetPositions() const override { return this->positions; }
 
		const std::vector<Point> &GetPositions() const override { return this->positions; }
 
		const std::vector<int> &GetGlyphToCharMap() const override { return this->glyph_to_char; }
 

	
 
		const Font *GetFont() const override { return this->font;  }
 
		int GetLeading() const override { return this->font->fc->GetHeight(); }
 
		int GetGlyphCount() const override { return (int)this->glyphs.size(); }
 
		int GetAdvance() const { return this->total_advance; }
 
@@ -237,32 +237,31 @@ CoreTextParagraphLayout::CoreTextVisualR
 

	
 
	this->glyph_to_char.resize(this->glyphs.size());
 
	for (size_t i = 0; i < this->glyph_to_char.size(); i++) this->glyph_to_char[i] = (int)map[i];
 

	
 
	CGPoint pts[this->glyphs.size()];
 
	CTRunGetPositions(run, CFRangeMake(0, 0), pts);
 
	this->positions.resize(this->glyphs.size() * 2 + 2);
 
	this->positions.reserve(this->glyphs.size() + 1);
 

	
 
	/* Convert glyph array to our data type. At the same time, substitute
 
	 * the proper glyphs for our private sprite glyphs. */
 
	CGGlyph gl[this->glyphs.size()];
 
	CTRunGetGlyphs(run, CFRangeMake(0, 0), gl);
 
	for (size_t i = 0; i < this->glyphs.size(); i++) {
 
		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[i * 2 + 0] = pts[i].x;
 
			this->positions[i * 2 + 1] = (font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(font->fc->GetSize()))) / 2; // Align sprite font to centre
 
			this->positions.emplace_back(pts[i].x, (font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(font->fc->GetSize()))) / 2); // Align sprite font to centre
 
		} else {
 
			this->glyphs[i] = gl[i];
 
			this->positions[i * 2 + 0] = pts[i].x;
 
			this->positions[i * 2 + 1] = pts[i].y;
 
			this->positions.emplace_back(pts[i].x, pts[i].y);
 
		}
 
	}
 
	this->total_advance = (int)std::ceil(CTRunGetTypographicBounds(run, CFRangeMake(0, 0), nullptr, nullptr, nullptr));
 
	this->positions[this->glyphs.size() * 2] = this->positions[0] + this->total_advance;
 
	/* End-of-run position. */
 
	this->positions.emplace_back(this->positions.front().x + this->total_advance, 0);
 
}
 

	
 
/**
 
 * Get the height of the line.
 
 * @return The maximum height of the line.
 
 */
src/os/windows/string_uniscribe.cpp
Show inline comments
 
@@ -71,13 +71,13 @@ private:
 

	
 
public:
 
	/** Visual run contains data about the bit of text with the same font. */
 
	class UniscribeVisualRun : public ParagraphLayouter::VisualRun {
 
	private:
 
		std::vector<GlyphID> glyphs;
 
		std::vector<float> positions;
 
		std::vector<Point> positions;
 
		std::vector<WORD> char_to_glyph;
 

	
 
		int start_pos;
 
		int total_advance;
 
		int num_glyphs;
 
		Font *font;
 
@@ -86,13 +86,13 @@ public:
 

	
 
	public:
 
		UniscribeVisualRun(const UniscribeRun &range, int x);
 
		UniscribeVisualRun(UniscribeVisualRun &&other) noexcept;
 

	
 
		const std::vector<GlyphID> &GetGlyphs() const override { return this->glyphs; }
 
		const std::vector<float> &GetPositions() const override { return this->positions; }
 
		const std::vector<Point> &GetPositions() const override { return this->positions; }
 
		const std::vector<int> &GetGlyphToCharMap() const override;
 

	
 
		const Font *GetFont() const override { return this->font;  }
 
		int GetLeading() const override { return this->font->fc->GetHeight(); }
 
		int GetGlyphCount() const override { return this->num_glyphs; }
 
		int GetAdvance() const { return this->total_advance; }
 
@@ -471,22 +471,22 @@ int UniscribeParagraphLayout::UniscribeL
 
	return length;
 
}
 

	
 
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.resize(this->num_glyphs * 2 + 2);
 
	this->positions.reserve(this->num_glyphs + 1);
 

	
 
	int advance = 0;
 
	int advance = x;
 
	for (int i = 0; i < this->num_glyphs; i++) {
 
		this->positions[i * 2 + 0] = range.offsets[i].du + advance + x;
 
		this->positions[i * 2 + 1] = range.offsets[i].dv;
 
		this->positions.emplace_back(range.offsets[i].du + advance, range.offsets[i].dv);
 

	
 
		advance += range.advances[i];
 
	}
 
	this->positions[this->num_glyphs * 2] = advance + x;
 
	/* End-of-run position. */
 
	this->positions.emplace_back(advance, 0);
 
}
 

	
 
UniscribeParagraphLayout::UniscribeVisualRun::UniscribeVisualRun(UniscribeVisualRun&& other) noexcept
 
								: glyphs(std::move(other.glyphs)), positions(std::move(other.positions)), char_to_glyph(std::move(other.char_to_glyph)),
 
								  start_pos(other.start_pos), total_advance(other.total_advance), num_glyphs(other.num_glyphs), font(other.font),
 
								  glyph_to_char(std::move(other.glyph_to_char))
0 comments (0 inline, 0 general)