| Flutter Impeller |

text_contents.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "impeller/entity/contents/text_contents.h"
6
7 #include <cstring>
8 #include <optional>
9 #include <utility>
10
11 #include "impeller/core/formats.h"
12 #include "impeller/core/sampler_descriptor.h"
13 #include "impeller/entity/contents/content_context.h"
14 #include "impeller/entity/entity.h"
15 #include "impeller/renderer/render_pass.h"
16 #include "impeller/typographer/glyph_atlas.h"
17 #include "impeller/typographer/lazy_glyph_atlas.h"
18
19 namespace impeller {
20
21 TextContents::TextContents() = default;
22
23 TextContents::~TextContents() = default;
24
25 void TextContents::SetTextFrame(const std::shared_ptr<TextFrame>& frame) {
26 frame_ = frame;
27 }
28
29 void TextContents::SetColor(Color color) {
30 color_ = color;
31 }
32
33 Color TextContents::GetColor() const {
34 return color_.WithAlpha(color_.alpha * inherited_opacity_);
35 }
36
37 bool TextContents::CanInheritOpacity(const Entity& entity) const {
38 return !frame_->MaybeHasOverlapping();
39 }
40
41 void TextContents::SetInheritedOpacity(Scalar opacity) {
42 inherited_opacity_ = opacity;
43 }
44
45 void TextContents::SetOffset(Vector2 offset) {
46 offset_ = offset;
47 }
48
49 void TextContents::SetForceTextColor(bool value) {
50 force_text_color_ = value;
51 }
52
53 std::optional<Rect> TextContents::GetCoverage(const Entity& entity) const {
54 return frame_->GetBounds().TransformBounds(entity.GetTransform());
55 }
56
57 void TextContents::PopulateGlyphAtlas(
58 const std::shared_ptr<LazyGlyphAtlas>& lazy_glyph_atlas,
59 Scalar scale) {
60 lazy_glyph_atlas->AddTextFrame(*frame_, scale);
61 scale_ = scale;
62 }
63
64 bool TextContents::Render(const ContentContext& renderer,
65 const Entity& entity,
66 RenderPass& pass) const {
67 auto color = GetColor();
68 if (color.IsTransparent()) {
69 return true;
70 }
71
72 auto type = frame_->GetAtlasType();
73 const std::shared_ptr<GlyphAtlas>& atlas =
74 renderer.GetLazyGlyphAtlas()->CreateOrGetGlyphAtlas(
75 *renderer.GetContext(), type);
76
77 if (!atlas || !atlas->IsValid()) {
78 VALIDATION_LOG << "Cannot render glyphs without prepared atlas.";
79 return false;
80 }
81
82 // Information shared by all glyph draw calls.
83 pass.SetCommandLabel("TextFrame");
84 auto opts = OptionsFromPassAndEntity(pass, entity);
85 opts.primitive_type = PrimitiveType::kTriangle;
86 if (type == GlyphAtlas::Type::kAlphaBitmap) {
87 pass.SetPipeline(renderer.GetGlyphAtlasPipeline(opts));
88 } else {
89 pass.SetPipeline(renderer.GetGlyphAtlasColorPipeline(opts));
90 }
91 pass.SetStencilReference(entity.GetClipDepth());
92
93 using VS = GlyphAtlasPipeline::VertexShader;
94 using FS = GlyphAtlasPipeline::FragmentShader;
95
96 // Common vertex uniforms for all glyphs.
97 VS::FrameInfo frame_info;
98 frame_info.mvp =
99 Entity::GetShaderTransform(entity.GetShaderClipDepth(), pass, Matrix());
100 frame_info.atlas_size =
101 Vector2{static_cast<Scalar>(atlas->GetTexture()->GetSize().width),
102 static_cast<Scalar>(atlas->GetTexture()->GetSize().height)};
103 frame_info.offset = offset_;
104 frame_info.is_translation_scale =
105 entity.GetTransform().IsTranslationScaleOnly();
106 frame_info.entity_transform = entity.GetTransform();
107 frame_info.text_color = ToVector(color.Premultiply());
108
109 VS::BindFrameInfo(pass,
110 renderer.GetTransientsBuffer().EmplaceUniform(frame_info));
111
112 if (type == GlyphAtlas::Type::kColorBitmap) {
113 using FSS = GlyphAtlasColorPipeline::FragmentShader;
114 FSS::FragInfo frag_info;
115 frag_info.use_text_color = force_text_color_ ? 1.0 : 0.0;
116 FSS::BindFragInfo(pass,
117 renderer.GetTransientsBuffer().EmplaceUniform(frag_info));
118 }
119
120 SamplerDescriptor sampler_desc;
121 if (frame_info.is_translation_scale) {
122 sampler_desc.min_filter = MinMagFilter::kNearest;
123 sampler_desc.mag_filter = MinMagFilter::kNearest;
124 } else {
125 // Currently, we only propagate the scale of the transform to the atlas
126 // renderer, so if the transform has more than just a translation, we turn
127 // on linear sampling to prevent crunchiness caused by the pixel grid not
128 // being perfectly aligned.
129 // The downside is that this slightly over-blurs rotated/skewed text.
130 sampler_desc.min_filter = MinMagFilter::kLinear;
131 sampler_desc.mag_filter = MinMagFilter::kLinear;
132 }
133 sampler_desc.mip_filter = MipFilter::kNearest;
134
135 FS::BindGlyphAtlasSampler(
136 pass, // command
137 atlas->GetTexture(), // texture
138 renderer.GetContext()->GetSamplerLibrary()->GetSampler(
139 sampler_desc) // sampler
140 );
141
142 // Common vertex information for all glyphs.
143 // All glyphs are given the same vertex information in the form of a
144 // unit-sized quad. The size of the glyph is specified in per instance data
145 // and the vertex shader uses this to size the glyph correctly. The
146 // interpolated vertex information is also used in the fragment shader to
147 // sample from the glyph atlas.
148
149 constexpr std::array<Point, 6> unit_points = {Point{0, 0}, Point{1, 0},
150 Point{0, 1}, Point{1, 0},
151 Point{0, 1}, Point{1, 1}};
152
153 auto& host_buffer = renderer.GetTransientsBuffer();
154 size_t vertex_count = 0;
155 for (const auto& run : frame_->GetRuns()) {
156 vertex_count += run.GetGlyphPositions().size();
157 }
158 vertex_count *= 6;
159
160 auto buffer_view = host_buffer.Emplace(
161 vertex_count * sizeof(VS::PerVertexData), alignof(VS::PerVertexData),
162 [&](uint8_t* contents) {
163 VS::PerVertexData vtx;
164 VS::PerVertexData* vtx_contents =
165 reinterpret_cast<VS::PerVertexData*>(contents);
166 for (const TextRun& run : frame_->GetRuns()) {
167 const Font& font = run.GetFont();
168 Scalar rounded_scale = TextFrame::RoundScaledFontSize(
169 scale_, font.GetMetrics().point_size);
170 const FontGlyphAtlas* font_atlas =
171 atlas->GetFontGlyphAtlas(font, rounded_scale);
172 if (!font_atlas) {
173 VALIDATION_LOG << "Could not find font in the atlas.";
174 continue;
175 }
176
177 for (const TextRun::GlyphPosition& glyph_position :
178 run.GetGlyphPositions()) {
179 std::optional<Rect> maybe_atlas_glyph_bounds =
180 font_atlas->FindGlyphBounds(glyph_position.glyph);
181 if (!maybe_atlas_glyph_bounds.has_value()) {
182 VALIDATION_LOG << "Could not find glyph position in the atlas.";
183 continue;
184 }
185 const Rect& atlas_glyph_bounds = maybe_atlas_glyph_bounds.value();
186 vtx.atlas_glyph_bounds = Vector4(atlas_glyph_bounds.GetXYWH());
187 vtx.glyph_bounds = Vector4(glyph_position.glyph.bounds.GetXYWH());
188 vtx.glyph_position = glyph_position.position;
189
190 for (const Point& point : unit_points) {
191 vtx.unit_position = point;
192 std::memcpy(vtx_contents++, &vtx, sizeof(VS::PerVertexData));
193 }
194 }
195 }
196 });
197
198 pass.SetVertexBuffer({
199 .vertex_buffer = std::move(buffer_view),
200 .index_buffer = {},
201 .vertex_count = vertex_count,
202 .index_type = IndexType::kNone,
203 });
204
205 return pass.Draw().ok();
206 }
207
208 } // namespace impeller
text_contents.h
impeller::GlyphAtlas::Type::kColorBitmap
@ kColorBitmap
impeller::Entity::GetShaderTransform
Matrix GetShaderTransform(const RenderPass &pass) const
Get the vertex shader transform used for drawing this Entity.
Definition: entity.cc:53
impeller::TextContents::CanInheritOpacity
bool CanInheritOpacity(const Entity &entity) const override
Whether or not this contents can accept the opacity peephole optimization.
Definition: text_contents.cc:37
lazy_glyph_atlas.h
impeller::ContentContext::GetGlyphAtlasColorPipeline
std::shared_ptr< Pipeline< PipelineDescriptor > > GetGlyphAtlasColorPipeline(ContentContextOptions opts) const
Definition: content_context.h:576
impeller::Entity::GetShaderClipDepth
float GetShaderClipDepth() const
Definition: entity.cc:117
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::Font
Describes a typeface along with any modifications to its intrinsic properties.
Definition: font.h:22
impeller::ContentContext::GetLazyGlyphAtlas
const std::shared_ptr< LazyGlyphAtlas > & GetLazyGlyphAtlas() const
Definition: content_context.h:801
impeller::GlyphAtlas::Type::kAlphaBitmap
@ kAlphaBitmap
impeller::Entity::GetTransform
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
Definition: entity.cc:49
entity.h
impeller::Color
Definition: color.h:124
vtx
SolidFillVertexShader::PerVertexData vtx
Definition: stroke_path_geometry.cc:301
impeller::FontGlyphAtlas
An object that can look up glyph locations within the GlyphAtlas for a particular typeface.
Definition: glyph_atlas.h:185
impeller::Vector4
Definition: vector.h:232
impeller::TextContents::SetForceTextColor
void SetForceTextColor(bool value)
Force the text color to apply to the rendered glyphs, even if those glyphs are bitmaps.
Definition: text_contents.cc:49
impeller::TextContents::GetCoverage
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.
Definition: text_contents.cc:53
formats.h
impeller::HostBuffer::Emplace
BufferView Emplace(const BufferType &buffer)
Emplace non-uniform data (like contiguous vertices) onto the host buffer.
Definition: host_buffer.h:94
impeller::RenderPipelineT::FragmentShader
FragmentShader_ FragmentShader
Definition: pipeline.h:94
impeller::Color::alpha
Scalar alpha
Definition: color.h:143
impeller::RenderPass::SetVertexBuffer
virtual bool SetVertexBuffer(VertexBuffer buffer)
Specify the vertex and index buffer to use for this command.
Definition: render_pass.cc:123
impeller::TextFrame::RoundScaledFontSize
static Scalar RoundScaledFontSize(Scalar scale, Scalar point_size)
Definition: text_frame.cc:66
impeller::TextRun
Represents a collection of positioned glyphs from a specific font.
Definition: text_run.h:20
impeller::RenderPass::SetCommandLabel
virtual void SetCommandLabel(std::string_view label)
The debugging label to use for the command.
Definition: render_pass.cc:97
impeller::TextContents::SetColor
void SetColor(Color color)
Definition: text_contents.cc:29
impeller::RenderPass::Draw
virtual fml::Status Draw()
Record the currently pending command.
Definition: render_pass.cc:127
impeller::MinMagFilter::kNearest
@ kNearest
Select nearest to the sample point. Most widely supported.
impeller::SamplerDescriptor::mag_filter
MinMagFilter mag_filter
Definition: sampler_descriptor.h:17
impeller::VS
SolidFillVertexShader VS
Definition: stroke_path_geometry.cc:15
impeller::SamplerDescriptor
Definition: sampler_descriptor.h:15
impeller::PrimitiveType::kTriangle
@ kTriangle
impeller::Entity
Definition: entity.h:21
impeller::OptionsFromPassAndEntity
ContentContextOptions OptionsFromPassAndEntity(const RenderPass &pass, const Entity &entity)
Definition: contents.cc:37
impeller::MipFilter::kNearest
@ kNearest
Sample from the nearest mip level.
impeller::SamplerDescriptor::min_filter
MinMagFilter min_filter
Definition: sampler_descriptor.h:16
render_pass.h
impeller::TextContents::PopulateGlyphAtlas
void PopulateGlyphAtlas(const std::shared_ptr< LazyGlyphAtlas > &lazy_glyph_atlas, Scalar scale) override
Add any text data to the specified lazy atlas. The scale parameter must be used again later when draw...
Definition: text_contents.cc:57
impeller::ContentContext::GetContext
std::shared_ptr< Context > GetContext() const
Definition: content_context.cc:564
impeller::MinMagFilter::kLinear
@ kLinear
impeller::Color::WithAlpha
constexpr Color WithAlpha(Scalar new_alpha) const
Definition: color.h:270
impeller::Matrix::IsTranslationScaleOnly
constexpr bool IsTranslationScaleOnly() const
Returns true if the matrix has a scale-only basis and is non-projective. Note that an identity matrix...
Definition: matrix.h:363
impeller::IndexType::kNone
@ kNone
Does not use the index buffer.
impeller::Font::Metrics::point_size
Scalar point_size
Definition: font.h:35
impeller::RenderPass::SetStencilReference
virtual void SetStencilReference(uint32_t value)
Definition: render_pass.cc:103
impeller::TextContents::~TextContents
~TextContents()
impeller::Font::GetMetrics
const Metrics & GetMetrics() const
Definition: font.cc:37
impeller::TextContents::SetOffset
void SetOffset(Vector2 offset)
Definition: text_contents.cc:45
impeller::SamplerDescriptor::mip_filter
MipFilter mip_filter
Definition: sampler_descriptor.h:18
impeller::RenderPass
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:33
impeller::Entity::GetClipDepth
uint32_t GetClipDepth() const
Definition: entity.cc:105
sampler_descriptor.h
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:73
content_context.h
impeller::TextContents::TextContents
TextContents()
impeller::TextContents::SetInheritedOpacity
void SetInheritedOpacity(Scalar opacity) override
Inherit the provided opacity.
Definition: text_contents.cc:41
impeller::ToVector
constexpr Vector4 ToVector(Color color)
Definition: shader_types.h:185
impeller::TPoint< Scalar >
impeller::TextRun::GlyphPosition
Definition: text_run.h:22
impeller::HostBuffer::EmplaceUniform
BufferView EmplaceUniform(const UniformType &uniform)
Emplace uniform data onto the host buffer. Ensure that backend specific uniform alignment requirement...
Definition: host_buffer.h:50
impeller::TextContents::Render
bool Render(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
Definition: text_contents.cc:64
scale
const Scalar scale
Definition: stroke_path_geometry.cc:297
impeller::TextContents::GetColor
Color GetColor() const
Definition: text_contents.cc:33
impeller::FontGlyphAtlas::FindGlyphBounds
std::optional< Rect > FindGlyphBounds(const Glyph &glyph) const
Find the location of a glyph in the atlas.
Definition: glyph_atlas.cc:111
impeller::RenderPass::SetPipeline
virtual void SetPipeline(const std::shared_ptr< Pipeline< PipelineDescriptor >> &pipeline)
The pipeline to use for this command.
Definition: render_pass.cc:92
impeller::TextContents::SetTextFrame
void SetTextFrame(const std::shared_ptr< TextFrame > &frame)
Definition: text_contents.cc:25
glyph_atlas.h
offset
Point offset
Definition: stroke_path_geometry.cc:300
impeller::ContentContext::GetGlyphAtlasPipeline
std::shared_ptr< Pipeline< PipelineDescriptor > > GetGlyphAtlasPipeline(ContentContextOptions opts) const
Definition: content_context.h:571
impeller::RenderPipelineT::VertexShader
VertexShader_ VertexShader
Definition: pipeline.h:93
impeller
Definition: aiks_blur_unittests.cc:20
impeller::TRect::GetXYWH
constexpr std::array< T, 4 > GetXYWH() const
Get the x, y coordinates of the origin and the width and height of the rectangle in an array.
Definition: rect.h:361
impeller::ContentContext
Definition: content_context.h:392
impeller::TRect< Scalar >
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::ContentContext::GetTransientsBuffer
HostBuffer & GetTransientsBuffer() const
Retrieve the currnent host buffer for transient storage.
Definition: content_context.h:833