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: 16 additions & 1 deletion impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#include "impeller/aiks/color_filter.h"
#include "impeller/aiks/image.h"
#include "impeller/aiks/image_filter.h"
#include "impeller/aiks/paint_pass_delegate.h"
#include "impeller/aiks/testing/context_spy.h"
#include "impeller/core/device_buffer.h"
#include "impeller/entity/contents/solid_color_contents.h"
Expand Down Expand Up @@ -632,6 +631,7 @@ TEST_P(AiksTest, CanRenderRoundedRectWithNonUniformRadii) {
}

struct TextRenderOptions {
bool stroke = false;
Scalar font_size = 50;
Color color = Color::Yellow();
Point position = Vector2(100, 200);
Expand Down Expand Up @@ -671,6 +671,9 @@ bool RenderTextInCanvasSkia(const std::shared_ptr<Context>& context,
Paint text_paint;
text_paint.color = options.color;
text_paint.mask_blur_descriptor = options.mask_blur_descriptor;
text_paint.stroke_width = 1;
text_paint.style =
options.stroke ? Paint::Style::kStroke : Paint::Style::kFill;
canvas.DrawTextFrame(frame, options.position, text_paint);
return true;
}
Expand Down Expand Up @@ -714,6 +717,18 @@ TEST_P(AiksTest, CanRenderTextFrame) {
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, CanRenderStrokedTextFrame) {
Canvas canvas;
canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)});
ASSERT_TRUE(RenderTextInCanvasSkia(
GetContext(), canvas, "the quick brown fox jumped over the lazy dog!.?",
"Roboto-Regular.ttf",
{
.stroke = true,
}));
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, CanRenderTextFrameWithHalfScaling) {
Canvas canvas;
canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)});
Expand Down
9 changes: 8 additions & 1 deletion impeller/aiks/canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -889,9 +889,16 @@ void Canvas::DrawTextFrame(const std::shared_ptr<TextFrame>& text_frame,

auto text_contents = std::make_shared<TextContents>();
text_contents->SetTextFrame(text_frame);
text_contents->SetColor(paint.color);
text_contents->SetForceTextColor(paint.mask_blur_descriptor.has_value());
text_contents->SetOffset(position);
text_contents->SetColor(paint.color);
text_contents->SetTextProperties(paint.color, //
paint.style == Paint::Style::kStroke, //
paint.stroke_width, //
paint.stroke_cap, //
paint.stroke_join, //
paint.stroke_miter //
);

entity.SetTransform(GetCurrentTransform() *
Matrix::MakeTranslation(position));
Expand Down
9 changes: 8 additions & 1 deletion impeller/aiks/experimental_canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -388,9 +388,16 @@ void ExperimentalCanvas::DrawTextFrame(

auto text_contents = std::make_shared<TextContents>();
text_contents->SetTextFrame(text_frame);
text_contents->SetColor(paint.color);
text_contents->SetForceTextColor(paint.mask_blur_descriptor.has_value());
text_contents->SetScale(GetCurrentTransform().GetMaxBasisLengthXY());
text_contents->SetColor(paint.color);
text_contents->SetTextProperties(paint.color, //
paint.style == Paint::Style::kStroke, //
paint.stroke_width, //
paint.stroke_cap, //
paint.stroke_join, //
paint.stroke_miter //
);

entity.SetTransform(GetCurrentTransform() *
Matrix::MakeTranslation(position));
Expand Down
74 changes: 72 additions & 2 deletions impeller/display_list/dl_dispatcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "impeller/geometry/path_builder.h"
#include "impeller/geometry/scalar.h"
#include "impeller/geometry/sigma.h"
#include "impeller/typographer/font_glyph_pair.h"

#if IMPELLER_ENABLE_3D
#include "impeller/entity/contents/scene_contents.h"
Expand Down Expand Up @@ -1252,8 +1253,22 @@ void TextFrameDispatcher::drawTextFrame(
const std::shared_ptr<impeller::TextFrame>& text_frame,
SkScalar x,
SkScalar y) {
renderer_.GetLazyGlyphAtlas()->AddTextFrame(
*text_frame, matrix_.GetMaxBasisLengthXY(), Point(x, y));
GlyphProperties properties;
if (paint_.style == Paint::Style::kStroke) {
properties.stroke = true;
properties.stroke_cap = paint_.stroke_cap;
properties.stroke_join = paint_.stroke_join;
properties.stroke_miter = paint_.stroke_miter;
properties.stroke_width = paint_.stroke_width;
}
if (text_frame->HasColor()) {
properties.color = paint_.color;
}
renderer_.GetLazyGlyphAtlas()->AddTextFrame(*text_frame, //
matrix_.GetMaxBasisLengthXY(), //
Point(x, y), //
properties //
);
}

void TextFrameDispatcher::drawDisplayList(
Expand All @@ -1266,4 +1281,59 @@ void TextFrameDispatcher::drawDisplayList(
FML_DCHECK(stack_depth == stack_.size());
}

// |flutter::DlOpReceiver|
void TextFrameDispatcher::setDrawStyle(flutter::DlDrawStyle style) {
paint_.style = ToStyle(style);
}

// |flutter::DlOpReceiver|
void TextFrameDispatcher::setColor(flutter::DlColor color) {
paint_.color = {
color.getRedF(),
color.getGreenF(),
color.getBlueF(),
color.getAlphaF(),
};
}

// |flutter::DlOpReceiver|
void TextFrameDispatcher::setStrokeWidth(SkScalar width) {
paint_.stroke_width = width;
}

// |flutter::DlOpReceiver|
void TextFrameDispatcher::setStrokeMiter(SkScalar limit) {
paint_.stroke_miter = limit;
}

// |flutter::DlOpReceiver|
void TextFrameDispatcher::setStrokeCap(flutter::DlStrokeCap cap) {
switch (cap) {
case flutter::DlStrokeCap::kButt:
paint_.stroke_cap = Cap::kButt;
break;
case flutter::DlStrokeCap::kRound:
paint_.stroke_cap = Cap::kRound;
break;
case flutter::DlStrokeCap::kSquare:
paint_.stroke_cap = Cap::kSquare;
break;
}
}

// |flutter::DlOpReceiver|
void TextFrameDispatcher::setStrokeJoin(flutter::DlStrokeJoin join) {
switch (join) {
case flutter::DlStrokeJoin::kMiter:
paint_.stroke_join = Join::kMiter;
break;
case flutter::DlStrokeJoin::kRound:
paint_.stroke_join = Join::kRound;
break;
case flutter::DlStrokeJoin::kBevel:
paint_.stroke_join = Join::kBevel;
break;
}
}

} // namespace impeller
19 changes: 19 additions & 0 deletions impeller/display_list/dl_dispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -366,10 +366,29 @@ class TextFrameDispatcher : public flutter::IgnoreAttributeDispatchHelper,
void drawDisplayList(const sk_sp<flutter::DisplayList> display_list,
SkScalar opacity) override;

// |flutter::DlOpReceiver|
void setDrawStyle(flutter::DlDrawStyle style) override;

// |flutter::DlOpReceiver|
void setColor(flutter::DlColor color) override;

// |flutter::DlOpReceiver|
void setStrokeWidth(SkScalar width) override;

// |flutter::DlOpReceiver|
void setStrokeMiter(SkScalar limit) override;

// |flutter::DlOpReceiver|
void setStrokeCap(flutter::DlStrokeCap cap) override;

// |flutter::DlOpReceiver|
void setStrokeJoin(flutter::DlStrokeJoin join) override;

private:
const ContentContext& renderer_;
Matrix matrix_;
std::vector<Matrix> stack_;
Paint paint_;
};

} // namespace impeller
Expand Down
26 changes: 23 additions & 3 deletions impeller/entity/contents/text_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,30 @@ std::optional<Rect> TextContents::GetCoverage(const Entity& entity) const {
void TextContents::PopulateGlyphAtlas(
const std::shared_ptr<LazyGlyphAtlas>& lazy_glyph_atlas,
Scalar scale) {
lazy_glyph_atlas->AddTextFrame(*frame_, scale, offset_);
lazy_glyph_atlas->AddTextFrame(*frame_, scale, offset_, properties_);
scale_ = scale;
}

void TextContents::SetTextProperties(Color color,
bool stroke,
Scalar stroke_width,
Cap stroke_cap,
Join stroke_join,
Scalar stroke_miter) {
if (frame_->HasColor()) {
// Alpha is always applied when rendering, remove it here so
// we do not double-apply the alpha.
properties_.color = color.WithAlpha(1.0);
}
if (stroke) {
properties_.stroke = true;
properties_.stroke_width = stroke_width;
properties_.stroke_cap = stroke_cap;
properties_.stroke_join = stroke_join;
properties_.stroke_miter = stroke_miter;
}
}

bool TextContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
Expand Down Expand Up @@ -171,7 +191,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, frame_->GetColor());
atlas->GetFontGlyphAtlas(font, rounded_scale);
if (!font_atlas) {
VALIDATION_LOG << "Could not find font in the atlas.";
continue;
Expand Down Expand Up @@ -203,7 +223,7 @@ bool TextContents::Render(const ContentContext& renderer,
glyph_position, font.GetAxisAlignment(), offset_, scale_);
std::optional<std::pair<Rect, Rect>> maybe_atlas_glyph_bounds =
font_atlas->FindGlyphBounds(
SubpixelGlyph{glyph_position.glyph, subpixel});
SubpixelGlyph{glyph_position.glyph, subpixel, properties_});
if (!maybe_atlas_glyph_bounds.has_value()) {
VALIDATION_LOG << "Could not find glyph position in the atlas.";
continue;
Expand Down
13 changes: 11 additions & 2 deletions impeller/entity/contents/text_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

#include "impeller/entity/contents/contents.h"
#include "impeller/geometry/color.h"
#include "impeller/typographer/glyph_atlas.h"
#include "impeller/typographer/font_glyph_pair.h"
#include "impeller/typographer/text_frame.h"

namespace impeller {
Expand All @@ -33,6 +33,14 @@ class TextContents final : public Contents {
/// This is used to ensure that mask blurs work correctly on emoji.
void SetForceTextColor(bool value);

/// Must be set after text frame.
void SetTextProperties(Color color,
bool stroke,
Scalar stroke_width,
Cap stroke_cap,
Join stroke_join,
Scalar stroke_miter);

Color GetColor() const;

// |Contents|
Expand Down Expand Up @@ -64,10 +72,11 @@ class TextContents final : public Contents {
private:
std::shared_ptr<TextFrame> frame_;
Scalar scale_ = 1.0;
Color color_;
Scalar inherited_opacity_ = 1.0;
Vector2 offset_;
bool force_text_color_ = false;
Color color_;
GlyphProperties properties_;

TextContents(const TextContents&) = delete;

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

#include <vector>

#include "display_list/dl_color.h"
#include "flutter/fml/logging.h"
#include "impeller/typographer/backends/skia/typeface_skia.h"
#include "impeller/typographer/font.h"
Expand Down Expand Up @@ -39,15 +38,6 @@ static AxisAlignment ToAxisAligment(SkAxisAlignment aligment) {
FML_UNREACHABLE();
}

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, AxisAlignment alignment) {
auto& font = run.font();
auto typeface = std::make_shared<TypefaceSkia>(font.refTypeface());
Expand All @@ -69,10 +59,8 @@ static Rect ToRect(const SkRect& rect) {
}

std::shared_ptr<TextFrame> MakeTextFrameFromTextBlobSkia(
const sk_sp<SkTextBlob>& blob,
flutter::DlColor dl_color) {
const sk_sp<SkTextBlob>& blob) {
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 @@ -114,8 +102,7 @@ std::shared_ptr<TextFrame> MakeTextFrameFromTextBlobSkia(
continue;
}
}
return std::make_shared<TextFrame>(runs, ToRect(blob->bounds()), has_color,
has_color ? color : Color::Black());
return std::make_shared<TextFrame>(runs, ToRect(blob->bounds()), has_color);
}

} // namespace impeller
4 changes: 1 addition & 3 deletions impeller/typographer/backends/skia/text_frame_skia.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@
#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,
flutter::DlColor color = flutter::DlColor::kBlack());
const sk_sp<SkTextBlob>& blob);

} // namespace impeller

Expand Down
Loading