11
11
#include " impeller/core/buffer_view.h"
12
12
#include " impeller/core/formats.h"
13
13
#include " impeller/core/sampler_descriptor.h"
14
- #include " impeller/entity/contents/content_context.h"
15
14
#include " impeller/entity/entity.h"
16
15
#include " impeller/geometry/color.h"
17
16
#include " impeller/geometry/point.h"
20
19
21
20
namespace impeller {
22
21
22
+ using VS = GlyphAtlasPipeline::VertexShader;
23
+ using FS = GlyphAtlasPipeline::FragmentShader;
24
+
23
25
TextContents::TextContents () = default ;
24
26
25
27
TextContents::~TextContents () = default ;
@@ -72,6 +74,130 @@ void TextContents::SetTextProperties(Color color,
72
74
}
73
75
}
74
76
77
+ void TextContents::ComputeVertexData (
78
+ VS::PerVertexData* vtx_contents,
79
+ const std::shared_ptr<TextFrame>& frame,
80
+ Scalar scale,
81
+ const Matrix& entity_transform,
82
+ Vector2 offset,
83
+ std::optional<GlyphProperties> glyph_properties,
84
+ const std::shared_ptr<GlyphAtlas>& atlas) {
85
+ // Common vertex information for all glyphs.
86
+ // All glyphs are given the same vertex information in the form of a
87
+ // unit-sized quad. The size of the glyph is specified in per instance data
88
+ // and the vertex shader uses this to size the glyph correctly. The
89
+ // interpolated vertex information is also used in the fragment shader to
90
+ // sample from the glyph atlas.
91
+
92
+ constexpr std::array<Point, 6 > unit_points = {Point{0 , 0 }, Point{1 , 0 },
93
+ Point{0 , 1 }, Point{1 , 0 },
94
+ Point{0 , 1 }, Point{1 , 1 }};
95
+
96
+ ISize atlas_size = atlas->GetTexture ()->GetSize ();
97
+ bool is_translation_scale = entity_transform.IsTranslationScaleOnly ();
98
+ Matrix basis_transform = entity_transform.Basis ();
99
+
100
+ VS::PerVertexData vtx;
101
+ size_t i = 0u ;
102
+ size_t bounds_offset = 0u ;
103
+ for (const TextRun& run : frame->GetRuns ()) {
104
+ const Font& font = run.GetFont ();
105
+ Scalar rounded_scale = TextFrame::RoundScaledFontSize (scale);
106
+ FontGlyphAtlas* font_atlas = nullptr ;
107
+
108
+ // Adjust glyph position based on the subpixel rounding
109
+ // used by the font.
110
+ Point subpixel_adjustment (0.5 , 0.5 );
111
+ switch (font.GetAxisAlignment ()) {
112
+ case AxisAlignment::kNone :
113
+ break ;
114
+ case AxisAlignment::kX :
115
+ subpixel_adjustment.x = 0.125 ;
116
+ break ;
117
+ case AxisAlignment::kY :
118
+ subpixel_adjustment.y = 0.125 ;
119
+ break ;
120
+ case AxisAlignment::kAll :
121
+ subpixel_adjustment.x = 0.125 ;
122
+ subpixel_adjustment.y = 0.125 ;
123
+ break ;
124
+ }
125
+
126
+ Point screen_offset = (entity_transform * Point (0 , 0 ));
127
+ for (const TextRun::GlyphPosition& glyph_position :
128
+ run.GetGlyphPositions ()) {
129
+ const FrameBounds& frame_bounds = frame->GetFrameBounds (bounds_offset);
130
+ bounds_offset++;
131
+ auto atlas_glyph_bounds = frame_bounds.atlas_bounds ;
132
+ auto glyph_bounds = frame_bounds.glyph_bounds ;
133
+
134
+ // If frame_bounds.is_placeholder is true, this is the first frame
135
+ // the glyph has been rendered and so its atlas position was not
136
+ // known when the glyph was recorded. Perform a slow lookup into the
137
+ // glyph atlas hash table.
138
+ if (frame_bounds.is_placeholder ) {
139
+ if (!font_atlas) {
140
+ font_atlas =
141
+ atlas->GetOrCreateFontGlyphAtlas (ScaledFont{font, rounded_scale});
142
+ }
143
+
144
+ if (!font_atlas) {
145
+ VALIDATION_LOG << " Could not find font in the atlas." ;
146
+ continue ;
147
+ }
148
+ Point subpixel = TextFrame::ComputeSubpixelPosition (
149
+ glyph_position, font.GetAxisAlignment (), offset, rounded_scale);
150
+
151
+ std::optional<FrameBounds> maybe_atlas_glyph_bounds =
152
+ font_atlas->FindGlyphBounds (SubpixelGlyph{
153
+ glyph_position.glyph , //
154
+ subpixel, //
155
+ glyph_properties //
156
+ });
157
+ if (!maybe_atlas_glyph_bounds.has_value ()) {
158
+ VALIDATION_LOG << " Could not find glyph position in the atlas." ;
159
+ continue ;
160
+ }
161
+ atlas_glyph_bounds = maybe_atlas_glyph_bounds.value ().atlas_bounds ;
162
+ }
163
+
164
+ Rect scaled_bounds = glyph_bounds.Scale (1.0 / rounded_scale);
165
+ // For each glyph, we compute two rectangles. One for the vertex
166
+ // positions and one for the texture coordinates (UVs). The atlas
167
+ // glyph bounds are used to compute UVs in cases where the
168
+ // destination and source sizes may differ due to clamping the sizes
169
+ // of large glyphs.
170
+ Point uv_origin =
171
+ (atlas_glyph_bounds.GetLeftTop () - Point (0.5 , 0.5 )) / atlas_size;
172
+ Point uv_size = (atlas_glyph_bounds.GetSize () + Point (1 , 1 )) / atlas_size;
173
+
174
+ Point unrounded_glyph_position =
175
+ basis_transform *
176
+ (glyph_position.position + scaled_bounds.GetLeftTop ());
177
+
178
+ Point screen_glyph_position =
179
+ (screen_offset + unrounded_glyph_position + subpixel_adjustment)
180
+ .Floor ();
181
+
182
+ for (const Point& point : unit_points) {
183
+ Point position;
184
+ if (is_translation_scale) {
185
+ position = (screen_glyph_position +
186
+ (basis_transform * point * scaled_bounds.GetSize ()))
187
+ .Round ();
188
+ } else {
189
+ position = entity_transform *
190
+ (glyph_position.position + scaled_bounds.GetLeftTop () +
191
+ point * scaled_bounds.GetSize ());
192
+ }
193
+ vtx.uv = uv_origin + (uv_size * point);
194
+ vtx.position = position;
195
+ vtx_contents[i++] = vtx;
196
+ }
197
+ }
198
+ }
199
+ }
200
+
75
201
bool TextContents::Render (const ContentContext& renderer,
76
202
const Entity& entity,
77
203
RenderPass& pass) const {
@@ -100,17 +226,12 @@ bool TextContents::Render(const ContentContext& renderer,
100
226
opts.primitive_type = PrimitiveType::kTriangle ;
101
227
pass.SetPipeline (renderer.GetGlyphAtlasPipeline (opts));
102
228
103
- using VS = GlyphAtlasPipeline::VertexShader;
104
- using FS = GlyphAtlasPipeline::FragmentShader;
105
-
106
229
// Common vertex uniforms for all glyphs.
107
230
VS::FrameInfo frame_info;
108
231
frame_info.mvp =
109
232
Entity::GetShaderTransform (entity.GetShaderClipDepth (), pass, Matrix ());
110
- ISize atlas_size = atlas->GetTexture ()->GetSize ();
111
233
bool is_translation_scale = entity.GetTransform ().IsTranslationScaleOnly ();
112
234
Matrix entity_transform = entity.GetTransform ();
113
- Matrix basis_transform = entity_transform.Basis ();
114
235
115
236
VS::BindFrameInfo (pass,
116
237
renderer.GetTransientsBuffer ().EmplaceUniform (frame_info));
@@ -147,17 +268,6 @@ bool TextContents::Render(const ContentContext& renderer,
147
268
sampler_desc) // sampler
148
269
);
149
270
150
- // Common vertex information for all glyphs.
151
- // All glyphs are given the same vertex information in the form of a
152
- // unit-sized quad. The size of the glyph is specified in per instance data
153
- // and the vertex shader uses this to size the glyph correctly. The
154
- // interpolated vertex information is also used in the fragment shader to
155
- // sample from the glyph atlas.
156
-
157
- constexpr std::array<Point, 6 > unit_points = {Point{0 , 0 }, Point{1 , 0 },
158
- Point{0 , 1 }, Point{1 , 0 },
159
- Point{0 , 1 }, Point{1 , 1 }};
160
-
161
271
auto & host_buffer = renderer.GetTransientsBuffer ();
162
272
size_t vertex_count = 0 ;
163
273
for (const auto & run : frame_->GetRuns ()) {
@@ -168,112 +278,11 @@ bool TextContents::Render(const ContentContext& renderer,
168
278
BufferView buffer_view = host_buffer.Emplace (
169
279
vertex_count * sizeof (VS::PerVertexData), alignof (VS::PerVertexData),
170
280
[&](uint8_t * contents) {
171
- VS::PerVertexData vtx;
172
281
VS::PerVertexData* vtx_contents =
173
282
reinterpret_cast <VS::PerVertexData*>(contents);
174
- size_t i = 0u ;
175
- size_t bounds_offset = 0u ;
176
- for (const TextRun& run : frame_->GetRuns ()) {
177
- const Font& font = run.GetFont ();
178
- Scalar rounded_scale = TextFrame::RoundScaledFontSize (scale_);
179
- FontGlyphAtlas* font_atlas = nullptr ;
180
-
181
- // Adjust glyph position based on the subpixel rounding
182
- // used by the font.
183
- Point subpixel_adjustment (0.5 , 0.5 );
184
- switch (font.GetAxisAlignment ()) {
185
- case AxisAlignment::kNone :
186
- break ;
187
- case AxisAlignment::kX :
188
- subpixel_adjustment.x = 0.125 ;
189
- break ;
190
- case AxisAlignment::kY :
191
- subpixel_adjustment.y = 0.125 ;
192
- break ;
193
- case AxisAlignment::kAll :
194
- subpixel_adjustment.x = 0.125 ;
195
- subpixel_adjustment.y = 0.125 ;
196
- break ;
197
- }
198
-
199
- Point screen_offset = (entity_transform * Point (0 , 0 ));
200
- for (const TextRun::GlyphPosition& glyph_position :
201
- run.GetGlyphPositions ()) {
202
- const FrameBounds& frame_bounds =
203
- frame_->GetFrameBounds (bounds_offset);
204
- bounds_offset++;
205
- auto atlas_glyph_bounds = frame_bounds.atlas_bounds ;
206
- auto glyph_bounds = frame_bounds.glyph_bounds ;
207
-
208
- // If frame_bounds.is_placeholder is true, this is the first frame
209
- // the glyph has been rendered and so its atlas position was not
210
- // known when the glyph was recorded. Perform a slow lookup into the
211
- // glyph atlas hash table.
212
- if (frame_bounds.is_placeholder ) {
213
- if (!font_atlas) {
214
- font_atlas = atlas->GetOrCreateFontGlyphAtlas (
215
- ScaledFont{font, rounded_scale});
216
- }
217
-
218
- if (!font_atlas) {
219
- VALIDATION_LOG << " Could not find font in the atlas." ;
220
- continue ;
221
- }
222
- Point subpixel = TextFrame::ComputeSubpixelPosition (
223
- glyph_position, font.GetAxisAlignment (), offset_,
224
- rounded_scale);
225
-
226
- std::optional<FrameBounds> maybe_atlas_glyph_bounds =
227
- font_atlas->FindGlyphBounds (SubpixelGlyph{
228
- glyph_position.glyph , //
229
- subpixel, //
230
- GetGlyphProperties () //
231
- });
232
- if (!maybe_atlas_glyph_bounds.has_value ()) {
233
- VALIDATION_LOG << " Could not find glyph position in the atlas." ;
234
- continue ;
235
- }
236
- atlas_glyph_bounds =
237
- maybe_atlas_glyph_bounds.value ().atlas_bounds ;
238
- }
239
-
240
- Rect scaled_bounds = glyph_bounds.Scale (1.0 / rounded_scale);
241
- // For each glyph, we compute two rectangles. One for the vertex
242
- // positions and one for the texture coordinates (UVs). The atlas
243
- // glyph bounds are used to compute UVs in cases where the
244
- // destination and source sizes may differ due to clamping the sizes
245
- // of large glyphs.
246
- Point uv_origin =
247
- (atlas_glyph_bounds.GetLeftTop () - Point (0.5 , 0.5 )) /
248
- atlas_size;
249
- Point uv_size =
250
- (atlas_glyph_bounds.GetSize () + Point (1 , 1 )) / atlas_size;
251
-
252
- Point unrounded_glyph_position =
253
- basis_transform *
254
- (glyph_position.position + scaled_bounds.GetLeftTop ());
255
-
256
- Point screen_glyph_position =
257
- (screen_offset + unrounded_glyph_position + subpixel_adjustment)
258
- .Floor ();
259
-
260
- for (const Point& point : unit_points) {
261
- Point position;
262
- if (is_translation_scale) {
263
- position = (screen_glyph_position +
264
- (basis_transform * point * scaled_bounds.GetSize ()))
265
- .Round ();
266
- } else {
267
- position = entity_transform * (glyph_position.position +
268
- scaled_bounds.GetLeftTop () +
269
- point * scaled_bounds.GetSize ());
270
- }
271
- vtx.uv = uv_origin + (uv_size * point);
272
- vtx.position = position;
273
- vtx_contents[i++] = vtx;
274
- }
275
- }
276
- }
283
+ ComputeVertexData (vtx_contents, frame_, scale_,
284
+ /* entity_transform=*/ entity_transform, offset_,
285
+ GetGlyphProperties (), atlas);
277
286
});
278
287
279
288
pass.SetVertexBuffer (std::move (buffer_view));
0 commit comments