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:
parent
b4cabde4a4
commit
50d33f79fa
14 changed files with 186 additions and 88 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue