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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
341 changes: 169 additions & 172 deletions impeller/typographer/backends/skia/typographer_context_skia.cc

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ std::shared_ptr<GlyphAtlas> TypographerContextSTB::CreateGlyphAtlas(
context.GetResourceAllocator()->GetMaxTextureSizeSupported() //
);

atlas_context->UpdateGlyphAtlas(glyph_atlas, atlas_size);
atlas_context->UpdateGlyphAtlas(glyph_atlas, atlas_size, 0);
if (atlas_size.IsEmpty()) {
return nullptr;
}
Expand Down
8 changes: 7 additions & 1 deletion impeller/typographer/glyph_atlas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,20 @@ const ISize& GlyphAtlasContext::GetAtlasSize() const {
return atlas_size_;
}

int64_t GlyphAtlasContext::GetHeightAdjustment() const {
return height_adjustment_;
}

std::shared_ptr<RectanglePacker> GlyphAtlasContext::GetRectPacker() const {
return rect_packer_;
}

void GlyphAtlasContext::UpdateGlyphAtlas(std::shared_ptr<GlyphAtlas> atlas,
ISize size) {
ISize size,
int64_t height_adjustment) {
atlas_ = std::move(atlas);
atlas_size_ = size;
height_adjustment_ = height_adjustment;
}

