diff --git a/DEPS b/DEPS index ac7ed16313225..52681dac25d17 100644 --- a/DEPS +++ b/DEPS @@ -214,6 +214,7 @@ vars = { "upstream_sqlite": "https://github.com/sqlite/sqlite.git", "upstream_sse": "https://github.com/dart-lang/sse.git", "upstream_stack_trace": "https://github.com/dart-lang/stack_trace.git", + "upstream_stb": "https://github.com/nothings/stb.git", "upstream_stream_channel": "https://github.com/dart-lang/stream_channel.git", "upstream_string_scanner": "https://github.com/dart-lang/string_scanner.git", "upstream_SwiftShader": "https://swiftshader.googlesource.com/SwiftShader.git", @@ -257,7 +258,7 @@ allowed_hosts = [ ] deps = { - 'src': 'https://github.com/flutter/buildroot.git' + '@' + 'a067408d923ccf80742571bb7a71705499f5779e', + 'src': 'https://github.com/flutter/buildroot.git' + '@' + 'f91786b0f7ed84f4d55fef7707b68bea180281f5', # Fuchsia compatibility # @@ -681,6 +682,9 @@ deps = { 'src/third_party/json': Var('github_git') + '/nlohmann/json.git' + '@' + '17d9eacd248f58b73f4d1be518ef649fe2295642', + 'src/third_party/stb': + Var('github_git') + '/nothings/stb.git' + '@' + '5736b15f7ea0ffb08dd38af21067c314d6a3aae9', + 'src/third_party/gradle': { 'packages': [ { diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 91b8b6d2c283a..3f8f77c0a85c3 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -2890,6 +2890,7 @@ ../../../third_party/sqlite/Makefile ../../../third_party/sqlite/README.md ../../../third_party/sqlite/VERSION +../../../third_party/stb ../../../third_party/swiftshader ../../../third_party/tinygltf ../../../third_party/vulkan-deps/.git diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index f02a1846afa9f..19858013ccd9c 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1705,12 +1705,22 @@ ORIGIN: ../../../flutter/impeller/toolkit/egl/surface.cc + ../../../flutter/LICE ORIGIN: ../../../flutter/impeller/toolkit/egl/surface.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/toolkit/gles/gles.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/toolkit/gles/texture.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/typographer/backends/skia/glyph_atlas_context_skia.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/typographer/backends/skia/glyph_atlas_context_skia.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/backends/skia/text_frame_skia.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/backends/skia/text_frame_skia.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/typographer/backends/skia/text_render_context_skia.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/typographer/backends/skia/text_render_context_skia.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/backends/skia/typeface_skia.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/backends/skia/typeface_skia.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/typographer/backends/skia/typographer_context_skia.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/typographer/backends/skia/typographer_context_skia.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/typographer/backends/stb/glyph_atlas_context_stb.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/typographer/backends/stb/glyph_atlas_context_stb.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/typographer/backends/stb/text_frame_stb.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/typographer/backends/stb/text_frame_stb.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/typographer/backends/stb/typeface_stb.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/typographer/backends/stb/typeface_stb.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/typographer/backends/stb/typographer_context_stb.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/typographer/backends/stb/typographer_context_stb.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/font.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/font.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/font_glyph_pair.cc + ../../../flutter/LICENSE @@ -1725,12 +1735,12 @@ ORIGIN: ../../../flutter/impeller/typographer/rectangle_packer.cc + ../../../flu ORIGIN: ../../../flutter/impeller/typographer/rectangle_packer.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/text_frame.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/text_frame.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/typographer/text_render_context.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/typographer/text_render_context.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/text_run.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/text_run.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/typeface.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/typeface.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/typographer/typographer_context.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/typographer/typographer_context.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/context.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/context.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/export.cc + ../../../flutter/LICENSE @@ -4436,12 +4446,22 @@ FILE: ../../../flutter/impeller/toolkit/gles/gles.h FILE: ../../../flutter/impeller/toolkit/gles/texture.cc FILE: ../../../flutter/impeller/toolkit/gles/texture.h FILE: ../../../flutter/impeller/tools/malioc.json +FILE: ../../../flutter/impeller/typographer/backends/skia/glyph_atlas_context_skia.cc +FILE: ../../../flutter/impeller/typographer/backends/skia/glyph_atlas_context_skia.h FILE: ../../../flutter/impeller/typographer/backends/skia/text_frame_skia.cc FILE: ../../../flutter/impeller/typographer/backends/skia/text_frame_skia.h -FILE: ../../../flutter/impeller/typographer/backends/skia/text_render_context_skia.cc -FILE: ../../../flutter/impeller/typographer/backends/skia/text_render_context_skia.h FILE: ../../../flutter/impeller/typographer/backends/skia/typeface_skia.cc FILE: ../../../flutter/impeller/typographer/backends/skia/typeface_skia.h +FILE: ../../../flutter/impeller/typographer/backends/skia/typographer_context_skia.cc +FILE: ../../../flutter/impeller/typographer/backends/skia/typographer_context_skia.h +FILE: ../../../flutter/impeller/typographer/backends/stb/glyph_atlas_context_stb.cc +FILE: ../../../flutter/impeller/typographer/backends/stb/glyph_atlas_context_stb.h +FILE: ../../../flutter/impeller/typographer/backends/stb/text_frame_stb.cc +FILE: ../../../flutter/impeller/typographer/backends/stb/text_frame_stb.h +FILE: ../../../flutter/impeller/typographer/backends/stb/typeface_stb.cc +FILE: ../../../flutter/impeller/typographer/backends/stb/typeface_stb.h +FILE: ../../../flutter/impeller/typographer/backends/stb/typographer_context_stb.cc +FILE: ../../../flutter/impeller/typographer/backends/stb/typographer_context_stb.h FILE: ../../../flutter/impeller/typographer/font.cc FILE: ../../../flutter/impeller/typographer/font.h FILE: ../../../flutter/impeller/typographer/font_glyph_pair.cc @@ -4456,12 +4476,12 @@ FILE: ../../../flutter/impeller/typographer/rectangle_packer.cc FILE: ../../../flutter/impeller/typographer/rectangle_packer.h FILE: ../../../flutter/impeller/typographer/text_frame.cc FILE: ../../../flutter/impeller/typographer/text_frame.h -FILE: ../../../flutter/impeller/typographer/text_render_context.cc -FILE: ../../../flutter/impeller/typographer/text_render_context.h FILE: ../../../flutter/impeller/typographer/text_run.cc FILE: ../../../flutter/impeller/typographer/text_run.h FILE: ../../../flutter/impeller/typographer/typeface.cc FILE: ../../../flutter/impeller/typographer/typeface.h +FILE: ../../../flutter/impeller/typographer/typographer_context.cc +FILE: ../../../flutter/impeller/typographer/typographer_context.h FILE: ../../../flutter/lib/gpu/context.cc FILE: ../../../flutter/lib/gpu/context.h FILE: ../../../flutter/lib/gpu/export.cc diff --git a/ci/licenses_golden/tool_signature b/ci/licenses_golden/tool_signature index 8ce45750979aa..c6a8bbffb78fd 100644 --- a/ci/licenses_golden/tool_signature +++ b/ci/licenses_golden/tool_signature @@ -1,2 +1,2 @@ -Signature: d8b5e1bcc7593e590ac227d01043c4a8 +Signature: 996bda987bb421e5aecf9238c247c296 diff --git a/impeller/BUILD.gn b/impeller/BUILD.gn index c55631be197ff..9855acc959de5 100644 --- a/impeller/BUILD.gn +++ b/impeller/BUILD.gn @@ -62,7 +62,7 @@ group("impeller") { "image:image_skia_backend", "renderer", "renderer/backend", - "typographer", + "typographer/backends/skia:typographer_skia_backend", ] } } diff --git a/impeller/aiks/BUILD.gn b/impeller/aiks/BUILD.gn index d63facbd642fd..91ba4d190bac2 100644 --- a/impeller/aiks/BUILD.gn +++ b/impeller/aiks/BUILD.gn @@ -37,6 +37,7 @@ impeller_component("aiks") { impeller_component("aiks_playground") { testonly = true + sources = [ "aiks_playground.cc", "aiks_playground.h", @@ -45,10 +46,14 @@ impeller_component("aiks_playground") { ":aiks", "../playground:playground_test", ] + public_deps = [ + "//flutter/impeller/typographer/backends/skia:typographer_skia_backend", + ] } impeller_component("aiks_unittests") { testonly = true + sources = [ "aiks_unittests.cc", "canvas_unittests.cc", @@ -62,6 +67,7 @@ impeller_component("aiks_unittests") { "//flutter/impeller/geometry:geometry_asserts", "//flutter/impeller/golden_tests:golden_playground_test", "//flutter/impeller/playground:playground_test", + "//flutter/impeller/typographer/backends/stb:typographer_stb_backend", "//flutter/testing:testing_lib", ] } @@ -86,6 +92,7 @@ impeller_component("aiks_unittests_golden") { "//flutter/impeller/geometry:geometry_asserts", "//flutter/impeller/golden_tests:golden_playground_test", "//flutter/impeller/playground:playground_test", + "//flutter/impeller/typographer/backends/stb:typographer_stb_backend", "//flutter/testing:testing_lib", ] } diff --git a/impeller/aiks/aiks_context.cc b/impeller/aiks/aiks_context.cc index fc0a3efc45557..86baab74d7953 100644 --- a/impeller/aiks/aiks_context.cc +++ b/impeller/aiks/aiks_context.cc @@ -5,19 +5,20 @@ #include "impeller/aiks/aiks_context.h" #include "impeller/aiks/picture.h" -#include "impeller/typographer/text_render_context.h" +#include "impeller/typographer/typographer_context.h" namespace impeller { -AiksContext::AiksContext(std::shared_ptr context, - std::shared_ptr text_render_context) +AiksContext::AiksContext( + std::shared_ptr context, + std::shared_ptr typographer_context) : context_(std::move(context)) { if (!context_ || !context_->IsValid()) { return; } content_context_ = std::make_unique( - context_, std::move(text_render_context)); + context_, std::move(typographer_context)); if (!content_context_->IsValid()) { return; } diff --git a/impeller/aiks/aiks_context.h b/impeller/aiks/aiks_context.h index 9564a8a19cbab..1b46ebdc9b268 100644 --- a/impeller/aiks/aiks_context.h +++ b/impeller/aiks/aiks_context.h @@ -10,7 +10,7 @@ #include "impeller/entity/contents/content_context.h" #include "impeller/renderer/context.h" #include "impeller/renderer/render_target.h" -#include "impeller/typographer/text_render_context.h" +#include "impeller/typographer/typographer_context.h" namespace impeller { @@ -24,12 +24,12 @@ class AiksContext { /// @param context The Impeller context that Aiks should use for /// allocating resources and executing device /// commands. Required. - /// @param text_render_context The text backend to use for rendering text. If + /// @param typographer_context The text backend to use for rendering text. If /// `nullptr` is supplied, then attempting to draw /// text with Aiks will result in validation /// errors. AiksContext(std::shared_ptr context, - std::shared_ptr text_render_context); + std::shared_ptr typographer_context); ~AiksContext(); diff --git a/impeller/aiks/aiks_playground.cc b/impeller/aiks/aiks_playground.cc index cb39ce7647182..d23a7315e21ae 100644 --- a/impeller/aiks/aiks_playground.cc +++ b/impeller/aiks/aiks_playground.cc @@ -7,20 +7,20 @@ #include #include "impeller/aiks/aiks_context.h" -#include "impeller/typographer/backends/skia/text_render_context_skia.h" -#include "impeller/typographer/text_render_context.h" +#include "impeller/typographer/backends/skia/typographer_context_skia.h" +#include "impeller/typographer/typographer_context.h" #include "third_party/imgui/imgui.h" namespace impeller { AiksPlayground::AiksPlayground() - : text_render_context_(TextRenderContextSkia::Make()) {} + : typographer_context_(TypographerContextSkia::Make()) {} AiksPlayground::~AiksPlayground() = default; -void AiksPlayground::SetTextRenderContext( - std::shared_ptr text_render_context) { - text_render_context_ = std::move(text_render_context); +void AiksPlayground::SetTypographerContext( + std::shared_ptr typographer_context) { + typographer_context_ = std::move(typographer_context); } bool AiksPlayground::OpenPlaygroundHere(const Picture& picture) { @@ -35,7 +35,7 @@ bool AiksPlayground::OpenPlaygroundHere(AiksPlaygroundCallback callback) { return true; } - AiksContext renderer(GetContext(), text_render_context_); + AiksContext renderer(GetContext(), typographer_context_); if (!renderer.IsValid()) { return false; diff --git a/impeller/aiks/aiks_playground.h b/impeller/aiks/aiks_playground.h index f391ea4d87776..2d854b0c21468 100644 --- a/impeller/aiks/aiks_playground.h +++ b/impeller/aiks/aiks_playground.h @@ -8,7 +8,7 @@ #include "impeller/aiks/aiks_context.h" #include "impeller/aiks/picture.h" #include "impeller/playground/playground_test.h" -#include "impeller/typographer/text_render_context.h" +#include "impeller/typographer/typographer_context.h" namespace impeller { @@ -21,15 +21,15 @@ class AiksPlayground : public PlaygroundTest { ~AiksPlayground(); - void SetTextRenderContext( - std::shared_ptr text_render_context); + void SetTypographerContext( + std::shared_ptr typographer_context); bool OpenPlaygroundHere(const Picture& picture); bool OpenPlaygroundHere(AiksPlaygroundCallback callback); private: - std::shared_ptr text_render_context_; + std::shared_ptr typographer_context_; FML_DISALLOW_COPY_AND_ASSIGN(AiksPlayground); }; diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 557e122b62f24..ba4305c1b63d4 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -36,7 +36,10 @@ #include "impeller/scene/material.h" #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 "impeller/typographer/backends/skia/typographer_context_skia.h" +#include "impeller/typographer/backends/stb/text_frame_stb.h" +#include "impeller/typographer/backends/stb/typeface_stb.h" +#include "impeller/typographer/backends/stb/typographer_context_stb.h" #include "third_party/imgui/imgui.h" #include "third_party/skia/include/core/SkData.h" @@ -1249,11 +1252,11 @@ struct TextRenderOptions { Point position = Vector2(100, 200); }; -bool RenderTextInCanvas(const std::shared_ptr& context, - Canvas& canvas, - const std::string& text, - const std::string& font_fixture, - TextRenderOptions options = {}) { +bool RenderTextInCanvasSkia(const std::shared_ptr& context, + Canvas& canvas, + const std::string& text, + const std::string& font_fixture, + TextRenderOptions options = {}) { // Draw the baseline. canvas.DrawRect({options.position.x - 50, options.position.y, 900, 10}, Paint{.color = Color::Aqua().WithAlpha(0.25)}); @@ -1274,7 +1277,36 @@ bool RenderTextInCanvas(const std::shared_ptr& context, } // Create the Impeller text frame and draw it at the designated baseline. - auto frame = TextFrameFromTextBlob(blob); + auto frame = MakeTextFrameFromTextBlobSkia(blob); + + Paint text_paint; + text_paint.color = Color::Yellow().WithAlpha(options.alpha); + canvas.DrawTextFrame(frame, options.position, text_paint); + return true; +} + +bool RenderTextInCanvasSTB(const std::shared_ptr& context, + Canvas& canvas, + const std::string& text, + const std::string& font_fixture, + TextRenderOptions options = {}) { + // Draw the baseline. + 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(options.position, 5.0, + Paint{.color = Color::Red().WithAlpha(0.25)}); + + // Construct the text blob. + auto mapping = flutter::testing::OpenFixtureAsMapping(font_fixture.c_str()); + if (!mapping) { + return false; + } + auto typeface_stb = std::make_shared(std::move(mapping)); + + auto frame = MakeTextFrameSTB( + typeface_stb, Font::Metrics{.point_size = options.font_size}, text); Paint text_paint; text_paint.color = Color::Yellow().WithAlpha(options.alpha); @@ -1285,9 +1317,20 @@ bool RenderTextInCanvas(const std::shared_ptr& context, TEST_P(AiksTest, CanRenderTextFrame) { Canvas canvas; canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)}); - ASSERT_TRUE(RenderTextInCanvas( + ASSERT_TRUE(RenderTextInCanvasSkia( + GetContext(), canvas, "the quick brown fox jumped over the lazy dog!.?", + "Roboto-Regular.ttf")); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +TEST_P(AiksTest, CanRenderTextFrameSTB) { + Canvas canvas; + canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)}); + ASSERT_TRUE(RenderTextInCanvasSTB( GetContext(), canvas, "the quick brown fox jumped over the lazy dog!.?", "Roboto-Regular.ttf")); + + SetTypographerContext(TypographerContextSTB::Make()); ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } @@ -1320,11 +1363,12 @@ TEST_P(AiksTest, TextFrameSubpixelAlignment) { 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})) { + if (!RenderTextInCanvasSkia( + GetContext(), canvas, + "the quick brown fox jumped over " + "the lazy dog!.?", + "Roboto-Regular.ttf", + {.font_size = font_size, .position = position})) { return false; } } @@ -1338,7 +1382,7 @@ TEST_P(AiksTest, CanRenderItalicizedText) { Canvas canvas; canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)}); - ASSERT_TRUE(RenderTextInCanvas( + ASSERT_TRUE(RenderTextInCanvasSkia( GetContext(), canvas, "the quick brown fox jumped over the lazy dog!.?", "HomemadeApple.ttf")); ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); @@ -1348,12 +1392,12 @@ TEST_P(AiksTest, CanRenderEmojiTextFrame) { Canvas canvas; canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)}); - ASSERT_TRUE(RenderTextInCanvas(GetContext(), canvas, - "😀 😃 😄 😁 😆 😅 😂 🤣 🥲 😊", + ASSERT_TRUE(RenderTextInCanvasSkia(GetContext(), canvas, + "😀 😃 😄 😁 😆 😅 😂 🤣 🥲 😊", #if FML_OS_MACOSX - "Apple Color Emoji.ttc")); + "Apple Color Emoji.ttc")); #else - "NotoColorEmoji.ttf")); + "NotoColorEmoji.ttf")); #endif ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } @@ -1362,14 +1406,14 @@ TEST_P(AiksTest, CanRenderEmojiTextFrameWithAlpha) { Canvas canvas; canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)}); - ASSERT_TRUE(RenderTextInCanvas(GetContext(), canvas, - "😀 😃 😄 😁 😆 😅 😂 🤣 🥲 😊", + ASSERT_TRUE(RenderTextInCanvasSkia(GetContext(), canvas, + "😀 😃 😄 😁 😆 😅 😂 🤣 🥲 😊", #if FML_OS_MACOSX - "Apple Color Emoji.ttc", { .alpha = 0.5 } + "Apple Color Emoji.ttc", { .alpha = 0.5 } #else - "NotoColorEmoji.ttf", {.alpha = 0.5} + "NotoColorEmoji.ttf", {.alpha = 0.5} #endif - )); + )); ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } @@ -1382,13 +1426,13 @@ TEST_P(AiksTest, CanRenderTextInSaveLayer) { // Blend the layer with the parent pass using kClear to expose the coverage. canvas.SaveLayer({.blend_mode = BlendMode::kClear}); - ASSERT_TRUE(RenderTextInCanvas( + ASSERT_TRUE(RenderTextInCanvasSkia( GetContext(), canvas, "the quick brown fox jumped over the lazy dog!.?", "Roboto-Regular.ttf")); canvas.Restore(); // Render the text again over the cleared coverage rect. - ASSERT_TRUE(RenderTextInCanvas( + ASSERT_TRUE(RenderTextInCanvasSkia( GetContext(), canvas, "the quick brown fox jumped over the lazy dog!.?", "Roboto-Regular.ttf")); @@ -1423,7 +1467,7 @@ TEST_P(AiksTest, CanRenderTextOutsideBoundaries) { { auto blob = SkTextBlob::MakeFromString(t.text, sk_font); ASSERT_NE(blob, nullptr); - auto frame = TextFrameFromTextBlob(blob); + auto frame = MakeTextFrameFromTextBlobSkia(blob); canvas.DrawTextFrame(frame, Point(), text_paint); } canvas.Restore(); @@ -1441,7 +1485,7 @@ TEST_P(AiksTest, TextRotated) { 0, 0.5, 0, 0, // 0, 0, 0.3, 0, // 100, 100, 0, 1.3)); - ASSERT_TRUE(RenderTextInCanvas( + ASSERT_TRUE(RenderTextInCanvasSkia( GetContext(), canvas, "the quick brown fox jumped over the lazy dog!.?", "Roboto-Regular.ttf")); @@ -3011,7 +3055,7 @@ TEST_P(AiksTest, TextForegroundShaderWithTransform) { auto blob = SkTextBlob::MakeFromString("Hello", sk_font); ASSERT_NE(blob, nullptr); - auto frame = TextFrameFromTextBlob(blob); + auto frame = MakeTextFrameFromTextBlobSkia(blob); canvas.DrawTextFrame(frame, Point(), text_paint); ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); @@ -3033,12 +3077,12 @@ TEST_P(AiksTest, CanCanvasDrawPicture) { TEST_P(AiksTest, DrawPictureWithText) { Canvas subcanvas; - ASSERT_TRUE(RenderTextInCanvas( + ASSERT_TRUE(RenderTextInCanvasSkia( GetContext(), subcanvas, "the quick brown fox jumped over the lazy dog!.?", "Roboto-Regular.ttf")); subcanvas.Translate({0, 10}); subcanvas.Scale(Vector2(3, 3)); - ASSERT_TRUE(RenderTextInCanvas( + ASSERT_TRUE(RenderTextInCanvasSkia( GetContext(), subcanvas, "the quick brown fox jumped over the very big lazy dog!.?", "Roboto-Regular.ttf")); @@ -3053,7 +3097,7 @@ TEST_P(AiksTest, DrawPictureWithText) { canvas.Restore(); canvas.Scale(Vector2(1.5, 1.5)); - ASSERT_TRUE(RenderTextInCanvas( + ASSERT_TRUE(RenderTextInCanvasSkia( GetContext(), canvas, "the quick brown fox jumped over the smaller lazy dog!.?", "Roboto-Regular.ttf")); @@ -3181,8 +3225,8 @@ TEST_P(AiksTest, DrawScaledTextWithPerspectiveNoSaveLayer) { )); // clang-format on - ASSERT_TRUE(RenderTextInCanvas(GetContext(), canvas, "Hello world", - "Roboto-Regular.ttf")); + ASSERT_TRUE(RenderTextInCanvasSkia(GetContext(), canvas, "Hello world", + "Roboto-Regular.ttf")); ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } @@ -3200,8 +3244,8 @@ TEST_P(AiksTest, DrawScaledTextWithPerspectiveSaveLayer) { )); // clang-format on - ASSERT_TRUE(RenderTextInCanvas(GetContext(), canvas, "Hello world", - "Roboto-Regular.ttf")); + ASSERT_TRUE(RenderTextInCanvasSkia(GetContext(), canvas, "Hello world", + "Roboto-Regular.ttf")); } TEST_P(AiksTest, PipelineBlendSingleParameter) { diff --git a/impeller/display_list/BUILD.gn b/impeller/display_list/BUILD.gn index f27e8f52ad2dd..c84a693a5fb1a 100644 --- a/impeller/display_list/BUILD.gn +++ b/impeller/display_list/BUILD.gn @@ -37,6 +37,7 @@ impeller_component("display_list") { "../aiks", "//flutter/display_list", "//flutter/fml", + "//flutter/impeller/typographer/backends/skia:typographer_skia_backend", "//third_party/skia", ] @@ -60,6 +61,7 @@ impeller_component("display_list_unittests") { deps = [ ":display_list", "../playground:playground_test", + "//flutter/impeller/typographer/backends/stb:typographer_stb_backend", ] if (!defined(defines)) { diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index 4e98a996e24f8..6dce3dc52b788 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -1108,7 +1108,7 @@ void DlDispatcher::drawDisplayList( void DlDispatcher::drawTextBlob(const sk_sp& blob, SkScalar x, SkScalar y) { - const auto text_frame = TextFrameFromTextBlob(blob); + const auto text_frame = MakeTextFrameFromTextBlobSkia(blob); if (paint_.style == Paint::Style::kStroke) { auto path = skia_conversions::PathDataFromTextBlob(blob); auto bounds = text_frame.GetBounds(); diff --git a/impeller/display_list/dl_playground.cc b/impeller/display_list/dl_playground.cc index b6d1f5468fe1e..aa47f81850ebe 100644 --- a/impeller/display_list/dl_playground.cc +++ b/impeller/display_list/dl_playground.cc @@ -7,7 +7,7 @@ #include "flutter/testing/testing.h" #include "impeller/aiks/aiks_context.h" #include "impeller/display_list/dl_dispatcher.h" -#include "impeller/typographer/backends/skia/text_render_context_skia.h" +#include "impeller/typographer/backends/skia/typographer_context_skia.h" #include "third_party/imgui/imgui.h" #include "third_party/skia/include/core/SkData.h" @@ -30,7 +30,7 @@ bool DlPlayground::OpenPlaygroundHere(DisplayListPlaygroundCallback callback) { return true; } - AiksContext context(GetContext(), TextRenderContextSkia::Make()); + AiksContext context(GetContext(), TypographerContextSkia::Make()); if (!context.IsValid()) { return false; } diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 1929514076645..0b55979172c2e 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -283,6 +283,7 @@ impeller_component("entity_unittests") { ":entity", "../geometry:geometry_asserts", "../playground:playground_test", + "//flutter/impeller/typographer/backends/skia:typographer_skia_backend", ] } diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 6f76a60ab8eb2..081895bd0182c 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -16,7 +16,7 @@ #include "impeller/renderer/render_pass.h" #include "impeller/renderer/render_target.h" #include "impeller/tessellator/tessellator.h" -#include "impeller/typographer/text_render_context.h" +#include "impeller/typographer/typographer_context.h" namespace impeller { @@ -162,10 +162,10 @@ static std::unique_ptr CreateDefaultPipeline( ContentContext::ContentContext( std::shared_ptr context, - std::shared_ptr text_render_context) + std::shared_ptr typographer_context) : context_(std::move(context)), lazy_glyph_atlas_( - std::make_shared(std::move(text_render_context))), + std::make_shared(std::move(typographer_context))), tessellator_(std::make_shared()), scene_context_(std::make_shared(context_)), render_target_cache_(std::make_shared( diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 3c67f85c66fc4..fd976542d0d41 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -19,7 +19,7 @@ #include "impeller/renderer/pipeline.h" #include "impeller/renderer/render_target.h" #include "impeller/scene/scene_context.h" -#include "impeller/typographer/text_render_context.h" +#include "impeller/typographer/typographer_context.h" #ifdef IMPELLER_DEBUG #include "impeller/entity/checkerboard.frag.h" @@ -342,7 +342,7 @@ class ContentContext { public: explicit ContentContext( std::shared_ptr context, - std::shared_ptr text_render_context); + std::shared_ptr typographer_context); ~ContentContext(); diff --git a/impeller/entity/entity_playground.cc b/impeller/entity/entity_playground.cc index 103dfab02f4f6..0f9eebe3ab0d0 100644 --- a/impeller/entity/entity_playground.cc +++ b/impeller/entity/entity_playground.cc @@ -5,19 +5,19 @@ #include "impeller/entity/entity_playground.h" #include "impeller/entity/contents/content_context.h" -#include "impeller/typographer/backends/skia/text_render_context_skia.h" +#include "impeller/typographer/backends/skia/typographer_context_skia.h" #include "third_party/imgui/imgui.h" namespace impeller { EntityPlayground::EntityPlayground() - : text_render_context_(TextRenderContextSkia::Make()) {} + : typographer_context_(TypographerContextSkia::Make()) {} EntityPlayground::~EntityPlayground() = default; -void EntityPlayground::SetTextRenderContext( - std::shared_ptr text_render_context) { - text_render_context_ = std::move(text_render_context); +void EntityPlayground::SetTypographerContext( + std::shared_ptr typographer_context) { + typographer_context_ = std::move(typographer_context); } bool EntityPlayground::OpenPlaygroundHere(EntityPass& entity_pass) { @@ -25,7 +25,7 @@ bool EntityPlayground::OpenPlaygroundHere(EntityPass& entity_pass) { return true; } - ContentContext content_context(GetContext(), text_render_context_); + ContentContext content_context(GetContext(), typographer_context_); if (!content_context.IsValid()) { return false; } @@ -41,7 +41,7 @@ bool EntityPlayground::OpenPlaygroundHere(Entity entity) { return true; } - ContentContext content_context(GetContext(), text_render_context_); + ContentContext content_context(GetContext(), typographer_context_); if (!content_context.IsValid()) { return false; } @@ -56,7 +56,7 @@ bool EntityPlayground::OpenPlaygroundHere(EntityPlaygroundCallback callback) { return true; } - ContentContext content_context(GetContext(), text_render_context_); + ContentContext content_context(GetContext(), typographer_context_); if (!content_context.IsValid()) { return false; } diff --git a/impeller/entity/entity_playground.h b/impeller/entity/entity_playground.h index d9d83259b710f..dbd1ac1bbc51e 100644 --- a/impeller/entity/entity_playground.h +++ b/impeller/entity/entity_playground.h @@ -10,7 +10,7 @@ #include "impeller/entity/contents/content_context.h" #include "impeller/entity/entity.h" #include "impeller/entity/entity_pass.h" -#include "impeller/typographer/text_render_context.h" +#include "impeller/typographer/typographer_context.h" namespace impeller { @@ -23,8 +23,8 @@ class EntityPlayground : public PlaygroundTest { ~EntityPlayground(); - void SetTextRenderContext( - std::shared_ptr text_render_context); + void SetTypographerContext( + std::shared_ptr typographer_context); bool OpenPlaygroundHere(Entity entity); @@ -33,7 +33,7 @@ class EntityPlayground : public PlaygroundTest { bool OpenPlaygroundHere(EntityPlaygroundCallback callback); private: - std::shared_ptr text_render_context_; + std::shared_ptr typographer_context_; FML_DISALLOW_COPY_AND_ASSIGN(EntityPlayground); }; diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 90edc60222883..0b7140c8b9951 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -50,7 +50,7 @@ #include "impeller/runtime_stage/runtime_stage.h" #include "impeller/tessellator/tessellator.h" #include "impeller/typographer/backends/skia/text_frame_skia.h" -#include "impeller/typographer/backends/skia/text_render_context_skia.h" +#include "impeller/typographer/backends/skia/typographer_context_skia.h" #include "include/core/SkBlendMode.h" #include "third_party/imgui/imgui.h" #include "third_party/skia/include/core/SkTextBlob.h" @@ -2174,9 +2174,9 @@ TEST_P(EntityTest, InheritOpacityTest) { SkFont font; font.setSize(30); auto blob = SkTextBlob::MakeFromString("A", font); - auto frame = TextFrameFromTextBlob(blob); + auto frame = MakeTextFrameFromTextBlobSkia(blob); auto lazy_glyph_atlas = - std::make_shared(TextRenderContextSkia::Make()); + std::make_shared(TypographerContextSkia::Make()); lazy_glyph_atlas->AddTextFrame(frame, 1.0f); auto text_contents = std::make_shared(); diff --git a/impeller/golden_tests/BUILD.gn b/impeller/golden_tests/BUILD.gn index 8efbb0b7141c5..6682a0732725a 100644 --- a/impeller/golden_tests/BUILD.gn +++ b/impeller/golden_tests/BUILD.gn @@ -15,6 +15,7 @@ impeller_component("golden_playground_test") { "//flutter/fml", "//flutter/impeller/aiks", "//flutter/impeller/playground", + "//flutter/impeller/typographer/backends/skia:typographer_skia_backend", "//flutter/testing:testing_lib", ] diff --git a/impeller/golden_tests/golden_playground_test.h b/impeller/golden_tests/golden_playground_test.h index 34f879c0d225f..955d39f4b978f 100644 --- a/impeller/golden_tests/golden_playground_test.h +++ b/impeller/golden_tests/golden_playground_test.h @@ -11,7 +11,7 @@ #include "flutter/impeller/playground/playground.h" #include "flutter/impeller/renderer/render_target.h" #include "flutter/testing/testing.h" -#include "impeller/typographer/text_render_context.h" +#include "impeller/typographer/typographer_context.h" #if FML_OS_MACOSX #include "flutter/fml/platform/darwin/scoped_nsautorelease_pool.h" @@ -35,8 +35,8 @@ class GoldenPlaygroundTest PlaygroundBackend GetBackend() const; - void SetTextRenderContext( - std::shared_ptr text_render_context); + void SetTypographerContext( + std::shared_ptr typographer_context); bool OpenPlaygroundHere(const Picture& picture); @@ -64,7 +64,7 @@ class GoldenPlaygroundTest fml::ScopedNSAutoreleasePool autorelease_pool_; #endif - std::shared_ptr text_render_context_; + std::shared_ptr typographer_context_; struct GoldenPlaygroundTestImpl; // This is only a shared_ptr so it can work with a forward declared type. diff --git a/impeller/golden_tests/golden_playground_test_mac.cc b/impeller/golden_tests/golden_playground_test_mac.cc index 0b57755dba6e8..574caad3ea829 100644 --- a/impeller/golden_tests/golden_playground_test_mac.cc +++ b/impeller/golden_tests/golden_playground_test_mac.cc @@ -11,8 +11,8 @@ #include "flutter/impeller/aiks/picture.h" #include "flutter/impeller/golden_tests/golden_digest.h" #include "flutter/impeller/golden_tests/metal_screenshoter.h" -#include "impeller/typographer/backends/skia/text_render_context_skia.h" -#include "impeller/typographer/text_render_context.h" +#include "impeller/typographer/backends/skia/typographer_context_skia.h" +#include "impeller/typographer/typographer_context.h" namespace impeller { @@ -88,14 +88,14 @@ struct GoldenPlaygroundTest::GoldenPlaygroundTestImpl { }; GoldenPlaygroundTest::GoldenPlaygroundTest() - : text_render_context_(TextRenderContextSkia::Make()), + : typographer_context_(TypographerContextSkia::Make()), pimpl_(new GoldenPlaygroundTest::GoldenPlaygroundTestImpl()) {} GoldenPlaygroundTest::~GoldenPlaygroundTest() = default; -void GoldenPlaygroundTest::SetTextRenderContext( - std::shared_ptr text_render_context) { - text_render_context_ = std::move(text_render_context); +void GoldenPlaygroundTest::SetTypographerContext( + std::shared_ptr typographer_context) { + typographer_context_ = std::move(typographer_context); }; void GoldenPlaygroundTest::TearDown() { @@ -135,7 +135,7 @@ PlaygroundBackend GoldenPlaygroundTest::GetBackend() const { } bool GoldenPlaygroundTest::OpenPlaygroundHere(const Picture& picture) { - AiksContext renderer(GetContext(), text_render_context_); + AiksContext renderer(GetContext(), typographer_context_); auto screenshot = pimpl_->screenshoter->MakeScreenshot(renderer, picture, pimpl_->window_size); diff --git a/impeller/golden_tests/golden_playground_test_stub.cc b/impeller/golden_tests/golden_playground_test_stub.cc index 44da5a642e0b2..10805238f5368 100644 --- a/impeller/golden_tests/golden_playground_test_stub.cc +++ b/impeller/golden_tests/golden_playground_test_stub.cc @@ -10,9 +10,9 @@ GoldenPlaygroundTest::GoldenPlaygroundTest() = default; GoldenPlaygroundTest::~GoldenPlaygroundTest() = default; -void GoldenPlaygroundTest::SetTextRenderContext( - std::shared_ptr text_render_context) { - text_render_context_ = std::move(text_render_context); +void GoldenPlaygroundTest::SetTypographerContext( + std::shared_ptr typographer_context) { + typographer_context_ = std::move(typographer_context); }; void GoldenPlaygroundTest::TearDown() {} diff --git a/impeller/typographer/BUILD.gn b/impeller/typographer/BUILD.gn index 9abec666774fd..32287b7d52f24 100644 --- a/impeller/typographer/BUILD.gn +++ b/impeller/typographer/BUILD.gn @@ -6,12 +6,6 @@ import("//flutter/impeller/tools/impeller.gni") impeller_component("typographer") { sources = [ - "backends/skia/text_frame_skia.cc", - "backends/skia/text_frame_skia.h", - "backends/skia/text_render_context_skia.cc", - "backends/skia/text_render_context_skia.h", - "backends/skia/typeface_skia.cc", - "backends/skia/typeface_skia.h", "font.cc", "font.h", "font_glyph_pair.cc", @@ -26,19 +20,18 @@ impeller_component("typographer") { "rectangle_packer.h", "text_frame.cc", "text_frame.h", - "text_render_context.cc", - "text_render_context.h", "text_run.cc", "text_run.h", "typeface.cc", "typeface.h", + "typographer_context.cc", + "typographer_context.h", ] public_deps = [ "../base", "../geometry", "../renderer", - "//third_party/skia", ] deps = [ "//flutter/fml" ] @@ -50,7 +43,8 @@ impeller_component("typographer_unittests") { sources = [ "typographer_unittests.cc" ] deps = [ - ":typographer", "../playground:playground_test", + "backends/skia:typographer_skia_backend", + "backends/stb:typographer_stb_backend", ] } diff --git a/impeller/typographer/backends/skia/BUILD.gn b/impeller/typographer/backends/skia/BUILD.gn new file mode 100644 index 0000000000000..f135edcc17458 --- /dev/null +++ b/impeller/typographer/backends/skia/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//flutter/impeller/tools/impeller.gni") + +impeller_component("typographer_skia_backend") { + sources = [ + "glyph_atlas_context_skia.cc", + "glyph_atlas_context_skia.h", + "text_frame_skia.cc", + "text_frame_skia.h", + "typeface_skia.cc", + "typeface_skia.h", + "typographer_context_skia.cc", + "typographer_context_skia.h", + ] + + public_deps = [ + "//flutter/impeller/typographer", + "//third_party/skia", + ] +} diff --git a/impeller/typographer/backends/skia/glyph_atlas_context_skia.cc b/impeller/typographer/backends/skia/glyph_atlas_context_skia.cc new file mode 100644 index 0000000000000..78826736d81da --- /dev/null +++ b/impeller/typographer/backends/skia/glyph_atlas_context_skia.cc @@ -0,0 +1,23 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/typographer/backends/skia/glyph_atlas_context_skia.h" + +#include "third_party/skia/include/core/SkBitmap.h" + +namespace impeller { + +GlyphAtlasContextSkia::GlyphAtlasContextSkia() = default; + +GlyphAtlasContextSkia::~GlyphAtlasContextSkia() = default; + +std::shared_ptr GlyphAtlasContextSkia::GetBitmap() const { + return bitmap_; +} + +void GlyphAtlasContextSkia::UpdateBitmap(std::shared_ptr bitmap) { + bitmap_ = std::move(bitmap); +} + +} // namespace impeller diff --git a/impeller/typographer/backends/skia/glyph_atlas_context_skia.h b/impeller/typographer/backends/skia/glyph_atlas_context_skia.h new file mode 100644 index 0000000000000..254290aac6b02 --- /dev/null +++ b/impeller/typographer/backends/skia/glyph_atlas_context_skia.h @@ -0,0 +1,37 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "impeller/base/backend_cast.h" +#include "impeller/typographer/glyph_atlas.h" + +class SkBitmap; + +namespace impeller { + +//------------------------------------------------------------------------------ +/// @brief A container for caching a glyph atlas across frames. +/// +class GlyphAtlasContextSkia + : public GlyphAtlasContext, + public BackendCast { + public: + GlyphAtlasContextSkia(); + + ~GlyphAtlasContextSkia() override; + + //---------------------------------------------------------------------------- + /// @brief Retrieve the previous (if any) SkBitmap instance. + std::shared_ptr GetBitmap() const; + + void UpdateBitmap(std::shared_ptr bitmap); + + private: + std::shared_ptr bitmap_; + + FML_DISALLOW_COPY_AND_ASSIGN(GlyphAtlasContextSkia); +}; + +} // namespace impeller diff --git a/impeller/typographer/backends/skia/text_frame_skia.cc b/impeller/typographer/backends/skia/text_frame_skia.cc index d458499c9d771..fded61328ef0b 100644 --- a/impeller/typographer/backends/skia/text_frame_skia.cc +++ b/impeller/typographer/backends/skia/text_frame_skia.cc @@ -39,7 +39,7 @@ static Rect ToRect(const SkRect& rect) { static constexpr Scalar kScaleSize = 100000.0f; -TextFrame TextFrameFromTextBlob(const sk_sp& blob) { +TextFrame MakeTextFrameFromTextBlobSkia(const sk_sp& blob) { if (!blob) { return {}; } diff --git a/impeller/typographer/backends/skia/text_frame_skia.h b/impeller/typographer/backends/skia/text_frame_skia.h index a12b0f5ec60fa..93431446afe32 100644 --- a/impeller/typographer/backends/skia/text_frame_skia.h +++ b/impeller/typographer/backends/skia/text_frame_skia.h @@ -10,6 +10,6 @@ namespace impeller { -TextFrame TextFrameFromTextBlob(const sk_sp& blob); +TextFrame MakeTextFrameFromTextBlobSkia(const sk_sp& blob); } // namespace impeller diff --git a/impeller/typographer/backends/skia/text_render_context_skia.cc b/impeller/typographer/backends/skia/typographer_context_skia.cc similarity index 94% rename from impeller/typographer/backends/skia/text_render_context_skia.cc rename to impeller/typographer/backends/skia/typographer_context_skia.cc index 89554e555f8ea..85bae56a15ecd 100644 --- a/impeller/typographer/backends/skia/text_render_context_skia.cc +++ b/impeller/typographer/backends/skia/typographer_context_skia.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "impeller/typographer/backends/skia/text_render_context_skia.h" +#include "impeller/typographer/backends/skia/typographer_context_skia.h" #include @@ -10,9 +10,10 @@ #include "flutter/fml/trace_event.h" #include "impeller/base/allocation.h" #include "impeller/core/allocator.h" +#include "impeller/typographer/backends/skia/glyph_atlas_context_skia.h" #include "impeller/typographer/backends/skia/typeface_skia.h" #include "impeller/typographer/rectangle_packer.h" -#include "impeller/typographer/text_render_context.h" +#include "impeller/typographer/typographer_context.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkFont.h" @@ -28,13 +29,18 @@ using FontGlyphPairRefVector = // https://github.com/flutter/flutter/issues/114563 constexpr auto kPadding = 2; -std::shared_ptr TextRenderContextSkia::Make() { - return std::make_shared(); +std::shared_ptr TypographerContextSkia::Make() { + return std::make_shared(); } -TextRenderContextSkia::TextRenderContextSkia() = default; +TypographerContextSkia::TypographerContextSkia() = default; -TextRenderContextSkia::~TextRenderContextSkia() = default; +TypographerContextSkia::~TypographerContextSkia() = default; + +std::shared_ptr +TypographerContextSkia::CreateGlyphAtlasContext() const { + return std::make_shared(); +} static size_t PairsFitInAtlasOfSize( const FontGlyphPair::Set& pairs, @@ -107,8 +113,7 @@ static bool CanAppendToExistingAtlas( return true; } -namespace { -ISize OptimumAtlasSizeForFontGlyphPairs( +static ISize OptimumAtlasSizeForFontGlyphPairs( const FontGlyphPair::Set& pairs, std::vector& glyph_positions, const std::shared_ptr& atlas_context, @@ -146,7 +151,6 @@ ISize OptimumAtlasSizeForFontGlyphPairs( current_size.height <= kMaxAtlasSize); return ISize{0, 0}; } -} // namespace static void DrawGlyph(SkCanvas* canvas, const FontGlyphPair& font_glyph, @@ -305,7 +309,7 @@ static std::shared_ptr UploadGlyphTextureAtlas( return texture; } -std::shared_ptr TextRenderContextSkia::CreateGlyphAtlas( +std::shared_ptr TypographerContextSkia::CreateGlyphAtlas( Context& context, GlyphAtlas::Type type, std::shared_ptr atlas_context, @@ -314,6 +318,7 @@ std::shared_ptr TextRenderContextSkia::CreateGlyphAtlas( if (!IsValid()) { return nullptr; } + auto& atlas_context_skia = GlyphAtlasContextSkia::Cast(*atlas_context); std::shared_ptr last_atlas = atlas_context->GetGlyphAtlas(); if (font_glyph_pairs.empty()) { @@ -358,7 +363,7 @@ std::shared_ptr TextRenderContextSkia::CreateGlyphAtlas( // --------------------------------------------------------------------------- // Step 4a: Draw new font-glyph pairs into the existing bitmap. // --------------------------------------------------------------------------- - auto bitmap = atlas_context->GetBitmap(); + auto bitmap = atlas_context_skia.GetBitmap(); if (!UpdateAtlasBitmap(*last_atlas, bitmap, new_glyphs)) { return nullptr; } @@ -412,7 +417,7 @@ std::shared_ptr TextRenderContextSkia::CreateGlyphAtlas( if (!bitmap) { return nullptr; } - atlas_context->UpdateBitmap(bitmap); + atlas_context_skia.UpdateBitmap(bitmap); // --------------------------------------------------------------------------- // Step 7b: Upload the atlas as a texture. diff --git a/impeller/typographer/backends/skia/text_render_context_skia.h b/impeller/typographer/backends/skia/typographer_context_skia.h similarity index 54% rename from impeller/typographer/backends/skia/text_render_context_skia.h rename to impeller/typographer/backends/skia/typographer_context_skia.h index 32d5a083c2dd9..3c1ebf503134a 100644 --- a/impeller/typographer/backends/skia/text_render_context_skia.h +++ b/impeller/typographer/backends/skia/typographer_context_skia.h @@ -5,19 +5,22 @@ #pragma once #include "flutter/fml/macros.h" -#include "impeller/typographer/text_render_context.h" +#include "impeller/typographer/typographer_context.h" namespace impeller { -class TextRenderContextSkia : public TextRenderContext { +class TypographerContextSkia : public TypographerContext { public: - static std::shared_ptr Make(); + static std::shared_ptr Make(); - TextRenderContextSkia(); + TypographerContextSkia(); - ~TextRenderContextSkia() override; + ~TypographerContextSkia() override; - // |TextRenderContext| + // |TypographerContext| + std::shared_ptr CreateGlyphAtlasContext() const override; + + // |TypographerContext| std::shared_ptr CreateGlyphAtlas( Context& context, GlyphAtlas::Type type, @@ -25,7 +28,7 @@ class TextRenderContextSkia : public TextRenderContext { const FontGlyphPair::Set& font_glyph_pairs) const override; private: - FML_DISALLOW_COPY_AND_ASSIGN(TextRenderContextSkia); + FML_DISALLOW_COPY_AND_ASSIGN(TypographerContextSkia); }; } // namespace impeller diff --git a/impeller/typographer/backends/stb/BUILD.gn b/impeller/typographer/backends/stb/BUILD.gn new file mode 100644 index 0000000000000..70b98ad9c6686 --- /dev/null +++ b/impeller/typographer/backends/stb/BUILD.gn @@ -0,0 +1,25 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//flutter/impeller/tools/impeller.gni") + +impeller_component("typographer_stb_backend") { + testonly = true + + sources = [ + "glyph_atlas_context_stb.cc", + "glyph_atlas_context_stb.h", + "text_frame_stb.cc", + "text_frame_stb.h", + "typeface_stb.cc", + "typeface_stb.h", + "typographer_context_stb.cc", + "typographer_context_stb.h", + ] + + public_deps = [ + "//flutter/impeller/typographer", + "//third_party/stb:stb_truetype", + ] +} diff --git a/impeller/typographer/backends/stb/glyph_atlas_context_stb.cc b/impeller/typographer/backends/stb/glyph_atlas_context_stb.cc new file mode 100644 index 0000000000000..fb6c105afe16d --- /dev/null +++ b/impeller/typographer/backends/stb/glyph_atlas_context_stb.cc @@ -0,0 +1,58 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/typographer/backends/stb/glyph_atlas_context_stb.h" + +namespace impeller { + +BitmapSTB::BitmapSTB() = default; + +BitmapSTB::~BitmapSTB() = default; + +BitmapSTB::BitmapSTB(size_t width, size_t height, size_t bytes_per_pixel) + : width_(width), + height_(height), + bytes_per_pixel_(bytes_per_pixel), + pixels_(std::vector(width * height * bytes_per_pixel, 0)) {} + +uint8_t* BitmapSTB::GetPixels() { + return pixels_.data(); +} + +uint8_t* BitmapSTB::GetPixelAddress(TPoint coords) { + FML_DCHECK(coords.x < width_); + FML_DCHECK(coords.x < height_); + + return &pixels_.data()[(coords.x + width_ * coords.y) * bytes_per_pixel_]; +} + +size_t BitmapSTB::GetRowBytes() const { + return width_ * bytes_per_pixel_; +} + +size_t BitmapSTB::GetWidth() const { + return width_; +} + +size_t BitmapSTB::GetHeight() const { + return height_; +} + +size_t BitmapSTB::GetSize() const { + return width_ * height_ * bytes_per_pixel_; +} + +GlyphAtlasContextSTB::GlyphAtlasContextSTB() = default; + +GlyphAtlasContextSTB::~GlyphAtlasContextSTB() = default; + +std::shared_ptr GlyphAtlasContextSTB::GetBitmap() const { + return bitmap_; +} + +void GlyphAtlasContextSTB::UpdateBitmap(std::shared_ptr bitmap) { + bitmap_ = std::move(bitmap); +} + +} // namespace impeller diff --git a/impeller/typographer/backends/stb/glyph_atlas_context_stb.h b/impeller/typographer/backends/stb/glyph_atlas_context_stb.h new file mode 100644 index 0000000000000..06b5a93e2f9dd --- /dev/null +++ b/impeller/typographer/backends/stb/glyph_atlas_context_stb.h @@ -0,0 +1,59 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "impeller/base/backend_cast.h" +#include "impeller/typographer/glyph_atlas.h" + +namespace impeller { + +class BitmapSTB { + public: + BitmapSTB(); + + ~BitmapSTB(); + + BitmapSTB(size_t width, size_t height, size_t bytes_per_pixel); + + uint8_t* GetPixels(); + + uint8_t* GetPixelAddress(TPoint coords); + + size_t GetRowBytes() const; + + size_t GetWidth() const; + + size_t GetHeight() const; + + size_t GetSize() const; + + private: + size_t width_ = 0; + size_t height_ = 0; + size_t bytes_per_pixel_ = 0; + std::vector pixels_; +}; + +class GlyphAtlasContextSTB + : public GlyphAtlasContext, + public BackendCast { + public: + GlyphAtlasContextSTB(); + + ~GlyphAtlasContextSTB() override; + + //---------------------------------------------------------------------------- + /// @brief Retrieve the previous (if any) BitmapSTB instance. + std::shared_ptr GetBitmap() const; + + void UpdateBitmap(std::shared_ptr bitmap); + + private: + std::shared_ptr bitmap_; + + FML_DISALLOW_COPY_AND_ASSIGN(GlyphAtlasContextSTB); +}; + +} // namespace impeller diff --git a/impeller/typographer/backends/stb/text_frame_stb.cc b/impeller/typographer/backends/stb/text_frame_stb.cc new file mode 100644 index 0000000000000..480cd9c786835 --- /dev/null +++ b/impeller/typographer/backends/stb/text_frame_stb.cc @@ -0,0 +1,61 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/typographer/backends/stb/text_frame_stb.h" + +#include "impeller/typographer/font.h" + +namespace impeller { + +TextFrame MakeTextFrameSTB(const std::shared_ptr& typeface_stb, + Font::Metrics metrics, + const std::string& text) { + TextRun run(Font(typeface_stb, metrics)); + + // Shape the text run using STB. The glyph positions could also be resolved + // using a more advanced text shaper such as harfbuzz. + + float scale = stbtt_ScaleForPixelHeight( + typeface_stb->GetFontInfo(), + metrics.point_size * TypefaceSTB::kPointsToPixels); + + int ascent, descent, line_gap; + stbtt_GetFontVMetrics(typeface_stb->GetFontInfo(), &ascent, &descent, + &line_gap); + ascent = std::round(ascent * scale); + descent = std::round(descent * scale); + + float x = 0; + for (size_t i = 0; i < text.size(); i++) { + int glyph_index = + stbtt_FindGlyphIndex(typeface_stb->GetFontInfo(), text[i]); + + int x0, y0, x1, y1; + stbtt_GetGlyphBitmapBox(typeface_stb->GetFontInfo(), glyph_index, scale, + scale, &x0, &y0, &x1, &y1); + float y = y0; + + int advance_width; + int left_side_bearing; + stbtt_GetGlyphHMetrics(typeface_stb->GetFontInfo(), glyph_index, + &advance_width, &left_side_bearing); + + Glyph glyph(glyph_index, Glyph::Type::kPath, + Rect::MakeXYWH(0, 0, x1 - x0, y1 - y0)); + run.AddGlyph(glyph, {x + (left_side_bearing * scale), y}); + + if (i + 1 < text.size()) { + int kerning = stbtt_GetCodepointKernAdvance(typeface_stb->GetFontInfo(), + text[i], text[i + 1]); + x += std::round((advance_width + kerning) * scale); + } + } + + TextFrame frame; + frame.AddTextRun(run); + + return frame; +} + +} // namespace impeller diff --git a/impeller/typographer/backends/stb/text_frame_stb.h b/impeller/typographer/backends/stb/text_frame_stb.h new file mode 100644 index 0000000000000..622cb1f3b72fd --- /dev/null +++ b/impeller/typographer/backends/stb/text_frame_stb.h @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "flutter/fml/macros.h" +#include "impeller/typographer/backends/stb/typeface_stb.h" +#include "impeller/typographer/text_frame.h" + +namespace impeller { + +TextFrame MakeTextFrameSTB(const std::shared_ptr& typeface_stb, + Font::Metrics metrics, + const std::string& text); + +} // namespace impeller diff --git a/impeller/typographer/backends/stb/typeface_stb.cc b/impeller/typographer/backends/stb/typeface_stb.cc new file mode 100644 index 0000000000000..ef0250a82100a --- /dev/null +++ b/impeller/typographer/backends/stb/typeface_stb.cc @@ -0,0 +1,54 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/typographer/backends/stb/typeface_stb.h" + +#include + +#include "flutter/fml/logging.h" + +namespace impeller { + +// Instantiate a typeface based on a .ttf or other font file +TypefaceSTB::TypefaceSTB(std::unique_ptr typeface_mapping) + : typeface_mapping_(std::move(typeface_mapping)), + font_info_(std::make_unique()), + is_valid_(false) { + // We need an "offset" into the ttf file + auto offset = stbtt_GetFontOffsetForIndex(typeface_mapping_->GetMapping(), 0); + if (stbtt_InitFont(font_info_.get(), typeface_mapping_->GetMapping(), + offset) == 0) { + FML_LOG(ERROR) << "Failed to initialize stb font from binary data."; + } else { + is_valid_ = true; + } +} + +TypefaceSTB::~TypefaceSTB() = default; + +bool TypefaceSTB::IsValid() const { + return is_valid_; +} + +std::size_t TypefaceSTB::GetHash() const { + if (!IsValid()) { + return 0u; + } + return reinterpret_cast(typeface_mapping_->GetMapping()); +} + +bool TypefaceSTB::IsEqual(const Typeface& other) const { + auto stb_other = reinterpret_cast(&other); + return stb_other->GetHash() == GetHash(); +} + +const uint8_t* TypefaceSTB::GetTypefaceFile() const { + return typeface_mapping_->GetMapping(); +} + +const stbtt_fontinfo* TypefaceSTB::GetFontInfo() const { + return font_info_.get(); +} + +} // namespace impeller diff --git a/impeller/typographer/backends/stb/typeface_stb.h b/impeller/typographer/backends/stb/typeface_stb.h new file mode 100644 index 0000000000000..81f0850edeab4 --- /dev/null +++ b/impeller/typographer/backends/stb/typeface_stb.h @@ -0,0 +1,46 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "flutter/fml/macros.h" +#include "flutter/fml/mapping.h" +#include "impeller/base/backend_cast.h" +#include "impeller/typographer/typeface.h" +#include "third_party/stb/stb_truetype.h" + +namespace impeller { + +class TypefaceSTB final : public Typeface, + public BackendCast { + public: + // "Typical" conversion from font Points to Pixels. + // This assumes a constant pixels per em. + static constexpr float kPointsToPixels = 96.0 / 72.0; + + explicit TypefaceSTB(std::unique_ptr typeface_mapping); + + ~TypefaceSTB() override; + + // |Typeface| + bool IsValid() const override; + + // |Comparable| + std::size_t GetHash() const override; + + // |Comparable| + bool IsEqual(const Typeface& other) const override; + + const uint8_t* GetTypefaceFile() const; + const stbtt_fontinfo* GetFontInfo() const; + + private: + std::unique_ptr typeface_mapping_; + std::unique_ptr font_info_; + bool is_valid_; + + FML_DISALLOW_COPY_AND_ASSIGN(TypefaceSTB); +}; + +} // namespace impeller diff --git a/impeller/typographer/backends/stb/typographer_context_stb.cc b/impeller/typographer/backends/stb/typographer_context_stb.cc new file mode 100644 index 0000000000000..5efdcf4c72b6c --- /dev/null +++ b/impeller/typographer/backends/stb/typographer_context_stb.cc @@ -0,0 +1,513 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/typographer/backends/stb/typographer_context_stb.h" + +#include + +#include "flutter/fml/logging.h" +#include "flutter/fml/trace_event.h" +#include "impeller/base/allocation.h" +#include "impeller/core/allocator.h" +#include "impeller/typographer/backends/stb/glyph_atlas_context_stb.h" +#include "impeller/typographer/font_glyph_pair.h" +#include "typeface_stb.h" + +#define DISABLE_COLOR_FONT_SUPPORT 1 +#ifdef DISABLE_COLOR_FONT_SUPPORT +constexpr auto kColorFontBitsPerPixel = 1; +#else +constexpr auto kColorFontBitsPerPixel = 4; +#endif + +namespace impeller { + +using FontGlyphPairRefVector = + std::vector>; + +constexpr size_t kPadding = 1; + +std::unique_ptr TypographerContextSTB::Make() { + return std::make_unique(); +} + +TypographerContextSTB::TypographerContextSTB() : TypographerContext() {} + +TypographerContextSTB::~TypographerContextSTB() = default; + +std::shared_ptr +TypographerContextSTB::CreateGlyphAtlasContext() const { + return std::make_shared(); +} + +// Function returns the count of "remaining pairs" not packed into rect of given +// size. +static size_t PairsFitInAtlasOfSize( + const FontGlyphPair::Set& pairs, + const ISize& atlas_size, + std::vector& glyph_positions, + const std::shared_ptr& rect_packer) { + if (atlas_size.IsEmpty()) { + return false; + } + + glyph_positions.clear(); + glyph_positions.reserve(pairs.size()); + + size_t i = 0; + for (auto it = pairs.begin(); it != pairs.end(); ++i, ++it) { + const auto& pair = *it; + + // We downcast to the correct typeface type to access `stb` specific + // methods. + std::shared_ptr typeface_stb = + std::reinterpret_pointer_cast(pair.font.GetTypeface()); + // Conversion factor to scale font size in Points to pixels. + // Note this assumes typical DPI. + float text_size_pixels = + pair.font.GetMetrics().point_size * TypefaceSTB::kPointsToPixels; + + ISize glyph_size; + { + int x0 = 0, y0 = 0, x1 = 0, y1 = 0; + // NOTE: We increase the size of the glyph by one pixel in all dimensions + // to allow us to cut out padding later. + float scale = stbtt_ScaleForPixelHeight(typeface_stb->GetFontInfo(), + text_size_pixels); + stbtt_GetGlyphBitmapBox(typeface_stb->GetFontInfo(), pair.glyph.index, + scale, scale, &x0, &y0, &x1, &y1); + + glyph_size = ISize(x1 - x0, y1 - y0); + } + + IPoint16 location_in_atlas; + if (!rect_packer->addRect(glyph_size.width + kPadding, // + glyph_size.height + kPadding, // + &location_in_atlas // + )) { + return pairs.size() - i; + } + glyph_positions.emplace_back(Rect::MakeXYWH(location_in_atlas.x(), // + location_in_atlas.y(), // + glyph_size.width, // + glyph_size.height // + )); + } + + return 0; +} + +static bool CanAppendToExistingAtlas( + const std::shared_ptr& atlas, + const FontGlyphPairRefVector& extra_pairs, + std::vector& glyph_positions, + ISize atlas_size, + const std::shared_ptr& rect_packer) { + TRACE_EVENT0("impeller", __FUNCTION__); + if (!rect_packer || atlas_size.IsEmpty()) { + return false; + } + + // We assume that all existing glyphs will fit. After all, they fit before. + // The glyph_positions only contains the values for the additional glyphs + // from extra_pairs. + FML_DCHECK(glyph_positions.size() == 0); + glyph_positions.reserve(extra_pairs.size()); + for (size_t i = 0; i < extra_pairs.size(); i++) { + const FontGlyphPair& pair = extra_pairs[i]; + + // We downcast to the correct typeface type to access `stb` specific methods + std::shared_ptr typeface_stb = + std::reinterpret_pointer_cast(pair.font.GetTypeface()); + // Conversion factor to scale font size in Points to pixels. + // Note this assumes typical DPI. + float text_size_pixels = + pair.font.GetMetrics().point_size * TypefaceSTB::kPointsToPixels; + + ISize glyph_size; + { + int x0 = 0, y0 = 0, x1 = 0, y1 = 0; + // NOTE: We increase the size of the glyph by one pixel in all dimensions + // to allow us to cut out padding later. + float scale_y = stbtt_ScaleForPixelHeight(typeface_stb->GetFontInfo(), + text_size_pixels); + float scale_x = scale_y; + stbtt_GetGlyphBitmapBox(typeface_stb->GetFontInfo(), pair.glyph.index, + scale_x, scale_y, &x0, &y0, &x1, &y1); + + glyph_size = ISize(x1 - x0, y1 - y0); + } + + IPoint16 location_in_atlas; + if (!rect_packer->addRect(glyph_size.width + kPadding, // + glyph_size.height + kPadding, // + &location_in_atlas // + )) { + return false; + } + glyph_positions.emplace_back(Rect::MakeXYWH(location_in_atlas.x(), // + location_in_atlas.y(), // + glyph_size.width, // + glyph_size.height // + )); + } + + return true; +} + +static ISize OptimumAtlasSizeForFontGlyphPairs( + const FontGlyphPair::Set& pairs, + std::vector& glyph_positions, + const std::shared_ptr& atlas_context, + GlyphAtlas::Type type) { + static constexpr auto kMinAtlasSize = 8u; + static constexpr auto kMinAlphaBitmapSize = 1024u; + static constexpr auto kMaxAtlasSize = 2048u; // QNX required 2048 or less. + + TRACE_EVENT0("impeller", __FUNCTION__); + + ISize current_size = type == GlyphAtlas::Type::kAlphaBitmap + ? ISize(kMinAlphaBitmapSize, kMinAlphaBitmapSize) + : ISize(kMinAtlasSize, kMinAtlasSize); + size_t total_pairs = pairs.size() + 1; + do { + auto rect_packer = std::shared_ptr( + RectanglePacker::Factory(current_size.width, current_size.height)); + + auto remaining_pairs = PairsFitInAtlasOfSize(pairs, current_size, + glyph_positions, rect_packer); + if (remaining_pairs == 0) { + atlas_context->UpdateRectPacker(rect_packer); + return current_size; + } else if (remaining_pairs < std::ceil(total_pairs / 2)) { + current_size = ISize::MakeWH( + std::max(current_size.width, current_size.height), + Allocation::NextPowerOfTwoSize( + std::min(current_size.width, current_size.height) + 1)); + } else { + current_size = ISize::MakeWH( + Allocation::NextPowerOfTwoSize(current_size.width + 1), + Allocation::NextPowerOfTwoSize(current_size.height + 1)); + } + } while (current_size.width <= kMaxAtlasSize && + current_size.height <= kMaxAtlasSize); + return ISize{0, 0}; +} + +static void DrawGlyph(BitmapSTB* bitmap, + const FontGlyphPair& font_glyph, + const Rect& location, + bool has_color) { + const auto& metrics = font_glyph.font.GetMetrics(); + + const impeller::Font& font = font_glyph.font; + const impeller::Glyph& glyph = font_glyph.glyph; + auto typeface = font.GetTypeface(); + // We downcast to the correct typeface type to access `stb` specific methods + std::shared_ptr typeface_stb = + std::reinterpret_pointer_cast(typeface); + // Conversion factor to scale font size in Points to pixels. + // Note this assumes typical DPI. + float text_size_pixels = metrics.point_size * TypefaceSTB::kPointsToPixels; + float scale_y = + stbtt_ScaleForPixelHeight(typeface_stb->GetFontInfo(), text_size_pixels); + float scale_x = scale_y; + + auto output = + bitmap->GetPixelAddress({static_cast(location.origin.x), + static_cast(location.origin.y)}); + // For Alpha and Signed Distance field bitmaps we can use STB to draw the + // Glyph in place + if (!has_color || DISABLE_COLOR_FONT_SUPPORT) { + stbtt_MakeGlyphBitmap(typeface_stb->GetFontInfo(), output, + location.size.width - kPadding, + location.size.height - kPadding, + bitmap->GetRowBytes(), scale_x, scale_y, glyph.index); + } else { + // But for color bitmaps we need to get the glyph pixels and then carry all + // channels into the atlas bitmap. This may not be performant but I'm unsure + // of any other approach currently. + int glyph_bitmap_width = 0; + int glyph_bitmap_height = 0; + int glyph_bitmap_xoff = 0; + int glyph_bitmap_yoff = 0; + auto glyph_pixels = stbtt_GetGlyphBitmap( + typeface_stb->GetFontInfo(), scale_x, scale_y, glyph.index, + &glyph_bitmap_width, &glyph_bitmap_height, &glyph_bitmap_xoff, + &glyph_bitmap_yoff); + + uint8_t* write_pos = output; + for (auto y = 0; y < glyph_bitmap_height; ++y) { + for (auto x = 0; x < glyph_bitmap_width; ++x) { + // Color bitmaps write as White (i.e. what is 0 in an alpha bitmap is + // 255 in a color bitmap) But not alpha. Alpha still carries + // transparency info in the normal way. + // There's some issue with color fonts, in that if the pixel color is + // nonzero, the alpha is ignored during rendering. That is, partially + // (or fully) transparent pixels with nonzero color are rendered as + // fully opaque. + uint8_t a = glyph_pixels[x + y * glyph_bitmap_width]; + uint8_t c = 255 - a; + + // Red channel + *write_pos = c; + write_pos++; + // Green channel + *write_pos = c; + write_pos++; + // Blue channel + *write_pos = c; + write_pos++; + // Alpha channel + *write_pos = a; + write_pos++; + } + // next row + write_pos = output + (y * bitmap->GetRowBytes()); + } + stbtt_FreeBitmap(glyph_pixels, nullptr); + } +} + +static bool UpdateAtlasBitmap(const GlyphAtlas& atlas, + const std::shared_ptr& bitmap, + const FontGlyphPairRefVector& new_pairs) { + TRACE_EVENT0("impeller", __FUNCTION__); + FML_DCHECK(bitmap != nullptr); + + bool has_color = atlas.GetType() == GlyphAtlas::Type::kColorBitmap; + + for (const FontGlyphPair& pair : new_pairs) { + auto pos = atlas.FindFontGlyphBounds(pair); + if (!pos.has_value()) { + continue; + } + DrawGlyph(bitmap.get(), pair, pos.value(), has_color); + } + return true; +} + +static std::shared_ptr CreateAtlasBitmap(const GlyphAtlas& atlas, + const ISize& atlas_size) { + TRACE_EVENT0("impeller", __FUNCTION__); + + size_t bytes_per_pixel = 1; + if (atlas.GetType() == GlyphAtlas::Type::kColorBitmap && + !DISABLE_COLOR_FONT_SUPPORT) { + bytes_per_pixel = kColorFontBitsPerPixel; + } + auto bitmap = std::make_shared(atlas_size.width, atlas_size.height, + bytes_per_pixel); + + bool has_color = atlas.GetType() == GlyphAtlas::Type::kColorBitmap; + + atlas.IterateGlyphs([&bitmap, has_color](const FontGlyphPair& font_glyph, + const Rect& location) -> bool { + DrawGlyph(bitmap.get(), font_glyph, location, has_color); + return true; + }); + + return bitmap; +} + +// static bool UpdateGlyphTextureAtlas(std::shared_ptr bitmap, +static bool UpdateGlyphTextureAtlas(std::shared_ptr& bitmap, + const std::shared_ptr& texture) { + TRACE_EVENT0("impeller", __FUNCTION__); + + FML_DCHECK(bitmap != nullptr); + + auto texture_descriptor = texture->GetTextureDescriptor(); + + auto mapping = std::make_shared( + reinterpret_cast(bitmap->GetPixels()), // data + texture_descriptor.GetByteSizeOfBaseMipLevel() // size + // As the bitmap is static in this module I believe we don't need to + // specify a release proc. + ); + + return texture->SetContents(mapping); +} + +static std::shared_ptr UploadGlyphTextureAtlas( + const std::shared_ptr& allocator, + std::shared_ptr& bitmap, + const ISize& atlas_size, + PixelFormat format) { + TRACE_EVENT0("impeller", __FUNCTION__); + if (!allocator) { + return nullptr; + } + + FML_DCHECK(bitmap != nullptr); + + TextureDescriptor texture_descriptor; + texture_descriptor.storage_mode = StorageMode::kHostVisible; + texture_descriptor.format = format; + texture_descriptor.size = atlas_size; + + if (bitmap->GetRowBytes() * bitmap->GetHeight() != + texture_descriptor.GetByteSizeOfBaseMipLevel()) { + return nullptr; + } + + auto texture = allocator->CreateTexture(texture_descriptor); + if (!texture || !texture->IsValid()) { + return nullptr; + } + texture->SetLabel("GlyphAtlas"); + + auto mapping = std::make_shared( + reinterpret_cast(bitmap->GetPixels()), // data + texture_descriptor.GetByteSizeOfBaseMipLevel() // size + // As the bitmap is static in this module I believe we don't need to + // specify a release proc. + ); + + if (!texture->SetContents(mapping)) { + return nullptr; + } + return texture; +} + +std::shared_ptr TypographerContextSTB::CreateGlyphAtlas( + Context& context, + GlyphAtlas::Type type, + std::shared_ptr atlas_context, + const FontGlyphPair::Set& font_glyph_pairs) const { + TRACE_EVENT0("impeller", __FUNCTION__); + if (!IsValid()) { + return nullptr; + } + auto& atlas_context_stb = GlyphAtlasContextSTB::Cast(*atlas_context); + std::shared_ptr last_atlas = atlas_context->GetGlyphAtlas(); + + if (font_glyph_pairs.empty()) { + return last_atlas; + } + + // --------------------------------------------------------------------------- + // Step 1: Determine if the atlas type and font glyph pairs are compatible + // with the current atlas and reuse if possible. + // --------------------------------------------------------------------------- + FontGlyphPairRefVector new_glyphs; + for (const FontGlyphPair& pair : font_glyph_pairs) { + if (!last_atlas->FindFontGlyphBounds(pair).has_value()) { + new_glyphs.push_back(pair); + } + } + if (last_atlas->GetType() == type && new_glyphs.size() == 0) { + return last_atlas; + } + + // --------------------------------------------------------------------------- + // Step 2: Determine if the additional missing glyphs can be appended to the + // existing bitmap without recreating the atlas. This requires that + // the type is identical. + // --------------------------------------------------------------------------- + std::vector glyph_positions; + if (last_atlas->GetType() == type && + CanAppendToExistingAtlas(last_atlas, new_glyphs, glyph_positions, + atlas_context->GetAtlasSize(), + atlas_context->GetRectPacker())) { + // The old bitmap will be reused and only the additional glyphs will be + // added. + + // --------------------------------------------------------------------------- + // Step 3a: Record the positions in the glyph atlas of the newly added + // glyphs. + // --------------------------------------------------------------------------- + for (size_t i = 0, count = glyph_positions.size(); i < count; i++) { + last_atlas->AddTypefaceGlyphPosition(new_glyphs[i], glyph_positions[i]); + } + + // --------------------------------------------------------------------------- + // Step 4a: Draw new font-glyph pairs into the existing bitmap. + // --------------------------------------------------------------------------- + // auto bitmap = atlas_context->GetBitmap(); + auto bitmap = atlas_context_stb.GetBitmap(); + if (!UpdateAtlasBitmap(*last_atlas, bitmap, new_glyphs)) { + return nullptr; + } + + // --------------------------------------------------------------------------- + // Step 5a: Update the existing texture with the updated bitmap. + // --------------------------------------------------------------------------- + if (!UpdateGlyphTextureAtlas(bitmap, last_atlas->GetTexture())) { + return nullptr; + } + return last_atlas; + } + // A new glyph atlas must be created. + + // --------------------------------------------------------------------------- + // Step 3b: Get the optimum size of the texture atlas. + // --------------------------------------------------------------------------- + auto glyph_atlas = std::make_shared(type); + auto atlas_size = OptimumAtlasSizeForFontGlyphPairs( + font_glyph_pairs, glyph_positions, atlas_context, type); + + atlas_context->UpdateGlyphAtlas(glyph_atlas, atlas_size); + if (atlas_size.IsEmpty()) { + return nullptr; + } + + // --------------------------------------------------------------------------- + // Step 4b: Find location of font-glyph pairs in the atlas. We have this from + // the last step. So no need to do create another rect packer. But just do a + // sanity check of counts. This could also be just an assertion as only a + // construction issue would cause such a failure. + // --------------------------------------------------------------------------- + if (glyph_positions.size() != font_glyph_pairs.size()) { + return nullptr; + } + + // --------------------------------------------------------------------------- + // Step 5b: Record the positions in the glyph atlas. + // --------------------------------------------------------------------------- + { + size_t i = 0; + for (auto it = font_glyph_pairs.begin(); it != font_glyph_pairs.end(); + ++i, ++it) { + glyph_atlas->AddTypefaceGlyphPosition(*it, glyph_positions[i]); + } + } + + // --------------------------------------------------------------------------- + // Step 6b: Draw font-glyph pairs in the correct spot in the atlas. + // --------------------------------------------------------------------------- + auto bitmap = CreateAtlasBitmap(*glyph_atlas, atlas_size); + if (!bitmap) { + return nullptr; + } + atlas_context_stb.UpdateBitmap(bitmap); + + // --------------------------------------------------------------------------- + // Step 7b: Upload the atlas as a texture. + // --------------------------------------------------------------------------- + PixelFormat format; + switch (type) { + case GlyphAtlas::Type::kAlphaBitmap: + format = PixelFormat::kA8UNormInt; + break; + case GlyphAtlas::Type::kColorBitmap: + format = DISABLE_COLOR_FONT_SUPPORT ? PixelFormat::kA8UNormInt + : PixelFormat::kR8G8B8A8UNormInt; + break; + } + auto texture = UploadGlyphTextureAtlas(context.GetResourceAllocator(), bitmap, + atlas_size, format); + if (!texture) { + return nullptr; + } + + // --------------------------------------------------------------------------- + // Step 8b: Record the texture in the glyph atlas. + // --------------------------------------------------------------------------- + glyph_atlas->SetTexture(std::move(texture)); + + return glyph_atlas; +} + +} // namespace impeller diff --git a/impeller/typographer/backends/stb/typographer_context_stb.h b/impeller/typographer/backends/stb/typographer_context_stb.h new file mode 100644 index 0000000000000..5496931363ed5 --- /dev/null +++ b/impeller/typographer/backends/stb/typographer_context_stb.h @@ -0,0 +1,36 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "impeller/typographer/typographer_context.h" + +#include +#include "flutter/fml/macros.h" + +namespace impeller { + +class TypographerContextSTB : public TypographerContext { + public: + static std::unique_ptr Make(); + + TypographerContextSTB(); + + ~TypographerContextSTB() override; + + // |TypographerContext| + std::shared_ptr CreateGlyphAtlasContext() const override; + + // |TypographerContext| + std::shared_ptr CreateGlyphAtlas( + Context& context, + GlyphAtlas::Type type, + std::shared_ptr atlas_context, + const FontGlyphPair::Set& font_glyph_pairs) const override; + + private: + FML_DISALLOW_COPY_AND_ASSIGN(TypographerContextSTB); +}; + +} // namespace impeller diff --git a/impeller/typographer/glyph_atlas.cc b/impeller/typographer/glyph_atlas.cc index fd3fb1556c354..21a30ad4d8f80 100644 --- a/impeller/typographer/glyph_atlas.cc +++ b/impeller/typographer/glyph_atlas.cc @@ -22,10 +22,6 @@ const ISize& GlyphAtlasContext::GetAtlasSize() const { return atlas_size_; } -std::shared_ptr GlyphAtlasContext::GetBitmap() const { - return bitmap_; -} - std::shared_ptr GlyphAtlasContext::GetRectPacker() const { return rect_packer_; } @@ -36,10 +32,6 @@ void GlyphAtlasContext::UpdateGlyphAtlas(std::shared_ptr atlas, atlas_size_ = size; } -void GlyphAtlasContext::UpdateBitmap(std::shared_ptr bitmap) { - bitmap_ = std::move(bitmap); -} - void GlyphAtlasContext::UpdateRectPacker( std::shared_ptr rect_packer) { rect_packer_ = std::move(rect_packer); diff --git a/impeller/typographer/glyph_atlas.h b/impeller/typographer/glyph_atlas.h index 5f9ba61f628b3..c7d4ea4acfcd4 100644 --- a/impeller/typographer/glyph_atlas.h +++ b/impeller/typographer/glyph_atlas.h @@ -16,8 +16,6 @@ #include "impeller/typographer/font_glyph_pair.h" #include "impeller/typographer/rectangle_packer.h" -class SkBitmap; - namespace impeller { //------------------------------------------------------------------------------ @@ -130,9 +128,7 @@ class GlyphAtlas { /// class GlyphAtlasContext { public: - GlyphAtlasContext(); - - ~GlyphAtlasContext(); + virtual ~GlyphAtlasContext(); //---------------------------------------------------------------------------- /// @brief Retrieve the current glyph atlas. @@ -142,10 +138,6 @@ class GlyphAtlasContext { /// @brief Retrieve the size of the current glyph atlas. const ISize& GetAtlasSize() const; - //---------------------------------------------------------------------------- - /// @brief Retrieve the previous (if any) SkBitmap instance. - std::shared_ptr GetBitmap() const; - //---------------------------------------------------------------------------- /// @brief Retrieve the previous (if any) rect packer. std::shared_ptr GetRectPacker() const; @@ -154,14 +146,14 @@ class GlyphAtlasContext { /// @brief Update the context with a newly constructed glyph atlas. void UpdateGlyphAtlas(std::shared_ptr atlas, ISize size); - void UpdateBitmap(std::shared_ptr bitmap); - void UpdateRectPacker(std::shared_ptr rect_packer); + protected: + GlyphAtlasContext(); + private: std::shared_ptr atlas_; ISize atlas_size_; - std::shared_ptr bitmap_; std::shared_ptr rect_packer_; FML_DISALLOW_COPY_AND_ASSIGN(GlyphAtlasContext); diff --git a/impeller/typographer/lazy_glyph_atlas.cc b/impeller/typographer/lazy_glyph_atlas.cc index 85f7c5dce0da2..bf45acda95985 100644 --- a/impeller/typographer/lazy_glyph_atlas.cc +++ b/impeller/typographer/lazy_glyph_atlas.cc @@ -5,17 +5,21 @@ #include "impeller/typographer/lazy_glyph_atlas.h" #include "impeller/base/validation.h" -#include "impeller/typographer/text_render_context.h" +#include "impeller/typographer/typographer_context.h" #include namespace impeller { LazyGlyphAtlas::LazyGlyphAtlas( - std::shared_ptr text_render_context) - : text_render_context_(std::move(text_render_context)), - alpha_context_(std::make_shared()), - color_context_(std::make_shared()) {} + std::shared_ptr typographer_context) + : typographer_context_(std::move(typographer_context)), + alpha_context_(typographer_context_ + ? typographer_context_->CreateGlyphAtlasContext() + : nullptr), + color_context_(typographer_context_ + ? typographer_context_->CreateGlyphAtlasContext() + : nullptr) {} LazyGlyphAtlas::~LazyGlyphAtlas() = default; @@ -44,14 +48,14 @@ std::shared_ptr LazyGlyphAtlas::CreateOrGetGlyphAtlas( } } - if (!text_render_context_) { - VALIDATION_LOG << "Unable to render text because a TextRenderContext has " + if (!typographer_context_) { + VALIDATION_LOG << "Unable to render text because a TypographerContext has " "not been set."; return nullptr; } - if (!text_render_context_->IsValid()) { + if (!typographer_context_->IsValid()) { VALIDATION_LOG - << "Unable to render text because the TextRenderContext is invalid."; + << "Unable to render text because the TypographerContext is invalid."; return nullptr; } @@ -59,7 +63,7 @@ std::shared_ptr LazyGlyphAtlas::CreateOrGetGlyphAtlas( auto atlas_context = type == GlyphAtlas::Type::kAlphaBitmap ? alpha_context_ : color_context_; auto atlas = - text_render_context_->CreateGlyphAtlas(context, type, atlas_context, set); + typographer_context_->CreateGlyphAtlas(context, type, atlas_context, set); if (!atlas || !atlas->IsValid()) { VALIDATION_LOG << "Could not create valid atlas."; return nullptr; diff --git a/impeller/typographer/lazy_glyph_atlas.h b/impeller/typographer/lazy_glyph_atlas.h index f29dbfea6e506..3794a7dcccac9 100644 --- a/impeller/typographer/lazy_glyph_atlas.h +++ b/impeller/typographer/lazy_glyph_atlas.h @@ -10,14 +10,14 @@ #include "impeller/renderer/context.h" #include "impeller/typographer/glyph_atlas.h" #include "impeller/typographer/text_frame.h" -#include "impeller/typographer/text_render_context.h" +#include "impeller/typographer/typographer_context.h" namespace impeller { class LazyGlyphAtlas { public: explicit LazyGlyphAtlas( - std::shared_ptr text_render_context); + std::shared_ptr typographer_context); ~LazyGlyphAtlas(); @@ -30,7 +30,7 @@ class LazyGlyphAtlas { GlyphAtlas::Type type) const; private: - std::shared_ptr text_render_context_; + std::shared_ptr typographer_context_; FontGlyphPair::Set alpha_set_; FontGlyphPair::Set color_set_; diff --git a/impeller/typographer/text_render_context.cc b/impeller/typographer/typographer_context.cc similarity index 59% rename from impeller/typographer/text_render_context.cc rename to impeller/typographer/typographer_context.cc index 8476b62c7b6aa..91c3129039ccf 100644 --- a/impeller/typographer/text_render_context.cc +++ b/impeller/typographer/typographer_context.cc @@ -2,19 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "impeller/typographer/text_render_context.h" +#include "impeller/typographer/typographer_context.h" #include namespace impeller { -TextRenderContext::TextRenderContext() { +TypographerContext::TypographerContext() { is_valid_ = true; } -TextRenderContext::~TextRenderContext() = default; +TypographerContext::~TypographerContext() = default; -bool TextRenderContext::IsValid() const { +bool TypographerContext::IsValid() const { return is_valid_; } diff --git a/impeller/typographer/text_render_context.h b/impeller/typographer/typographer_context.h similarity index 85% rename from impeller/typographer/text_render_context.h rename to impeller/typographer/typographer_context.h index 754e9c26bb5c0..8ed74ce1fcbf1 100644 --- a/impeller/typographer/text_render_context.h +++ b/impeller/typographer/typographer_context.h @@ -20,12 +20,15 @@ namespace impeller { /// rendering text on the GPU. /// /// -class TextRenderContext { +class TypographerContext { public: - virtual ~TextRenderContext(); + virtual ~TypographerContext(); virtual bool IsValid() const; + virtual std::shared_ptr CreateGlyphAtlasContext() + const = 0; + // TODO(dnfield): Callers should not need to know which type of atlas to // create. https://github.com/flutter/flutter/issues/111640 @@ -40,12 +43,12 @@ class TextRenderContext { /// @brief Create a new context to render text that talks to an /// underlying graphics context. /// - TextRenderContext(); + TypographerContext(); private: bool is_valid_ = false; - FML_DISALLOW_COPY_AND_ASSIGN(TextRenderContext); + FML_DISALLOW_COPY_AND_ASSIGN(TypographerContext); }; } // namespace impeller diff --git a/impeller/typographer/typographer_unittests.cc b/impeller/typographer/typographer_unittests.cc index 09c78daea06b3..4a2bed4dc52cc 100644 --- a/impeller/typographer/typographer_unittests.cc +++ b/impeller/typographer/typographer_unittests.cc @@ -5,7 +5,7 @@ #include "flutter/testing/testing.h" #include "impeller/playground/playground_test.h" #include "impeller/typographer/backends/skia/text_frame_skia.h" -#include "impeller/typographer/backends/skia/text_render_context_skia.h" +#include "impeller/typographer/backends/skia/typographer_context_skia.h" #include "impeller/typographer/lazy_glyph_atlas.h" #include "impeller/typographer/rectangle_packer.h" #include "third_party/skia/include/core/SkData.h" @@ -24,14 +24,14 @@ INSTANTIATE_PLAYGROUND_SUITE(TypographerTest); static std::shared_ptr CreateGlyphAtlas( Context& context, - const TextRenderContext* text_render_context, + const TypographerContext* typographer_context, GlyphAtlas::Type type, Scalar scale, const std::shared_ptr& atlas_context, const TextFrame& frame) { FontGlyphPair::Set set; frame.CollectUniqueFontGlyphPairs(set, scale); - return text_render_context->CreateGlyphAtlas(context, type, atlas_context, + return typographer_context->CreateGlyphAtlas(context, type, atlas_context, set); } @@ -40,7 +40,7 @@ TEST_P(TypographerTest, CanConvertTextBlob) { auto blob = SkTextBlob::MakeFromString( "the quick brown fox jumped over the lazy dog.", font); ASSERT_TRUE(blob); - auto frame = TextFrameFromTextBlob(blob); + auto frame = MakeTextFrameFromTextBlobSkia(blob); ASSERT_EQ(frame.GetRunCount(), 1u); for (const auto& run : frame.GetRuns()) { ASSERT_TRUE(run.IsValid()); @@ -49,20 +49,20 @@ TEST_P(TypographerTest, CanConvertTextBlob) { } TEST_P(TypographerTest, CanCreateRenderContext) { - auto context = TextRenderContextSkia::Make(); + auto context = TypographerContextSkia::Make(); ASSERT_TRUE(context && context->IsValid()); } TEST_P(TypographerTest, CanCreateGlyphAtlas) { - auto context = TextRenderContextSkia::Make(); - auto atlas_context = std::make_shared(); + auto context = TypographerContextSkia::Make(); + auto atlas_context = context->CreateGlyphAtlasContext(); ASSERT_TRUE(context && context->IsValid()); SkFont sk_font; auto blob = SkTextBlob::MakeFromString("hello", sk_font); ASSERT_TRUE(blob); - auto atlas = CreateGlyphAtlas(*GetContext(), context.get(), - GlyphAtlas::Type::kAlphaBitmap, 1.0f, - atlas_context, TextFrameFromTextBlob(blob)); + auto atlas = CreateGlyphAtlas( + *GetContext(), context.get(), GlyphAtlas::Type::kAlphaBitmap, 1.0f, + atlas_context, MakeTextFrameFromTextBlobSkia(blob)); ASSERT_NE(atlas, nullptr); ASSERT_NE(atlas->GetTexture(), nullptr); ASSERT_EQ(atlas->GetType(), GlyphAtlas::Type::kAlphaBitmap); @@ -108,15 +108,16 @@ TEST_P(TypographerTest, LazyAtlasTracksColor) { auto blob = SkTextBlob::MakeFromString("hello", sk_font); ASSERT_TRUE(blob); - auto frame = TextFrameFromTextBlob(blob); + auto frame = MakeTextFrameFromTextBlobSkia(blob); ASSERT_FALSE(frame.GetAtlasType() == GlyphAtlas::Type::kColorBitmap); - LazyGlyphAtlas lazy_atlas(TextRenderContextSkia::Make()); + LazyGlyphAtlas lazy_atlas(TypographerContextSkia::Make()); lazy_atlas.AddTextFrame(frame, 1.0f); - frame = TextFrameFromTextBlob(SkTextBlob::MakeFromString("😀 ", emoji_font)); + frame = MakeTextFrameFromTextBlobSkia( + SkTextBlob::MakeFromString("😀 ", emoji_font)); ASSERT_TRUE(frame.GetAtlasType() == GlyphAtlas::Type::kColorBitmap); @@ -133,15 +134,15 @@ TEST_P(TypographerTest, LazyAtlasTracksColor) { } TEST_P(TypographerTest, GlyphAtlasWithOddUniqueGlyphSize) { - auto context = TextRenderContextSkia::Make(); - auto atlas_context = std::make_shared(); + auto context = TypographerContextSkia::Make(); + auto atlas_context = context->CreateGlyphAtlasContext(); ASSERT_TRUE(context && context->IsValid()); SkFont sk_font; auto blob = SkTextBlob::MakeFromString("AGH", sk_font); ASSERT_TRUE(blob); - auto atlas = CreateGlyphAtlas(*GetContext(), context.get(), - GlyphAtlas::Type::kAlphaBitmap, 1.0f, - atlas_context, TextFrameFromTextBlob(blob)); + auto atlas = CreateGlyphAtlas( + *GetContext(), context.get(), GlyphAtlas::Type::kAlphaBitmap, 1.0f, + atlas_context, MakeTextFrameFromTextBlobSkia(blob)); ASSERT_NE(atlas, nullptr); ASSERT_NE(atlas->GetTexture(), nullptr); @@ -150,15 +151,15 @@ TEST_P(TypographerTest, GlyphAtlasWithOddUniqueGlyphSize) { } TEST_P(TypographerTest, GlyphAtlasIsRecycledIfUnchanged) { - auto context = TextRenderContextSkia::Make(); - auto atlas_context = std::make_shared(); + auto context = TypographerContextSkia::Make(); + auto atlas_context = context->CreateGlyphAtlasContext(); ASSERT_TRUE(context && context->IsValid()); SkFont sk_font; auto blob = SkTextBlob::MakeFromString("spooky skellingtons", sk_font); ASSERT_TRUE(blob); - auto atlas = CreateGlyphAtlas(*GetContext(), context.get(), - GlyphAtlas::Type::kAlphaBitmap, 1.0f, - atlas_context, TextFrameFromTextBlob(blob)); + auto atlas = CreateGlyphAtlas( + *GetContext(), context.get(), GlyphAtlas::Type::kAlphaBitmap, 1.0f, + atlas_context, MakeTextFrameFromTextBlobSkia(blob)); ASSERT_NE(atlas, nullptr); ASSERT_NE(atlas->GetTexture(), nullptr); ASSERT_EQ(atlas, atlas_context->GetGlyphAtlas()); @@ -167,14 +168,14 @@ TEST_P(TypographerTest, GlyphAtlasIsRecycledIfUnchanged) { auto next_atlas = CreateGlyphAtlas( *GetContext(), context.get(), GlyphAtlas::Type::kAlphaBitmap, 1.0f, - atlas_context, TextFrameFromTextBlob(blob)); + atlas_context, MakeTextFrameFromTextBlobSkia(blob)); ASSERT_EQ(atlas, next_atlas); ASSERT_EQ(atlas_context->GetGlyphAtlas(), atlas); } TEST_P(TypographerTest, GlyphAtlasWithLotsOfdUniqueGlyphSize) { - auto context = TextRenderContextSkia::Make(); - auto atlas_context = std::make_shared(); + auto context = TypographerContextSkia::Make(); + auto atlas_context = context->CreateGlyphAtlasContext(); ASSERT_TRUE(context && context->IsValid()); const char* test_string = @@ -190,7 +191,8 @@ TEST_P(TypographerTest, GlyphAtlasWithLotsOfdUniqueGlyphSize) { FontGlyphPair::Set set; size_t size_count = 8; for (size_t index = 0; index < size_count; index += 1) { - TextFrameFromTextBlob(blob).CollectUniqueFontGlyphPairs(set, 0.6 * index); + MakeTextFrameFromTextBlobSkia(blob).CollectUniqueFontGlyphPairs( + set, 0.6 * index); }; auto atlas = context->CreateGlyphAtlas(*GetContext(), GlyphAtlas::Type::kAlphaBitmap, @@ -215,15 +217,15 @@ TEST_P(TypographerTest, GlyphAtlasWithLotsOfdUniqueGlyphSize) { } TEST_P(TypographerTest, GlyphAtlasTextureIsRecycledIfUnchanged) { - auto context = TextRenderContextSkia::Make(); - auto atlas_context = std::make_shared(); + auto context = TypographerContextSkia::Make(); + auto atlas_context = context->CreateGlyphAtlasContext(); ASSERT_TRUE(context && context->IsValid()); SkFont sk_font; auto blob = SkTextBlob::MakeFromString("spooky 1", sk_font); ASSERT_TRUE(blob); - auto atlas = CreateGlyphAtlas(*GetContext(), context.get(), - GlyphAtlas::Type::kAlphaBitmap, 1.0f, - atlas_context, TextFrameFromTextBlob(blob)); + auto atlas = CreateGlyphAtlas( + *GetContext(), context.get(), GlyphAtlas::Type::kAlphaBitmap, 1.0f, + atlas_context, MakeTextFrameFromTextBlobSkia(blob)); auto old_packer = atlas_context->GetRectPacker(); ASSERT_NE(atlas, nullptr); @@ -237,7 +239,7 @@ TEST_P(TypographerTest, GlyphAtlasTextureIsRecycledIfUnchanged) { auto blob2 = SkTextBlob::MakeFromString("spooky 2", sk_font); auto next_atlas = CreateGlyphAtlas( *GetContext(), context.get(), GlyphAtlas::Type::kAlphaBitmap, 1.0f, - atlas_context, TextFrameFromTextBlob(blob2)); + atlas_context, MakeTextFrameFromTextBlobSkia(blob2)); ASSERT_EQ(atlas, next_atlas); auto* second_texture = next_atlas->GetTexture().get(); @@ -248,15 +250,15 @@ TEST_P(TypographerTest, GlyphAtlasTextureIsRecycledIfUnchanged) { } TEST_P(TypographerTest, GlyphAtlasTextureIsRecreatedIfTypeChanges) { - auto context = TextRenderContextSkia::Make(); - auto atlas_context = std::make_shared(); + auto context = TypographerContextSkia::Make(); + auto atlas_context = context->CreateGlyphAtlasContext(); ASSERT_TRUE(context && context->IsValid()); SkFont sk_font; auto blob = SkTextBlob::MakeFromString("spooky 1", sk_font); ASSERT_TRUE(blob); - auto atlas = CreateGlyphAtlas(*GetContext(), context.get(), - GlyphAtlas::Type::kAlphaBitmap, 1.0f, - atlas_context, TextFrameFromTextBlob(blob)); + auto atlas = CreateGlyphAtlas( + *GetContext(), context.get(), GlyphAtlas::Type::kAlphaBitmap, 1.0f, + atlas_context, MakeTextFrameFromTextBlobSkia(blob)); auto old_packer = atlas_context->GetRectPacker(); ASSERT_NE(atlas, nullptr); @@ -271,7 +273,7 @@ TEST_P(TypographerTest, GlyphAtlasTextureIsRecreatedIfTypeChanges) { auto blob2 = SkTextBlob::MakeFromString("spooky 1", sk_font); auto next_atlas = CreateGlyphAtlas( *GetContext(), context.get(), GlyphAtlas::Type::kColorBitmap, 1.0f, - atlas_context, TextFrameFromTextBlob(blob2)); + atlas_context, MakeTextFrameFromTextBlobSkia(blob2)); ASSERT_NE(atlas, next_atlas); auto* second_texture = next_atlas->GetTexture().get(); @@ -305,12 +307,13 @@ TEST_P(TypographerTest, MaybeHasOverlapping) { font_mgr->matchFamilyStyle("Arial", SkFontStyle::Normal()); SkFont sk_font(typeface, 0.5f); - auto frame = TextFrameFromTextBlob(SkTextBlob::MakeFromString("1", sk_font)); + auto frame = + MakeTextFrameFromTextBlobSkia(SkTextBlob::MakeFromString("1", sk_font)); // Single character has no overlapping ASSERT_FALSE(frame.MaybeHasOverlapping()); - auto frame_2 = - TextFrameFromTextBlob(SkTextBlob::MakeFromString("123456789", sk_font)); + auto frame_2 = MakeTextFrameFromTextBlobSkia( + SkTextBlob::MakeFromString("123456789", sk_font)); ASSERT_FALSE(frame_2.MaybeHasOverlapping()); } diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index d413edf6ac2cb..7d0f9d9fe3c80 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -27,7 +27,7 @@ // GN is having trouble understanding how this works in the Fuchsia builds. #include "impeller/aiks/aiks_context.h" // nogncheck #include "impeller/renderer/context.h" // nogncheck -#include "impeller/typographer/backends/skia/text_render_context_skia.h" // nogncheck +#include "impeller/typographer/backends/skia/typographer_context_skia.h" // nogncheck #endif // IMPELLER_SUPPORTS_RENDERING #include "flutter/lib/ui/snapshot_delegate.h" #include "flutter/shell/common/pipeline.h" @@ -546,7 +546,7 @@ class Rasterizer final : public SnapshotDelegate, } if (auto context = impeller_context_.lock()) { return std::make_shared( - context, impeller::TextRenderContextSkia::Make()); + context, impeller::TypographerContextSkia::Make()); } #endif return nullptr; diff --git a/shell/gpu/gpu_surface_gl_impeller.cc b/shell/gpu/gpu_surface_gl_impeller.cc index 6cb4faa8dbed1..19e2669c997a2 100644 --- a/shell/gpu/gpu_surface_gl_impeller.cc +++ b/shell/gpu/gpu_surface_gl_impeller.cc @@ -8,7 +8,7 @@ #include "impeller/display_list/dl_dispatcher.h" #include "impeller/renderer/backend/gles/surface_gles.h" #include "impeller/renderer/renderer.h" -#include "impeller/typographer/backends/skia/text_render_context_skia.h" +#include "impeller/typographer/backends/skia/typographer_context_skia.h" namespace flutter { @@ -30,7 +30,7 @@ GPUSurfaceGLImpeller::GPUSurfaceGLImpeller( } auto aiks_context = std::make_shared( - context, impeller::TextRenderContextSkia::Make()); + context, impeller::TypographerContextSkia::Make()); if (!aiks_context->IsValid()) { return; diff --git a/shell/gpu/gpu_surface_metal_impeller.mm b/shell/gpu/gpu_surface_metal_impeller.mm index c95e53599b57e..d76b13824c86e 100644 --- a/shell/gpu/gpu_surface_metal_impeller.mm +++ b/shell/gpu/gpu_surface_metal_impeller.mm @@ -13,7 +13,7 @@ #include "flutter/fml/trace_event.h" #include "impeller/display_list/dl_dispatcher.h" #include "impeller/renderer/backend/metal/surface_mtl.h" -#include "impeller/typographer/backends/skia/text_render_context_skia.h" +#include "impeller/typographer/backends/skia/typographer_context_skia.h" static_assert(!__has_feature(objc_arc), "ARC must be disabled."); @@ -37,7 +37,7 @@ impeller_renderer_(CreateImpellerRenderer(context)), aiks_context_( std::make_shared(impeller_renderer_ ? context : nullptr, - impeller::TextRenderContextSkia::Make())), + impeller::TypographerContextSkia::Make())), render_to_surface_(render_to_surface) { // If this preference is explicitly set, we allow for disabling partial repaint. NSNumber* disablePartialRepaint = diff --git a/shell/gpu/gpu_surface_vulkan_impeller.cc b/shell/gpu/gpu_surface_vulkan_impeller.cc index 4ffc92afdb10d..3b6ec9d876ec0 100644 --- a/shell/gpu/gpu_surface_vulkan_impeller.cc +++ b/shell/gpu/gpu_surface_vulkan_impeller.cc @@ -9,7 +9,7 @@ #include "impeller/renderer/backend/vulkan/surface_context_vk.h" #include "impeller/renderer/renderer.h" #include "impeller/renderer/surface.h" -#include "impeller/typographer/backends/skia/text_render_context_skia.h" +#include "impeller/typographer/backends/skia/typographer_context_skia.h" namespace flutter { @@ -25,7 +25,7 @@ GPUSurfaceVulkanImpeller::GPUSurfaceVulkanImpeller( } auto aiks_context = std::make_shared( - context, impeller::TextRenderContextSkia::Make()); + context, impeller::TypographerContextSkia::Make()); if (!aiks_context->IsValid()) { return; } diff --git a/tools/licenses/lib/paths.dart b/tools/licenses/lib/paths.dart index 93ab31f5ffb8a..ca5b8f6689030 100644 --- a/tools/licenses/lib/paths.dart +++ b/tools/licenses/lib/paths.dart @@ -184,6 +184,7 @@ final Set skippedPaths = { r'third_party/skia/third_party/lua', // not linked in r'third_party/skia/third_party/vello', // not linked in r'third_party/skia/tools', // contains nothing that ends up in the binary executable + r'third_party/stb', r'third_party/swiftshader', // only used on hosts for tests r'third_party/tinygltf', r'third_party/vulkan-deps/glslang/LICENSE', // excluded to make sure we don't accidentally apply it as a default license