Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[Impeller] support for foreground shaders on text #40193

Merged
merged 7 commits into from
Mar 13, 2023
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
4 changes: 4 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,8 @@ ORIGIN: ../../../flutter/impeller/entity/contents/clip_contents.cc + ../../../fl
ORIGIN: ../../../flutter/impeller/entity/contents/clip_contents.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/color_source_contents.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/color_source_contents.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/color_source_text_contents.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/color_source_text_contents.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/content_context.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/content_context.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/contents.cc + ../../../flutter/LICENSE
Expand Down Expand Up @@ -3655,6 +3657,8 @@ FILE: ../../../flutter/impeller/entity/contents/clip_contents.cc
FILE: ../../../flutter/impeller/entity/contents/clip_contents.h
FILE: ../../../flutter/impeller/entity/contents/color_source_contents.cc
FILE: ../../../flutter/impeller/entity/contents/color_source_contents.h
FILE: ../../../flutter/impeller/entity/contents/color_source_text_contents.cc
FILE: ../../../flutter/impeller/entity/contents/color_source_text_contents.h
FILE: ../../../flutter/impeller/entity/contents/content_context.cc
FILE: ../../../flutter/impeller/entity/contents/content_context.h
FILE: ../../../flutter/impeller/entity/contents/contents.cc
Expand Down
31 changes: 28 additions & 3 deletions impeller/aiks/canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "impeller/aiks/paint_pass_delegate.h"
#include "impeller/entity/contents/atlas_contents.h"
#include "impeller/entity/contents/clip_contents.h"
#include "impeller/entity/contents/color_source_text_contents.h"
#include "impeller/entity/contents/rrect_shadow_contents.h"
#include "impeller/entity/contents/text_contents.h"
#include "impeller/entity/contents/texture_contents.h"
Expand Down Expand Up @@ -380,16 +381,40 @@ void Canvas::DrawTextFrame(const TextFrame& text_frame,
const Paint& paint) {
lazy_glyph_atlas_->AddTextFrame(text_frame);

Entity entity;
entity.SetStencilDepth(GetStencilDepth());
entity.SetBlendMode(paint.blend_mode);

auto text_contents = std::make_shared<TextContents>();
text_contents->SetTextFrame(text_frame);
text_contents->SetGlyphAtlas(lazy_glyph_atlas_);

if (paint.color_source.has_value()) {
auto& source = paint.color_source.value();
auto color_text_contents = std::make_shared<ColorSourceTextContents>();
entity.SetTransformation(GetCurrentTransformation());

Entity test;
auto cvg = text_contents->GetCoverage(test).value();
color_text_contents->SetTextPosition(cvg.origin + position);

text_contents->SetInverseMatrix(
Matrix::MakeTranslation(Vector3(-cvg.origin.x, -cvg.origin.y, 0)));
Copy link
Member

Choose a reason for hiding this comment

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

Rather than creating a new parameter, just amend this matrix to the entity transform?

color_text_contents->SetTextContents(std::move(text_contents));
color_text_contents->SetColorSourceContents(source());

entity.SetContents(
paint.WithFilters(std::move(color_text_contents), false));

GetCurrentPass().AddEntity(entity);
return;
}

text_contents->SetColor(paint.color);

Entity entity;
entity.SetTransformation(GetCurrentTransformation() *
Matrix::MakeTranslation(position));
entity.SetStencilDepth(GetStencilDepth());
entity.SetBlendMode(paint.blend_mode);

entity.SetContents(paint.WithFilters(std::move(text_contents), true));

GetCurrentPass().AddEntity(entity);
Expand Down
19 changes: 19 additions & 0 deletions impeller/display_list/display_list_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,25 @@ TEST_P(DisplayListTest, CanDrawTextBlob) {
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}

TEST_P(DisplayListTest, CanDrawTextBlobWithGradient) {
flutter::DisplayListBuilder builder;

std::vector<flutter::DlColor> colors = {flutter::DlColor::kBlue(),
flutter::DlColor::kRed()};
const float stops[2] = {0.0, 1.0};

auto linear = flutter::DlColorSource::MakeLinear({0.0, 0.0}, {300.0, 300.0},
2, colors.data(), stops,
flutter::DlTileMode::kClamp);
flutter::DlPaint paint;
paint.setColorSource(linear);

builder.DrawTextBlob(
SkTextBlob::MakeFromString("Hello World", CreateTestFont()), 100, 100,
paint);
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}

TEST_P(DisplayListTest, CanDrawTextWithSaveLayer) {
flutter::DisplayListBuilder builder;
builder.setColor(SK_ColorRED);
Expand Down
2 changes: 2 additions & 0 deletions impeller/entity/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ impeller_component("entity") {
"contents/clip_contents.h",
"contents/color_source_contents.cc",
"contents/color_source_contents.h",
"contents/color_source_text_contents.cc",
"contents/color_source_text_contents.h",
"contents/content_context.cc",
"contents/content_context.h",
"contents/contents.cc",
Expand Down
4 changes: 2 additions & 2 deletions impeller/entity/contents/color_source_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class ColorSourceContents : public Contents {

void SetEffectTransform(Matrix matrix);

const Matrix& GetInverseMatrix() const;

void SetAlpha(Scalar alpha);

// |Contents|
Expand All @@ -34,8 +36,6 @@ class ColorSourceContents : public Contents {
protected:
const std::shared_ptr<Geometry>& GetGeometry() const;

const Matrix& GetInverseMatrix() const;

Scalar GetAlpha() const;

private:
Expand Down
84 changes: 84 additions & 0 deletions impeller/entity/contents/color_source_text_contents.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// 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/entity/contents/color_source_text_contents.h"

#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/contents/texture_contents.h"
#include "impeller/renderer/render_pass.h"

namespace impeller {

ColorSourceTextContents::ColorSourceTextContents() = default;

ColorSourceTextContents::~ColorSourceTextContents() = default;

void ColorSourceTextContents::SetTextContents(
std::shared_ptr<TextContents> text_contents) {
text_contents_ = std::move(text_contents);
}

void ColorSourceTextContents::SetColorSourceContents(
std::shared_ptr<ColorSourceContents> color_source_contents) {
color_source_contents_ = std::move(color_source_contents);
}

std::optional<Rect> ColorSourceTextContents::GetCoverage(
const Entity& entity) const {
return text_contents_->GetCoverage(entity);
}

void ColorSourceTextContents::SetTextPosition(Point position) {
position_ = position;
}

bool ColorSourceTextContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
auto coverage = text_contents_->GetCoverage(entity);
if (!coverage.has_value()) {
return true;
}
auto transform = entity.GetTransformation();

text_contents_->SetColor(Color::Black());
color_source_contents_->SetGeometry(
Geometry::MakeRect(Rect::MakeSize(coverage->size)));

// offset the color source so it behaves as if it were drawn in the original
// position.
auto effect_transform =
color_source_contents_->GetInverseMatrix().Invert().Translate(-position_);
color_source_contents_->SetEffectTransform(effect_transform);

auto new_texture = renderer.MakeSubpass(
"Text Color Blending", ISize::Ceil(coverage.value().size),
[&](const ContentContext& context, RenderPass& pass) {
Entity sub_entity;
sub_entity.SetTransformation(transform);
sub_entity.SetContents(text_contents_);
sub_entity.SetBlendMode(BlendMode::kSource);
if (!sub_entity.Render(context, pass)) {
return false;
}

sub_entity.SetContents(color_source_contents_);
sub_entity.SetBlendMode(BlendMode::kSourceIn);
return sub_entity.Render(context, pass);
});
if (!new_texture) {
return false;
}

auto dest_rect = Rect::MakeSize(new_texture->GetSize())
.TransformBounds(transform.Invert())
.Shift(position_);

auto texture_contents = TextureContents::MakeRect(dest_rect);
texture_contents->SetTexture(new_texture);
texture_contents->SetSourceRect(Rect::MakeSize(new_texture->GetSize()));
return texture_contents->Render(renderer, entity, pass);
}

} // namespace impeller
48 changes: 48 additions & 0 deletions impeller/entity/contents/color_source_text_contents.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// 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 <functional>
#include <memory>
#include <variant>
#include <vector>

#include "flutter/fml/macros.h"
#include "impeller/entity/contents/color_source_contents.h"
#include "impeller/entity/contents/contents.h"
#include "impeller/entity/contents/text_contents.h"

namespace impeller {

class ColorSourceTextContents final : public Contents {
public:
ColorSourceTextContents();

~ColorSourceTextContents();

void SetTextContents(std::shared_ptr<TextContents> text_contents);

void SetColorSourceContents(
std::shared_ptr<ColorSourceContents> color_source_contents);

void SetTextPosition(Point position);

// |Contents|
std::optional<Rect> GetCoverage(const Entity& entity) const override;

// |Contents|
bool Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const override;

private:
Point position_;
std::shared_ptr<TextContents> text_contents_;
std::shared_ptr<ColorSourceContents> color_source_contents_;

FML_DISALLOW_COPY_AND_ASSIGN(ColorSourceTextContents);
};

} // namespace impeller
17 changes: 12 additions & 5 deletions impeller/entity/contents/text_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ void TextContents::SetColor(Color color) {
color_ = color;
}

void TextContents::SetInverseMatrix(Matrix matrix) {
inverse_matrix_ = matrix;
}

std::optional<Rect> TextContents::GetCoverage(const Entity& entity) const {
auto bounds = frame_.GetBounds();
if (!bounds.has_value()) {
Expand All @@ -71,6 +75,7 @@ static bool CommonRender(
RenderPass& pass,
const Color& color,
const TextFrame& frame,
const Matrix& inverse_matrix,
std::shared_ptr<GlyphAtlas>
atlas, // NOLINT(performance-unnecessary-value-param)
Command& cmd) {
Expand Down Expand Up @@ -159,8 +164,10 @@ static bool CommonRender(

auto uv_scaler_a = atlas_glyph_pos->size / atlas_size;
auto uv_scaler_b = (Point::Round(atlas_glyph_pos->origin) / atlas_size);
auto translation = Matrix::MakeTranslation(
Vector3(offset_glyph_position.x, offset_glyph_position.y, 0));
auto translation =
Matrix::MakeTranslation(
Vector3(offset_glyph_position.x, offset_glyph_position.y, 0)) *
inverse_matrix;

for (const auto& point : unit_points) {
typename VS::PerVertexData vtx;
Expand Down Expand Up @@ -209,8 +216,8 @@ bool TextContents::RenderSdf(const ContentContext& renderer,
cmd.pipeline = renderer.GetGlyphAtlasSdfPipeline(opts);
cmd.stencil_reference = entity.GetStencilDepth();

return CommonRender<GlyphAtlasSdfPipeline>(renderer, entity, pass, color_,
frame_, atlas, cmd);
return CommonRender<GlyphAtlasSdfPipeline>(
renderer, entity, pass, color_, frame_, inverse_matrix_, atlas, cmd);
}

bool TextContents::Render(const ContentContext& renderer,
Expand Down Expand Up @@ -245,7 +252,7 @@ bool TextContents::Render(const ContentContext& renderer,
cmd.stencil_reference = entity.GetStencilDepth();

return CommonRender<GlyphAtlasPipeline>(renderer, entity, pass, color_,
frame_, atlas, cmd);
frame_, inverse_matrix_, atlas, cmd);
}

} // namespace impeller
3 changes: 3 additions & 0 deletions impeller/entity/contents/text_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ class TextContents final : public Contents {

void SetColor(Color color);

void SetInverseMatrix(Matrix matrix);

// |Contents|
std::optional<Rect> GetCoverage(const Entity& entity) const override;

Expand All @@ -49,6 +51,7 @@ class TextContents final : public Contents {
TextFrame frame_;
Color color_;
mutable std::shared_ptr<LazyGlyphAtlas> lazy_atlas_;
Matrix inverse_matrix_;

std::shared_ptr<GlyphAtlas> ResolveAtlas(
GlyphAtlas::Type type,
Expand Down
7 changes: 7 additions & 0 deletions impeller/geometry/geometry_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1646,6 +1646,13 @@ TEST(GeometryTest, RectGetPoints) {
ASSERT_POINT_NEAR(points[3], Point(400, 600));
}

TEST(GeometryTest, RectShift) {
auto r = Rect::MakeLTRB(0, 0, 100, 100);

ASSERT_EQ(r.Shift(Point(10, 5)), Rect::MakeLTRB(10, 5, 110, 105));
ASSERT_EQ(r.Shift(Point(-10, -5)), Rect::MakeLTRB(-10, -5, 90, 95));
}

TEST(GeometryTest, RectGetTransformedPoints) {
Rect r(100, 200, 300, 400);
auto points = r.GetTransformedPoints(Matrix::MakeTranslation({10, 20}));
Expand Down
6 changes: 6 additions & 0 deletions impeller/geometry/rect.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,12 @@ struct TRect {

return *this;
}

/// @brief Returns a new rectangle translated by the given offset.
constexpr TRect<T> Shift(TPoint<T> offset) const {
return TRect(origin.x + offset.x, origin.y + offset.y, size.width,
size.height);
}
};

using Rect = TRect<Scalar>;
Expand Down