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 
6 
7 #include <cstring>
8 #include <optional>
9 #include <type_traits>
10 #include <utility>
11 
12 #include "impeller/core/formats.h"
15 #include "impeller/entity/entity.h"
20 
21 namespace impeller {
22 
23 TextContents::TextContents() = default;
24 
25 TextContents::~TextContents() = default;
26 
27 void TextContents::SetTextFrame(const std::shared_ptr<TextFrame>& frame) {
28  frame_ = frame;
29 }
30 
31 std::shared_ptr<GlyphAtlas> TextContents::ResolveAtlas(
32  Context& context,
33  GlyphAtlas::Type type,
34  const std::shared_ptr<LazyGlyphAtlas>& lazy_atlas) const {
35  FML_DCHECK(lazy_atlas);
36  if (lazy_atlas) {
37  return lazy_atlas->CreateOrGetGlyphAtlas(context, type);
38  }
39 
40  return nullptr;
41 }
42 
44  color_ = color;
45 }
46 
48  return color_.WithAlpha(color_.alpha * inherited_opacity_);
49 }
50 
51 bool TextContents::CanInheritOpacity(const Entity& entity) const {
52  return !frame_->MaybeHasOverlapping();
53 }
54 
56  inherited_opacity_ = opacity;
57 }
58 
60  offset_ = offset;
61 }
62 
63 std::optional<Rect> TextContents::GetCoverage(const Entity& entity) const {
64  return frame_->GetBounds().TransformBounds(entity.GetTransformation());
65 }
66 
68  const std::shared_ptr<LazyGlyphAtlas>& lazy_glyph_atlas,
69  Scalar scale) {
70  lazy_glyph_atlas->AddTextFrame(*frame_, scale);
71  scale_ = scale;
72 }
73 
74 bool TextContents::Render(const ContentContext& renderer,
75  const Entity& entity,
76  RenderPass& pass) const {
77  auto color = GetColor();
78  if (color.IsTransparent()) {
79  return true;
80  }
81 
82  auto type = frame_->GetAtlasType();
83  auto atlas =
84  ResolveAtlas(*renderer.GetContext(), type, renderer.GetLazyGlyphAtlas());
85 
86  if (!atlas || !atlas->IsValid()) {
87  VALIDATION_LOG << "Cannot render glyphs without prepared atlas.";
88  return false;
89  }
90 
91  // Information shared by all glyph draw calls.
92  Command cmd;
93  DEBUG_COMMAND_INFO(cmd, "TextFrame");
94  auto opts = OptionsFromPassAndEntity(pass, entity);
95  opts.primitive_type = PrimitiveType::kTriangle;
96  if (type == GlyphAtlas::Type::kAlphaBitmap) {
97  cmd.pipeline = renderer.GetGlyphAtlasPipeline(opts);
98  } else {
99  cmd.pipeline = renderer.GetGlyphAtlasColorPipeline(opts);
100  }
101  cmd.stencil_reference = entity.GetStencilDepth();
102 
105 
106  // Common vertex uniforms for all glyphs.
107  VS::FrameInfo frame_info;
108  frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize());
109  frame_info.atlas_size =
110  Vector2{static_cast<Scalar>(atlas->GetTexture()->GetSize().width),
111  static_cast<Scalar>(atlas->GetTexture()->GetSize().height)};
112  frame_info.offset = offset_;
113  frame_info.is_translation_scale =
115  frame_info.entity_transform = entity.GetTransformation();
116  frame_info.text_color = ToVector(color.Premultiply());
117 
118  VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info));
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  cmd, // 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 = pass.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(
187  atlas_glyph_bounds.origin.x, atlas_glyph_bounds.origin.y,
188  atlas_glyph_bounds.size.width, atlas_glyph_bounds.size.height);
189  vtx.glyph_bounds = Vector4(glyph_position.glyph.bounds.origin.x,
190  glyph_position.glyph.bounds.origin.y,
191  glyph_position.glyph.bounds.size.width,
192  glyph_position.glyph.bounds.size.height);
193  vtx.glyph_position = glyph_position.position;
194 
195  for (const Point& point : unit_points) {
196  vtx.unit_position = point;
197  std::memcpy(vtx_contents++, &vtx, sizeof(VS::PerVertexData));
198  }
199  }
200  }
201  });
202 
203  cmd.BindVertices({
204  .vertex_buffer = buffer_view,
205  .index_buffer = {},
206  .vertex_count = vertex_count,
207  .index_type = IndexType::kNone,
208  });
209 
210  return pass.AddCommand(std::move(cmd));
211 }
212 
213 } // namespace impeller
text_contents.h
impeller::Command
An object used to specify work to the GPU along with references to resources the GPU will used when d...
Definition: command.h:99
DEBUG_COMMAND_INFO
#define DEBUG_COMMAND_INFO(obj, arg)
Definition: command.h:31
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:51
lazy_glyph_atlas.h
impeller::ContentContext::GetGlyphAtlasColorPipeline
std::shared_ptr< Pipeline< PipelineDescriptor > > GetGlyphAtlasColorPipeline(ContentContextOptions opts) const
Definition: content_context.h:496
impeller::Entity::GetStencilDepth
uint32_t GetStencilDepth() const
Definition: entity.cc:89
impeller::TRect::size
TSize< Type > size
Definition: rect.h:24
impeller::TPoint::y
Type y
Definition: point.h:24
impeller::Scalar
float Scalar
Definition: scalar.h:15
impeller::Font
Describes a typeface along with any modifications to its intrinsic properties.
Definition: font.h:21
impeller::GlyphAtlas::Type::kAlphaBitmap
@ kAlphaBitmap
sampler_library.h
impeller::ContentContext::GetLazyGlyphAtlas
std::shared_ptr< LazyGlyphAtlas > GetLazyGlyphAtlas() const
Definition: content_context.h:712
entity.h
impeller::Color
Definition: color.h:122
impeller::FontGlyphAtlas
An object that can look up glyph locations within the GlyphAtlas for a particular typeface.
Definition: glyph_atlas.h:179
impeller::Vector4
Definition: vector.h:229
impeller::TextContents::GetCoverage
std::optional< Rect > GetCoverage(const Entity &entity) const override
Get the screen space bounding rectangle that this contents affects.
Definition: text_contents.cc:63
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:87
impeller::RenderPipelineT::FragmentShader
FragmentShader_ FragmentShader
Definition: pipeline.h:91
impeller::Color::alpha
Scalar alpha
Definition: color.h:141
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:19
impeller::TextContents::SetColor
void SetColor(Color color)
Definition: text_contents.cc:43
impeller::Entity::GetTransformation
const Matrix & GetTransformation() const
Definition: entity.cc:49
impeller::MinMagFilter::kNearest
@ kNearest
Select nearest to the sample point. Most widely supported.
impeller::SamplerDescriptor::mag_filter
MinMagFilter mag_filter
Definition: sampler_descriptor.h:20
impeller::SamplerDescriptor
Definition: sampler_descriptor.h:18
impeller::Entity
Definition: entity.h:21
impeller::OptionsFromPassAndEntity
ContentContextOptions OptionsFromPassAndEntity(const RenderPass &pass, const Entity &entity)
Definition: contents.cc:30
impeller::MipFilter::kNearest
@ kNearest
Sample from the nearest mip level.
impeller::RenderPass::GetRenderTargetSize
ISize GetRenderTargetSize() const
Definition: render_pass.cc:30
impeller::SamplerDescriptor::min_filter
MinMagFilter min_filter
Definition: sampler_descriptor.h:19
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:67
impeller::ContentContext::GetContext
std::shared_ptr< Context > GetContext() const
Definition: content_context.cc:440
impeller::MinMagFilter::kLinear
@ kLinear
impeller::Color::WithAlpha
constexpr Color WithAlpha(Scalar new_alpha) const
Definition: color.h:268
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:358
impeller::GlyphAtlas::Type
Type
Describes how the glyphs are represented in the texture.
Definition: glyph_atlas.h:32
impeller::IndexType::kNone
@ kNone
Does not use the index buffer.
impeller::Font::Metrics::point_size
Scalar point_size
Definition: font.h:34
impeller::TRect::origin
TPoint< Type > origin
Definition: rect.h:23
impeller::TextContents::~TextContents
~TextContents()
impeller::Font::GetMetrics
const Metrics & GetMetrics() const
Definition: font.cc:37
impeller::TSize::width
Type width
Definition: size.h:21
impeller::TextContents::SetOffset
void SetOffset(Vector2 offset)
Definition: text_contents.cc:59
impeller::SamplerDescriptor::mip_filter
MipFilter mip_filter
Definition: sampler_descriptor.h:21
impeller::TPoint::x
Type x
Definition: point.h:23
impeller::RenderPass
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:27
sampler_descriptor.h
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:60
impeller::Command::stencil_reference
uint32_t stencil_reference
Definition: command.h:152
content_context.h
impeller::TextContents::TextContents
TextContents()
impeller::Context
To do anything rendering related with Impeller, you need a context.
Definition: context.h:47
impeller::TextContents::SetInheritedOpacity
void SetInheritedOpacity(Scalar opacity) override
Inherit the provided opacity.
Definition: text_contents.cc:55
impeller::ToVector
constexpr Vector4 ToVector(Color color)
Definition: shader_types.h:172
impeller::TPoint< Scalar >
impeller::TextRun::GlyphPosition
Definition: text_run.h:21
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:43
impeller::TextContents::Render
bool Render(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
Definition: text_contents.cc:74
impeller::Matrix::MakeOrthographic
static constexpr Matrix MakeOrthographic(TSize< T > size)
Definition: matrix.h:448
impeller::TextContents::GetColor
Color GetColor() const
Definition: text_contents.cc:47
impeller::PrimitiveType::kTriangle
@ kTriangle
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::TSize::height
Type height
Definition: size.h:22
impeller::TextContents::SetTextFrame
void SetTextFrame(const std::shared_ptr< TextFrame > &frame)
Definition: text_contents.cc:27
glyph_atlas.h
impeller::Command::BindVertices
bool BindVertices(const VertexBuffer &buffer)
Specify the vertex and index buffer to use for this command.
Definition: command.cc:15
impeller::Command::pipeline
std::shared_ptr< Pipeline< PipelineDescriptor > > pipeline
Definition: command.h:103
impeller::ContentContext::GetGlyphAtlasPipeline
std::shared_ptr< Pipeline< PipelineDescriptor > > GetGlyphAtlasPipeline(ContentContextOptions opts) const
Definition: content_context.h:491
impeller::RenderPipelineT::VertexShader
VertexShader_ VertexShader
Definition: pipeline.h:90
impeller::RenderPass::AddCommand
bool AddCommand(Command &&command)
Record a command for subsequent encoding to the underlying command buffer. No work is encoded into th...
Definition: render_pass.cc:46
impeller
Definition: aiks_context.cc:10
impeller::ContentContext
Definition: content_context.h:344
impeller::TRect< Scalar >
impeller::RenderPass::GetTransientsBuffer
HostBuffer & GetTransientsBuffer()
Definition: render_pass.cc:34