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
2 changes: 1 addition & 1 deletion impeller/entity/contents/text_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ bool TextContents::Render(const ContentContext& renderer,
Scalar rounded_scale = TextFrame::RoundScaledFontSize(
scale_, font.GetMetrics().point_size);
const FontGlyphAtlas* font_atlas =
atlas->GetFontGlyphAtlas(font, rounded_scale);
atlas->GetFontGlyphAtlas(font, rounded_scale, frame_->GetColor());
if (!font_atlas) {
VALIDATION_LOG << "Could not find font in the atlas.";
continue;
Expand Down
10 changes: 10 additions & 0 deletions impeller/geometry/color.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,16 @@ struct Color {
return {r, g, b, a};
}

/**
* @brief Convert to ARGB 32 bit color.
*
* @return constexpr uint32_t
*/
constexpr uint32_t ToARGB() const {
std::array<uint8_t, 4> result = ToR8G8B8A8();
return result[3] << 24 | result[0] << 16 | result[1] << 8 | result[2];
}

static constexpr Color White() { return {1.0f, 1.0f, 1.0f, 1.0f}; }

static constexpr Color Black() { return {0.0f, 0.0f, 0.0f, 1.0f}; }
Expand Down
1 change: 1 addition & 0 deletions impeller/typographer/backends/skia/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ impeller_component("typographer_skia_backend") {
]

public_deps = [
"//flutter/display_list",
"//flutter/impeller/typographer",
"//flutter/skia",
]
Expand Down
17 changes: 15 additions & 2 deletions impeller/typographer/backends/skia/text_frame_skia.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <vector>

#include "display_list/dl_color.h"
#include "flutter/fml/logging.h"
#include "impeller/typographer/backends/skia/typeface_skia.h"
#include "include/core/SkRect.h"
Expand All @@ -16,6 +17,15 @@

namespace impeller {

static Color ToColor(const flutter::DlColor& color) {
return {
static_cast<Scalar>(color.getRedF()), //
static_cast<Scalar>(color.getGreenF()), //
static_cast<Scalar>(color.getBlueF()), //
static_cast<Scalar>(color.getAlphaF()) //
};
}

static Font ToFont(const SkTextBlobRunIterator& run) {
auto& font = run.font();
auto typeface = std::make_shared<TypefaceSkia>(font.refTypeface());
Expand All @@ -39,8 +49,10 @@ static Rect ToRect(const SkRect& rect) {
static constexpr Scalar kScaleSize = 64.0f;

std::shared_ptr<TextFrame> MakeTextFrameFromTextBlobSkia(
const sk_sp<SkTextBlob>& blob) {
const sk_sp<SkTextBlob>& blob,
flutter::DlColor dl_color) {
bool has_color = false;
Color color = ToColor(dl_color);
std::vector<TextRun> runs;
for (SkTextBlobRunIterator run(blob.get()); !run.done(); run.next()) {
// TODO(jonahwilliams): ask Skia for a public API to look this up.
Expand Down Expand Up @@ -89,7 +101,8 @@ std::shared_ptr<TextFrame> MakeTextFrameFromTextBlobSkia(
continue;
}
}
return std::make_shared<TextFrame>(runs, ToRect(blob->bounds()), has_color);
return std::make_shared<TextFrame>(runs, ToRect(blob->bounds()), has_color,
has_color ? color : Color::Black());
}

} // namespace impeller
4 changes: 3 additions & 1 deletion impeller/typographer/backends/skia/text_frame_skia.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
#ifndef FLUTTER_IMPELLER_TYPOGRAPHER_BACKENDS_SKIA_TEXT_FRAME_SKIA_H_
#define FLUTTER_IMPELLER_TYPOGRAPHER_BACKENDS_SKIA_TEXT_FRAME_SKIA_H_

#include "display_list/dl_color.h"
#include "impeller/typographer/text_frame.h"
#include "third_party/skia/include/core/SkTextBlob.h"

namespace impeller {

std::shared_ptr<impeller::TextFrame> MakeTextFrameFromTextBlobSkia(
const sk_sp<SkTextBlob>& blob);
const sk_sp<SkTextBlob>& blob,
flutter::DlColor color = flutter::DlColor::kBlack());

} // namespace impeller

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ static void DrawGlyph(SkCanvas* canvas,
sk_font.setHinting(SkFontHinting::kSlight);
sk_font.setEmbolden(metrics.embolden);

auto glyph_color = has_color ? SK_ColorWHITE : SK_ColorBLACK;
auto glyph_color = has_color ? scaled_font.color.ToARGB() : SK_ColorBLACK;

SkPaint glyph_paint;
glyph_paint.setColor(glyph_color);
Expand Down Expand Up @@ -331,8 +331,8 @@ std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
std::vector<FontGlyphPair> new_glyphs;
for (const auto& font_value : font_glyph_map) {
const ScaledFont& scaled_font = font_value.first;
const FontGlyphAtlas* font_glyph_atlas =
last_atlas->GetFontGlyphAtlas(scaled_font.font, scaled_font.scale);
const FontGlyphAtlas* font_glyph_atlas = last_atlas->GetFontGlyphAtlas(
scaled_font.font, scaled_font.scale, scaled_font.color);
if (font_glyph_atlas) {
for (const Glyph& glyph : font_value.second) {
if (!font_glyph_atlas->FindGlyphBounds(glyph)) {
Expand Down
2 changes: 1 addition & 1 deletion impeller/typographer/backends/stb/text_frame_stb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ std::shared_ptr<TextFrame> MakeTextFrameSTB(

std::vector<TextRun> runs = {run};
return std::make_shared<TextFrame>(
runs, result.value_or(Rect::MakeLTRB(0, 0, 0, 0)), false);
runs, result.value_or(Rect::MakeLTRB(0, 0, 0, 0)), false, Color::Black());
}

} // namespace impeller
4 changes: 2 additions & 2 deletions impeller/typographer/backends/stb/typographer_context_stb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -412,8 +412,8 @@ std::shared_ptr<GlyphAtlas> TypographerContextSTB::CreateGlyphAtlas(
std::vector<FontGlyphPair> new_glyphs;
for (const auto& font_value : font_glyph_map) {
const ScaledFont& scaled_font = font_value.first;
const FontGlyphAtlas* font_glyph_atlas =
last_atlas->GetFontGlyphAtlas(scaled_font.font, scaled_font.scale);
const FontGlyphAtlas* font_glyph_atlas = last_atlas->GetFontGlyphAtlas(
scaled_font.font, scaled_font.scale, scaled_font.color);
if (font_glyph_atlas) {
for (const Glyph& glyph : font_value.second) {
if (!font_glyph_atlas->FindGlyphBounds(glyph)) {
Expand Down
6 changes: 4 additions & 2 deletions impeller/typographer/font_glyph_pair.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace impeller {
struct ScaledFont {
Font font;
Scalar scale;
Color color;
};

using FontGlyphMap = std::unordered_map<ScaledFont, std::unordered_set<Glyph>>;
Expand All @@ -40,15 +41,16 @@ struct FontGlyphPair {
template <>
struct std::hash<impeller::ScaledFont> {
constexpr std::size_t operator()(const impeller::ScaledFont& sf) const {
return fml::HashCombine(sf.font.GetHash(), sf.scale);
return fml::HashCombine(sf.font.GetHash(), sf.scale, sf.color.ToARGB());
}
};

template <>
struct std::equal_to<impeller::ScaledFont> {
constexpr bool operator()(const impeller::ScaledFont& lhs,
const impeller::ScaledFont& rhs) const {
return lhs.font.IsEqual(rhs.font) && lhs.scale == rhs.scale;
return lhs.font.IsEqual(rhs.font) && lhs.scale == rhs.scale &&
lhs.color == rhs.color;
}
};

Expand Down
5 changes: 3 additions & 2 deletions impeller/typographer/glyph_atlas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,9 @@ std::optional<Rect> GlyphAtlas::FindFontGlyphBounds(
}

const FontGlyphAtlas* GlyphAtlas::GetFontGlyphAtlas(const Font& font,
Scalar scale) const {
const auto& found = font_atlas_map_.find({font, scale});
Scalar scale,
Color color) const {
const auto& found = font_atlas_map_.find({font, scale, color});
if (found == font_atlas_map_.end()) {
return nullptr;
}
Expand Down
4 changes: 3 additions & 1 deletion impeller/typographer/glyph_atlas.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ class GlyphAtlas {
/// scale are not available in the atlas. The pointer is only
/// valid for the lifetime of the GlyphAtlas.
///
const FontGlyphAtlas* GetFontGlyphAtlas(const Font& font, Scalar scale) const;
const FontGlyphAtlas* GetFontGlyphAtlas(const Font& font,
Scalar scale,
Color color) const;

private:
const Type type_;
Expand Down
17 changes: 14 additions & 3 deletions impeller/typographer/text_frame.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@
// found in the LICENSE file.

#include "impeller/typographer/text_frame.h"
#include "impeller/typographer/font_glyph_pair.h"

namespace impeller {

TextFrame::TextFrame() = default;

TextFrame::TextFrame(std::vector<TextRun>& runs, Rect bounds, bool has_color)
: runs_(std::move(runs)), bounds_(bounds), has_color_(has_color) {}
TextFrame::TextFrame(std::vector<TextRun>& runs,
Rect bounds,
bool has_color,
Color color)
: runs_(std::move(runs)),
bounds_(bounds),
has_color_(has_color),
color_(color) {}

TextFrame::~TextFrame() = default;

Expand All @@ -30,6 +37,10 @@ GlyphAtlas::Type TextFrame::GetAtlasType() const {
: GlyphAtlas::Type::kAlphaBitmap;
}

Color TextFrame::GetColor() const {
return color_;
}

bool TextFrame::MaybeHasOverlapping() const {
if (runs_.size() > 1) {
return true;
Expand Down Expand Up @@ -78,7 +89,7 @@ void TextFrame::CollectUniqueFontGlyphPairs(FontGlyphMap& glyph_map,
const Font& font = run.GetFont();
auto rounded_scale =
RoundScaledFontSize(scale, font.GetMetrics().point_size);
auto& set = glyph_map[{font, rounded_scale}];
auto& set = glyph_map[ScaledFont{font, rounded_scale, color_}];
for (const TextRun::GlyphPosition& glyph_position :
run.GetGlyphPositions()) {
#if false
Expand Down
17 changes: 15 additions & 2 deletions impeller/typographer/text_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ class TextFrame {
public:
TextFrame();

TextFrame(std::vector<TextRun>& runs, Rect bounds, bool has_color);
TextFrame(std::vector<TextRun>& runs,
Rect bounds,
bool has_color,
Color color);

~TextFrame();

Expand Down Expand Up @@ -60,6 +63,15 @@ class TextFrame {
/// to apply opacity peephole optimizations to text blobs.
bool MaybeHasOverlapping() const;

//----------------------------------------------------------------------------
/// @brief Returns the paint color this text frame was recorded with.
///
/// Non-bitmap/COLR fonts always use a black text color here, but
/// COLR fonts can potentially use the paint color in the glyph
/// atlas, so this color must be considered as part of the cache
/// key.
Color GetColor() const;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need doc comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


//----------------------------------------------------------------------------
/// @brief The type of atlas this run should be emplaced in.
GlyphAtlas::Type GetAtlasType() const;
Expand All @@ -71,7 +83,8 @@ class TextFrame {
private:
std::vector<TextRun> runs_;
Rect bounds_;
bool has_color_ = false;
bool has_color_;
Color color_;
};

} // namespace impeller
Expand Down
73 changes: 73 additions & 0 deletions impeller/typographer/typographer_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "display_list/dl_color.h"
#include "flutter/display_list/testing/dl_test_snippets.h"
#include "flutter/testing/testing.h"
#include "gtest/gtest.h"
Expand All @@ -10,6 +11,7 @@
#include "impeller/playground/playground_test.h"
#include "impeller/typographer/backends/skia/text_frame_skia.h"
#include "impeller/typographer/backends/skia/typographer_context_skia.h"
#include "impeller/typographer/font_glyph_pair.h"
#include "impeller/typographer/lazy_glyph_atlas.h"
#include "impeller/typographer/rectangle_packer.h"
#include "third_party/skia/include/core/SkFont.h"
Expand Down Expand Up @@ -42,6 +44,22 @@ static std::shared_ptr<GlyphAtlas> CreateGlyphAtlas(
atlas_context, font_glyph_map);
}

static std::shared_ptr<GlyphAtlas> CreateGlyphAtlas(
Context& context,
const TypographerContext* typographer_context,
HostBuffer& host_buffer,
GlyphAtlas::Type type,
Scalar scale,
const std::shared_ptr<GlyphAtlasContext>& atlas_context,
const std::vector<std::shared_ptr<TextFrame>>& frames) {
FontGlyphMap font_glyph_map;
for (auto& frame : frames) {
frame->CollectUniqueFontGlyphPairs(font_glyph_map, scale);
}
return typographer_context->CreateGlyphAtlas(context, type, host_buffer,
atlas_context, font_glyph_map);
}

TEST_P(TypographerTest, CanConvertTextBlob) {
SkFont font = flutter::testing::CreateTestFontOfSize(12);
auto blob = SkTextBlob::MakeFromString(
Expand Down Expand Up @@ -281,6 +299,61 @@ TEST_P(TypographerTest, MaybeHasOverlapping) {
ASSERT_FALSE(frame_2->MaybeHasOverlapping());
}

TEST_P(TypographerTest, GlyphColorIsPartOfCacheKey) {
auto host_buffer = HostBuffer::Create(GetContext()->GetResourceAllocator());
#if FML_OS_MACOSX
auto mapping = flutter::testing::OpenFixtureAsSkData("Apple Color Emoji.ttc");
#else
auto mapping = flutter::testing::OpenFixtureAsSkData("NotoColorEmoji.ttf");
#endif
ASSERT_TRUE(mapping);
sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
SkFont emoji_font(font_mgr->makeFromData(mapping), 50.0);

auto context = TypographerContextSkia::Make();
auto atlas_context =
context->CreateGlyphAtlasContext(GlyphAtlas::Type::kColorBitmap);

// Create two frames with the same character and a different color, expect
// that it adds a character.
auto frame = MakeTextFrameFromTextBlobSkia(
SkTextBlob::MakeFromString("😂", emoji_font), flutter::DlColor::kCyan());
auto frame_2 = MakeTextFrameFromTextBlobSkia(
SkTextBlob::MakeFromString("😂", emoji_font),
flutter::DlColor::kMagenta());

auto next_atlas = CreateGlyphAtlas(*GetContext(), context.get(), *host_buffer,
GlyphAtlas::Type::kColorBitmap, 1.0f,
atlas_context, {frame, frame_2});

EXPECT_EQ(next_atlas->GetGlyphCount(), 2u);
}

TEST_P(TypographerTest, GlyphColorIsIgnoredForNonEmojiFonts) {
auto host_buffer = HostBuffer::Create(GetContext()->GetResourceAllocator());
sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
sk_sp<SkTypeface> typeface =
font_mgr->matchFamilyStyle("Arial", SkFontStyle::Normal());
SkFont sk_font(typeface, 0.5f);

auto context = TypographerContextSkia::Make();
auto atlas_context =
context->CreateGlyphAtlasContext(GlyphAtlas::Type::kColorBitmap);

// Create two frames with the same character and a different color, but as a
// non-emoji font the text frame constructor will ignore it.
auto frame = MakeTextFrameFromTextBlobSkia(
SkTextBlob::MakeFromString("A", sk_font), flutter::DlColor::kCyan());
auto frame_2 = MakeTextFrameFromTextBlobSkia(
SkTextBlob::MakeFromString("A", sk_font), flutter::DlColor::kMagenta());

auto next_atlas = CreateGlyphAtlas(*GetContext(), context.get(), *host_buffer,
GlyphAtlas::Type::kColorBitmap, 1.0f,
atlas_context, {frame, frame_2});

EXPECT_EQ(next_atlas->GetGlyphCount(), 1u);
}

TEST_P(TypographerTest, RectanglePackerAddsNonoverlapingRectangles) {
auto packer = RectanglePacker::Factory(200, 100);
ASSERT_NE(packer, nullptr);
Expand Down
4 changes: 2 additions & 2 deletions third_party/txt/src/skia/paragraph_skia.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class DisplayListParagraphPainter : public skt::ParagraphPainter {
return;
}

builder_->DrawTextFrame(impeller::MakeTextFrameFromTextBlobSkia(blob), x,
builder_->DrawTextFrame(impeller::MakeTextFrameFromTextBlobSkia(blob, dl_paints_[paint_id].getColor()), x,
y, dl_paints_[paint_id]);
return;
}
Expand All @@ -116,7 +116,7 @@ class DisplayListParagraphPainter : public skt::ParagraphPainter {
paint.setMaskFilter(&filter);
}
if (impeller_enabled_) {
builder_->DrawTextFrame(impeller::MakeTextFrameFromTextBlobSkia(blob), x,
builder_->DrawTextFrame(impeller::MakeTextFrameFromTextBlobSkia(blob, paint.getColor()), x,
y, paint);
return;
}
Expand Down