void GlyphAtlasContext::UpdateRectPacker(
Expand Down
15 changes: 14 additions & 1 deletion impeller/typographer/glyph_atlas.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,16 +160,29 @@ class GlyphAtlasContext {
/// @brief Retrieve the previous (if any) rect packer.
std::shared_ptr<RectanglePacker> GetRectPacker() const;

//----------------------------------------------------------------------------
/// @brief A y-coordinate shift that must be applied to glyphs appended
/// to
/// the atlas.
///
/// The rectangle packer is only initialized for unfilled regions
/// of the atlas. The area the rectangle packer covers is offset
/// from the origin by this height adjustment.
int64_t GetHeightAdjustment() const;

//----------------------------------------------------------------------------
/// @brief Update the context with a newly constructed glyph atlas.
void UpdateGlyphAtlas(std::shared_ptr<GlyphAtlas> atlas, ISize size);
void UpdateGlyphAtlas(std::shared_ptr<GlyphAtlas> atlas,
ISize size,
int64_t height_adjustment_);

void UpdateRectPacker(std::shared_ptr<RectanglePacker> rect_packer);

private:
std::shared_ptr<GlyphAtlas> atlas_;
ISize atlas_size_;
std::shared_ptr<RectanglePacker> rect_packer_;
int64_t height_adjustment_;

GlyphAtlasContext(const GlyphAtlasContext&) = delete;

Expand Down
13 changes: 0 additions & 13 deletions impeller/typographer/rectangle_packer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ class SkylineRectanglePacker final : public RectanglePacker {
return area_so_far_ / ((float)width() * height());
}

std::unique_ptr<RectanglePacker> Clone(uint32_t scale) final;

private:
struct SkylineSegment {
int x_;
Expand Down Expand Up @@ -173,17 +171,6 @@ void SkylineRectanglePacker::AddSkylineLevel(size_t skyline_index,
}
}

std::unique_ptr<RectanglePacker> SkylineRectanglePacker::Clone(uint32_t scale) {
FML_DCHECK(scale != 0);
auto packer =
std::make_unique<SkylineRectanglePacker>(width(), height() * scale);
for (SkylineSegment segment : skyline_) {
packer->skyline_.push_back(segment);
}
packer->area_so_far_ = area_so_far_;
return packer;
}

std::shared_ptr<RectanglePacker> RectanglePacker::Factory(int width,
int height) {
return std::make_shared<SkylineRectanglePacker>(width, height);
Expand Down
13 changes: 0 additions & 13 deletions impeller/typographer/rectangle_packer.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,6 @@ class RectanglePacker {
///
virtual Scalar PercentFull() const = 0;

//----------------------------------------------------------------------------
/// @brief Create a new rectangle packer with a larger scaled height
/// scaled and initialize its contents to the current packer.
///
/// @param[in] scale The scaling factor to be applied to the new height.
///
/// @return A new rectangle packer.
///
/// This method is used for growing the glyph atlas while keeping
/// existing rects in place. The width of the rectangle packer
/// cannot be increased.
virtual std::unique_ptr<RectanglePacker> Clone(uint32_t scale) = 0;

//----------------------------------------------------------------------------
/// @brief Empty out all previously added rectangles.
///
Expand Down
103 changes: 51 additions & 52 deletions impeller/typographer/typographer_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -325,58 +325,6 @@ TEST_P(TypographerTest, RectanglePackerAddsNonoverlapingRectangles) {
ASSERT_EQ(packer->PercentFull(), 0);
}

TEST(TypographerTest, CanCloneRectanglePackerEmpty) {
auto skyline = RectanglePacker::Factory(256, 256);

EXPECT_EQ(skyline->PercentFull(), 0);

auto skyline_2 = skyline->Clone(/*scale=*/2);

EXPECT_EQ(skyline->PercentFull(), 0);
}

TEST(TypographerTest, CanCloneRectanglePackerAndPreservePositions) {
auto skyline = RectanglePacker::Factory(256, 256);
IPoint16 loc;
EXPECT_TRUE(skyline->AddRect(100, 100, &loc));

EXPECT_EQ(loc.x(), 0);
EXPECT_EQ(loc.y(), 0);
auto percent = skyline->PercentFull();

auto skyline_2 = skyline->Clone(/*scale=*/2);

EXPECT_LT(skyline_2->PercentFull(), percent);
}

TEST(TypographerTest, CanCloneRectanglePackerWhileFull) {
auto skyline = RectanglePacker::Factory(256, 256);
IPoint16 loc;
// Add a rectangle the size of the entire area.
EXPECT_TRUE(skyline->AddRect(256, 256, &loc));
// Packer is now full.
EXPECT_FALSE(skyline->AddRect(256, 256, &loc));

auto skyline_2 = skyline->Clone(/*scale=*/2);

// Can now fit one more
EXPECT_TRUE(skyline_2->AddRect(256, 256, &loc));
}

TEST(TypographerTest, CloneToSameSizePreservesContents) {
auto skyline = RectanglePacker::Factory(256, 256);
IPoint16 loc;
// Add a rectangle the size of the entire area.
EXPECT_TRUE(skyline->AddRect(256, 256, &loc));
// Packer is now full.
EXPECT_FALSE(skyline->AddRect(256, 256, &loc));

auto skyline_2 = skyline->Clone(/*scale=*/1);

// Packer is still full.
EXPECT_FALSE(skyline->AddRect(256, 256, &loc));
}

TEST(TypographerTest, RectanglePackerFillsRows) {
auto skyline = RectanglePacker::Factory(257, 256);

Expand All @@ -398,6 +346,57 @@ TEST(TypographerTest, RectanglePackerFillsRows) {
EXPECT_EQ(loc.y(), 16);
}

TEST_P(TypographerTest, GlyphAtlasTextureWillGrowTilMaxTextureSize) {
if (GetBackend() == PlaygroundBackend::kOpenGLES) {
GTEST_SKIP() << "Atlas growth isn't supported for OpenGLES currently.";
}

auto host_buffer = HostBuffer::Create(GetContext()->GetResourceAllocator());
auto context = TypographerContextSkia::Make();
auto atlas_context =
context->CreateGlyphAtlasContext(GlyphAtlas::Type::kAlphaBitmap);
ASSERT_TRUE(context && context->IsValid());
SkFont sk_font = flutter::testing::CreateTestFontOfSize(12);
auto blob = SkTextBlob::MakeFromString("A", sk_font);
ASSERT_TRUE(blob);
auto atlas =
CreateGlyphAtlas(*GetContext(), context.get(), *host_buffer,
GlyphAtlas::Type::kAlphaBitmap, 1.0f, atlas_context,
*MakeTextFrameFromTextBlobSkia(blob));
// Continually append new glyphs until the glyph size grows to the maximum.
// Note that the sizes here are more or less experimentally determined, but
// the important expectation is that the atlas size will shrink again after
// growing to the maximum size.
constexpr ISize expected_sizes[13] = {
{4096, 4096}, //
{4096, 4096}, //
{4096, 8192}, //
{4096, 8192}, //
{4096, 8192}, //
{4096, 8192}, //
{4096, 16384}, //
{4096, 16384}, //
{4096, 16384}, //
{4096, 16384}, //
{4096, 16384}, //
{4096, 16384}, //
{4096, 4096} // Shrinks!
};

for (int i = 0; i < 13; i++) {
SkFont sk_font = flutter::testing::CreateTestFontOfSize(50 + i);
auto blob = SkTextBlob::MakeFromString("A", sk_font);

atlas =
CreateGlyphAtlas(*GetContext(), context.get(), *host_buffer,
GlyphAtlas::Type::kAlphaBitmap, 50 + i, atlas_context,
*MakeTextFrameFromTextBlobSkia(blob));
ASSERT_TRUE(!!atlas);
EXPECT_EQ(atlas->GetTexture()->GetTextureDescriptor().size,
expected_sizes[i]);
}
}

} // namespace testing
} // namespace impeller

Expand Down