From adc2ccaea3224ef190941e67fac6a3c763a87c72 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Sun, 20 Aug 2023 17:04:06 -0700 Subject: [PATCH 01/12] [Impeller] Add STB text backend. --- DEPS | 4 + impeller/BUILD.gn | 2 +- impeller/aiks/BUILD.gn | 7 + impeller/display_list/BUILD.gn | 2 + impeller/entity/BUILD.gn | 1 + impeller/golden_tests/BUILD.gn | 1 + impeller/typographer/BUILD.gn | 10 +- impeller/typographer/backends/skia/BUILD.gn | 21 + impeller/typographer/backends/stb/BUILD.gn | 21 + .../backends/stb/text_render_context_stb.cc | 789 ++++++++++++++++++ .../backends/stb/text_render_context_stb.h | 29 + .../typographer/backends/stb/typeface_stb.cc | 57 ++ .../typographer/backends/stb/typeface_stb.h | 43 + 13 files changed, 978 insertions(+), 9 deletions(-) create mode 100644 impeller/typographer/backends/skia/BUILD.gn create mode 100644 impeller/typographer/backends/stb/BUILD.gn create mode 100644 impeller/typographer/backends/stb/text_render_context_stb.cc create mode 100644 impeller/typographer/backends/stb/text_render_context_stb.h create mode 100644 impeller/typographer/backends/stb/typeface_stb.cc create mode 100644 impeller/typographer/backends/stb/typeface_stb.h diff --git a/DEPS b/DEPS index ac7ed16313225..5dedfbe35f331 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", @@ -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/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/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/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/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/typographer/BUILD.gn b/impeller/typographer/BUILD.gn index 9abec666774fd..bc2b759508888 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", @@ -38,7 +32,6 @@ impeller_component("typographer") { "../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..6db350059c004 --- /dev/null +++ b/impeller/typographer/backends/skia/BUILD.gn @@ -0,0 +1,21 @@ +# 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 = [ + "text_frame_skia.cc", + "text_frame_skia.h", + "text_render_context_skia.cc", + "text_render_context_skia.h", + "typeface_skia.cc", + "typeface_skia.h", + ] + + public_deps = [ + "//flutter/impeller/typographer", + "//third_party/skia", + ] +} diff --git a/impeller/typographer/backends/stb/BUILD.gn b/impeller/typographer/backends/stb/BUILD.gn new file mode 100644 index 0000000000000..b407266aa339f --- /dev/null +++ b/impeller/typographer/backends/stb/BUILD.gn @@ -0,0 +1,21 @@ +# 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 = [ + "text_render_context_stb.cc", + "text_render_context_stb.h", + "typeface_stb.cc", + "typeface_stb.h", + ] + + public_deps = [ + "//flutter/impeller/typographer", + "//third_party/stb:stb_truetype", + ] +} diff --git a/impeller/typographer/backends/stb/text_render_context_stb.cc b/impeller/typographer/backends/stb/text_render_context_stb.cc new file mode 100644 index 0000000000000..d6185de73789f --- /dev/null +++ b/impeller/typographer/backends/stb/text_render_context_stb.cc @@ -0,0 +1,789 @@ +// 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_render_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/font_glyph_pair.h" +#include "typeface_stb.h" + +// These values can be customize per build. +// Glyph atlases are always square. +#ifndef MAX_GLYPH_ATLAS_SIZE +#define MAX_GLYPH_ATLAS_SIZE 2048u +#endif +#ifndef MIN_GLYPH_ATLAS_SIZE +#define MIN_GLYPH_ATLAS_SIZE 8u +#endif + +#define DISABLE_COLOR_FONT_SUPPORT 1 +#ifdef DISABLE_COLOR_FONT_SUPPORT +#define COLOR_FONT_BPP 1 +#else +#define COLOR_FONT_BPP 4 +#endif + +// "Typical" conversion from font Points to Pixels. +// This assumes a constant pixels per em. +constexpr float POINTS_TO_PIXELS = 96.0/72.0; +// An available font scaling to improve rendering in the atlas if desired. +constexpr float FONT_RENDER_SCALING = 1.0; + +// An stb rect packer instead of Skia based rect packer +struct STBRectPacker { + // Standard rect pack context which can be used over N rect pack calls + std::unique_ptr context; + // Workspace which also must remain valid over N rect pack calls. + // In the ideal the `nodes` array should be >= the width of the target rect. + std::unique_ptr nodes; + + ~STBRectPacker() = default; + + STBRectPacker() = delete; + + STBRectPacker(int width, int height) + :context(std::make_unique()) + ,nodes(std::make_unique(width)) + { + stbrp_init_target(context.get(),width,height,nodes.get(),width); + } + + int PackRects(std::vector& rects) { + return stbrp_pack_rects(context.get(), rects.data(), (int)rects.size()); + } +}; + +// Analogous to the rect packer stored on the atlas context. But this uses STB. +static auto s_rect_packer = std::make_unique(MIN_GLYPH_ATLAS_SIZE, MIN_GLYPH_ATLAS_SIZE); + +// An simple bitmap in lieu of a skia bitmap. +struct STBBitmap { + size_t width; + size_t height; + size_t bytes_per_pixel; + std::unique_ptr pixels; + + ~STBBitmap() = default; + + STBBitmap() = delete; + + STBBitmap(size_t width, size_t height, size_t bytes_per_pixel) + :width(width) + ,height(height) + ,bytes_per_pixel(bytes_per_pixel) + ,pixels(std::make_unique(width*height*bytes_per_pixel)) {} + + uint8_t* const getPixels() const { return pixels.get() ; } + + uint8_t* getAddr(size_t x, size_t y) const { + if(x >= width) return nullptr; + if(y >= height) return nullptr; + if(x < 0) x = 0; + if(y < 0) y = 0; + auto p = pixels.get(); + return &p[(x + width * y) * bytes_per_pixel]; + } + + size_t rowBytes() const { return width * bytes_per_pixel; } + + size_t stride() const { return rowBytes(); } + + size_t getWidth() const { return width; } + + size_t getHeight() const { return height; } + + size_t getSize() const { return width * height * bytes_per_pixel ; } +}; + +// Analogous to the bitmaps (one for each type) stored in each Atlas context. +static auto alpha_bitmap = std::make_shared(MIN_GLYPH_ATLAS_SIZE, MIN_GLYPH_ATLAS_SIZE, 1); +static auto color_bitmap = std::make_shared(MIN_GLYPH_ATLAS_SIZE, MIN_GLYPH_ATLAS_SIZE, COLOR_FONT_BPP); +static auto signed_distance_bitmap = std::make_shared(MIN_GLYPH_ATLAS_SIZE, MIN_GLYPH_ATLAS_SIZE, 1); + +static std::shared_ptr get_atlas_bitmap(impeller::GlyphAtlas::Type type) { + switch(type) { + case impeller::GlyphAtlas::Type::kSignedDistanceField: + { + return signed_distance_bitmap; + break; + } + case impeller::GlyphAtlas::Type::kAlphaBitmap: + { + return alpha_bitmap; + break; + } + case impeller::GlyphAtlas::Type::kColorBitmap: + { + return color_bitmap ; + break; + } + } +} + +static void update_atlas_bitmap(std::shared_ptr& bitmap, impeller::GlyphAtlas::Type type) { + switch(type) { + case impeller::GlyphAtlas::Type::kSignedDistanceField: + { + signed_distance_bitmap = bitmap; + break; + } + case impeller::GlyphAtlas::Type::kAlphaBitmap: + { + alpha_bitmap = bitmap; + break; + } + case impeller::GlyphAtlas::Type::kColorBitmap: + { + color_bitmap = bitmap; + break; + } + } +} + +namespace impeller { + +using FontGlyphPairRefVector = + std::vector>; + +std::unique_ptr TextRenderContext::Create( + std::shared_ptr context) { + // There is only one backend today. + return std::make_unique(std::move(context)); +} + +constexpr auto kPadding = 1; + +TextRenderContextSTB::TextRenderContextSTB(std::shared_ptr context) + : TextRenderContext(std::move(context)) {} + +TextRenderContextSTB::~TextRenderContextSTB() = default; + +static FontGlyphPair::Set CollectUniqueFontGlyphPairs( + GlyphAtlas::Type type, + const TextRenderContext::FrameIterator& frame_iterator) { + TRACE_EVENT0("impeller", __FUNCTION__); + FontGlyphPair::Set set; + while (const TextFrame* frame = frame_iterator()) { + for (const TextRun& run : frame->GetRuns()) { + const Font& font = run.GetFont(); + // TODO(dnfield): If we're doing SDF here, we should be using a consistent + // point size. + // https://github.com/flutter/flutter/issues/112016 + for (const TextRun::GlyphPosition& glyph_position : + run.GetGlyphPositions()) { + set.insert({font, glyph_position.glyph}); + } + } + } + return set; +} + +// 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, + std::unique_ptr& rect_packer) { + if (atlas_size.IsEmpty()) { + return false; + } + + glyph_positions.clear(); + glyph_positions.reserve(pairs.size()); + + size_t i = 0; + std::vector rect_packer_glyph_rects; + for (auto it = pairs.begin(); it != pairs.end(); ++i, ++it) { + const auto& pair = *it; + + const impeller::Font& font = pair.font; + const impeller::Glyph& glyph = pair.glyph; + const impeller::Font::Metrics& metrics = font.GetMetrics(); + auto typeface = font.GetTypeface(); + // We downcast to the correct typeface type to access `stb` specific methods. + // NOTE: We use `static_pointer_cast` rather than `dynamic_cast` to obviate the + // need for RTTI. + 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 * POINTS_TO_PIXELS * FONT_RENDER_SCALING; + + 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(), glyph.index, scale_x, scale_y, &x0, &y0, &x1, &y1); + auto width = x1 - x0; + auto height = y1 - y0; + + // DEBUG + //printf("**> font point size: %f scale: %f desired pixel height: %f \n", pair.font.GetMetrics().point_size, pair.font.GetMetrics().scale, text_size_pixels); + //printf("**> glyph index: %u width: %d height: %d\n", pair.glyph.index, width, height); + + rect_packer_glyph_rects.push_back(stbrp_rect { + .id = 0, // TODO: We might need to pack some id to trace back to the font/glyph pair. + .w = width, + .h = height, + .x = 0, // rect pack will fill this out + .y = 0, // rect pack will fill this out + .was_packed = 0, // rect pack will fill this out + }); + } + + size_t number_packed = 0; + rect_packer->PackRects(rect_packer_glyph_rects); + for(auto& packed_rect: rect_packer_glyph_rects) { + if(packed_rect.was_packed) { + glyph_positions.emplace_back( + Rect::MakeXYWH( + packed_rect.x + kPadding, + packed_rect.y + kPadding, + packed_rect.w - 2 * kPadding, + packed_rect.h - 2 * kPadding + ) + ); + number_packed++; + } + } + // return the number NOT PACKED. + return pairs.size() - number_packed; +} + +static bool CanAppendToExistingAtlas( + const std::shared_ptr& atlas, + const FontGlyphPairRefVector& extra_pairs, + std::vector& glyph_positions, + ISize atlas_size, + std::unique_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()); + std::vector rect_packer_glyph_rects; + for (size_t i = 0; i < extra_pairs.size(); i++) { + const FontGlyphPair& pair = extra_pairs[i]; + + const impeller::Font& font = pair.font; + const impeller::Glyph& glyph = pair.glyph; + const impeller::Font::Metrics& metrics = font.GetMetrics(); + auto typeface = font.GetTypeface(); + // We downcast to the correct typeface type to access `stb` specific methods + std::shared_ptr typeface_stb = std::dynamic_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 * POINTS_TO_PIXELS * FONT_RENDER_SCALING; + + 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(), glyph.index, scale_x, scale_y, &x0, &y0, &x1, &y1); + auto width = x1 - x0; + auto height = y1 - y0; + + // DEBUG: + // printf("--> font point size: %f scale: %f desired pixel height: %f \n", pair.font.GetMetrics().point_size, pair.font.GetMetrics().scale, text_size_pixels); + // printf("--> glyph index: %u width: %d height: %d\n", glyph.index, width, height); + + + rect_packer_glyph_rects.push_back(stbrp_rect { + .id = 0, + .w = width, + .h = height, + .x = 0, // rect pack will fill this out + .y = 0, // rect pack will fill this out + .was_packed = 0, // rect pack will fill this out + }); + } + + rect_packer->PackRects(rect_packer_glyph_rects); + for(const auto& packed_rect: rect_packer_glyph_rects) { + if(packed_rect.was_packed) { + glyph_positions.emplace_back( + Rect::MakeXYWH( + packed_rect.x + kPadding, + packed_rect.y + kPadding, + packed_rect.w - 2 * kPadding, + packed_rect.h - 2 * kPadding + ) + ); + } else { + return false; + } + } + + return true; +} + +namespace { +ISize OptimumAtlasSizeForFontGlyphPairs( + const FontGlyphPair::Set& pairs, + std::vector& glyph_positions, + const std::shared_ptr& atlas_context) { + static constexpr auto kMinAtlasSize = MIN_GLYPH_ATLAS_SIZE; + static constexpr auto kMaxAtlasSize = MAX_GLYPH_ATLAS_SIZE; + + TRACE_EVENT0("impeller", __FUNCTION__); + + ISize current_size(kMinAtlasSize, kMinAtlasSize); + size_t total_pairs = pairs.size() + 1; + do { + + auto rect_packer = std::make_unique(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); + s_rect_packer.swap(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}; +} +} // namespace + +/// Compute signed-distance field for an 8-bpp grayscale image (values greater +/// than 127 are considered "on") For details of this algorithm, see "The 'dead +/// reckoning' signed distance transform" [Grevera 2004] +static void ConvertBitmapToSignedDistanceField(uint8_t* pixels, + uint16_t width, + uint16_t height) { + if (!pixels || width == 0 || height == 0) { + return; + } + + using ShortPoint = TPoint; + + // distance to nearest boundary point map + std::vector distance_map(width * height); + // nearest boundary point map + std::vector boundary_point_map(width * height); + + // Some helpers for manipulating the above arrays +#define image(_x, _y) (pixels[(_y)*width + (_x)] > 0x7f) +#define distance(_x, _y) distance_map[(_y)*width + (_x)] +#define nearestpt(_x, _y) boundary_point_map[(_y)*width + (_x)] + + const Scalar maxDist = hypot(width, height); + const Scalar distUnit = 1; + const Scalar distDiag = sqrt(2); + + // Initialization phase: set all distances to "infinity"; zero out nearest + // boundary point map + for (uint16_t y = 0; y < height; ++y) { + for (uint16_t x = 0; x < width; ++x) { + distance(x, y) = maxDist; + nearestpt(x, y) = ShortPoint{0, 0}; + } + } + + // Immediate interior/exterior phase: mark all points along the boundary as + // such + for (uint16_t y = 1; y < height - 1; ++y) { + for (uint16_t x = 1; x < width - 1; ++x) { + bool inside = image(x, y); + if (image(x - 1, y) != inside || image(x + 1, y) != inside || + image(x, y - 1) != inside || image(x, y + 1) != inside) { + distance(x, y) = 0; + nearestpt(x, y) = ShortPoint{x, y}; + } + } + } + + // Forward dead-reckoning pass + for (uint16_t y = 1; y < height - 2; ++y) { + for (uint16_t x = 1; x < width - 2; ++x) { + if (distance_map[(y - 1) * width + (x - 1)] + distDiag < distance(x, y)) { + nearestpt(x, y) = nearestpt(x - 1, y - 1); + distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); + } + if (distance(x, y - 1) + distUnit < distance(x, y)) { + nearestpt(x, y) = nearestpt(x, y - 1); + distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); + } + if (distance(x + 1, y - 1) + distDiag < distance(x, y)) { + nearestpt(x, y) = nearestpt(x + 1, y - 1); + distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); + } + if (distance(x - 1, y) + distUnit < distance(x, y)) { + nearestpt(x, y) = nearestpt(x - 1, y); + distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); + } + } + } + + // Backward dead-reckoning pass + for (uint16_t y = height - 2; y >= 1; --y) { + for (uint16_t x = width - 2; x >= 1; --x) { + if (distance(x + 1, y) + distUnit < distance(x, y)) { + nearestpt(x, y) = nearestpt(x + 1, y); + distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); + } + if (distance(x - 1, y + 1) + distDiag < distance(x, y)) { + nearestpt(x, y) = nearestpt(x - 1, y + 1); + distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); + } + if (distance(x, y + 1) + distUnit < distance(x, y)) { + nearestpt(x, y) = nearestpt(x, y + 1); + distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); + } + if (distance(x + 1, y + 1) + distDiag < distance(x, y)) { + nearestpt(x, y) = nearestpt(x + 1, y + 1); + distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); + } + } + } + + // Interior distance negation pass; distances outside the figure are + // considered negative + // Also does final quantization. + for (uint16_t y = 0; y < height; ++y) { + for (uint16_t x = 0; x < width; ++x) { + if (!image(x, y)) { + distance(x, y) = -distance(x, y); + } + + float norm_factor = 13.5; + float dist = distance(x, y); + float clamped_dist = fmax(-norm_factor, fmin(dist, norm_factor)); + float scaled_dist = clamped_dist / norm_factor; + uint8_t quantized_value = ((scaled_dist + 1) / 2) * UINT8_MAX; + pixels[y * width + x] = quantized_value; + } + } + +#undef image +#undef distance +#undef nearestpt +} + +//static void DrawGlyph(SkCanvas* canvas, +static void DrawGlyph(STBBitmap* 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::dynamic_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 * POINTS_TO_PIXELS * FONT_RENDER_SCALING; + float scale_y = stbtt_ScaleForPixelHeight(typeface_stb->GetFontInfo(), text_size_pixels); + float scale_x = scale_y; + + auto output = bitmap->getAddr(location.origin.x - kPadding, location.origin.y - kPadding); + // 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 + 2 * kPadding, location.size.height + 2 * kPadding, bitmap->stride(), 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. + // TODO: 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->stride()); + } + 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 = COLOR_FONT_BPP; + } + 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->getAddr(0, 0)), // 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->rowBytes() * 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->getAddr(0, 0)), // 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 TextRenderContextSTB::CreateGlyphAtlas( + GlyphAtlas::Type type, + std::shared_ptr atlas_context, + FrameIterator frame_iterator) const { + TRACE_EVENT0("impeller", __FUNCTION__); + if (!IsValid()) { + return nullptr; + } + std::shared_ptr last_atlas = atlas_context->GetGlyphAtlas(); + + // --------------------------------------------------------------------------- + // Step 1: Collect unique font-glyph pairs in the frame. + // --------------------------------------------------------------------------- + + FontGlyphPair::Set font_glyph_pairs = + CollectUniqueFontGlyphPairs(type, frame_iterator); + if (font_glyph_pairs.empty()) { + return last_atlas; + } + + // --------------------------------------------------------------------------- + // Step 2: 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 3: 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(), + s_rect_packer)) { + // The old bitmap will be reused and only the additional glyphs will be + // added. + + // --------------------------------------------------------------------------- + // Step 4: 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 5: Draw new font-glyph pairs into the existing bitmap. + // --------------------------------------------------------------------------- + //auto bitmap = atlas_context->GetBitmap(); + auto bitmap = get_atlas_bitmap(type); + if (!UpdateAtlasBitmap(*last_atlas, bitmap, new_glyphs)) { + return nullptr; + } + + // --------------------------------------------------------------------------- + // Step 6: 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 4: 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); + + atlas_context->UpdateGlyphAtlas(glyph_atlas, atlas_size); + if (atlas_size.IsEmpty()) { + return nullptr; + } + + // --------------------------------------------------------------------------- + // Step 5: 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 6: 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 7: Draw font-glyph pairs in the correct spot in the atlas. + // --------------------------------------------------------------------------- + auto bitmap = CreateAtlasBitmap(*glyph_atlas, atlas_size); + if (!bitmap) { + return nullptr; + } + + update_atlas_bitmap(bitmap, type); + + // --------------------------------------------------------------------------- + // Step 8: Upload the atlas as a texture. + // --------------------------------------------------------------------------- + PixelFormat format; + switch (type) { + case GlyphAtlas::Type::kSignedDistanceField: + ConvertBitmapToSignedDistanceField( + reinterpret_cast(bitmap->getPixels()), atlas_size.width, + atlas_size.height); + 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(GetContext()->GetResourceAllocator(), + bitmap, atlas_size, format); + if (!texture) { + return nullptr; + } + + // --------------------------------------------------------------------------- + // Step 9: 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/text_render_context_stb.h b/impeller/typographer/backends/stb/text_render_context_stb.h new file mode 100644 index 0000000000000..9d9ab6f1e6b12 --- /dev/null +++ b/impeller/typographer/backends/stb/text_render_context_stb.h @@ -0,0 +1,29 @@ +// 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/text_render_context.h" + +#include "flutter/fml/macros.h" + +namespace impeller { + +class TextRenderContextSTB : public TextRenderContext { + public: + TextRenderContextSTB(std::shared_ptr context); + + ~TextRenderContextSTB() override; + + // |TextRenderContext| + std::shared_ptr CreateGlyphAtlas( + GlyphAtlas::Type type, + std::shared_ptr atlas_context, + FrameIterator iterator) const override; + + private: + FML_DISALLOW_COPY_AND_ASSIGN(TextRenderContextSTB); +}; + +} // 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..9ba8a3115821a --- /dev/null +++ b/impeller/typographer/backends/stb/typeface_stb.cc @@ -0,0 +1,57 @@ +// 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 // memcpy +#include "flutter/fml/logging.h" + +namespace impeller { + +TypefaceSTB::~TypefaceSTB() = default; + +// Instantiate a typeface based on a .ttf or other font file +TypefaceSTB::TypefaceSTB(const unsigned char* ttf_buffer, size_t buffer_size) + : _font_file(std::make_unique(buffer_size)), + _font_info(std::make_unique()), + is_valid(false) { + // As we lazily create atlases based on this font, we have to store the binary + // font file itself This seems memory intensive, so maybe we could improve + // this in time (extract needed info now e.g.). + memcpy((void*)_font_file.get(), (void*)ttf_buffer, buffer_size); + + // We need an "offset" into the ttf file + auto offset = stbtt_GetFontOffsetForIndex(ttf_buffer, 0); + if (stbtt_InitFont(_font_info.get(), ttf_buffer, offset) == 0) { + FML_LOG(ERROR) << "Failed to initialize stb font from binary data."; + } else { + is_valid = true; + } +} + +bool TypefaceSTB::IsValid() const { + return is_valid; +} + +std::size_t TypefaceSTB::GetHash() const { + if (!IsValid()) { + return 0u; + } + return reinterpret_cast(_font_file.get()); +} + +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 _font_file.get(); +} + +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..510642c032b88 --- /dev/null +++ b/impeller/typographer/backends/stb/typeface_stb.h @@ -0,0 +1,43 @@ +// 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/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: + TypefaceSTB() = delete; + + TypefaceSTB(const unsigned char * ttf_buffer, size_t buffer_size); + + ~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 _font_file; + std::unique_ptr _font_info; + bool is_valid; + + FML_DISALLOW_COPY_AND_ASSIGN(TypefaceSTB); +}; + +} // namespace impeller From bb24c8df39f67bd643151229ee26fcdba4507080 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Sun, 20 Aug 2023 21:41:33 -0700 Subject: [PATCH 02/12] Engine-fy, upgrade to head, add TextFrame shaper factory, and add Aiks test --- impeller/aiks/aiks_unittests.cc | 111 ++-- impeller/display_list/dl_dispatcher.cc | 2 +- impeller/entity/entity_unittests.cc | 2 +- .../backends/skia/text_frame_skia.cc | 2 +- .../backends/skia/text_frame_skia.h | 2 +- impeller/typographer/backends/stb/BUILD.gn | 2 + .../backends/stb/text_frame_stb.cc | 61 ++ .../typographer/backends/stb/text_frame_stb.h | 17 + .../backends/stb/text_render_context_stb.cc | 566 ++++++------------ .../backends/stb/text_render_context_stb.h | 8 +- .../typographer/backends/stb/typeface_stb.cc | 31 +- .../typographer/backends/stb/typeface_stb.h | 15 +- impeller/typographer/typographer_unittests.cc | 53 +- 13 files changed, 401 insertions(+), 471 deletions(-) create mode 100644 impeller/typographer/backends/stb/text_frame_stb.cc create mode 100644 impeller/typographer/backends/stb/text_frame_stb.h diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 557e122b62f24..f2fb1d3f7430a 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -37,6 +37,9 @@ #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/stb/text_frame_stb.h" +#include "impeller/typographer/backends/stb/text_render_context_stb.h" +#include "impeller/typographer/backends/stb/typeface_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,12 +1317,22 @@ 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")); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture(), + TextRenderContextSTB::Make())); +} + TEST_P(AiksTest, TextFrameSubpixelAlignment) { std::array phase_offsets; for (Scalar& offset : phase_offsets) { @@ -1320,11 +1362,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 +1381,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 +1391,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 +1405,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 +1425,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 +1466,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 +1484,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 +3054,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 +3076,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 +3096,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 +3224,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 +3243,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/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/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 90edc60222883..bdb491a431189 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -2174,7 +2174,7 @@ 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()); lazy_glyph_atlas->AddTextFrame(frame, 1.0f); 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/stb/BUILD.gn b/impeller/typographer/backends/stb/BUILD.gn index b407266aa339f..ba4b599d10f2d 100644 --- a/impeller/typographer/backends/stb/BUILD.gn +++ b/impeller/typographer/backends/stb/BUILD.gn @@ -8,6 +8,8 @@ impeller_component("typographer_stb_backend") { testonly = true sources = [ + "text_frame_stb.cc", + "text_frame_stb.h", "text_render_context_stb.cc", "text_render_context_stb.h", "typeface_stb.cc", 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/text_render_context_stb.cc b/impeller/typographer/backends/stb/text_render_context_stb.cc index d6185de73789f..9e615ce591875 100644 --- a/impeller/typographer/backends/stb/text_render_context_stb.cc +++ b/impeller/typographer/backends/stb/text_render_context_stb.cc @@ -16,7 +16,7 @@ // These values can be customize per build. // Glyph atlases are always square. #ifndef MAX_GLYPH_ATLAS_SIZE -#define MAX_GLYPH_ATLAS_SIZE 2048u +#define MAX_GLYPH_ATLAS_SIZE 4096u #endif #ifndef MIN_GLYPH_ATLAS_SIZE #define MIN_GLYPH_ATLAS_SIZE 8u @@ -29,167 +29,101 @@ #define COLOR_FONT_BPP 4 #endif -// "Typical" conversion from font Points to Pixels. -// This assumes a constant pixels per em. -constexpr float POINTS_TO_PIXELS = 96.0/72.0; -// An available font scaling to improve rendering in the atlas if desired. -constexpr float FONT_RENDER_SCALING = 1.0; - -// An stb rect packer instead of Skia based rect packer -struct STBRectPacker { - // Standard rect pack context which can be used over N rect pack calls - std::unique_ptr context; - // Workspace which also must remain valid over N rect pack calls. - // In the ideal the `nodes` array should be >= the width of the target rect. - std::unique_ptr nodes; - - ~STBRectPacker() = default; - - STBRectPacker() = delete; - - STBRectPacker(int width, int height) - :context(std::make_unique()) - ,nodes(std::make_unique(width)) - { - stbrp_init_target(context.get(),width,height,nodes.get(),width); - } - - int PackRects(std::vector& rects) { - return stbrp_pack_rects(context.get(), rects.data(), (int)rects.size()); - } -}; - -// Analogous to the rect packer stored on the atlas context. But this uses STB. -static auto s_rect_packer = std::make_unique(MIN_GLYPH_ATLAS_SIZE, MIN_GLYPH_ATLAS_SIZE); +namespace impeller { // An simple bitmap in lieu of a skia bitmap. -struct STBBitmap { - size_t width; - size_t height; - size_t bytes_per_pixel; - std::unique_ptr pixels; - +class STBBitmap { + public: ~STBBitmap() = default; STBBitmap() = delete; STBBitmap(size_t width, size_t height, size_t bytes_per_pixel) - :width(width) - ,height(height) - ,bytes_per_pixel(bytes_per_pixel) - ,pixels(std::make_unique(width*height*bytes_per_pixel)) {} - - uint8_t* const getPixels() const { return pixels.get() ; } - - uint8_t* getAddr(size_t x, size_t y) const { - if(x >= width) return nullptr; - if(y >= height) return nullptr; - if(x < 0) x = 0; - if(y < 0) y = 0; - auto p = pixels.get(); - return &p[(x + width * y) * bytes_per_pixel]; + : width_(width), + height_(height), + bytes_per_pixel_(bytes_per_pixel), + pixels_(std::make_unique(width * height * bytes_per_pixel)) { } - size_t rowBytes() const { return width * bytes_per_pixel; } + uint8_t* GetPixels() const { return pixels_.get(); } - size_t stride() const { return rowBytes(); } + uint8_t* GetPixelAddress(TPoint coords) const { + FML_DCHECK(coords.x < width_); + FML_DCHECK(coords.x < height_); - size_t getWidth() const { return width; } + return &pixels_.get()[(coords.x + width_ * coords.y) * bytes_per_pixel_]; + } + + size_t GetRowBytes() const { return width_ * bytes_per_pixel_; } + + size_t GetWidth() const { return width_; } - size_t getHeight() const { return height; } + size_t GetHeight() const { return height_; } - size_t getSize() const { return width * height * bytes_per_pixel ; } + size_t GetSize() const { return width_ * height_ * bytes_per_pixel_; } + + private: + size_t width_; + size_t height_; + size_t bytes_per_pixel_; + std::unique_ptr pixels_; }; // Analogous to the bitmaps (one for each type) stored in each Atlas context. -static auto alpha_bitmap = std::make_shared(MIN_GLYPH_ATLAS_SIZE, MIN_GLYPH_ATLAS_SIZE, 1); -static auto color_bitmap = std::make_shared(MIN_GLYPH_ATLAS_SIZE, MIN_GLYPH_ATLAS_SIZE, COLOR_FONT_BPP); -static auto signed_distance_bitmap = std::make_shared(MIN_GLYPH_ATLAS_SIZE, MIN_GLYPH_ATLAS_SIZE, 1); - -static std::shared_ptr get_atlas_bitmap(impeller::GlyphAtlas::Type type) { - switch(type) { - case impeller::GlyphAtlas::Type::kSignedDistanceField: - { - return signed_distance_bitmap; - break; - } - case impeller::GlyphAtlas::Type::kAlphaBitmap: - { +static auto alpha_bitmap = + std::make_shared(MIN_GLYPH_ATLAS_SIZE, MIN_GLYPH_ATLAS_SIZE, 1); +static auto color_bitmap = std::make_shared(MIN_GLYPH_ATLAS_SIZE, + MIN_GLYPH_ATLAS_SIZE, + COLOR_FONT_BPP); + +static std::shared_ptr get_atlas_bitmap( + impeller::GlyphAtlas::Type type) { + switch (type) { + case impeller::GlyphAtlas::Type::kAlphaBitmap: { return alpha_bitmap; break; } - case impeller::GlyphAtlas::Type::kColorBitmap: - { - return color_bitmap ; + case impeller::GlyphAtlas::Type::kColorBitmap: { + return color_bitmap; break; } } } -static void update_atlas_bitmap(std::shared_ptr& bitmap, impeller::GlyphAtlas::Type type) { - switch(type) { - case impeller::GlyphAtlas::Type::kSignedDistanceField: - { - signed_distance_bitmap = bitmap; - break; - } - case impeller::GlyphAtlas::Type::kAlphaBitmap: - { +static void update_atlas_bitmap(std::shared_ptr& bitmap, + impeller::GlyphAtlas::Type type) { + switch (type) { + case impeller::GlyphAtlas::Type::kAlphaBitmap: { alpha_bitmap = bitmap; break; } - case impeller::GlyphAtlas::Type::kColorBitmap: - { + case impeller::GlyphAtlas::Type::kColorBitmap: { color_bitmap = bitmap; break; } } } -namespace impeller { - using FontGlyphPairRefVector = std::vector>; -std::unique_ptr TextRenderContext::Create( - std::shared_ptr context) { - // There is only one backend today. - return std::make_unique(std::move(context)); -} +constexpr size_t kPadding = 1; -constexpr auto kPadding = 1; +std::unique_ptr TextRenderContextSTB::Make() { + return std::make_unique(); +} -TextRenderContextSTB::TextRenderContextSTB(std::shared_ptr context) - : TextRenderContext(std::move(context)) {} +TextRenderContextSTB::TextRenderContextSTB() : TextRenderContext() {} TextRenderContextSTB::~TextRenderContextSTB() = default; -static FontGlyphPair::Set CollectUniqueFontGlyphPairs( - GlyphAtlas::Type type, - const TextRenderContext::FrameIterator& frame_iterator) { - TRACE_EVENT0("impeller", __FUNCTION__); - FontGlyphPair::Set set; - while (const TextFrame* frame = frame_iterator()) { - for (const TextRun& run : frame->GetRuns()) { - const Font& font = run.GetFont(); - // TODO(dnfield): If we're doing SDF here, we should be using a consistent - // point size. - // https://github.com/flutter/flutter/issues/112016 - for (const TextRun::GlyphPosition& glyph_position : - run.GetGlyphPositions()) { - set.insert({font, glyph_position.glyph}); - } - } - } - return set; -} - -// Function returns the count of "remaining pairs" not packed into rect of given size. +// 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, - std::unique_ptr& rect_packer) { + const std::shared_ptr& rect_packer) { if (atlas_size.IsEmpty()) { return false; } @@ -198,61 +132,46 @@ static size_t PairsFitInAtlasOfSize( glyph_positions.reserve(pairs.size()); size_t i = 0; - std::vector rect_packer_glyph_rects; for (auto it = pairs.begin(); it != pairs.end(); ++i, ++it) { const auto& pair = *it; - const impeller::Font& font = pair.font; - const impeller::Glyph& glyph = pair.glyph; - const impeller::Font::Metrics& metrics = font.GetMetrics(); - auto typeface = font.GetTypeface(); - // We downcast to the correct typeface type to access `stb` specific methods. - // NOTE: We use `static_pointer_cast` rather than `dynamic_cast` to obviate the - // need for RTTI. - std::shared_ptr typeface_stb = std::reinterpret_pointer_cast(typeface); + // 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 = metrics.point_size * POINTS_TO_PIXELS * FONT_RENDER_SCALING; - - 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(), glyph.index, scale_x, scale_y, &x0, &y0, &x1, &y1); - auto width = x1 - x0; - auto height = y1 - y0; - - // DEBUG - //printf("**> font point size: %f scale: %f desired pixel height: %f \n", pair.font.GetMetrics().point_size, pair.font.GetMetrics().scale, text_size_pixels); - //printf("**> glyph index: %u width: %d height: %d\n", pair.glyph.index, width, height); - - rect_packer_glyph_rects.push_back(stbrp_rect { - .id = 0, // TODO: We might need to pack some id to trace back to the font/glyph pair. - .w = width, - .h = height, - .x = 0, // rect pack will fill this out - .y = 0, // rect pack will fill this out - .was_packed = 0, // rect pack will fill this out - }); - } + float text_size_pixels = + pair.font.GetMetrics().point_size * TypefaceSTB::kPointsToPixels; - size_t number_packed = 0; - rect_packer->PackRects(rect_packer_glyph_rects); - for(auto& packed_rect: rect_packer_glyph_rects) { - if(packed_rect.was_packed) { - glyph_positions.emplace_back( - Rect::MakeXYWH( - packed_rect.x + kPadding, - packed_rect.y + kPadding, - packed_rect.w - 2 * kPadding, - packed_rect.h - 2 * kPadding - ) - ); - number_packed++; + 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 the number NOT PACKED. - return pairs.size() - number_packed; + + return 0; } static bool CanAppendToExistingAtlas( @@ -260,7 +179,7 @@ static bool CanAppendToExistingAtlas( const FontGlyphPairRefVector& extra_pairs, std::vector& glyph_positions, ISize atlas_size, - std::unique_ptr& rect_packer) { + const std::shared_ptr& rect_packer) { TRACE_EVENT0("impeller", __FUNCTION__); if (!rect_packer || atlas_size.IsEmpty()) { return false; @@ -271,57 +190,43 @@ static bool CanAppendToExistingAtlas( // from extra_pairs. FML_DCHECK(glyph_positions.size() == 0); glyph_positions.reserve(extra_pairs.size()); - std::vector rect_packer_glyph_rects; for (size_t i = 0; i < extra_pairs.size(); i++) { const FontGlyphPair& pair = extra_pairs[i]; - const impeller::Font& font = pair.font; - const impeller::Glyph& glyph = pair.glyph; - const impeller::Font::Metrics& metrics = font.GetMetrics(); - auto typeface = font.GetTypeface(); // We downcast to the correct typeface type to access `stb` specific methods - std::shared_ptr typeface_stb = std::dynamic_pointer_cast(typeface); + 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 = metrics.point_size * POINTS_TO_PIXELS * FONT_RENDER_SCALING; - - 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(), glyph.index, scale_x, scale_y, &x0, &y0, &x1, &y1); - auto width = x1 - x0; - auto height = y1 - y0; - - // DEBUG: - // printf("--> font point size: %f scale: %f desired pixel height: %f \n", pair.font.GetMetrics().point_size, pair.font.GetMetrics().scale, text_size_pixels); - // printf("--> glyph index: %u width: %d height: %d\n", glyph.index, width, height); - - - rect_packer_glyph_rects.push_back(stbrp_rect { - .id = 0, - .w = width, - .h = height, - .x = 0, // rect pack will fill this out - .y = 0, // rect pack will fill this out - .was_packed = 0, // rect pack will fill this out - }); - } + float text_size_pixels = + pair.font.GetMetrics().point_size * TypefaceSTB::kPointsToPixels; - rect_packer->PackRects(rect_packer_glyph_rects); - for(const auto& packed_rect: rect_packer_glyph_rects) { - if(packed_rect.was_packed) { - glyph_positions.emplace_back( - Rect::MakeXYWH( - packed_rect.x + kPadding, - packed_rect.y + kPadding, - packed_rect.w - 2 * kPadding, - packed_rect.h - 2 * kPadding - ) - ); - } else { + 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; @@ -340,15 +245,13 @@ ISize OptimumAtlasSizeForFontGlyphPairs( ISize current_size(kMinAtlasSize, kMinAtlasSize); size_t total_pairs = pairs.size() + 1; do { - - auto rect_packer = std::make_unique(current_size.width, current_size.height); + 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); - s_rect_packer.swap(rect_packer); - + atlas_context->UpdateRectPacker(rect_packer); return current_size; } else if (remaining_pairs < std::ceil(total_pairs / 2)) { current_size = ISize::MakeWH( @@ -366,122 +269,6 @@ ISize OptimumAtlasSizeForFontGlyphPairs( } } // namespace -/// Compute signed-distance field for an 8-bpp grayscale image (values greater -/// than 127 are considered "on") For details of this algorithm, see "The 'dead -/// reckoning' signed distance transform" [Grevera 2004] -static void ConvertBitmapToSignedDistanceField(uint8_t* pixels, - uint16_t width, - uint16_t height) { - if (!pixels || width == 0 || height == 0) { - return; - } - - using ShortPoint = TPoint; - - // distance to nearest boundary point map - std::vector distance_map(width * height); - // nearest boundary point map - std::vector boundary_point_map(width * height); - - // Some helpers for manipulating the above arrays -#define image(_x, _y) (pixels[(_y)*width + (_x)] > 0x7f) -#define distance(_x, _y) distance_map[(_y)*width + (_x)] -#define nearestpt(_x, _y) boundary_point_map[(_y)*width + (_x)] - - const Scalar maxDist = hypot(width, height); - const Scalar distUnit = 1; - const Scalar distDiag = sqrt(2); - - // Initialization phase: set all distances to "infinity"; zero out nearest - // boundary point map - for (uint16_t y = 0; y < height; ++y) { - for (uint16_t x = 0; x < width; ++x) { - distance(x, y) = maxDist; - nearestpt(x, y) = ShortPoint{0, 0}; - } - } - - // Immediate interior/exterior phase: mark all points along the boundary as - // such - for (uint16_t y = 1; y < height - 1; ++y) { - for (uint16_t x = 1; x < width - 1; ++x) { - bool inside = image(x, y); - if (image(x - 1, y) != inside || image(x + 1, y) != inside || - image(x, y - 1) != inside || image(x, y + 1) != inside) { - distance(x, y) = 0; - nearestpt(x, y) = ShortPoint{x, y}; - } - } - } - - // Forward dead-reckoning pass - for (uint16_t y = 1; y < height - 2; ++y) { - for (uint16_t x = 1; x < width - 2; ++x) { - if (distance_map[(y - 1) * width + (x - 1)] + distDiag < distance(x, y)) { - nearestpt(x, y) = nearestpt(x - 1, y - 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x, y - 1) + distUnit < distance(x, y)) { - nearestpt(x, y) = nearestpt(x, y - 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x + 1, y - 1) + distDiag < distance(x, y)) { - nearestpt(x, y) = nearestpt(x + 1, y - 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x - 1, y) + distUnit < distance(x, y)) { - nearestpt(x, y) = nearestpt(x - 1, y); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - } - } - - // Backward dead-reckoning pass - for (uint16_t y = height - 2; y >= 1; --y) { - for (uint16_t x = width - 2; x >= 1; --x) { - if (distance(x + 1, y) + distUnit < distance(x, y)) { - nearestpt(x, y) = nearestpt(x + 1, y); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x - 1, y + 1) + distDiag < distance(x, y)) { - nearestpt(x, y) = nearestpt(x - 1, y + 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x, y + 1) + distUnit < distance(x, y)) { - nearestpt(x, y) = nearestpt(x, y + 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - if (distance(x + 1, y + 1) + distDiag < distance(x, y)) { - nearestpt(x, y) = nearestpt(x + 1, y + 1); - distance(x, y) = hypot(x - nearestpt(x, y).x, y - nearestpt(x, y).y); - } - } - } - - // Interior distance negation pass; distances outside the figure are - // considered negative - // Also does final quantization. - for (uint16_t y = 0; y < height; ++y) { - for (uint16_t x = 0; x < width; ++x) { - if (!image(x, y)) { - distance(x, y) = -distance(x, y); - } - - float norm_factor = 13.5; - float dist = distance(x, y); - float clamped_dist = fmax(-norm_factor, fmin(dist, norm_factor)); - float scaled_dist = clamped_dist / norm_factor; - uint8_t quantized_value = ((scaled_dist + 1) / 2) * UINT8_MAX; - pixels[y * width + x] = quantized_value; - } - } - -#undef image -#undef distance -#undef nearestpt -} - -//static void DrawGlyph(SkCanvas* canvas, static void DrawGlyph(STBBitmap* bitmap, const FontGlyphPair& font_glyph, const Rect& location, @@ -492,33 +279,48 @@ static void DrawGlyph(STBBitmap* bitmap, 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::dynamic_pointer_cast(typeface); + 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 * POINTS_TO_PIXELS * FONT_RENDER_SCALING; - float scale_y = stbtt_ScaleForPixelHeight(typeface_stb->GetFontInfo(), text_size_pixels); + 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->getAddr(location.origin.x - kPadding, location.origin.y - kPadding); - // 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 + 2 * kPadding, location.size.height + 2 * kPadding, bitmap->stride(), scale_x, scale_y, glyph.index); + 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. + // 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); + 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. - // TODO: 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. + 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. + // TODO: 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; @@ -536,7 +338,7 @@ static void DrawGlyph(STBBitmap* bitmap, write_pos++; } // next row - write_pos = output + ( y * bitmap->stride()); + write_pos = output + (y * bitmap->GetRowBytes()); } stbtt_FreeBitmap(glyph_pixels, nullptr); } @@ -561,19 +363,21 @@ static bool UpdateAtlasBitmap(const GlyphAtlas& atlas, } static std::shared_ptr CreateAtlasBitmap(const GlyphAtlas& atlas, - const ISize& atlas_size) { + const ISize& atlas_size) { TRACE_EVENT0("impeller", __FUNCTION__); size_t bytes_per_pixel = 1; - if(atlas.GetType() == GlyphAtlas::Type::kColorBitmap && !DISABLE_COLOR_FONT_SUPPORT) { + if (atlas.GetType() == GlyphAtlas::Type::kColorBitmap && + !DISABLE_COLOR_FONT_SUPPORT) { bytes_per_pixel = COLOR_FONT_BPP; } - auto bitmap = std::make_shared(atlas_size.width, atlas_size.height, bytes_per_pixel); + 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 { + const Rect& location) -> bool { DrawGlyph(bitmap.get(), font_glyph, location, has_color); return true; }); @@ -581,7 +385,7 @@ static std::shared_ptr CreateAtlasBitmap(const GlyphAtlas& atlas, return bitmap; } -//static bool UpdateGlyphTextureAtlas(std::shared_ptr bitmap, +// static bool UpdateGlyphTextureAtlas(std::shared_ptr bitmap, static bool UpdateGlyphTextureAtlas(std::shared_ptr& bitmap, const std::shared_ptr& texture) { TRACE_EVENT0("impeller", __FUNCTION__); @@ -591,9 +395,10 @@ static bool UpdateGlyphTextureAtlas(std::shared_ptr& bitmap, auto texture_descriptor = texture->GetTextureDescriptor(); auto mapping = std::make_shared( - reinterpret_cast(bitmap->getAddr(0, 0)), // data - texture_descriptor.GetByteSizeOfBaseMipLevel() // size - // As the bitmap is static in this module I believe we don't need to specify a release proc. + 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); @@ -616,7 +421,7 @@ static std::shared_ptr UploadGlyphTextureAtlas( texture_descriptor.format = format; texture_descriptor.size = atlas_size; - if (bitmap->rowBytes() * bitmap->getHeight() != + if (bitmap->GetRowBytes() * bitmap->GetHeight() != texture_descriptor.GetByteSizeOfBaseMipLevel()) { return nullptr; } @@ -628,9 +433,10 @@ static std::shared_ptr UploadGlyphTextureAtlas( texture->SetLabel("GlyphAtlas"); auto mapping = std::make_shared( - reinterpret_cast(bitmap->getAddr(0, 0)), // data - texture_descriptor.GetByteSizeOfBaseMipLevel() // size - // As the bitmap is static in this module I believe we don't need to specify a release proc. + 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)) { @@ -640,27 +446,22 @@ static std::shared_ptr UploadGlyphTextureAtlas( } std::shared_ptr TextRenderContextSTB::CreateGlyphAtlas( + Context& context, GlyphAtlas::Type type, std::shared_ptr atlas_context, - FrameIterator frame_iterator) const { + const FontGlyphPair::Set& font_glyph_pairs) const { TRACE_EVENT0("impeller", __FUNCTION__); if (!IsValid()) { return nullptr; } std::shared_ptr last_atlas = atlas_context->GetGlyphAtlas(); - // --------------------------------------------------------------------------- - // Step 1: Collect unique font-glyph pairs in the frame. - // --------------------------------------------------------------------------- - - FontGlyphPair::Set font_glyph_pairs = - CollectUniqueFontGlyphPairs(type, frame_iterator); if (font_glyph_pairs.empty()) { return last_atlas; } // --------------------------------------------------------------------------- - // Step 2: Determine if the atlas type and font glyph pairs are compatible + // Step 1: Determine if the atlas type and font glyph pairs are compatible // with the current atlas and reuse if possible. // --------------------------------------------------------------------------- FontGlyphPairRefVector new_glyphs; @@ -674,7 +475,7 @@ std::shared_ptr TextRenderContextSTB::CreateGlyphAtlas( } // --------------------------------------------------------------------------- - // Step 3: Determine if the additional missing glyphs can be appended to the + // 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. // --------------------------------------------------------------------------- @@ -682,12 +483,12 @@ std::shared_ptr TextRenderContextSTB::CreateGlyphAtlas( if (last_atlas->GetType() == type && CanAppendToExistingAtlas(last_atlas, new_glyphs, glyph_positions, atlas_context->GetAtlasSize(), - s_rect_packer)) { + atlas_context->GetRectPacker())) { // The old bitmap will be reused and only the additional glyphs will be // added. // --------------------------------------------------------------------------- - // Step 4: Record the positions in the glyph atlas of the newly 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++) { @@ -695,16 +496,16 @@ std::shared_ptr TextRenderContextSTB::CreateGlyphAtlas( } // --------------------------------------------------------------------------- - // Step 5: Draw new font-glyph pairs into the existing bitmap. + // Step 4a: Draw new font-glyph pairs into the existing bitmap. // --------------------------------------------------------------------------- - //auto bitmap = atlas_context->GetBitmap(); + // auto bitmap = atlas_context->GetBitmap(); auto bitmap = get_atlas_bitmap(type); if (!UpdateAtlasBitmap(*last_atlas, bitmap, new_glyphs)) { return nullptr; } // --------------------------------------------------------------------------- - // Step 6: Update the existing texture with the updated bitmap. + // Step 5a: Update the existing texture with the updated bitmap. // --------------------------------------------------------------------------- if (!UpdateGlyphTextureAtlas(bitmap, last_atlas->GetTexture())) { return nullptr; @@ -714,7 +515,7 @@ std::shared_ptr TextRenderContextSTB::CreateGlyphAtlas( // A new glyph atlas must be created. // --------------------------------------------------------------------------- - // Step 4: Get the optimum size of the texture atlas. + // Step 3b: Get the optimum size of the texture atlas. // --------------------------------------------------------------------------- auto glyph_atlas = std::make_shared(type); auto atlas_size = OptimumAtlasSizeForFontGlyphPairs( @@ -726,7 +527,7 @@ std::shared_ptr TextRenderContextSTB::CreateGlyphAtlas( } // --------------------------------------------------------------------------- - // Step 5: Find location of font-glyph pairs in the atlas. We have this from + // 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. @@ -736,7 +537,7 @@ std::shared_ptr TextRenderContextSTB::CreateGlyphAtlas( } // --------------------------------------------------------------------------- - // Step 6: Record the positions in the glyph atlas. + // Step 5b: Record the positions in the glyph atlas. // --------------------------------------------------------------------------- { size_t i = 0; @@ -747,7 +548,7 @@ std::shared_ptr TextRenderContextSTB::CreateGlyphAtlas( } // --------------------------------------------------------------------------- - // Step 7: Draw font-glyph pairs in the correct spot in the atlas. + // Step 6b: Draw font-glyph pairs in the correct spot in the atlas. // --------------------------------------------------------------------------- auto bitmap = CreateAtlasBitmap(*glyph_atlas, atlas_size); if (!bitmap) { @@ -757,29 +558,26 @@ std::shared_ptr TextRenderContextSTB::CreateGlyphAtlas( update_atlas_bitmap(bitmap, type); // --------------------------------------------------------------------------- - // Step 8: Upload the atlas as a texture. + // Step 7b: Upload the atlas as a texture. // --------------------------------------------------------------------------- PixelFormat format; switch (type) { - case GlyphAtlas::Type::kSignedDistanceField: - ConvertBitmapToSignedDistanceField( - reinterpret_cast(bitmap->getPixels()), atlas_size.width, - atlas_size.height); case GlyphAtlas::Type::kAlphaBitmap: format = PixelFormat::kA8UNormInt; break; case GlyphAtlas::Type::kColorBitmap: - format = DISABLE_COLOR_FONT_SUPPORT ? PixelFormat::kA8UNormInt : PixelFormat::kR8G8B8A8UNormInt; + format = DISABLE_COLOR_FONT_SUPPORT ? PixelFormat::kA8UNormInt + : PixelFormat::kR8G8B8A8UNormInt; break; } - auto texture = UploadGlyphTextureAtlas(GetContext()->GetResourceAllocator(), - bitmap, atlas_size, format); + auto texture = UploadGlyphTextureAtlas(context.GetResourceAllocator(), bitmap, + atlas_size, format); if (!texture) { return nullptr; } // --------------------------------------------------------------------------- - // Step 9: Record the texture in the glyph atlas. + // Step 8b: Record the texture in the glyph atlas. // --------------------------------------------------------------------------- glyph_atlas->SetTexture(std::move(texture)); diff --git a/impeller/typographer/backends/stb/text_render_context_stb.h b/impeller/typographer/backends/stb/text_render_context_stb.h index 9d9ab6f1e6b12..bccbe05e2492a 100644 --- a/impeller/typographer/backends/stb/text_render_context_stb.h +++ b/impeller/typographer/backends/stb/text_render_context_stb.h @@ -6,21 +6,25 @@ #include "impeller/typographer/text_render_context.h" +#include #include "flutter/fml/macros.h" namespace impeller { class TextRenderContextSTB : public TextRenderContext { public: - TextRenderContextSTB(std::shared_ptr context); + static std::unique_ptr Make(); + + TextRenderContextSTB(); ~TextRenderContextSTB() override; // |TextRenderContext| std::shared_ptr CreateGlyphAtlas( + Context& context, GlyphAtlas::Type type, std::shared_ptr atlas_context, - FrameIterator iterator) const override; + const FontGlyphPair::Set& font_glyph_pairs) const override; private: FML_DISALLOW_COPY_AND_ASSIGN(TextRenderContextSTB); diff --git a/impeller/typographer/backends/stb/typeface_stb.cc b/impeller/typographer/backends/stb/typeface_stb.cc index 9ba8a3115821a..64349299ccaf8 100644 --- a/impeller/typographer/backends/stb/typeface_stb.cc +++ b/impeller/typographer/backends/stb/typeface_stb.cc @@ -4,7 +4,8 @@ #include "impeller/typographer/backends/stb/typeface_stb.h" -#include // memcpy +#include + #include "flutter/fml/logging.h" namespace impeller { @@ -12,33 +13,29 @@ namespace impeller { TypefaceSTB::~TypefaceSTB() = default; // Instantiate a typeface based on a .ttf or other font file -TypefaceSTB::TypefaceSTB(const unsigned char* ttf_buffer, size_t buffer_size) - : _font_file(std::make_unique(buffer_size)), - _font_info(std::make_unique()), - is_valid(false) { - // As we lazily create atlases based on this font, we have to store the binary - // font file itself This seems memory intensive, so maybe we could improve - // this in time (extract needed info now e.g.). - memcpy((void*)_font_file.get(), (void*)ttf_buffer, buffer_size); - +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(ttf_buffer, 0); - if (stbtt_InitFont(_font_info.get(), ttf_buffer, offset) == 0) { + 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; + is_valid_ = true; } } bool TypefaceSTB::IsValid() const { - return is_valid; + return is_valid_; } std::size_t TypefaceSTB::GetHash() const { if (!IsValid()) { return 0u; } - return reinterpret_cast(_font_file.get()); + return reinterpret_cast(typeface_mapping_->GetMapping()); } bool TypefaceSTB::IsEqual(const Typeface& other) const { @@ -47,11 +44,11 @@ bool TypefaceSTB::IsEqual(const Typeface& other) const { } const uint8_t* TypefaceSTB::GetTypefaceFile() const { - return _font_file.get(); + return typeface_mapping_->GetMapping(); } const stbtt_fontinfo* TypefaceSTB::GetFontInfo() const { - return _font_info.get(); + return font_info_.get(); } } // namespace impeller diff --git a/impeller/typographer/backends/stb/typeface_stb.h b/impeller/typographer/backends/stb/typeface_stb.h index 510642c032b88..62c25ce7b6f24 100644 --- a/impeller/typographer/backends/stb/typeface_stb.h +++ b/impeller/typographer/backends/stb/typeface_stb.h @@ -5,6 +5,7 @@ #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" @@ -12,11 +13,15 @@ namespace impeller { class TypefaceSTB final : public Typeface, - public BackendCast { + 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; + TypefaceSTB() = delete; - TypefaceSTB(const unsigned char * ttf_buffer, size_t buffer_size); + explicit TypefaceSTB(std::unique_ptr typeface_mapping); ~TypefaceSTB() override; @@ -33,9 +38,9 @@ class TypefaceSTB final : public Typeface, const stbtt_fontinfo* GetFontInfo() const; private: - std::unique_ptr _font_file; - std::unique_ptr _font_info; - bool is_valid; + std::unique_ptr typeface_mapping_; + std::unique_ptr font_info_; + bool is_valid_; FML_DISALLOW_COPY_AND_ASSIGN(TypefaceSTB); }; diff --git a/impeller/typographer/typographer_unittests.cc b/impeller/typographer/typographer_unittests.cc index 09c78daea06b3..88450a885103a 100644 --- a/impeller/typographer/typographer_unittests.cc +++ b/impeller/typographer/typographer_unittests.cc @@ -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()); @@ -60,9 +60,9 @@ TEST_P(TypographerTest, CanCreateGlyphAtlas) { 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,7 +108,7 @@ 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); @@ -116,7 +116,8 @@ TEST_P(TypographerTest, LazyAtlasTracksColor) { 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); @@ -139,9 +140,9 @@ TEST_P(TypographerTest, GlyphAtlasWithOddUniqueGlyphSize) { 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); @@ -156,9 +157,9 @@ TEST_P(TypographerTest, GlyphAtlasIsRecycledIfUnchanged) { 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,7 +168,7 @@ 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); } @@ -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, @@ -221,9 +223,9 @@ TEST_P(TypographerTest, GlyphAtlasTextureIsRecycledIfUnchanged) { 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(); @@ -254,9 +256,9 @@ TEST_P(TypographerTest, GlyphAtlasTextureIsRecreatedIfTypeChanges) { 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()); } From 49ad67bc7c00dcb9f906af901a098343c80a4492 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Sun, 20 Aug 2023 21:51:00 -0700 Subject: [PATCH 03/12] Licenses --- ci/licenses_golden/licenses_flutter | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index f02a1846afa9f..62604c3fa599f 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1711,6 +1711,12 @@ ORIGIN: ../../../flutter/impeller/typographer/backends/skia/text_render_context_ 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/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/text_render_context_stb.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/typographer/backends/stb/text_render_context_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/font.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/font.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/font_glyph_pair.cc + ../../../flutter/LICENSE @@ -4442,6 +4448,12 @@ FILE: ../../../flutter/impeller/typographer/backends/skia/text_render_context_sk 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/stb/text_frame_stb.cc +FILE: ../../../flutter/impeller/typographer/backends/stb/text_frame_stb.h +FILE: ../../../flutter/impeller/typographer/backends/stb/text_render_context_stb.cc +FILE: ../../../flutter/impeller/typographer/backends/stb/text_render_context_stb.h +FILE: ../../../flutter/impeller/typographer/backends/stb/typeface_stb.cc +FILE: ../../../flutter/impeller/typographer/backends/stb/typeface_stb.h FILE: ../../../flutter/impeller/typographer/font.cc FILE: ../../../flutter/impeller/typographer/font.h FILE: ../../../flutter/impeller/typographer/font_glyph_pair.cc From fc4058fe5464ee7763ce9ad67958bdd73d223978 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Sun, 20 Aug 2023 22:10:05 -0700 Subject: [PATCH 04/12] Buildroot bump --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 5dedfbe35f331..f27a6ded250fd 100644 --- a/DEPS +++ b/DEPS @@ -258,7 +258,7 @@ allowed_hosts = [ ] deps = { - 'src': 'https://github.com/flutter/buildroot.git' + '@' + 'a067408d923ccf80742571bb7a71705499f5779e', + 'src': 'https://github.com/flutter/buildroot.git' + '@' + '30e6ac913e2cd23ed060d59ff38deca2b655b184', # Fuchsia compatibility # From cd10c1072a0e0669698cfcbfe319ff2860f14ef4 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 21 Aug 2023 09:10:10 -0700 Subject: [PATCH 05/12] Remove todo --- impeller/typographer/backends/stb/text_render_context_stb.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/impeller/typographer/backends/stb/text_render_context_stb.cc b/impeller/typographer/backends/stb/text_render_context_stb.cc index 9e615ce591875..46b92fc64806f 100644 --- a/impeller/typographer/backends/stb/text_render_context_stb.cc +++ b/impeller/typographer/backends/stb/text_render_context_stb.cc @@ -317,8 +317,8 @@ static void DrawGlyph(STBBitmap* bitmap, // 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. - // TODO: There's some issue with color fonts, in that if the pixel color - // is nonzero, the alpha is ignored during rendering. That is, partially + // 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]; From 01d0122a5e0d8c7b2ff1ee43e7c1d4c635054702 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 21 Aug 2023 09:23:57 -0700 Subject: [PATCH 06/12] Licenses 2 --- ci/licenses_golden/excluded_files | 1 + ci/licenses_golden/tool_signature | 2 +- tools/licenses/lib/paths.dart | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) 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/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/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 From bd1ee8b7f2f2d5b8e3a99b6f87b3fd33321baba5 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 21 Aug 2023 21:59:48 -0700 Subject: [PATCH 07/12] Rebase --- impeller/aiks/aiks_unittests.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index f2fb1d3f7430a..fb09d413db211 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -1329,8 +1329,9 @@ TEST_P(AiksTest, CanRenderTextFrameSTB) { ASSERT_TRUE(RenderTextInCanvasSTB( GetContext(), canvas, "the quick brown fox jumped over the lazy dog!.?", "Roboto-Regular.ttf")); - ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture(), - TextRenderContextSTB::Make())); + + SetTextRenderContext(TextRenderContextSTB::Make()); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } TEST_P(AiksTest, TextFrameSubpixelAlignment) { From 8bf1bc5c4e46d8a4b33d64c4c9ea11c231471361 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 21 Aug 2023 22:09:42 -0700 Subject: [PATCH 08/12] Rename TextRenderContext to TypographerContext --- ci/licenses_golden/licenses_flutter | 24 +++++++++---------- impeller/aiks/aiks_context.cc | 9 +++---- impeller/aiks/aiks_context.h | 6 ++--- impeller/aiks/aiks_playground.cc | 14 +++++------ impeller/aiks/aiks_playground.h | 8 +++---- impeller/aiks/aiks_unittests.cc | 6 ++--- impeller/display_list/dl_playground.cc | 4 ++-- impeller/entity/contents/content_context.cc | 6 ++--- impeller/entity/contents/content_context.h | 4 ++-- impeller/entity/entity_playground.cc | 16 ++++++------- impeller/entity/entity_playground.h | 8 +++---- impeller/entity/entity_unittests.cc | 4 ++-- .../golden_tests/golden_playground_test.h | 8 +++---- .../golden_playground_test_mac.cc | 14 +++++------ .../golden_playground_test_stub.cc | 6 ++--- impeller/typographer/BUILD.gn | 4 ++-- impeller/typographer/backends/skia/BUILD.gn | 4 ++-- ...xt_skia.cc => typographer_context_skia.cc} | 14 +++++------ ...text_skia.h => typographer_context_skia.h} | 14 +++++------ impeller/typographer/backends/stb/BUILD.gn | 4 ++-- ...text_stb.cc => typographer_context_stb.cc} | 12 +++++----- ...ontext_stb.h => typographer_context_stb.h} | 14 +++++------ impeller/typographer/lazy_glyph_atlas.cc | 16 ++++++------- impeller/typographer/lazy_glyph_atlas.h | 6 ++--- ...nder_context.cc => typographer_context.cc} | 8 +++---- ...render_context.h => typographer_context.h} | 8 +++---- impeller/typographer/typographer_unittests.cc | 22 ++++++++--------- shell/common/rasterizer.h | 4 ++-- shell/gpu/gpu_surface_gl_impeller.cc | 4 ++-- shell/gpu/gpu_surface_metal_impeller.mm | 4 ++-- shell/gpu/gpu_surface_vulkan_impeller.cc | 4 ++-- 31 files changed, 140 insertions(+), 139 deletions(-) rename impeller/typographer/backends/skia/{text_render_context_skia.cc => typographer_context_skia.cc} (97%) rename impeller/typographer/backends/skia/{text_render_context_skia.h => typographer_context_skia.h} (61%) rename impeller/typographer/backends/stb/{text_render_context_stb.cc => typographer_context_stb.cc} (98%) rename impeller/typographer/backends/stb/{text_render_context_stb.h => typographer_context_stb.h} (63%) rename impeller/typographer/{text_render_context.cc => typographer_context.cc} (59%) rename impeller/typographer/{text_render_context.h => typographer_context.h} (90%) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 62604c3fa599f..2669bf58ddbdd 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1707,16 +1707,16 @@ ORIGIN: ../../../flutter/impeller/toolkit/gles/gles.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/toolkit/gles/texture.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/text_frame_stb.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/backends/stb/text_frame_stb.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/typographer/backends/stb/text_render_context_stb.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/typographer/backends/stb/text_render_context_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 @@ -1731,12 +1731,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 @@ -4444,16 +4444,16 @@ FILE: ../../../flutter/impeller/toolkit/gles/texture.h FILE: ../../../flutter/impeller/tools/malioc.json 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/text_frame_stb.cc FILE: ../../../flutter/impeller/typographer/backends/stb/text_frame_stb.h -FILE: ../../../flutter/impeller/typographer/backends/stb/text_render_context_stb.cc -FILE: ../../../flutter/impeller/typographer/backends/stb/text_render_context_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 @@ -4468,12 +4468,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/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 fb09d413db211..ba4305c1b63d4 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -36,10 +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/text_render_context_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" @@ -1330,7 +1330,7 @@ TEST_P(AiksTest, CanRenderTextFrameSTB) { GetContext(), canvas, "the quick brown fox jumped over the lazy dog!.?", "Roboto-Regular.ttf")); - SetTextRenderContext(TextRenderContextSTB::Make()); + SetTypographerContext(TypographerContextSTB::Make()); ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } 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/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 bdb491a431189..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" @@ -2176,7 +2176,7 @@ TEST_P(EntityTest, InheritOpacityTest) { auto blob = SkTextBlob::MakeFromString("A", font); 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/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 bc2b759508888..32287b7d52f24 100644 --- a/impeller/typographer/BUILD.gn +++ b/impeller/typographer/BUILD.gn @@ -20,12 +20,12 @@ 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 = [ diff --git a/impeller/typographer/backends/skia/BUILD.gn b/impeller/typographer/backends/skia/BUILD.gn index 6db350059c004..17aca0c54eb7b 100644 --- a/impeller/typographer/backends/skia/BUILD.gn +++ b/impeller/typographer/backends/skia/BUILD.gn @@ -8,10 +8,10 @@ impeller_component("typographer_skia_backend") { sources = [ "text_frame_skia.cc", "text_frame_skia.h", - "text_render_context_skia.cc", - "text_render_context_skia.h", "typeface_skia.cc", "typeface_skia.h", + "typographer_context_skia.cc", + "typographer_context_skia.h", ] public_deps = [ diff --git a/impeller/typographer/backends/skia/text_render_context_skia.cc b/impeller/typographer/backends/skia/typographer_context_skia.cc similarity index 97% rename from impeller/typographer/backends/skia/text_render_context_skia.cc rename to impeller/typographer/backends/skia/typographer_context_skia.cc index 89554e555f8ea..e5c7341f83e4a 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 @@ -12,7 +12,7 @@ #include "impeller/core/allocator.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 +28,13 @@ 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; static size_t PairsFitInAtlasOfSize( const FontGlyphPair::Set& pairs, @@ -305,7 +305,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, diff --git a/impeller/typographer/backends/skia/text_render_context_skia.h b/impeller/typographer/backends/skia/typographer_context_skia.h similarity index 61% rename from impeller/typographer/backends/skia/text_render_context_skia.h rename to impeller/typographer/backends/skia/typographer_context_skia.h index 32d5a083c2dd9..28fd2fe05bf81 100644 --- a/impeller/typographer/backends/skia/text_render_context_skia.h +++ b/impeller/typographer/backends/skia/typographer_context_skia.h @@ -5,19 +5,19 @@ #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 CreateGlyphAtlas( Context& context, GlyphAtlas::Type type, @@ -25,7 +25,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 index ba4b599d10f2d..b33e7a85496b7 100644 --- a/impeller/typographer/backends/stb/BUILD.gn +++ b/impeller/typographer/backends/stb/BUILD.gn @@ -10,10 +10,10 @@ impeller_component("typographer_stb_backend") { sources = [ "text_frame_stb.cc", "text_frame_stb.h", - "text_render_context_stb.cc", - "text_render_context_stb.h", "typeface_stb.cc", "typeface_stb.h", + "typographer_context_stb.cc", + "typographer_context_stb.h", ] public_deps = [ diff --git a/impeller/typographer/backends/stb/text_render_context_stb.cc b/impeller/typographer/backends/stb/typographer_context_stb.cc similarity index 98% rename from impeller/typographer/backends/stb/text_render_context_stb.cc rename to impeller/typographer/backends/stb/typographer_context_stb.cc index 46b92fc64806f..7e2e0e3081481 100644 --- a/impeller/typographer/backends/stb/text_render_context_stb.cc +++ b/impeller/typographer/backends/stb/typographer_context_stb.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/stb/text_render_context_stb.h" +#include "impeller/typographer/backends/stb/typographer_context_stb.h" #include @@ -109,13 +109,13 @@ using FontGlyphPairRefVector = constexpr size_t kPadding = 1; -std::unique_ptr TextRenderContextSTB::Make() { - return std::make_unique(); +std::unique_ptr TypographerContextSTB::Make() { + return std::make_unique(); } -TextRenderContextSTB::TextRenderContextSTB() : TextRenderContext() {} +TypographerContextSTB::TypographerContextSTB() : TypographerContext() {} -TextRenderContextSTB::~TextRenderContextSTB() = default; +TypographerContextSTB::~TypographerContextSTB() = default; // Function returns the count of "remaining pairs" not packed into rect of given // size. @@ -445,7 +445,7 @@ static std::shared_ptr UploadGlyphTextureAtlas( return texture; } -std::shared_ptr TextRenderContextSTB::CreateGlyphAtlas( +std::shared_ptr TypographerContextSTB::CreateGlyphAtlas( Context& context, GlyphAtlas::Type type, std::shared_ptr atlas_context, diff --git a/impeller/typographer/backends/stb/text_render_context_stb.h b/impeller/typographer/backends/stb/typographer_context_stb.h similarity index 63% rename from impeller/typographer/backends/stb/text_render_context_stb.h rename to impeller/typographer/backends/stb/typographer_context_stb.h index bccbe05e2492a..fe1f041733ab3 100644 --- a/impeller/typographer/backends/stb/text_render_context_stb.h +++ b/impeller/typographer/backends/stb/typographer_context_stb.h @@ -4,22 +4,22 @@ #pragma once -#include "impeller/typographer/text_render_context.h" +#include "impeller/typographer/typographer_context.h" #include #include "flutter/fml/macros.h" namespace impeller { -class TextRenderContextSTB : public TextRenderContext { +class TypographerContextSTB : public TypographerContext { public: - static std::unique_ptr Make(); + static std::unique_ptr Make(); - TextRenderContextSTB(); + TypographerContextSTB(); - ~TextRenderContextSTB() override; + ~TypographerContextSTB() override; - // |TextRenderContext| + // |TypographerContext| std::shared_ptr CreateGlyphAtlas( Context& context, GlyphAtlas::Type type, @@ -27,7 +27,7 @@ class TextRenderContextSTB : public TextRenderContext { const FontGlyphPair::Set& font_glyph_pairs) const override; private: - FML_DISALLOW_COPY_AND_ASSIGN(TextRenderContextSTB); + FML_DISALLOW_COPY_AND_ASSIGN(TypographerContextSTB); }; } // namespace impeller diff --git a/impeller/typographer/lazy_glyph_atlas.cc b/impeller/typographer/lazy_glyph_atlas.cc index 85f7c5dce0da2..47e68834c0367 100644 --- a/impeller/typographer/lazy_glyph_atlas.cc +++ b/impeller/typographer/lazy_glyph_atlas.cc @@ -5,15 +5,15 @@ #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)), + std::shared_ptr typographer_context) + : typographer_context_(std::move(typographer_context)), alpha_context_(std::make_shared()), color_context_(std::make_shared()) {} @@ -44,14 +44,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 +59,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 90% rename from impeller/typographer/text_render_context.h rename to impeller/typographer/typographer_context.h index 754e9c26bb5c0..03fdc1efd602c 100644 --- a/impeller/typographer/text_render_context.h +++ b/impeller/typographer/typographer_context.h @@ -20,9 +20,9 @@ namespace impeller { /// rendering text on the GPU. /// /// -class TextRenderContext { +class TypographerContext { public: - virtual ~TextRenderContext(); + virtual ~TypographerContext(); virtual bool IsValid() const; @@ -40,12 +40,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 88450a885103a..4c43eb445a403 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); } @@ -49,12 +49,12 @@ 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 context = TypographerContextSkia::Make(); auto atlas_context = std::make_shared(); ASSERT_TRUE(context && context->IsValid()); SkFont sk_font; @@ -112,7 +112,7 @@ TEST_P(TypographerTest, LazyAtlasTracksColor) { ASSERT_FALSE(frame.GetAtlasType() == GlyphAtlas::Type::kColorBitmap); - LazyGlyphAtlas lazy_atlas(TextRenderContextSkia::Make()); + LazyGlyphAtlas lazy_atlas(TypographerContextSkia::Make()); lazy_atlas.AddTextFrame(frame, 1.0f); @@ -134,7 +134,7 @@ TEST_P(TypographerTest, LazyAtlasTracksColor) { } TEST_P(TypographerTest, GlyphAtlasWithOddUniqueGlyphSize) { - auto context = TextRenderContextSkia::Make(); + auto context = TypographerContextSkia::Make(); auto atlas_context = std::make_shared(); ASSERT_TRUE(context && context->IsValid()); SkFont sk_font; @@ -151,7 +151,7 @@ TEST_P(TypographerTest, GlyphAtlasWithOddUniqueGlyphSize) { } TEST_P(TypographerTest, GlyphAtlasIsRecycledIfUnchanged) { - auto context = TextRenderContextSkia::Make(); + auto context = TypographerContextSkia::Make(); auto atlas_context = std::make_shared(); ASSERT_TRUE(context && context->IsValid()); SkFont sk_font; @@ -174,7 +174,7 @@ TEST_P(TypographerTest, GlyphAtlasIsRecycledIfUnchanged) { } TEST_P(TypographerTest, GlyphAtlasWithLotsOfdUniqueGlyphSize) { - auto context = TextRenderContextSkia::Make(); + auto context = TypographerContextSkia::Make(); auto atlas_context = std::make_shared(); ASSERT_TRUE(context && context->IsValid()); @@ -217,7 +217,7 @@ TEST_P(TypographerTest, GlyphAtlasWithLotsOfdUniqueGlyphSize) { } TEST_P(TypographerTest, GlyphAtlasTextureIsRecycledIfUnchanged) { - auto context = TextRenderContextSkia::Make(); + auto context = TypographerContextSkia::Make(); auto atlas_context = std::make_shared(); ASSERT_TRUE(context && context->IsValid()); SkFont sk_font; @@ -250,7 +250,7 @@ TEST_P(TypographerTest, GlyphAtlasTextureIsRecycledIfUnchanged) { } TEST_P(TypographerTest, GlyphAtlasTextureIsRecreatedIfTypeChanges) { - auto context = TextRenderContextSkia::Make(); + auto context = TypographerContextSkia::Make(); auto atlas_context = std::make_shared(); ASSERT_TRUE(context && context->IsValid()); SkFont sk_font; 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; } From 44498229aa17f5a2de1d034d7b4633eb635ea85c Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 21 Aug 2023 23:43:43 -0700 Subject: [PATCH 09/12] Address comments --- ci/licenses_golden/licenses_flutter | 8 ++ impeller/typographer/backends/skia/BUILD.gn | 2 + .../backends/skia/glyph_atlas_context_skia.cc | 23 ++++ .../backends/skia/glyph_atlas_context_skia.h | 37 +++++ .../backends/skia/typographer_context_skia.cc | 15 +- .../backends/skia/typographer_context_skia.h | 3 + impeller/typographer/backends/stb/BUILD.gn | 2 + .../backends/stb/glyph_atlas_context_stb.cc | 58 ++++++++ .../backends/stb/glyph_atlas_context_stb.h | 59 ++++++++ .../backends/stb/typographer_context_stb.cc | 130 ++++-------------- .../backends/stb/typographer_context_stb.h | 3 + impeller/typographer/glyph_atlas.cc | 8 -- impeller/typographer/glyph_atlas.h | 16 +-- impeller/typographer/lazy_glyph_atlas.cc | 4 +- impeller/typographer/typographer_context.h | 3 + impeller/typographer/typographer_unittests.cc | 12 +- 16 files changed, 248 insertions(+), 135 deletions(-) create mode 100644 impeller/typographer/backends/skia/glyph_atlas_context_skia.cc create mode 100644 impeller/typographer/backends/skia/glyph_atlas_context_skia.h create mode 100644 impeller/typographer/backends/stb/glyph_atlas_context_stb.cc create mode 100644 impeller/typographer/backends/stb/glyph_atlas_context_stb.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 2669bf58ddbdd..19858013ccd9c 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1705,12 +1705,16 @@ 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/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 @@ -4442,12 +4446,16 @@ 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/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 diff --git a/impeller/typographer/backends/skia/BUILD.gn b/impeller/typographer/backends/skia/BUILD.gn index 17aca0c54eb7b..f135edcc17458 100644 --- a/impeller/typographer/backends/skia/BUILD.gn +++ b/impeller/typographer/backends/skia/BUILD.gn @@ -6,6 +6,8 @@ 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", 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/typographer_context_skia.cc b/impeller/typographer/backends/skia/typographer_context_skia.cc index e5c7341f83e4a..85bae56a15ecd 100644 --- a/impeller/typographer/backends/skia/typographer_context_skia.cc +++ b/impeller/typographer/backends/skia/typographer_context_skia.cc @@ -10,6 +10,7 @@ #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/typographer_context.h" @@ -36,6 +37,11 @@ TypographerContextSkia::TypographerContextSkia() = default; TypographerContextSkia::~TypographerContextSkia() = default; +std::shared_ptr +TypographerContextSkia::CreateGlyphAtlasContext() const { + return std::make_shared(); +} + static size_t PairsFitInAtlasOfSize( const FontGlyphPair::Set& pairs, const ISize& atlas_size, @@ -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, @@ -314,6 +318,7 @@ std::shared_ptr TypographerContextSkia::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 TypographerContextSkia::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 TypographerContextSkia::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/typographer_context_skia.h b/impeller/typographer/backends/skia/typographer_context_skia.h index 28fd2fe05bf81..3c1ebf503134a 100644 --- a/impeller/typographer/backends/skia/typographer_context_skia.h +++ b/impeller/typographer/backends/skia/typographer_context_skia.h @@ -17,6 +17,9 @@ class TypographerContextSkia : public TypographerContext { ~TypographerContextSkia() override; + // |TypographerContext| + std::shared_ptr CreateGlyphAtlasContext() const override; + // |TypographerContext| std::shared_ptr CreateGlyphAtlas( Context& context, diff --git a/impeller/typographer/backends/stb/BUILD.gn b/impeller/typographer/backends/stb/BUILD.gn index b33e7a85496b7..70b98ad9c6686 100644 --- a/impeller/typographer/backends/stb/BUILD.gn +++ b/impeller/typographer/backends/stb/BUILD.gn @@ -8,6 +8,8 @@ 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", 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/typographer_context_stb.cc b/impeller/typographer/backends/stb/typographer_context_stb.cc index 7e2e0e3081481..5efdcf4c72b6c 100644 --- a/impeller/typographer/backends/stb/typographer_context_stb.cc +++ b/impeller/typographer/backends/stb/typographer_context_stb.cc @@ -10,100 +10,19 @@ #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" -// These values can be customize per build. -// Glyph atlases are always square. -#ifndef MAX_GLYPH_ATLAS_SIZE -#define MAX_GLYPH_ATLAS_SIZE 4096u -#endif -#ifndef MIN_GLYPH_ATLAS_SIZE -#define MIN_GLYPH_ATLAS_SIZE 8u -#endif - #define DISABLE_COLOR_FONT_SUPPORT 1 #ifdef DISABLE_COLOR_FONT_SUPPORT -#define COLOR_FONT_BPP 1 +constexpr auto kColorFontBitsPerPixel = 1; #else -#define COLOR_FONT_BPP 4 +constexpr auto kColorFontBitsPerPixel = 4; #endif namespace impeller { -// An simple bitmap in lieu of a skia bitmap. -class STBBitmap { - public: - ~STBBitmap() = default; - - STBBitmap() = delete; - - STBBitmap(size_t width, size_t height, size_t bytes_per_pixel) - : width_(width), - height_(height), - bytes_per_pixel_(bytes_per_pixel), - pixels_(std::make_unique(width * height * bytes_per_pixel)) { - } - - uint8_t* GetPixels() const { return pixels_.get(); } - - uint8_t* GetPixelAddress(TPoint coords) const { - FML_DCHECK(coords.x < width_); - FML_DCHECK(coords.x < height_); - - return &pixels_.get()[(coords.x + width_ * coords.y) * bytes_per_pixel_]; - } - - size_t GetRowBytes() const { return width_ * bytes_per_pixel_; } - - size_t GetWidth() const { return width_; } - - size_t GetHeight() const { return height_; } - - size_t GetSize() const { return width_ * height_ * bytes_per_pixel_; } - - private: - size_t width_; - size_t height_; - size_t bytes_per_pixel_; - std::unique_ptr pixels_; -}; - -// Analogous to the bitmaps (one for each type) stored in each Atlas context. -static auto alpha_bitmap = - std::make_shared(MIN_GLYPH_ATLAS_SIZE, MIN_GLYPH_ATLAS_SIZE, 1); -static auto color_bitmap = std::make_shared(MIN_GLYPH_ATLAS_SIZE, - MIN_GLYPH_ATLAS_SIZE, - COLOR_FONT_BPP); - -static std::shared_ptr get_atlas_bitmap( - impeller::GlyphAtlas::Type type) { - switch (type) { - case impeller::GlyphAtlas::Type::kAlphaBitmap: { - return alpha_bitmap; - break; - } - case impeller::GlyphAtlas::Type::kColorBitmap: { - return color_bitmap; - break; - } - } -} - -static void update_atlas_bitmap(std::shared_ptr& bitmap, - impeller::GlyphAtlas::Type type) { - switch (type) { - case impeller::GlyphAtlas::Type::kAlphaBitmap: { - alpha_bitmap = bitmap; - break; - } - case impeller::GlyphAtlas::Type::kColorBitmap: { - color_bitmap = bitmap; - break; - } - } -} - using FontGlyphPairRefVector = std::vector>; @@ -117,6 +36,11 @@ 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( @@ -232,17 +156,20 @@ 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) { - static constexpr auto kMinAtlasSize = MIN_GLYPH_ATLAS_SIZE; - static constexpr auto kMaxAtlasSize = MAX_GLYPH_ATLAS_SIZE; + 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(kMinAtlasSize, kMinAtlasSize); + 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( @@ -267,9 +194,8 @@ ISize OptimumAtlasSizeForFontGlyphPairs( current_size.height <= kMaxAtlasSize); return ISize{0, 0}; } -} // namespace -static void DrawGlyph(STBBitmap* bitmap, +static void DrawGlyph(BitmapSTB* bitmap, const FontGlyphPair& font_glyph, const Rect& location, bool has_color) { @@ -345,7 +271,7 @@ static void DrawGlyph(STBBitmap* bitmap, } static bool UpdateAtlasBitmap(const GlyphAtlas& atlas, - const std::shared_ptr& bitmap, + const std::shared_ptr& bitmap, const FontGlyphPairRefVector& new_pairs) { TRACE_EVENT0("impeller", __FUNCTION__); FML_DCHECK(bitmap != nullptr); @@ -362,16 +288,16 @@ static bool UpdateAtlasBitmap(const GlyphAtlas& atlas, return true; } -static std::shared_ptr CreateAtlasBitmap(const GlyphAtlas& atlas, +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 = COLOR_FONT_BPP; + bytes_per_pixel = kColorFontBitsPerPixel; } - auto bitmap = std::make_shared(atlas_size.width, atlas_size.height, + auto bitmap = std::make_shared(atlas_size.width, atlas_size.height, bytes_per_pixel); bool has_color = atlas.GetType() == GlyphAtlas::Type::kColorBitmap; @@ -386,7 +312,7 @@ static std::shared_ptr CreateAtlasBitmap(const GlyphAtlas& atlas, } // static bool UpdateGlyphTextureAtlas(std::shared_ptr bitmap, -static bool UpdateGlyphTextureAtlas(std::shared_ptr& bitmap, +static bool UpdateGlyphTextureAtlas(std::shared_ptr& bitmap, const std::shared_ptr& texture) { TRACE_EVENT0("impeller", __FUNCTION__); @@ -406,7 +332,7 @@ static bool UpdateGlyphTextureAtlas(std::shared_ptr& bitmap, static std::shared_ptr UploadGlyphTextureAtlas( const std::shared_ptr& allocator, - std::shared_ptr& bitmap, + std::shared_ptr& bitmap, const ISize& atlas_size, PixelFormat format) { TRACE_EVENT0("impeller", __FUNCTION__); @@ -454,6 +380,7 @@ std::shared_ptr TypographerContextSTB::CreateGlyphAtlas( 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()) { @@ -499,7 +426,7 @@ std::shared_ptr TypographerContextSTB::CreateGlyphAtlas( // Step 4a: Draw new font-glyph pairs into the existing bitmap. // --------------------------------------------------------------------------- // auto bitmap = atlas_context->GetBitmap(); - auto bitmap = get_atlas_bitmap(type); + auto bitmap = atlas_context_stb.GetBitmap(); if (!UpdateAtlasBitmap(*last_atlas, bitmap, new_glyphs)) { return nullptr; } @@ -519,7 +446,7 @@ std::shared_ptr TypographerContextSTB::CreateGlyphAtlas( // --------------------------------------------------------------------------- auto glyph_atlas = std::make_shared(type); auto atlas_size = OptimumAtlasSizeForFontGlyphPairs( - font_glyph_pairs, glyph_positions, atlas_context); + font_glyph_pairs, glyph_positions, atlas_context, type); atlas_context->UpdateGlyphAtlas(glyph_atlas, atlas_size); if (atlas_size.IsEmpty()) { @@ -554,8 +481,7 @@ std::shared_ptr TypographerContextSTB::CreateGlyphAtlas( if (!bitmap) { return nullptr; } - - update_atlas_bitmap(bitmap, type); + atlas_context_stb.UpdateBitmap(bitmap); // --------------------------------------------------------------------------- // Step 7b: Upload the atlas as a texture. diff --git a/impeller/typographer/backends/stb/typographer_context_stb.h b/impeller/typographer/backends/stb/typographer_context_stb.h index fe1f041733ab3..5496931363ed5 100644 --- a/impeller/typographer/backends/stb/typographer_context_stb.h +++ b/impeller/typographer/backends/stb/typographer_context_stb.h @@ -19,6 +19,9 @@ class TypographerContextSTB : public TypographerContext { ~TypographerContextSTB() override; + // |TypographerContext| + std::shared_ptr CreateGlyphAtlasContext() const override; + // |TypographerContext| std::shared_ptr CreateGlyphAtlas( Context& context, 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 47e68834c0367..c4fe9b3e99b3d 100644 --- a/impeller/typographer/lazy_glyph_atlas.cc +++ b/impeller/typographer/lazy_glyph_atlas.cc @@ -14,8 +14,8 @@ namespace impeller { LazyGlyphAtlas::LazyGlyphAtlas( std::shared_ptr typographer_context) : typographer_context_(std::move(typographer_context)), - alpha_context_(std::make_shared()), - color_context_(std::make_shared()) {} + alpha_context_(typographer_context_->CreateGlyphAtlasContext()), + color_context_(typographer_context_->CreateGlyphAtlasContext()) {} LazyGlyphAtlas::~LazyGlyphAtlas() = default; diff --git a/impeller/typographer/typographer_context.h b/impeller/typographer/typographer_context.h index 03fdc1efd602c..8ed74ce1fcbf1 100644 --- a/impeller/typographer/typographer_context.h +++ b/impeller/typographer/typographer_context.h @@ -26,6 +26,9 @@ class 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 diff --git a/impeller/typographer/typographer_unittests.cc b/impeller/typographer/typographer_unittests.cc index 4c43eb445a403..4a2bed4dc52cc 100644 --- a/impeller/typographer/typographer_unittests.cc +++ b/impeller/typographer/typographer_unittests.cc @@ -55,7 +55,7 @@ TEST_P(TypographerTest, CanCreateRenderContext) { TEST_P(TypographerTest, CanCreateGlyphAtlas) { auto context = TypographerContextSkia::Make(); - auto atlas_context = std::make_shared(); + auto atlas_context = context->CreateGlyphAtlasContext(); ASSERT_TRUE(context && context->IsValid()); SkFont sk_font; auto blob = SkTextBlob::MakeFromString("hello", sk_font); @@ -135,7 +135,7 @@ TEST_P(TypographerTest, LazyAtlasTracksColor) { TEST_P(TypographerTest, GlyphAtlasWithOddUniqueGlyphSize) { auto context = TypographerContextSkia::Make(); - auto atlas_context = std::make_shared(); + auto atlas_context = context->CreateGlyphAtlasContext(); ASSERT_TRUE(context && context->IsValid()); SkFont sk_font; auto blob = SkTextBlob::MakeFromString("AGH", sk_font); @@ -152,7 +152,7 @@ TEST_P(TypographerTest, GlyphAtlasWithOddUniqueGlyphSize) { TEST_P(TypographerTest, GlyphAtlasIsRecycledIfUnchanged) { auto context = TypographerContextSkia::Make(); - auto atlas_context = std::make_shared(); + auto atlas_context = context->CreateGlyphAtlasContext(); ASSERT_TRUE(context && context->IsValid()); SkFont sk_font; auto blob = SkTextBlob::MakeFromString("spooky skellingtons", sk_font); @@ -175,7 +175,7 @@ TEST_P(TypographerTest, GlyphAtlasIsRecycledIfUnchanged) { TEST_P(TypographerTest, GlyphAtlasWithLotsOfdUniqueGlyphSize) { auto context = TypographerContextSkia::Make(); - auto atlas_context = std::make_shared(); + auto atlas_context = context->CreateGlyphAtlasContext(); ASSERT_TRUE(context && context->IsValid()); const char* test_string = @@ -218,7 +218,7 @@ TEST_P(TypographerTest, GlyphAtlasWithLotsOfdUniqueGlyphSize) { TEST_P(TypographerTest, GlyphAtlasTextureIsRecycledIfUnchanged) { auto context = TypographerContextSkia::Make(); - auto atlas_context = std::make_shared(); + auto atlas_context = context->CreateGlyphAtlasContext(); ASSERT_TRUE(context && context->IsValid()); SkFont sk_font; auto blob = SkTextBlob::MakeFromString("spooky 1", sk_font); @@ -251,7 +251,7 @@ TEST_P(TypographerTest, GlyphAtlasTextureIsRecycledIfUnchanged) { TEST_P(TypographerTest, GlyphAtlasTextureIsRecreatedIfTypeChanges) { auto context = TypographerContextSkia::Make(); - auto atlas_context = std::make_shared(); + auto atlas_context = context->CreateGlyphAtlasContext(); ASSERT_TRUE(context && context->IsValid()); SkFont sk_font; auto blob = SkTextBlob::MakeFromString("spooky 1", sk_font); From c6d7d87df438d392a555fe478a8769956b4594d4 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 21 Aug 2023 23:55:36 -0700 Subject: [PATCH 10/12] Update buildroot to HEAD --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index f27a6ded250fd..52681dac25d17 100644 --- a/DEPS +++ b/DEPS @@ -258,7 +258,7 @@ allowed_hosts = [ ] deps = { - 'src': 'https://github.com/flutter/buildroot.git' + '@' + '30e6ac913e2cd23ed060d59ff38deca2b655b184', + 'src': 'https://github.com/flutter/buildroot.git' + '@' + 'f91786b0f7ed84f4d55fef7707b68bea180281f5', # Fuchsia compatibility # From 8351bf0c34d805393bc32b02a96c8bdde6a202a8 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Tue, 22 Aug 2023 20:03:40 -0700 Subject: [PATCH 11/12] Fix segv --- impeller/typographer/lazy_glyph_atlas.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/impeller/typographer/lazy_glyph_atlas.cc b/impeller/typographer/lazy_glyph_atlas.cc index c4fe9b3e99b3d..bf45acda95985 100644 --- a/impeller/typographer/lazy_glyph_atlas.cc +++ b/impeller/typographer/lazy_glyph_atlas.cc @@ -14,8 +14,12 @@ namespace impeller { LazyGlyphAtlas::LazyGlyphAtlas( std::shared_ptr typographer_context) : typographer_context_(std::move(typographer_context)), - alpha_context_(typographer_context_->CreateGlyphAtlasContext()), - color_context_(typographer_context_->CreateGlyphAtlasContext()) {} + alpha_context_(typographer_context_ + ? typographer_context_->CreateGlyphAtlasContext() + : nullptr), + color_context_(typographer_context_ + ? typographer_context_->CreateGlyphAtlasContext() + : nullptr) {} LazyGlyphAtlas::~LazyGlyphAtlas() = default; From dad7d3d0fa7afc8914edfc7ff30f54c5efc016a9 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Wed, 23 Aug 2023 12:31:23 -0700 Subject: [PATCH 12/12] Address comments --- impeller/typographer/backends/stb/typeface_stb.cc | 4 ++-- impeller/typographer/backends/stb/typeface_stb.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/impeller/typographer/backends/stb/typeface_stb.cc b/impeller/typographer/backends/stb/typeface_stb.cc index 64349299ccaf8..ef0250a82100a 100644 --- a/impeller/typographer/backends/stb/typeface_stb.cc +++ b/impeller/typographer/backends/stb/typeface_stb.cc @@ -10,8 +10,6 @@ namespace impeller { -TypefaceSTB::~TypefaceSTB() = default; - // Instantiate a typeface based on a .ttf or other font file TypefaceSTB::TypefaceSTB(std::unique_ptr typeface_mapping) : typeface_mapping_(std::move(typeface_mapping)), @@ -27,6 +25,8 @@ TypefaceSTB::TypefaceSTB(std::unique_ptr typeface_mapping) } } +TypefaceSTB::~TypefaceSTB() = default; + bool TypefaceSTB::IsValid() const { return is_valid_; } diff --git a/impeller/typographer/backends/stb/typeface_stb.h b/impeller/typographer/backends/stb/typeface_stb.h index 62c25ce7b6f24..81f0850edeab4 100644 --- a/impeller/typographer/backends/stb/typeface_stb.h +++ b/impeller/typographer/backends/stb/typeface_stb.h @@ -19,8 +19,6 @@ class TypefaceSTB final : public Typeface, // This assumes a constant pixels per em. static constexpr float kPointsToPixels = 96.0 / 72.0; - TypefaceSTB() = delete; - explicit TypefaceSTB(std::unique_ptr typeface_mapping); ~TypefaceSTB() override;