Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 61 additions & 12 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@

#include <array>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <tuple>
#include <utility>
#include <vector>

#include "flutter/testing/testing.h"
#include "impeller/aiks/aiks_playground.h"
Expand All @@ -29,6 +31,7 @@
#include "impeller/scene/node.h"
#include "impeller/typographer/backends/skia/text_frame_skia.h"
#include "impeller/typographer/backends/skia/text_render_context_skia.h"
#include "third_party/imgui/imgui.h"
#include "third_party/skia/include/core/SkData.h"

namespace impeller {
Expand Down Expand Up @@ -1126,29 +1129,31 @@ static sk_sp<SkData> OpenFixtureAsSkData(const char* fixture_name) {
return data;
}

struct TextRenderOptions {
Scalar font_size = 50;
Scalar alpha = 1;
Point position = Vector2(100, 200);
};

bool RenderTextInCanvas(const std::shared_ptr<Context>& context,
Canvas& canvas,
const std::string& text,
const std::string& font_fixture,
Scalar font_size = 50.0,
Scalar alpha = 1.0) {
Scalar baseline = 200.0;
Point text_position = {100, baseline};

TextRenderOptions options = {}) {
// Draw the baseline.
canvas.DrawRect({50, baseline, 900, 10},
canvas.DrawRect({options.position.x - 50, options.position.y, 900, 10},
Paint{.color = Color::Aqua().WithAlpha(0.25)});

// Mark the point at which the text is drawn.
canvas.DrawCircle(text_position, 5.0,
canvas.DrawCircle(options.position, 5.0,
Paint{.color = Color::Red().WithAlpha(0.25)});

// Construct the text blob.
auto mapping = OpenFixtureAsSkData(font_fixture.c_str());
if (!mapping) {
return false;
}
SkFont sk_font(SkTypeface::MakeFromData(mapping), 50.0);
SkFont sk_font(SkTypeface::MakeFromData(mapping), options.font_size);
auto blob = SkTextBlob::MakeFromString(text.c_str(), sk_font);
if (!blob) {
return false;
Expand All @@ -1158,8 +1163,8 @@ bool RenderTextInCanvas(const std::shared_ptr<Context>& context,
auto frame = TextFrameFromTextBlob(blob);

Paint text_paint;
text_paint.color = Color::Yellow().WithAlpha(alpha);
canvas.DrawTextFrame(frame, text_position, text_paint);
text_paint.color = Color::Yellow().WithAlpha(options.alpha);
canvas.DrawTextFrame(frame, options.position, text_paint);
return true;
}

Expand All @@ -1171,6 +1176,49 @@ TEST_P(AiksTest, CanRenderTextFrame) {
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, TextFrameSubpixelAlignment) {
std::array<Scalar, 20> phase_offsets;
for (Scalar& offset : phase_offsets) {
auto rand = std::rand(); // NOLINT
offset = (static_cast<float>(rand) / static_cast<float>(RAND_MAX)) * k2Pi;
}

auto callback = [&](AiksContext& renderer,
RenderTarget& render_target) -> bool {
static float font_size = 20;
static float phase_variation = 0.2;
static float speed = 0.5;
static float magnitude = 100;
ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
ImGui::SliderFloat("Font size", &font_size, 5, 50);
ImGui::SliderFloat("Phase variation", &phase_variation, 0, 1);
ImGui::SliderFloat("Oscillation speed", &speed, 0, 2);
ImGui::SliderFloat("Oscillation magnitude", &magnitude, 0, 300);
ImGui::End();

Canvas canvas;
canvas.Scale(GetContentScale());

for (size_t i = 0; i < phase_offsets.size(); i++) {
auto position = Point(
200 + magnitude * std::sin((-phase_offsets[i] * phase_variation +
GetSecondsElapsed() * speed)), //
200 + i * font_size * 1.1 //
);
if (!RenderTextInCanvas(GetContext(), canvas,
"the quick brown fox jumped over "
"the lazy dog!.?",
"Roboto-Regular.ttf",
{.font_size = font_size, .position = position})) {
return false;
}
}
return renderer.Render(canvas.EndRecordingAsPicture(), render_target);
};

ASSERT_TRUE(OpenPlaygroundHere(callback));
}

TEST_P(AiksTest, CanRenderItalicizedText) {
Canvas canvas;
ASSERT_TRUE(RenderTextInCanvas(
Expand All @@ -1196,10 +1244,11 @@ TEST_P(AiksTest, CanRenderEmojiTextFrameWithAlpha) {
ASSERT_TRUE(RenderTextInCanvas(GetContext(), canvas,
"😀 😃 😄 😁 😆 😅 😂 🤣 🥲 😊",
#if FML_OS_MACOSX
"Apple Color Emoji.ttc", 50, 0.5));
"Apple Color Emoji.ttc", { .alpha = 0.5 }
#else
"NotoColorEmoji.ttf", 50, 0.5));
"NotoColorEmoji.ttf", {.alpha = 0.5}
#endif
));
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

Expand Down
5 changes: 3 additions & 2 deletions impeller/typographer/backends/skia/text_frame_skia.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ TextFrame TextFrameFromTextBlob(const sk_sp<SkTextBlob>& blob, Scalar scale) {
? Glyph::Type::kBitmap
: Glyph::Type::kPath;

text_run.AddGlyph(Glyph{glyphs[i], type, ToRect(glyph_bounds[i])},
Point{point->x(), point->y()});
text_run.AddGlyph(
Glyph{glyphs[i], type, ToRect(glyph_bounds[i])},
Point{std::round(point->x()), std::round(point->y())});
}
break;
}
Expand Down