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
17 changes: 12 additions & 5 deletions impeller/entity/contents/text_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "impeller/entity/contents/text_contents.h"

#include <iostream>
#include <optional>

#include "impeller/entity/contents/content_context.h"
Expand Down Expand Up @@ -89,16 +90,19 @@ bool TextContents::Render(const ContentContext& renderer,
VS::FrameInfo frame_info;
frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
entity.GetTransformation();
frame_info.atlas_size =
Point{static_cast<Scalar>(atlas->GetTexture()->GetSize().width),
static_cast<Scalar>(atlas->GetTexture()->GetSize().height)};
frame_info.text_color = ToVector(color_.Premultiply());
VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info));

SamplerDescriptor sampler_desc;
sampler_desc.min_filter = MinMagFilter::kLinear;
sampler_desc.mag_filter = MinMagFilter::kLinear;

FS::FragInfo frag_info;
frag_info.text_color = ToVector(color_.Premultiply());
frag_info.atlas_size =
Point{static_cast<Scalar>(atlas->GetTexture()->GetSize().width),
static_cast<Scalar>(atlas->GetTexture()->GetSize().height)};
FS::BindFragInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frag_info));

// Common fragment uniforms for all glyphs.
FS::BindGlyphAtlasSampler(
cmd, // command
Expand All @@ -123,11 +127,13 @@ bool TextContents::Render(const ContentContext& renderer,
auto font = run.GetFont();
auto glyph_size = ISize::Ceil(font.GetMetrics().GetBoundingBox().size);
for (const auto& glyph_position : run.GetGlyphPositions()) {
FontGlyphPair font_glyph_pair{font, glyph_position.glyph};
auto color_glyph =
atlas->IsColorFontGlyphPair(font_glyph_pair) ? 1.0 : 0.0;
for (const auto& point : unit_vertex_points) {
VS::PerVertexData vtx;
vtx.unit_vertex = point;

FontGlyphPair font_glyph_pair{font, glyph_position.glyph};
auto atlas_glyph_pos = atlas->FindFontGlyphPosition(font_glyph_pair);
if (!atlas_glyph_pos.has_value()) {
VALIDATION_LOG << "Could not find glyph position in the atlas.";
Expand All @@ -143,6 +149,7 @@ bool TextContents::Render(const ContentContext& renderer,
1 / atlas_glyph_pos->size.height};
vtx.atlas_glyph_size =
Point{atlas_glyph_pos->size.width, atlas_glyph_pos->size.height};
vtx.color_glyph = color_glyph;
vertex_builder.AppendVertex(std::move(vtx));
}
}
Expand Down
29 changes: 20 additions & 9 deletions impeller/entity/shaders/glyph_atlas.frag
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,31 @@

uniform sampler2D glyph_atlas_sampler;

uniform FragInfo {
vec2 atlas_size;
vec4 text_color;
float font_has_color;
} frag_info;

in vec2 v_unit_vertex;
in vec2 v_atlas_position;
in vec2 v_atlas_glyph_size;
in vec2 v_atlas_size;
in vec4 v_text_color;
in float v_color_glyph;

out vec4 frag_color;

void main() {
vec2 scale_perspective = v_atlas_glyph_size / v_atlas_size;
vec2 offset = v_atlas_position / v_atlas_size;

frag_color = texture(
glyph_atlas_sampler,
v_unit_vertex * scale_perspective + offset
).aaaa * v_text_color;
vec2 scale_perspective = v_atlas_glyph_size / frag_info.atlas_size;
vec2 offset = v_atlas_position / frag_info.atlas_size;
if (v_color_glyph == 1.0) {
frag_color = texture(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need to ignore text color if we're using a bitmap font or colr font

glyph_atlas_sampler,
v_unit_vertex * scale_perspective + offset
);
} else {
frag_color = texture(
glyph_atlas_sampler,
v_unit_vertex * scale_perspective + offset
).aaaa * frag_info.text_color;
}
}
9 changes: 3 additions & 6 deletions impeller/entity/shaders/glyph_atlas.vert
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,19 @@

uniform FrameInfo {
mat4 mvp;
vec2 atlas_size;
vec4 text_color;
} frame_info;

in vec2 unit_vertex;
in vec2 glyph_position;
in vec2 glyph_size;
in vec2 atlas_position;
in vec2 atlas_glyph_size;
in float color_glyph;

out vec2 v_unit_vertex;
out vec2 v_atlas_position;
out vec2 v_atlas_glyph_size;
out vec2 v_atlas_size;
out vec4 v_text_color;
out float v_color_glyph;

void main() {
vec4 translate = frame_info.mvp[0] * glyph_position.x
Expand All @@ -40,6 +38,5 @@ void main() {
v_unit_vertex = unit_vertex;
v_atlas_position = atlas_position;
v_atlas_glyph_size = atlas_glyph_size;
v_atlas_size = frame_info.atlas_size;
v_text_color = frame_info.text_color;
v_color_glyph = color_glyph;
}
42 changes: 28 additions & 14 deletions impeller/typographer/backends/skia/text_render_context_skia.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
#include "third_party/skia/include/core/SkFontMetrics.h"
#include "third_party/skia/include/core/SkRSXform.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/src/core/SkIPoint16.h" //nogncheck
#include "third_party/skia/src/gpu/GrRectanizer.h" //nogncheck
#include "third_party/skia/src/core/SkIPoint16.h" //nogncheck
#include "third_party/skia/src/core/SkStrikeSpec.h" // nogncheck
#include "third_party/skia/src/gpu/GrRectanizer.h" //nogncheck

namespace impeller {

Expand Down Expand Up @@ -107,7 +108,9 @@ static std::shared_ptr<SkBitmap> CreateAtlasBitmap(const GlyphAtlas& atlas,
size_t atlas_size) {
TRACE_EVENT0("impeller", __FUNCTION__);
auto bitmap = std::make_shared<SkBitmap>();
auto image_info = SkImageInfo::MakeA8(atlas_size, atlas_size);
auto image_info = atlas.ContainsColorGlyph()
? SkImageInfo::MakeN32Premul(atlas_size, atlas_size)
: SkImageInfo::MakeA8(atlas_size, atlas_size);
if (!bitmap->tryAllocPixels(image_info)) {
return nullptr;
}
Expand All @@ -122,24 +125,21 @@ static std::shared_ptr<SkBitmap> CreateAtlasBitmap(const GlyphAtlas& atlas,

atlas.IterateGlyphs([canvas](const FontGlyphPair& font_glyph,
const Rect& location) -> bool {
const auto position =
SkPoint::Make(location.origin.x / font_glyph.font.GetMetrics().scale,
location.origin.y / font_glyph.font.GetMetrics().scale);
const auto& metrics = font_glyph.font.GetMetrics();
const auto position = SkPoint::Make(location.origin.x / metrics.scale,
location.origin.y / metrics.scale);
SkGlyphID glyph_id = font_glyph.glyph.index;

SkFont sk_font(
TypefaceSkia::Cast(*font_glyph.font.GetTypeface()).GetSkiaTypeface(),
font_glyph.font.GetMetrics().point_size);

const auto& metrics = font_glyph.font.GetMetrics();
metrics.point_size);

auto glyph_color = SK_ColorWHITE;

SkPaint glyph_paint;
glyph_paint.setColor(glyph_color);
canvas->resetMatrix();
canvas->scale(font_glyph.font.GetMetrics().scale,
font_glyph.font.GetMetrics().scale);
canvas->scale(metrics.scale, metrics.scale);
canvas->drawGlyphs(1u, // count
&glyph_id, // glyphs
&position, // positions
Expand All @@ -157,7 +157,8 @@ static std::shared_ptr<SkBitmap> CreateAtlasBitmap(const GlyphAtlas& atlas,
static std::shared_ptr<Texture> UploadGlyphTextureAtlas(
std::shared_ptr<Allocator> allocator,
std::shared_ptr<SkBitmap> bitmap,
size_t atlas_size) {
size_t atlas_size,
PixelFormat format) {
TRACE_EVENT0("impeller", __FUNCTION__);
if (!allocator) {
return nullptr;
Expand All @@ -168,7 +169,7 @@ static std::shared_ptr<Texture> UploadGlyphTextureAtlas(

TextureDescriptor texture_descriptor;
texture_descriptor.storage_mode = StorageMode::kHostVisible;
texture_descriptor.format = PixelFormat::kA8UNormInt;
texture_descriptor.format = format;
texture_descriptor.size = ISize::MakeWH(atlas_size, atlas_size);

if (pixmap.rowBytes() * pixmap.height() !=
Expand Down Expand Up @@ -202,6 +203,16 @@ std::shared_ptr<GlyphAtlas> TextRenderContextSkia::CreateGlyphAtlas(
}

auto glyph_atlas = std::make_shared<GlyphAtlas>();
glyph_atlas->SetFontColorCallback([](const FontGlyphPair& font_glyph) {
// TODO(jonahwilliams): ask Skia for a public API to look this up.
SkFont sk_font(
TypefaceSkia::Cast(*font_glyph.font.GetTypeface()).GetSkiaTypeface(),
font_glyph.font.GetMetrics().point_size);

SkStrikeSpec strikeSpec = SkStrikeSpec::MakeWithNoDevice(sk_font);
SkBulkGlyphMetricsAndPaths paths{strikeSpec};
return paths.glyph(font_glyph.glyph.index)->isColor();
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: file an issue and a TODO here to use some public API from Skia for this.

also nit: maybe this belongs on impeller's Glyph type.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Todo added. I agree this could probably be refactored. Lets see what we need to do for SDF and large glyphs.

});

// ---------------------------------------------------------------------------
// Step 1: Collect unique font-glyph pairs in the frame.
Expand Down Expand Up @@ -251,8 +262,11 @@ std::shared_ptr<GlyphAtlas> TextRenderContextSkia::CreateGlyphAtlas(
// ---------------------------------------------------------------------------
// Step 6: Upload the atlas as a texture.
// ---------------------------------------------------------------------------
auto format = glyph_atlas->ContainsColorGlyph()
? PixelFormat::kR8G8B8A8UNormInt
: PixelFormat::kA8UNormInt;
auto texture = UploadGlyphTextureAtlas(GetContext()->GetResourceAllocator(),
bitmap, atlas_size);
bitmap, atlas_size, format);
if (!texture) {
return nullptr;
}
Expand Down
24 changes: 24 additions & 0 deletions impeller/typographer/glyph_atlas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

#include "impeller/typographer/glyph_atlas.h"
#include <iostream>

namespace impeller {

Expand All @@ -14,6 +15,10 @@ bool GlyphAtlas::IsValid() const {
return !!texture_;
}

bool GlyphAtlas::ContainsColorGlyph() const {
return has_color_glyph;
}

const std::shared_ptr<Texture>& GlyphAtlas::GetTexture() const {
return texture_;
}
Expand All @@ -23,9 +28,28 @@ void GlyphAtlas::SetTexture(std::shared_ptr<Texture> texture) {
}

void GlyphAtlas::AddTypefaceGlyphPosition(FontGlyphPair pair, Rect rect) {
if (callback_.has_value()) {
auto has_color = callback_.value()(pair);
has_color_glyph |= has_color;
colors_[pair] = has_color;
}

positions_[pair] = rect;
}

void GlyphAtlas::SetFontColorCallback(
std::function<bool(const FontGlyphPair& pair)> callback) {
callback_ = std::move(callback);
}

bool GlyphAtlas::IsColorFontGlyphPair(const FontGlyphPair& pair) const {
auto found = colors_.find(pair);
if (found == colors_.end()) {
return false;
}
return found->second;
}

std::optional<Rect> GlyphAtlas::FindFontGlyphPosition(
const FontGlyphPair& pair) const {
auto found = positions_.find(pair);
Expand Down
27 changes: 27 additions & 0 deletions impeller/typographer/glyph_atlas.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,32 @@ class GlyphAtlas {

bool IsValid() const;

//----------------------------------------------------------------------------
/// @brief Whether at least one font-glyph pair has colors.
///
bool ContainsColorGlyph() const;

//----------------------------------------------------------------------------
/// @brief Set the texture for the glyph atlas.
///
/// @param[in] texture The texture
///
void SetTexture(std::shared_ptr<Texture> texture);

//----------------------------------------------------------------------------
/// @brief Set a callback that determines if a glyph-font pair
/// has color.
///
/// @param[in] callback The callback
///
void SetFontColorCallback(
std::function<bool(const FontGlyphPair& pair)> callback);

//----------------------------------------------------------------------------
/// @brief Whether the provided glyph-font pair contains color.
///
bool IsColorFontGlyphPair(const FontGlyphPair& pair) const;

//----------------------------------------------------------------------------
/// @brief Get the texture for the glyph atlas.
///
Expand Down Expand Up @@ -86,13 +105,21 @@ class GlyphAtlas {

private:
std::shared_ptr<Texture> texture_;
std::optional<std::function<bool(const FontGlyphPair& pair)>> callback_;
bool has_color_glyph = false;

std::unordered_map<FontGlyphPair,
Rect,
FontGlyphPair::Hash,
FontGlyphPair::Equal>
positions_;

std::unordered_map<FontGlyphPair,
bool,
FontGlyphPair::Hash,
FontGlyphPair::Equal>
colors_;

FML_DISALLOW_COPY_AND_ASSIGN(GlyphAtlas);
};

Expand Down
1 change: 1 addition & 0 deletions impeller/typographer/typographer_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ TEST_P(TypographerTest, CanCreateGlyphAtlas) {
ASSERT_TRUE(blob);
auto atlas = context->CreateGlyphAtlas(TextFrameFromTextBlob(blob));
ASSERT_NE(atlas, nullptr);
ASSERT_FALSE(atlas->ContainsColorGlyph());
OpenPlaygroundHere([](RenderTarget&) { return true; });
}

Expand Down