1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 19:47:46 +00:00

LibGfx: Allow extracting paths from fonts and add Gfx::Path::text()

This updates fonts so rather than rastering directly to a bitmap, you
can extract paths for glyphs. This is then used to implement a
Gfx::Path::text("some text", font) API, that if given a vector font
appends the path of the text to your Gfx::Path. This then allows
arbitrary manipulation of the text (rotation, skewing, etc), paving the
way for Word Art in Serenity.
This commit is contained in:
MacDue 2023-11-04 21:41:24 +00:00 committed by Alexander Kalenik
parent b4cabde4a4
commit 50d33f79fa
14 changed files with 186 additions and 88 deletions

View file

@ -7,6 +7,7 @@
#pragma once
#include <AK/CharacterTypes.h>
#include <AK/DeprecatedString.h>
#include <AK/Forward.h>
#include <AK/Utf32View.h>
@ -64,4 +65,59 @@ private:
FloatRect m_rect;
};
inline bool should_paint_as_space(u32 code_point)
{
return is_ascii_space(code_point) || code_point == 0xa0;
}
enum class IncludeLeftBearing {
Yes,
No
};
struct GlyphPosition {
FloatPoint position;
float glyph_width;
AK::Utf8CodePointIterator& it;
};
template<typename Callback>
void for_each_glyph_position(FloatPoint start, Utf8View text, Font const& font, Callback callback, IncludeLeftBearing include_left_bearing = IncludeLeftBearing::No)
{
float space_width = font.glyph_width(' ') + font.glyph_spacing();
u32 last_code_point = 0;
auto point = start;
point.translate_by(0, -font.pixel_metrics().ascent);
for (auto code_point_iterator = text.begin(); code_point_iterator != text.end(); ++code_point_iterator) {
auto code_point = *code_point_iterator;
if (should_paint_as_space(code_point)) {
point.translate_by(space_width, 0);
last_code_point = code_point;
continue;
}
auto kerning = font.glyphs_horizontal_kerning(last_code_point, code_point);
if (kerning != 0.0f)
point.translate_by(kerning, 0);
auto it = code_point_iterator; // The callback function will advance the iterator, so create a copy for this lookup.
auto glyph_width = font.glyph_or_emoji_width(it) + font.glyph_spacing();
auto glyph_point = point;
if (include_left_bearing == IncludeLeftBearing::Yes)
glyph_point += FloatPoint(font.glyph_left_bearing(code_point), 0);
callback(GlyphPosition {
.position = glyph_point,
.glyph_width = glyph_width,
.it = code_point_iterator });
point.translate_by(glyph_width, 0);
last_code_point = code_point;
}
}
}