| Flutter Impeller |

Public Member Functions | Static Public Member Functions | List of all members
impeller::TextContents Class Referencefinal

`#include <text_contents.h>`

Inheritance diagram for impeller::TextContents:

## Public Member Functions
| TextContents ()
| ~TextContents ()
void | SetTextFrame (const std::shared_ptr< TextFrame > &frame)
void | SetColor (Color color)
void | SetForceTextColor (bool value)
| Force the text color to apply to the rendered glyphs, even if those glyphs are bitmaps. More...
void | SetTextProperties (Color color, bool stroke, Scalar stroke_width, Cap stroke_cap, Join stroke_join, Scalar stroke_miter)
| Must be set after text frame. More...
Color | GetColor () const
void | SetInheritedOpacity (Scalar opacity) override
| Inherit the provided opacity. More...
void | SetOffset (Vector2 offset)
std::optional< Rect > | GetTextFrameBounds () const
std::optional< Rect > | GetCoverage (const Entity &entity) const override
| Get the area of the render pass that will be affected when this contents is rendered. More...
void | SetScale (Scalar scale)
bool | Render (const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
Public Member Functions inherited from impeller::Contents
| Contents ()
virtual | ~Contents ()
void | SetCoverageHint (std::optional< Rect > coverage_hint)
| Hint that specifies the coverage area of this Contents that will actually be used during rendering. This is for optimization purposes only and can not be relied on as a clip. May optionally affect the result of `GetCoverage()`. More...
const std::optional< Rect > & | GetCoverageHint () const
virtual bool | IsOpaque (const Matrix &transform) const
| Whether this Contents only emits opaque source colors from the fragment stage. This value does not account for any entity properties (e.g. the blend mode), clips/visibility culling, or inherited opacity. More...
virtual std::optional< Snapshot > | RenderToSnapshot (const ContentContext &renderer, const Entity &entity, std::optional< Rect > coverage_limit=std::nullopt, const std::optional< SamplerDescriptor > &sampler_descriptor=std::nullopt, bool msaa_enabled=true, int32_t mip_count=1, std::string_view label="Snapshot") const
| Render this contents to a snapshot, respecting the entity's transform, path, clip depth, and blend mode. The result texture size is always the size of `GetCoverage(entity)`. More...
std::optional< Size > | GetColorSourceSize () const
| Return the color source's intrinsic size, if available. More...
void | SetColorSourceSize (Size size)
virtual std::optional< Color > | AsBackgroundColor (const Entity &entity, ISize target_size) const
| Returns a color if this Contents will flood the given `target_size` with a color. This output color is the "Source" color that will be used for the Entity's blend operation. More...
virtual bool | ApplyColorFilter (const ColorFilterProc &color_filter_proc)
| If possible, applies a color filter to this contents inputs on the CPU. More...

## Static Public Member Functions
static void | ComputeVertexData (GlyphAtlasPipeline::VertexShader::PerVertexData *vtx_contents, const std::shared_ptr< TextFrame > &frame, Scalar scale, const Matrix &entity_transform, Vector2 offset, std::optional< GlyphProperties > glyph_properties, const std::shared_ptr< GlyphAtlas > &atlas)
Static Public Member Functions inherited from impeller::Contents
static std::shared_ptr< Contents > | MakeAnonymous (RenderProc render_proc, CoverageProc coverage_proc)

## Additional Inherited Members
Public Types inherited from impeller::Contents
using | ColorFilterProc = std::function< Color(Color)>
using | RenderProc = std::function< bool(const ContentContext &renderer, const Entity &entity, RenderPass &pass)>
using | CoverageProc = std::function< std::optional< Rect >(const Entity &entity)>

## Detailed Description

Definition at line 21 of file text_contents.h.

## Constructor & Destructor Documentation

## ◆ TextContents()

impeller::TextContents::TextContents | ( |  | ) |
| default

## ◆ ~TextContents()

impeller::TextContents::~TextContents | ( |  | ) |
| default

## Member Function Documentation

## ◆ ComputeVertexData()

void impeller::TextContents::ComputeVertexData | ( | GlyphAtlasPipeline::VertexShader::PerVertexData * | vtx_contents,
|  | const std::shared_ptr< TextFrame > & | frame,
|  | Scalar | scale,
|  | const Matrix & | entity_transform,
|  | Vector2 | offset,
|  | std::optional< GlyphProperties > | glyph_properties,
|  | const std::shared_ptr< GlyphAtlas > & | atlas
| ) |  |
| static

Definition at line 80 of file text_contents.cc.

87 {
88 // Common vertex information for all glyphs.
89 // All glyphs are given the same vertex information in the form of a
90 // unit-sized quad. The size of the glyph is specified in per instance data
91 // and the vertex shader uses this to size the glyph correctly. The
92 // interpolated vertex information is also used in the fragment shader to
93 // sample from the glyph atlas.
94
95 constexpr std::array<Point, 6> unit_points = {Point{0, 0}, Point{1, 0},
96 Point{0, 1}, Point{1, 0},
97 Point{0, 1}, Point{1, 1}};
98
99 ISize atlas_size = atlas->GetTexture()->GetSize();
100 bool is_translation_scale = entity_transform.IsTranslationScaleOnly();
101 Matrix basis_transform = entity_transform.Basis();
102
103 VS::PerVertexData vtx;
104 size_t i = 0u;
105 size_t bounds_offset = 0u;
106 for (const TextRun& run : frame->GetRuns()) {
107 const Font& font = run.GetFont();
108 Scalar rounded_scale = TextFrame::RoundScaledFontSize(scale);
109 FontGlyphAtlas* font_atlas = nullptr;
110
111 // Adjust glyph position based on the subpixel rounding
112 // used by the font.
113 Point subpixel_adjustment(0.5, 0.5);
114 switch (font.GetAxisAlignment()) {
115 case AxisAlignment::kNone:
116 break;
117 case AxisAlignment::kX:
118 subpixel_adjustment.x = 0.125;
119 break;
120 case AxisAlignment::kY:
121 subpixel_adjustment.y = 0.125;
122 break;
123 case AxisAlignment::kAll:
124 subpixel_adjustment.x = 0.125;
125 subpixel_adjustment.y = 0.125;
126 break;
127 }
128
129 Point screen_offset = (entity_transform * Point(0, 0));
130 for (const TextRun::GlyphPosition& glyph_position :
131 run.GetGlyphPositions()) {
132 const FrameBounds& frame_bounds = frame->GetFrameBounds(bounds_offset);
133 bounds_offset++;
134 auto atlas_glyph_bounds = frame_bounds.atlas_bounds;
135 auto glyph_bounds = frame_bounds.glyph_bounds;
136
137 // If frame_bounds.is_placeholder is true, this is the first frame
138 // the glyph has been rendered and so its atlas position was not
139 // known when the glyph was recorded. Perform a slow lookup into the
140 // glyph atlas hash table.
141 if (frame_bounds.is_placeholder) {
142 if (!font_atlas) {
143 font_atlas =
144 atlas->GetOrCreateFontGlyphAtlas(ScaledFont{font, rounded_scale});
145 }
146
147 if (!font_atlas) {
148 VALIDATION_LOG << "Could not find font in the atlas.";
149 continue;
150 }
151 Point subpixel = TextFrame::ComputeSubpixelPosition(
152 glyph_position, font.GetAxisAlignment(), entity_transform);
153
154 std::optional<FrameBounds> maybe_atlas_glyph_bounds =
155 font_atlas->FindGlyphBounds(SubpixelGlyph{
156 glyph_position.glyph, //
157 subpixel, //
158 glyph_properties //
159 });
160 if (!maybe_atlas_glyph_bounds.has_value()) {
161 VALIDATION_LOG << "Could not find glyph position in the atlas.";
162 continue;
163 }
164 atlas_glyph_bounds = maybe_atlas_glyph_bounds.value().atlas_bounds;
165 }
166
167 Rect scaled_bounds = glyph_bounds.Scale(1.0 / rounded_scale);
168 // For each glyph, we compute two rectangles. One for the vertex
169 // positions and one for the texture coordinates (UVs). The atlas
170 // glyph bounds are used to compute UVs in cases where the
171 // destination and source sizes may differ due to clamping the sizes
172 // of large glyphs.
173 Point uv_origin = (atlas_glyph_bounds.GetLeftTop()) / atlas_size;
174 Point uv_size = SizeToPoint(atlas_glyph_bounds.GetSize()) / atlas_size;
175
176 Point unrounded_glyph_position =
177 // This is for RTL text.
178 (basis_transform.m[0] < 0 ? Matrix::MakeScale({-1, 1, 1})
179 : Matrix()) *
180 glyph_bounds.GetLeftTop() +
181 (basis_transform * glyph_position.position);
182
183 Point screen_glyph_position =
184 (screen_offset + unrounded_glyph_position + subpixel_adjustment)
185 .Floor();
186 for (const Point& point : unit_points) {
187 Point position;
188 if (is_translation_scale) {
189 position = (screen_glyph_position +
190 (basis_transform * point * scaled_bounds.GetSize()))
191 .Round();
192 } else {
193 position = entity_transform *
194 (glyph_position.position + scaled_bounds.GetLeftTop() +
195 point * scaled_bounds.GetSize());
196 }
197 vtx.uv = uv_origin + (uv_size * point);
198 vtx.position = position;
199 vtx_contents[i++] = vtx;
200 }
201 }
202 }
203 }

References impeller::FrameBounds::atlas_bounds, impeller::Matrix::Basis(), impeller::TextFrame::ComputeSubpixelPosition(), impeller::FontGlyphAtlas::FindGlyphBounds(), impeller::Font::GetAxisAlignment(), impeller::TRect< T >::GetLeftTop(), impeller::TRect< T >::GetSize(), impeller::SubpixelGlyph::glyph, impeller::FrameBounds::glyph_bounds, impeller::FrameBounds::is_placeholder, impeller::Matrix::IsTranslationScaleOnly(), impeller::kAll, impeller::kNone, impeller::kX, impeller::kY, impeller::Matrix::m, impeller::Matrix::MakeScale(), impeller::TPoint< T >::Round(), impeller::TextFrame::RoundScaledFontSize(), impeller::TRect< T >::Scale(), scale, impeller::SizeToPoint(), VALIDATION_LOG, vtx, impeller::TPoint< T >::x, and impeller::TPoint< T >::y.

Referenced by Render(), and impeller::testing::TEST_P().

## ◆ GetColor()

Color impeller::TextContents::GetColor | ( |  | ) | const

Definition at line 40 of file text_contents.cc.

40 {
41 return color_.WithAlpha(color_.alpha * inherited_opacity_);
42 }

References impeller::Color::alpha, and impeller::Color::WithAlpha().

Referenced by Render().

## ◆ GetCoverage()

std::optional< Rect > impeller::TextContents::GetCoverage | ( | const Entity & | entity | ) | const
| override virtual

Get the area of the render pass that will be affected when this contents is rendered.

During rendering, coverage coordinates count pixels from the top left corner of the framebuffer.

Returns
  The coverage rectangle. An `std::nullopt` result means that rendering this contents has no effect on the output color.

Implements impeller::Contents.

Definition at line 56 of file text_contents.cc.

56 {
57 return frame_->GetBounds().TransformBounds(entity.GetTransform());
58 }

References impeller::Entity::GetTransform().

## ◆ GetTextFrameBounds()

std::optional<Rect> impeller::TextContents::GetTextFrameBounds | ( |  | ) | const

## ◆ Render()

bool impeller::TextContents::Render | ( | const ContentContext & | renderer,
|  | const Entity & | entity,
|  | RenderPass & | pass
| ) |  | const
| override virtual

Implements impeller::Contents.

Definition at line 205 of file text_contents.cc.

207 {
208 auto color = GetColor();
209 if (color.IsTransparent()) {
210 return true;
211 }
212
213 auto type = frame_->GetAtlasType();
214 const std::shared_ptr<GlyphAtlas>& atlas =
215 renderer.GetLazyGlyphAtlas()->CreateOrGetGlyphAtlas(
216 *renderer.GetContext(), renderer.GetTransientsBuffer(), type);
217
218 if (!atlas || !atlas->IsValid()) {
219 VALIDATION_LOG << "Cannot render glyphs without prepared atlas.";
220 return false;
221 }
222 if (!frame_->IsFrameComplete()) {
223 VALIDATION_LOG << "Failed to find font glyph bounds.";
224 return false;
225 }
226
227 // Information shared by all glyph draw calls.
228 pass.SetCommandLabel("TextFrame");
229 auto opts = OptionsFromPassAndEntity(pass, entity);
230 opts.primitive_type = PrimitiveType::kTriangle;
231 pass.SetPipeline(renderer.GetGlyphAtlasPipeline(opts));
232
233 // Common vertex uniforms for all glyphs.
234 VS::FrameInfo frame_info;
235 frame_info.mvp =
236 Entity::GetShaderTransform(entity.GetShaderClipDepth(), pass, Matrix());
237 bool is_translation_scale = entity.GetTransform().IsTranslationScaleOnly();
238 Matrix entity_transform = entity.GetTransform();
239
240 VS::BindFrameInfo(pass,
241 renderer.GetTransientsBuffer().EmplaceUniform(frame_info));
242
243 FS::FragInfo frag_info;
244 frag_info.use_text_color = force_text_color_ ? 1.0 : 0.0;
245 frag_info.text_color = ToVector(color.Premultiply());
246 frag_info.is_color_glyph = type == GlyphAtlas::Type::kColorBitmap;
247
248 FS::BindFragInfo(pass,
249 renderer.GetTransientsBuffer().EmplaceUniform(frag_info));
250
251 SamplerDescriptor sampler_desc;
252 if (is_translation_scale) {
253 sampler_desc.min_filter = MinMagFilter::kNearest;
254 sampler_desc.mag_filter = MinMagFilter::kNearest;
255 } else {
256 // Currently, we only propagate the scale of the transform to the atlas
257 // renderer, so if the transform has more than just a translation, we turn
258 // on linear sampling to prevent crunchiness caused by the pixel grid not
259 // being perfectly aligned.
260 // The downside is that this slightly over-blurs rotated/skewed text.
261 sampler_desc.min_filter = MinMagFilter::kLinear;
262 sampler_desc.mag_filter = MinMagFilter::kLinear;
263 }
264
265 // No mipmaps for glyph atlas (glyphs are generated at exact scales).
266 sampler_desc.mip_filter = MipFilter::kBase;
267
268 FS::BindGlyphAtlasSampler(
269 pass, // command
270 atlas->GetTexture(), // texture
271 renderer.GetContext()->GetSamplerLibrary()->GetSampler(
272 sampler_desc) // sampler
273 );
274
275 auto& host_buffer = renderer.GetTransientsBuffer();
276 size_t vertex_count = 0;
277 for (const auto& run : frame_->GetRuns()) {
278 vertex_count += run.GetGlyphPositions().size();
279 }
280 vertex_count *= 6;
281
282 BufferView buffer_view = host_buffer.Emplace(
283 vertex_count * sizeof(VS::PerVertexData), alignof(VS::PerVertexData),
284 [&](uint8_t* contents) {
285 VS::PerVertexData* vtx_contents =
286 reinterpret_cast<VS::PerVertexData*>(contents);
287 ComputeVertexData(vtx_contents, frame_, scale_,
288 /*entity_transform=*/entity_transform, offset_,
289 GetGlyphProperties(), atlas);
290 });
291
292 pass.SetVertexBuffer(std::move(buffer_view));
293 pass.SetIndexBuffer({}, IndexType::kNone);
294 pass.SetElementCount(vertex_count);
295
296 return pass.Draw().ok();
297 }

References buffer_view, ComputeVertexData(), impeller::RenderPass::Draw(), impeller::HostBuffer::EmplaceUniform(), GetColor(), impeller::ContentContext::GetContext(), impeller::ContentContext::GetGlyphAtlasPipeline(), impeller::ContentContext::GetLazyGlyphAtlas(), impeller::Entity::GetShaderClipDepth(), impeller::Entity::GetShaderTransform(), impeller::Entity::GetTransform(), impeller::ContentContext::GetTransientsBuffer(), impeller::Matrix::IsTranslationScaleOnly(), impeller::kBase, impeller::GlyphAtlas::kColorBitmap, impeller::kLinear, impeller::kNearest, impeller::kNone, impeller::kTriangle, impeller::SamplerDescriptor::mag_filter, impeller::SamplerDescriptor::min_filter, impeller::SamplerDescriptor::mip_filter, impeller::OptionsFromPassAndEntity(), impeller::RenderPass::SetCommandLabel(), impeller::RenderPass::SetElementCount(), impeller::RenderPass::SetIndexBuffer(), impeller::RenderPass::SetPipeline(), impeller::RenderPass::SetVertexBuffer(), impeller::ToVector(), type, and VALIDATION_LOG.

## ◆ SetColor()

void impeller::TextContents::SetColor | ( | Color | color | ) |

Definition at line 36 of file text_contents.cc.

36 {
37 color_ = color;
38 }

## ◆ SetForceTextColor()

void impeller::TextContents::SetForceTextColor | ( | bool | value | ) |

Force the text color to apply to the rendered glyphs, even if those glyphs are bitmaps.

This is used to ensure that mask blurs work correctly on emoji.

Definition at line 52 of file text_contents.cc.

52 {
53 force_text_color_ = value;
54 }

References value.

## ◆ SetInheritedOpacity()

void impeller::TextContents::SetInheritedOpacity | ( | Scalar | opacity | ) |
| override virtual

Inherit the provided opacity.

       Use of this method is invalid if CanAcceptOpacity returns false.

Reimplemented from impeller::Contents.

Definition at line 44 of file text_contents.cc.

44 {
45 inherited_opacity_ = opacity;
46 }

## ◆ SetOffset()

void impeller::TextContents::SetOffset | ( | Vector2 | offset | ) |

Definition at line 48 of file text_contents.cc.

48 {
49 offset_ = offset;
50 }

References offset.

## ◆ SetScale()

void impeller::TextContents::SetScale | ( | Scalar | scale | ) |
| inline

Definition at line 58 of file text_contents.h.

58 { scale_ = scale; }

References scale.

## ◆ SetTextFrame()

void impeller::TextContents::SetTextFrame | ( | const std::shared_ptr< TextFrame > & | frame | ) |

Definition at line 32 of file text_contents.cc.

32 {
33 frame_ = frame;
34 }

## ◆ SetTextProperties()

void impeller::TextContents::SetTextProperties | ( | Color | color,
|  | bool | stroke,
|  | Scalar | stroke_width,
|  | Cap | stroke_cap,
|  | Join | stroke_join,
|  | Scalar | stroke_miter
| ) |  |

Must be set after text frame.

Definition at line 60 of file text_contents.cc.

65 {
66 if (frame_->HasColor()) {
67 // Alpha is always applied when rendering, remove it here so
68 // we do not double-apply the alpha.
69 properties_.color = color.WithAlpha(1.0);
70 }
71 if (stroke) {
72 properties_.stroke = true;
73 properties_.stroke_width = stroke_width;
74 properties_.stroke_cap = stroke_cap;
75 properties_.stroke_join = stroke_join;
76 properties_.stroke_miter = stroke_miter;
77 }
78 }

References impeller::GlyphProperties::color, impeller::GlyphProperties::stroke, impeller::GlyphProperties::stroke_cap, impeller::GlyphProperties::stroke_join, impeller::GlyphProperties::stroke_miter, impeller::GlyphProperties::stroke_width, stroke_width, and impeller::Color::WithAlpha().

The documentation for this class was generated from the following files:

- impeller/entity/contents/text_contents.h
- impeller/entity/contents/text_contents.cc

impeller::ISize
ISize64 ISize
Definition: size.h:174
impeller::GlyphAtlas::Type::kColorBitmap
@ kColorBitmap
impeller::MipFilter::kBase
@ kBase
The texture is sampled as if it only had a single mipmap level.
impeller::Entity::GetShaderTransform
Matrix GetShaderTransform(const RenderPass &pass) const
Get the vertex shader transform used for drawing this Entity.
Definition: entity.cc:48
impeller::AxisAlignment::kAll
@ kAll
impeller::Scalar
float Scalar
Definition: scalar.h:18
vtx
SolidFillVertexShader::PerVertexData vtx
Definition: stroke_path_geometry.cc:320
value
int32_t value
Definition: dl_golden_unittests.cc:444
impeller::TPoint::Round
static constexpr TPoint Round(const TPoint< U > &other)
Definition: point.h:49
impeller::Color::alpha
Scalar alpha
Definition: color.h:142
buffer_view
BufferView buffer_view
Definition: blit_command_gles.cc:152
impeller::GlyphProperties::stroke_miter
Scalar stroke_miter
Definition: font_glyph_pair.h:21
stroke_width
const Scalar stroke_width
Definition: stroke_path_geometry.cc:312
offset
SeparatedVector2 offset
Definition: stroke_path_geometry.cc:319
impeller::MinMagFilter::kNearest
@ kNearest
Select nearest to the sample point. Most widely supported.
impeller::GlyphProperties::color
Color color
Definition: font_glyph_pair.h:17
impeller::PrimitiveType::kTriangle
@ kTriangle
impeller::OptionsFromPassAndEntity
ContentContextOptions OptionsFromPassAndEntity(const RenderPass &pass, const Entity &entity)
Definition: contents.cc:34
impeller::TextFrame::RoundScaledFontSize
static Scalar RoundScaledFontSize(Scalar scale)
Definition: text_frame.cc:54
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::TextContents::ComputeVertexData
static void ComputeVertexData(GlyphAtlasPipeline::VertexShader::PerVertexData *vtx_contents, const std::shared_ptr< TextFrame > &frame, Scalar scale, const Matrix &entity_transform, Vector2 offset, std::optional< GlyphProperties > glyph_properties, const std::shared_ptr< GlyphAtlas > &atlas)
Definition: text_contents.cc:80
impeller::Color::WithAlpha
constexpr Color WithAlpha(Scalar new_alpha) const
Definition: color.h:277
type
GLenum type
Definition: blit_command_gles.cc:151
impeller::IndexType::kNone
@ kNone
Does not use the index buffer.
impeller::TRect::Scale
constexpr TRect Scale(Type scale) const
Definition: rect.h:206
impeller::GlyphProperties::stroke_join
Join stroke_join
Definition: font_glyph_pair.h:20
impeller::GlyphProperties::stroke
bool stroke
Definition: font_glyph_pair.h:22
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:792
impeller::AxisAlignment::kX
@ kX
impeller::SizeToPoint
Point SizeToPoint(Size size)
Definition: text_contents.cc:21
impeller::GlyphProperties::stroke_width
Scalar stroke_width
Definition: font_glyph_pair.h:18
impeller::MinMagFilter::kLinear
@ kLinear
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:91
impeller::GlyphProperties::stroke_cap
Cap stroke_cap
Definition: font_glyph_pair.h:19
impeller::ToVector
constexpr Vector4 ToVector(Color color)
Definition: shader_types.h:190
scale
const Scalar scale
Definition: stroke_path_geometry.cc:316
impeller::TextContents::GetColor
Color GetColor() const
Definition: text_contents.cc:40
impeller::AxisAlignment::kNone
@ kNone
impeller::TextFrame::ComputeSubpixelPosition
static Point ComputeSubpixelPosition(const TextRun::GlyphPosition &glyph_position, AxisAlignment alignment, const Matrix &transform)
Definition: text_frame.cc:82
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
impeller::AxisAlignment::kY
@ kY