Text modifiers!

Adds support for text modifiers, which are a set a of operations that can run on a per character basis to transform, reshape, and fade resulting glyphs.

Adds:
- Modifier groups which encompass a set of modifications done to a range of the text.
- Range selectors which help define the range the modifier applies to (multiple range selectors can be included to build up the final selection of a modifier group).
- Variation modifiers which allow animating variable fonts per character.
- Origin, Translation, Rotation, and Scale modification.
- Opacity modifiers.

Diffs=
9695de6e3 Text modifiers! (#5288)
This commit is contained in:
luigi-rosso
2023-05-25 17:52:14 +00:00
parent 73fac9a837
commit fe711607db
6 changed files with 98 additions and 5 deletions

View File

@@ -1 +1 @@
a9f8a1c5d351a72b4537a6b8a27962d130f0a97c
9695de6e34a963dd4fa4dc73b72e366c7a68ff04

View File

@@ -24,6 +24,7 @@ public:
Axis getAxis(uint16_t index) const override;
uint16_t getAxisCount() const override;
float getAxisValue(uint32_t axisTag) const override;
std::vector<Coord> getCoords() const override;
rive::rcp<rive::Font> makeAtCoords(rive::Span<const Coord>) const override;
rive::RawPath getPath(rive::GlyphID) const override;

View File

@@ -132,6 +132,8 @@ public:
//
virtual std::vector<Coord> getCoords() const = 0;
virtual float getAxisValue(uint32_t axisTag) const = 0;
virtual rcp<Font> makeAtCoords(Span<const Coord>) const = 0;
rcp<Font> makeAtCoord(Coord c) { return this->makeAtCoords(Span<const Coord>(&c, 1)); }

View File

@@ -153,6 +153,39 @@ uint16_t HBFont::getAxisCount() const
return (uint16_t)hb_ot_var_get_axis_count(face);
}
float HBFont::getAxisValue(uint32_t axisTag) const
{
auto face = hb_font_get_face(m_Font);
uint32_t length;
// Check if we have a sepecified value.
const float* values = hb_font_get_var_coords_design(m_Font, &length);
for (uint32_t i = 0; i < length; ++i)
{
hb_ot_var_axis_info_t info;
uint32_t n = 1;
hb_ot_var_get_axis_infos(face, i, &n, &info);
if (info.tag == axisTag)
{
return values[i];
}
}
// No value specified, we're using a default.
uint32_t axisCount = hb_ot_var_get_axis_count(face);
for (uint32_t i = 0; i < axisCount; ++i)
{
hb_ot_var_axis_info_t info;
uint32_t n = 1;
hb_ot_var_get_axis_infos(face, i, &n, &info);
if (info.tag == axisTag)
{
return info.default_value;
}
}
return 0.0f;
}
std::vector<rive::Font::Coord> HBFont::getCoords() const
{
auto axes = this->getAxes();
@@ -220,7 +253,6 @@ static rive::GlyphRun shape_run(const rive::Unichar text[],
hb_glyph_position_t* glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count);
// todo: check for missing glyphs, and perform font-substitution
rive::GlyphRun gr(glyph_count);
gr.font = tr.font;
gr.size = tr.size;
@@ -290,7 +322,11 @@ static void perform_fallback(rive::rcp<rive::Font> fallbackFont,
orig.styleId,
orig.dir,
};
gruns.add(shape_run(&text[textStart], tr, textStart));
auto gr = shape_run(&text[textStart], tr, textStart);
if (gr.glyphs.size() > 0)
{
gruns.add(std::move(gr));
}
}
else
{
@@ -424,7 +460,10 @@ rive::SimpleArray<rive::Paragraph> HBFont::onShapeText(rive::Span<const rive::Un
auto iter = std::find(gr.glyphs.begin(), end, 0);
if (!gFallbackProc || iter == end)
{
gruns.add(std::move(gr));
if (gr.glyphs.size() > 0)
{
gruns.add(std::move(gr));
}
}
else
{
@@ -437,7 +476,7 @@ rive::SimpleArray<rive::Paragraph> HBFont::onShapeText(rive::Span<const rive::Un
{
perform_fallback(fallback, gruns, text.data(), gr, tr);
}
else
else if (gr.glyphs.size() > 0)
{
gruns.add(std::move(gr)); // oh well, just keep the missing glyphs
}

View File

@@ -75,3 +75,36 @@ TEST_CASE("fallback glyphs are found", "[text]")
fallbackFonts.clear();
HBFont::gFallbackProc = nullptr;
}
TEST_CASE("variable axis values can be read", "[text]")
{
REQUIRE(fallbackFonts.empty());
auto font = loadFont("../../test/assets/RobotoFlex.ttf");
REQUIRE(font != nullptr);
std::vector<rive::Font::Axis> axes = font->getAxes();
bool hasWeight = false;
for (rive::Font::Axis axis : axes)
{
if (axis.tag == 2003265652)
{
REQUIRE(axis.def == 400.0f);
hasWeight = true;
break;
}
}
REQUIRE(hasWeight);
float value = font->getAxisValue(2003265652);
REQUIRE(value == 400.0f);
rive::Font::Coord coord = {2003265652, 800.0f};
rive::rcp<rive::Font> vfont = font->makeAtCoords(rive::Span<HBFont::Coord>(&coord, 1));
REQUIRE(vfont->getAxisValue(2003265652) == 800.0f);
rive::Font::Coord coord2 = {2003265652, 822.0f};
rive::rcp<rive::Font> vfont2 = vfont->makeAtCoords(rive::Span<HBFont::Coord>(&coord2, 1));
REQUIRE(vfont2->getAxisValue(2003265652) == 822.0f);
}

View File

@@ -9,6 +9,24 @@
#include <cstdio>
#include <cstring>
TEST_CASE("transform order is as expected", "[transform]")
{
auto translation = rive::Mat2D::fromTranslate(10.0f, 20.0f);
auto rotation = rive::Mat2D::fromRotation(3.14f / 2.0f);
auto scale = rive::Mat2D::fromScale(2.0f, 3.0f);
auto xform = translation * rotation * scale;
auto xform2 = rive::Mat2D::fromRotation(3.14f / 2.0f);
xform2[0] *= 2.0f;
xform2[1] *= 2.0f;
xform2[2] *= 3.0f;
xform2[3] *= 3.0f;
xform2[4] = 10.0f;
xform2[5] = 20.0f;
REQUIRE(xform2 == xform);
}
TEST_CASE("file can be read", "[file]")
{
RenderObjectLeakChecker checker;