4
4
5
5
#include < array>
6
6
#include < cmath>
7
+ #include < cstdlib>
7
8
#include < iostream>
8
9
#include < memory>
9
10
#include < tuple>
10
11
#include < utility>
12
+ #include < vector>
11
13
12
14
#include " flutter/testing/testing.h"
13
15
#include " impeller/aiks/aiks_playground.h"
29
31
#include " impeller/scene/node.h"
30
32
#include " impeller/typographer/backends/skia/text_frame_skia.h"
31
33
#include " impeller/typographer/backends/skia/text_render_context_skia.h"
34
+ #include " third_party/imgui/imgui.h"
32
35
#include " third_party/skia/include/core/SkData.h"
33
36
34
37
namespace impeller {
@@ -1126,29 +1129,31 @@ static sk_sp<SkData> OpenFixtureAsSkData(const char* fixture_name) {
1126
1129
return data;
1127
1130
}
1128
1131
1132
+ struct TextRenderOptions {
1133
+ Scalar font_size = 50 ;
1134
+ Scalar alpha = 1 ;
1135
+ Point position = Vector2(100 , 200 );
1136
+ };
1137
+
1129
1138
bool RenderTextInCanvas (const std::shared_ptr<Context>& context,
1130
1139
Canvas& canvas,
1131
1140
const std::string& text,
1132
1141
const std::string& font_fixture,
1133
- Scalar font_size = 50.0 ,
1134
- Scalar alpha = 1.0 ) {
1135
- Scalar baseline = 200.0 ;
1136
- Point text_position = {100 , baseline};
1137
-
1142
+ TextRenderOptions options = {}) {
1138
1143
// Draw the baseline.
1139
- canvas.DrawRect ({50 , baseline , 900 , 10 },
1144
+ canvas.DrawRect ({options. position . x - 50 , options. position . y , 900 , 10 },
1140
1145
Paint{.color = Color::Aqua ().WithAlpha (0.25 )});
1141
1146
1142
1147
// Mark the point at which the text is drawn.
1143
- canvas.DrawCircle (text_position , 5.0 ,
1148
+ canvas.DrawCircle (options. position , 5.0 ,
1144
1149
Paint{.color = Color::Red ().WithAlpha (0.25 )});
1145
1150
1146
1151
// Construct the text blob.
1147
1152
auto mapping = OpenFixtureAsSkData (font_fixture.c_str ());
1148
1153
if (!mapping) {
1149
1154
return false ;
1150
1155
}
1151
- SkFont sk_font (SkTypeface::MakeFromData (mapping), 50.0 );
1156
+ SkFont sk_font (SkTypeface::MakeFromData (mapping), options. font_size );
1152
1157
auto blob = SkTextBlob::MakeFromString (text.c_str (), sk_font);
1153
1158
if (!blob) {
1154
1159
return false ;
@@ -1158,8 +1163,8 @@ bool RenderTextInCanvas(const std::shared_ptr<Context>& context,
1158
1163
auto frame = TextFrameFromTextBlob (blob);
1159
1164
1160
1165
Paint text_paint;
1161
- text_paint.color = Color::Yellow ().WithAlpha (alpha);
1162
- canvas.DrawTextFrame (frame, text_position , text_paint);
1166
+ text_paint.color = Color::Yellow ().WithAlpha (options. alpha );
1167
+ canvas.DrawTextFrame (frame, options. position , text_paint);
1163
1168
return true ;
1164
1169
}
1165
1170
@@ -1171,6 +1176,49 @@ TEST_P(AiksTest, CanRenderTextFrame) {
1171
1176
ASSERT_TRUE (OpenPlaygroundHere (canvas.EndRecordingAsPicture ()));
1172
1177
}
1173
1178
1179
+ TEST_P (AiksTest, TextFrameSubpixelAlignment) {
1180
+ std::array<Scalar, 20 > phase_offsets;
1181
+ for (Scalar& offset : phase_offsets) {
1182
+ offset = (static_cast <float >(std::rand ()) / static_cast <float >(RAND_MAX)) *
1183
+ k2Pi; // NOLINT
1184
+ }
1185
+
1186
+ auto callback = [&](AiksContext& renderer,
1187
+ RenderTarget& render_target) -> bool {
1188
+ static float font_size = 20 ;
1189
+ static float phase_variation = 0.2 ;
1190
+ static float speed = 0.5 ;
1191
+ static float magnitude = 100 ;
1192
+ ImGui::Begin (" Controls" , nullptr , ImGuiWindowFlags_AlwaysAutoResize);
1193
+ ImGui::SliderFloat (" Font size" , &font_size, 5 , 50 );
1194
+ ImGui::SliderFloat (" Phase variation" , &phase_variation, 0 , 1 );
1195
+ ImGui::SliderFloat (" Oscillation speed" , &speed, 0 , 2 );
1196
+ ImGui::SliderFloat (" Oscillation magnitude" , &magnitude, 0 , 300 );
1197
+ ImGui::End ();
1198
+
1199
+ Canvas canvas;
1200
+ canvas.Scale (GetContentScale ());
1201
+
1202
+ for (size_t i = 0 ; i < phase_offsets.size (); i++) {
1203
+ auto position = Point (
1204
+ 200 + magnitude * std::sin ((-phase_offsets[i] * phase_variation +
1205
+ GetSecondsElapsed () * speed)), //
1206
+ 200 + i * font_size * 1.1 //
1207
+ );
1208
+ if (!RenderTextInCanvas (GetContext (), canvas,
1209
+ " the quick brown fox jumped over "
1210
+ " the lazy dog!.?" ,
1211
+ " Roboto-Regular.ttf" ,
1212
+ {.font_size = font_size, .position = position})) {
1213
+ return false ;
1214
+ }
1215
+ }
1216
+ return renderer.Render (canvas.EndRecordingAsPicture (), render_target);
1217
+ };
1218
+
1219
+ ASSERT_TRUE (OpenPlaygroundHere (callback));
1220
+ }
1221
+
1174
1222
TEST_P (AiksTest, CanRenderItalicizedText) {
1175
1223
Canvas canvas;
1176
1224
ASSERT_TRUE (RenderTextInCanvas (
@@ -1196,10 +1244,11 @@ TEST_P(AiksTest, CanRenderEmojiTextFrameWithAlpha) {
1196
1244
ASSERT_TRUE (RenderTextInCanvas (GetContext (), canvas,
1197
1245
" π π π π π π
π π€£ π₯² π" ,
1198
1246
#if FML_OS_MACOSX
1199
- " Apple Color Emoji.ttc" , 50 , 0.5 ));
1247
+ " Apple Color Emoji.ttc" , { . alpha = 0.5 }
1200
1248
#else
1201
- " NotoColorEmoji.ttf" , 50 , 0.5 ));
1249
+ " NotoColorEmoji.ttf" , {. alpha = 0.5 }
1202
1250
#endif
1251
+ ));
1203
1252
ASSERT_TRUE (OpenPlaygroundHere (canvas.EndRecordingAsPicture ()));
1204
1253
}
1205
1254
0 commit comments