Flutter Impeller
typographer_context_skia.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 <cstddef>
8 #include <memory>
9 #include <numeric>
10 #include <utility>
11 #include <vector>
12 
13 #include "flutter/fml/logging.h"
14 #include "flutter/fml/trace_event.h"
15 #include "fml/closure.h"
16 
19 #include "impeller/core/formats.h"
21 #include "impeller/core/platform.h"
23 #include "impeller/geometry/rect.h"
24 #include "impeller/geometry/size.h"
34 #include "include/core/SkColor.h"
35 #include "include/core/SkImageInfo.h"
36 #include "include/core/SkPaint.h"
37 #include "include/core/SkSize.h"
38 
39 #include "third_party/skia/include/core/SkBitmap.h"
40 #include "third_party/skia/include/core/SkBlendMode.h"
41 #include "third_party/skia/include/core/SkCanvas.h"
42 #include "third_party/skia/include/core/SkFont.h"
43 #include "third_party/skia/include/core/SkSurface.h"
44 
45 namespace impeller {
46 
47 constexpr auto kPadding = 2;
48 
49 namespace {
50 SkPaint::Cap ToSkiaCap(Cap cap) {
51  switch (cap) {
52  case Cap::kButt:
53  return SkPaint::Cap::kButt_Cap;
54  case Cap::kRound:
55  return SkPaint::Cap::kRound_Cap;
56  case Cap::kSquare:
57  return SkPaint::Cap::kSquare_Cap;
58  }
59  FML_UNREACHABLE();
60 }
61 
62 SkPaint::Join ToSkiaJoin(Join join) {
63  switch (join) {
64  case Join::kMiter:
65  return SkPaint::Join::kMiter_Join;
66  case Join::kRound:
67  return SkPaint::Join::kRound_Join;
68  case Join::kBevel:
69  return SkPaint::Join::kBevel_Join;
70  }
71  FML_UNREACHABLE();
72 }
73 } // namespace
74 
75 std::shared_ptr<TypographerContext> TypographerContextSkia::Make() {
76  return std::make_shared<TypographerContextSkia>();
77 }
78 
80 
82 
83 std::shared_ptr<GlyphAtlasContext>
85  return std::make_shared<GlyphAtlasContext>(type);
86 }
87 
88 static SkImageInfo GetImageInfo(const GlyphAtlas& atlas, Size size) {
89  switch (atlas.GetType()) {
91  return SkImageInfo::MakeA8(SkISize{static_cast<int32_t>(size.width),
92  static_cast<int32_t>(size.height)});
94  return SkImageInfo::MakeN32Premul(size.width, size.height);
95  }
96  FML_UNREACHABLE();
97 }
98 
99 /// Append as many glyphs to the texture as will fit, and return the first index
100 /// of [extra_pairs] that did not fit.
101 static size_t AppendToExistingAtlas(
102  const std::shared_ptr<GlyphAtlas>& atlas,
103  const std::vector<FontGlyphPair>& extra_pairs,
104  std::vector<Rect>& glyph_positions,
105  const std::vector<Rect>& glyph_sizes,
106  ISize atlas_size,
107  int64_t height_adjustment,
108  const std::shared_ptr<RectanglePacker>& rect_packer) {
109  TRACE_EVENT0("impeller", __FUNCTION__);
110  if (!rect_packer || atlas_size.IsEmpty()) {
111  return 0;
112  }
113 
114  for (size_t i = 0; i < extra_pairs.size(); i++) {
115  ISize glyph_size = ISize::Ceil(glyph_sizes[i].GetSize());
116  IPoint16 location_in_atlas;
117  if (!rect_packer->AddRect(glyph_size.width + kPadding, //
118  glyph_size.height + kPadding, //
119  &location_in_atlas //
120  )) {
121  return i;
122  }
123  // Position the glyph in the center of the 1px padding.
124  glyph_positions.push_back(Rect::MakeXYWH(
125  location_in_atlas.x() + 1, //
126  location_in_atlas.y() + height_adjustment + 1, //
127  glyph_size.width, //
128  glyph_size.height //
129  ));
130  }
131 
132  return extra_pairs.size();
133 }
134 
135 static size_t PairsFitInAtlasOfSize(
136  const std::vector<FontGlyphPair>& pairs,
137  const ISize& atlas_size,
138  std::vector<Rect>& glyph_positions,
139  const std::vector<Rect>& glyph_sizes,
140  int64_t height_adjustment,
141  const std::shared_ptr<RectanglePacker>& rect_packer,
142  size_t start_index) {
143  FML_DCHECK(!atlas_size.IsEmpty());
144 
145  for (size_t i = start_index; i < pairs.size(); i++) {
146  ISize glyph_size = ISize::Ceil(glyph_sizes[i].GetSize());
147  IPoint16 location_in_atlas;
148  if (!rect_packer->AddRect(glyph_size.width + kPadding, //
149  glyph_size.height + kPadding, //
150  &location_in_atlas //
151  )) {
152  return i;
153  }
154  glyph_positions.push_back(Rect::MakeXYWH(
155  location_in_atlas.x() + 1, //
156  location_in_atlas.y() + height_adjustment + 1, //
157  glyph_size.width, //
158  glyph_size.height //
159  ));
160  }
161 
162  return pairs.size();
163 }
164 
166  const std::shared_ptr<GlyphAtlasContext>& atlas_context,
167  const std::vector<FontGlyphPair>& extra_pairs,
168  std::vector<Rect>& glyph_positions,
169  const std::vector<Rect>& glyph_sizes,
170  size_t glyph_index_start,
171  int64_t max_texture_height) {
172  // Because we can't grow the skyline packer horizontally, pick a reasonable
173  // large width for all atlases.
174  static constexpr int64_t kAtlasWidth = 4096;
175  static constexpr int64_t kMinAtlasHeight = 1024;
176 
177  ISize current_size = ISize(kAtlasWidth, kMinAtlasHeight);
178  if (atlas_context->GetAtlasSize().height > current_size.height) {
179  current_size.height = atlas_context->GetAtlasSize().height * 2;
180  }
181 
182  auto height_adjustment = atlas_context->GetAtlasSize().height;
183  while (current_size.height <= max_texture_height) {
184  std::shared_ptr<RectanglePacker> rect_packer;
185  if (atlas_context->GetRectPacker() || glyph_index_start) {
186  rect_packer = RectanglePacker::Factory(
187  kAtlasWidth,
188  current_size.height - atlas_context->GetAtlasSize().height);
189  } else {
190  rect_packer = RectanglePacker::Factory(kAtlasWidth, current_size.height);
191  }
192  glyph_positions.erase(glyph_positions.begin() + glyph_index_start,
193  glyph_positions.end());
194  atlas_context->UpdateRectPacker(rect_packer);
195  auto next_index = PairsFitInAtlasOfSize(
196  extra_pairs, current_size, glyph_positions, glyph_sizes,
197  height_adjustment, rect_packer, glyph_index_start);
198  if (next_index == extra_pairs.size()) {
199  return current_size;
200  }
201  current_size = ISize(current_size.width, current_size.height * 2);
202  }
203  return {};
204 }
205 
206 static void DrawGlyph(SkCanvas* canvas,
207  const SkPoint position,
208  const ScaledFont& scaled_font,
209  const SubpixelGlyph& glyph,
210  const Rect& scaled_bounds,
211  const std::optional<GlyphProperties>& prop,
212  bool has_color) {
213  const auto& metrics = scaled_font.font.GetMetrics();
214  SkGlyphID glyph_id = glyph.glyph.index;
215 
216  SkFont sk_font(
218  metrics.point_size, metrics.scaleX, metrics.skewX);
219  sk_font.setEdging(SkFont::Edging::kAntiAlias);
220  sk_font.setHinting(SkFontHinting::kSlight);
221  sk_font.setEmbolden(metrics.embolden);
222  sk_font.setSubpixel(true);
223  sk_font.setSize(sk_font.getSize() * scaled_font.scale);
224 
225  auto glyph_color = prop.has_value() ? prop->color.ToARGB() : SK_ColorBLACK;
226 
227  SkPaint glyph_paint;
228  glyph_paint.setColor(glyph_color);
229  glyph_paint.setBlendMode(SkBlendMode::kSrc);
230  if (prop.has_value() && prop->stroke) {
231  glyph_paint.setStroke(true);
232  glyph_paint.setStrokeWidth(prop->stroke_width * scaled_font.scale);
233  glyph_paint.setStrokeCap(ToSkiaCap(prop->stroke_cap));
234  glyph_paint.setStrokeJoin(ToSkiaJoin(prop->stroke_join));
235  glyph_paint.setStrokeMiter(prop->stroke_miter);
236  }
237  canvas->save();
238  canvas->translate(glyph.subpixel_offset.x, glyph.subpixel_offset.y);
239  canvas->drawGlyphs(1u, // count
240  &glyph_id, // glyphs
241  &position, // positions
242  SkPoint::Make(-scaled_bounds.GetLeft(),
243  -scaled_bounds.GetTop()), // origin
244  sk_font, // font
245  glyph_paint // paint
246  );
247  canvas->restore();
248 }
249 
250 /// @brief Batch render to a single surface.
251 ///
252 /// This is only safe for use when updating a fresh texture.
253 static bool BulkUpdateAtlasBitmap(const GlyphAtlas& atlas,
254  std::shared_ptr<BlitPass>& blit_pass,
255  HostBuffer& host_buffer,
256  const std::shared_ptr<Texture>& texture,
257  const std::vector<FontGlyphPair>& new_pairs,
258  size_t start_index,
259  size_t end_index) {
260  TRACE_EVENT0("impeller", __FUNCTION__);
261 
262  bool has_color = atlas.GetType() == GlyphAtlas::Type::kColorBitmap;
263 
264  SkBitmap bitmap;
265  bitmap.setInfo(GetImageInfo(atlas, Size(texture->GetSize())));
266  if (!bitmap.tryAllocPixels()) {
267  return false;
268  }
269 
270  auto surface = SkSurfaces::WrapPixels(bitmap.pixmap());
271  if (!surface) {
272  return false;
273  }
274  auto canvas = surface->getCanvas();
275  if (!canvas) {
276  return false;
277  }
278 
279  for (size_t i = start_index; i < end_index; i++) {
280  const FontGlyphPair& pair = new_pairs[i];
281  auto data = atlas.FindFontGlyphBounds(pair);
282  if (!data.has_value()) {
283  continue;
284  }
285  auto [pos, bounds] = data.value();
286  Size size = pos.GetSize();
287  if (size.IsEmpty()) {
288  continue;
289  }
290 
291  DrawGlyph(canvas, SkPoint::Make(pos.GetLeft(), pos.GetTop()),
292  pair.scaled_font, pair.glyph, bounds, pair.glyph.properties,
293  has_color);
294  }
295 
296  // Writing to a malloc'd buffer and then copying to the staging buffers
297  // benchmarks as substantially faster on a number of Android devices.
298  BufferView buffer_view = host_buffer.Emplace(
299  bitmap.getAddr(0, 0),
300  texture->GetSize().Area() *
302  atlas.GetTexture()->GetTextureDescriptor().format),
304 
305  return blit_pass->AddCopy(std::move(buffer_view), //
306  texture, //
307  IRect::MakeXYWH(0, 0, texture->GetSize().width,
308  texture->GetSize().height));
309 }
310 
311 static bool UpdateAtlasBitmap(const GlyphAtlas& atlas,
312  std::shared_ptr<BlitPass>& blit_pass,
313  HostBuffer& host_buffer,
314  const std::shared_ptr<Texture>& texture,
315  const std::vector<FontGlyphPair>& new_pairs,
316  size_t start_index,
317  size_t end_index) {
318  TRACE_EVENT0("impeller", __FUNCTION__);
319 
320  bool has_color = atlas.GetType() == GlyphAtlas::Type::kColorBitmap;
321 
322  for (size_t i = start_index; i < end_index; i++) {
323  const FontGlyphPair& pair = new_pairs[i];
324  auto data = atlas.FindFontGlyphBounds(pair);
325  if (!data.has_value()) {
326  continue;
327  }
328  auto [pos, bounds] = data.value();
329  Size size = pos.GetSize();
330  if (size.IsEmpty()) {
331  continue;
332  }
333  // The uploaded bitmap is expanded by 1px of padding
334  // on each side.
335  size.width += 2;
336  size.height += 2;
337 
338  SkBitmap bitmap;
339  bitmap.setInfo(GetImageInfo(atlas, size));
340  if (!bitmap.tryAllocPixels()) {
341  return false;
342  }
343 
344  auto surface = SkSurfaces::WrapPixels(bitmap.pixmap());
345  if (!surface) {
346  return false;
347  }
348  auto canvas = surface->getCanvas();
349  if (!canvas) {
350  return false;
351  }
352 
353  DrawGlyph(canvas, SkPoint::Make(1, 1), pair.scaled_font, pair.glyph, bounds,
354  pair.glyph.properties, has_color);
355 
356  // Writing to a malloc'd buffer and then copying to the staging buffers
357  // benchmarks as substantially faster on a number of Android devices.
358  BufferView buffer_view = host_buffer.Emplace(
359  bitmap.getAddr(0, 0),
361  atlas.GetTexture()->GetTextureDescriptor().format),
363 
364  // convert_to_read is set to false so that the texture remains in a transfer
365  // dst layout until we finish writing to it below. This only has an impact
366  // on Vulkan where we are responsible for managing image layouts.
367  if (!blit_pass->AddCopy(std::move(buffer_view), //
368  texture, //
369  IRect::MakeXYWH(pos.GetLeft() - 1, pos.GetTop() - 1,
370  size.width, size.height), //
371  /*label=*/"", //
372  /*slice=*/0, //
373  /*convert_to_read=*/false //
374  )) {
375  return false;
376  }
377  }
378  return blit_pass->ConvertTextureToShaderRead(texture);
379 }
380 
381 static Rect ComputeGlyphSize(const SkFont& font,
382  const SubpixelGlyph& glyph,
383  Scalar scale) {
384  SkRect scaled_bounds;
385  SkPaint glyph_paint;
386  if (glyph.properties.has_value() && glyph.properties->stroke) {
387  glyph_paint.setStroke(true);
388  glyph_paint.setStrokeWidth(glyph.properties->stroke_width * scale);
389  glyph_paint.setStrokeCap(ToSkiaCap(glyph.properties->stroke_cap));
390  glyph_paint.setStrokeJoin(ToSkiaJoin(glyph.properties->stroke_join));
391  glyph_paint.setStrokeMiter(glyph.properties->stroke_miter);
392  }
393  font.getBounds(&glyph.glyph.index, 1, &scaled_bounds, &glyph_paint);
394 
395  // Expand the bounds of glyphs at subpixel offsets by 2 in the x direction.
396  Scalar adjustment = 0.0;
397  if (glyph.subpixel_offset != Point(0, 0)) {
398  adjustment = 1.0;
399  }
400  return Rect::MakeLTRB(scaled_bounds.fLeft - adjustment, scaled_bounds.fTop,
401  scaled_bounds.fRight + adjustment,
402  scaled_bounds.fBottom);
403 };
404 
405 static void CollectNewGlyphs(const std::shared_ptr<GlyphAtlas>& atlas,
406  const FontGlyphMap& font_glyph_map,
407  std::vector<FontGlyphPair>& new_glyphs,
408  std::vector<Rect>& glyph_sizes) {
409  for (const auto& font_value : font_glyph_map) {
410  const ScaledFont& scaled_font = font_value.first;
411  const FontGlyphAtlas* font_glyph_atlas =
412  atlas->GetFontGlyphAtlas(scaled_font.font, scaled_font.scale);
413 
414  auto metrics = scaled_font.font.GetMetrics();
415 
416  SkFont sk_font(
418  metrics.point_size, metrics.scaleX, metrics.skewX);
419  sk_font.setEdging(SkFont::Edging::kAntiAlias);
420  sk_font.setHinting(SkFontHinting::kSlight);
421  sk_font.setEmbolden(metrics.embolden);
422  // Rather than computing the bounds at the requested point size and scaling
423  // up the bounds, we scale up the font size and request the bounds. This
424  // seems to give more accurate bounds information.
425  sk_font.setSize(sk_font.getSize() * scaled_font.scale);
426  sk_font.setSubpixel(true);
427 
428  if (font_glyph_atlas) {
429  for (const SubpixelGlyph& glyph : font_value.second) {
430  if (!font_glyph_atlas->FindGlyphBounds(glyph)) {
431  new_glyphs.emplace_back(scaled_font, glyph);
432  glyph_sizes.push_back(
433  ComputeGlyphSize(sk_font, glyph, scaled_font.scale));
434  }
435  }
436  } else {
437  for (const SubpixelGlyph& glyph : font_value.second) {
438  new_glyphs.emplace_back(scaled_font, glyph);
439  glyph_sizes.push_back(
440  ComputeGlyphSize(sk_font, glyph, scaled_font.scale));
441  }
442  }
443  }
444 }
445 
446 std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
447  Context& context,
449  HostBuffer& host_buffer,
450  const std::shared_ptr<GlyphAtlasContext>& atlas_context,
451  const FontGlyphMap& font_glyph_map) const {
452  TRACE_EVENT0("impeller", __FUNCTION__);
453  if (!IsValid()) {
454  return nullptr;
455  }
456  std::shared_ptr<GlyphAtlas> last_atlas = atlas_context->GetGlyphAtlas();
457  FML_DCHECK(last_atlas->GetType() == type);
458 
459  if (font_glyph_map.empty()) {
460  return last_atlas;
461  }
462 
463  // ---------------------------------------------------------------------------
464  // Step 1: Determine if the atlas type and font glyph pairs are compatible
465  // with the current atlas and reuse if possible. For each new font and
466  // glyph pair, compute the glyph size at scale.
467  // ---------------------------------------------------------------------------
468  std::vector<FontGlyphPair> new_glyphs;
469  std::vector<Rect> glyph_sizes;
470  CollectNewGlyphs(last_atlas, font_glyph_map, new_glyphs, glyph_sizes);
471  if (new_glyphs.size() == 0) {
472  return last_atlas;
473  }
474 
475  // ---------------------------------------------------------------------------
476  // Step 2: Determine if the additional missing glyphs can be appended to the
477  // existing bitmap without recreating the atlas.
478  // ---------------------------------------------------------------------------
479  std::vector<Rect> glyph_positions;
480  glyph_positions.reserve(new_glyphs.size());
481  size_t first_missing_index = 0;
482 
483  if (last_atlas->GetTexture()) {
484  // Append all glyphs that fit into the current atlas.
485  first_missing_index = AppendToExistingAtlas(
486  last_atlas, new_glyphs, glyph_positions, glyph_sizes,
487  atlas_context->GetAtlasSize(), atlas_context->GetHeightAdjustment(),
488  atlas_context->GetRectPacker());
489 
490  // ---------------------------------------------------------------------------
491  // Step 3a: Record the positions in the glyph atlas of the newly added
492  // glyphs.
493  // ---------------------------------------------------------------------------
494  for (size_t i = 0; i < first_missing_index; i++) {
495  last_atlas->AddTypefaceGlyphPositionAndBounds(
496  new_glyphs[i], glyph_positions[i], glyph_sizes[i]);
497  }
498 
499  std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
500  std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
501 
502  fml::ScopedCleanupClosure closure([&]() {
503  blit_pass->EncodeCommands(context.GetResourceAllocator());
504  context.GetCommandQueue()->Submit({std::move(cmd_buffer)});
505  });
506 
507  // ---------------------------------------------------------------------------
508  // Step 4a: Draw new font-glyph pairs into the a host buffer and encode
509  // the uploads into the blit pass.
510  // ---------------------------------------------------------------------------
511  if (!UpdateAtlasBitmap(*last_atlas, blit_pass, host_buffer,
512  last_atlas->GetTexture(), new_glyphs, 0,
513  first_missing_index)) {
514  return nullptr;
515  }
516 
517  // If all glyphs fit, just return the old atlas.
518  if (first_missing_index == new_glyphs.size()) {
519  return last_atlas;
520  }
521  }
522 
523  int64_t height_adjustment = atlas_context->GetAtlasSize().height;
524  const int64_t max_texture_height =
525  context.GetResourceAllocator()->GetMaxTextureSizeSupported().height;
526 
527  // IF the current atlas size is as big as it can get, then "GC" and create an
528  // atlas with only the required glyphs. OpenGLES cannot reliably perform the
529  // blit required here, as 1) it requires attaching textures as read and write
530  // framebuffers which has substantially smaller size limits that max textures
531  // and 2) is missing a GLES 2.0 implementation and cap check.
532  bool blit_old_atlas = true;
533  std::shared_ptr<GlyphAtlas> new_atlas = last_atlas;
534  if (atlas_context->GetAtlasSize().height >= max_texture_height ||
536  blit_old_atlas = false;
537  new_atlas = std::make_shared<GlyphAtlas>(type);
538 
539  new_glyphs.clear();
540  glyph_sizes.clear();
541  CollectNewGlyphs(new_atlas, font_glyph_map, new_glyphs, glyph_sizes);
542  glyph_positions.clear();
543  glyph_positions.reserve(new_glyphs.size());
544  first_missing_index = 0;
545 
546  height_adjustment = 0;
547  atlas_context->UpdateRectPacker(nullptr);
548  atlas_context->UpdateGlyphAtlas(new_atlas, {0, 0}, 0);
549  }
550 
551  // A new glyph atlas must be created.
552  ISize atlas_size = ComputeNextAtlasSize(atlas_context, //
553  new_glyphs, //
554  glyph_positions, //
555  glyph_sizes, //
556  first_missing_index, //
557  max_texture_height //
558  );
559 
560  atlas_context->UpdateGlyphAtlas(new_atlas, atlas_size, height_adjustment);
561  if (atlas_size.IsEmpty()) {
562  return nullptr;
563  }
564  FML_DCHECK(new_glyphs.size() == glyph_positions.size());
565 
566  TextureDescriptor descriptor;
567  switch (type) {
569  descriptor.format =
570  context.GetCapabilities()->GetDefaultGlyphAtlasFormat();
571  break;
574  break;
575  }
576  descriptor.size = atlas_size;
578  descriptor.usage = TextureUsage::kShaderRead;
579  std::shared_ptr<Texture> new_texture =
580  context.GetResourceAllocator()->CreateTexture(descriptor);
581  if (!new_texture) {
582  return nullptr;
583  }
584 
585  new_texture->SetLabel("GlyphAtlas");
586 
587  std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
588  std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
589 
590  fml::ScopedCleanupClosure closure([&]() {
591  blit_pass->EncodeCommands(context.GetResourceAllocator());
592  context.GetCommandQueue()->Submit({std::move(cmd_buffer)});
593  });
594 
595  // Now append all remaining glyphs. This should never have any missing data...
596  auto old_texture = new_atlas->GetTexture();
597  new_atlas->SetTexture(std::move(new_texture));
598 
599  // ---------------------------------------------------------------------------
600  // Step 3a: Record the positions in the glyph atlas of the newly added
601  // glyphs.
602  // ---------------------------------------------------------------------------
603  for (size_t i = first_missing_index; i < glyph_positions.size(); i++) {
604  new_atlas->AddTypefaceGlyphPositionAndBounds(
605  new_glyphs[i], glyph_positions[i], glyph_sizes[i]);
606  }
607 
608  // ---------------------------------------------------------------------------
609  // Step 4a: Draw new font-glyph pairs into the a host buffer and encode
610  // the uploads into the blit pass.
611  // ---------------------------------------------------------------------------
612  if (!BulkUpdateAtlasBitmap(*new_atlas, blit_pass, host_buffer,
613  new_atlas->GetTexture(), new_glyphs,
614  first_missing_index, new_glyphs.size())) {
615  return nullptr;
616  }
617 
618  // Blit the old texture to the top left of the new atlas.
619  if (blit_old_atlas && old_texture) {
620  blit_pass->AddCopy(old_texture, new_atlas->GetTexture(),
621  IRect::MakeSize(new_atlas->GetTexture()->GetSize()),
622  {0, 0});
623  }
624 
625  // ---------------------------------------------------------------------------
626  // Step 8b: Record the texture in the glyph atlas.
627  // ---------------------------------------------------------------------------
628 
629  return new_atlas;
630 }
631 
632 } // namespace impeller
impeller::ISize
ISize64 ISize
Definition: size.h:140
impeller::GlyphAtlas::Type::kColorBitmap
@ kColorBitmap
host_buffer.h
impeller::Cap::kRound
@ kRound
impeller::Cap::kSquare
@ kSquare
impeller::HostBuffer::Emplace
BufferView Emplace(const BufferType &buffer, size_t alignment=0)
Emplace non-uniform data (like contiguous vertices) onto the host buffer.
Definition: host_buffer.h:95
impeller::TPoint::y
Type y
Definition: point.h:31
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::DrawGlyph
static void DrawGlyph(SkCanvas *canvas, const SkPoint position, const ScaledFont &scaled_font, const SubpixelGlyph &glyph, const Rect &scaled_bounds, const std::optional< GlyphProperties > &prop, bool has_color)
Definition: typographer_context_skia.cc:206
impeller::DefaultUniformAlignment
constexpr size_t DefaultUniformAlignment()
Definition: platform.h:14
impeller::GlyphAtlas::Type::kAlphaBitmap
@ kAlphaBitmap
impeller::FontGlyphMap
std::unordered_map< ScaledFont, std::unordered_set< SubpixelGlyph, SubpixelGlyph::Hash, SubpixelGlyph::Equal >, ScaledFont::Hash, ScaledFont::Equal > FontGlyphMap
Definition: font_glyph_pair.h:108
impeller::UpdateAtlasBitmap
static bool UpdateAtlasBitmap(const GlyphAtlas &atlas, std::shared_ptr< BlitPass > &blit_pass, HostBuffer &host_buffer, const std::shared_ptr< Texture > &texture, const std::vector< FontGlyphPair > &new_pairs, size_t start_index, size_t end_index)
Definition: typographer_context_skia.cc:311
impeller::TRect< Scalar >::MakeXYWH
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:136
impeller::FontGlyphAtlas
An object that can look up glyph locations within the GlyphAtlas for a particular typeface.
Definition: glyph_atlas.h:204
impeller::Context::GetCapabilities
virtual const std::shared_ptr< const Capabilities > & GetCapabilities() const =0
Get the capabilities of Impeller context. All optionally supported feature of the platform,...
impeller::HostBuffer
Definition: host_buffer.h:28
data
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
impeller::SubpixelGlyph::subpixel_offset
Point subpixel_offset
Definition: font_glyph_pair.h:56
impeller::TextureDescriptor::format
PixelFormat format
Definition: texture_descriptor.h:41
impeller::ScaledFont::font
Font font
Definition: font_glyph_pair.h:34
impeller::PixelFormat::kR8G8B8A8UNormInt
@ kR8G8B8A8UNormInt
texture_descriptor.h
impeller::SubpixelGlyph
A glyph and its subpixel position.
Definition: font_glyph_pair.h:54
impeller::TSize::Ceil
constexpr TSize Ceil() const
Definition: size.h:96
formats.h
impeller::IPoint16::x
int16_t x() const
Definition: rectangle_packer.h:16
typographer_context.h
buffer_view
BufferView buffer_view
Definition: blit_command_gles.cc:128
impeller::Size
TSize< Scalar > Size
Definition: size.h:137
impeller::Cap::kButt
@ kButt
impeller::TextureDescriptor::usage
TextureUsageMask usage
Definition: texture_descriptor.h:44
impeller::CollectNewGlyphs
static void CollectNewGlyphs(const std::shared_ptr< GlyphAtlas > &atlas, const FontGlyphMap &font_glyph_map, std::vector< FontGlyphPair > &new_glyphs, std::vector< Rect > &glyph_sizes)
Definition: typographer_context_skia.cc:405
impeller::IPoint16::y
int16_t y() const
Definition: rectangle_packer.h:17
impeller::SubpixelGlyph::properties
std::optional< GlyphProperties > properties
Definition: font_glyph_pair.h:57
impeller::Join::kMiter
@ kMiter
typographer_context_skia.h
impeller::Context::GetBackendType
virtual BackendType GetBackendType() const =0
Get the graphics backend of an Impeller context.
impeller::Font::GetTypeface
const std::shared_ptr< Typeface > & GetTypeface() const
The typeface whose intrinsic properties this font modifies.
Definition: font.cc:27
impeller::BulkUpdateAtlasBitmap
static bool BulkUpdateAtlasBitmap(const GlyphAtlas &atlas, std::shared_ptr< BlitPass > &blit_pass, HostBuffer &host_buffer, const std::shared_ptr< Texture > &texture, const std::vector< FontGlyphPair > &new_pairs, size_t start_index, size_t end_index)
Batch render to a single surface.
Definition: typographer_context_skia.cc:253
impeller::TypefaceSkia::GetSkiaTypeface
const sk_sp< SkTypeface > & GetSkiaTypeface() const
Definition: typeface_skia.cc:31
impeller::TSize< Scalar >
impeller::ComputeNextAtlasSize
static ISize ComputeNextAtlasSize(const std::shared_ptr< GlyphAtlasContext > &atlas_context, const std::vector< FontGlyphPair > &extra_pairs, std::vector< Rect > &glyph_positions, const std::vector< Rect > &glyph_sizes, size_t glyph_index_start, int64_t max_texture_height)
Definition: typographer_context_skia.cc:165
impeller::FontGlyphPair::glyph
const SubpixelGlyph & glyph
Definition: font_glyph_pair.h:118
render_pass.h
impeller::TRect::GetLeft
constexpr auto GetLeft() const
Definition: rect.h:345
impeller::BytesPerPixelForPixelFormat
constexpr size_t BytesPerPixelForPixelFormat(PixelFormat format)
Definition: formats.h:466
glyph.h
impeller::Context::BackendType::kOpenGLES
@ kOpenGLES
rectangle_packer.h
impeller::FontGlyphPair::scaled_font
const ScaledFont & scaled_font
Definition: font_glyph_pair.h:117
impeller::GlyphAtlas::GetType
Type GetType() const
Describes how the glyphs are represented in the texture.
Definition: glyph_atlas.cc:54
impeller::StorageMode::kDevicePrivate
@ kDevicePrivate
impeller::GlyphAtlas::GetTexture
const std::shared_ptr< Texture > & GetTexture() const
Get the texture for the glyph atlas.
Definition: glyph_atlas.cc:58
impeller::TypographerContextSkia::TypographerContextSkia
TypographerContextSkia()
impeller::GlyphAtlas::Type
Type
Describes how the glyphs are represented in the texture.
Definition: glyph_atlas.h:31
font_glyph_pair.h
type
GLenum type
Definition: blit_command_gles.cc:127
impeller::SubpixelGlyph::glyph
Glyph glyph
Definition: font_glyph_pair.h:55
impeller::RectanglePacker::Factory
static std::shared_ptr< RectanglePacker > Factory(int width, int height)
Return an empty packer with area specified by width and height.
Definition: rectangle_packer.cc:174
impeller::Glyph::index
uint16_t index
Definition: glyph.h:22
impeller::Context::CreateCommandBuffer
virtual std::shared_ptr< CommandBuffer > CreateCommandBuffer() const =0
Create a new command buffer. Command buffers can be used to encode graphics, blit,...
impeller::Context::GetCommandQueue
virtual std::shared_ptr< CommandQueue > GetCommandQueue() const =0
Return the graphics queue for submitting command buffers.
impeller::Join::kRound
@ kRound
impeller::FontGlyphPair
A font along with a glyph in that font rendered at a particular scale and subpixel position.
Definition: font_glyph_pair.h:114
impeller::Font::GetMetrics
const Metrics & GetMetrics() const
Definition: font.cc:45
platform.h
impeller::kPadding
constexpr auto kPadding
Definition: typographer_context_skia.cc:47
impeller::TSize::width
Type width
Definition: size.h:22
impeller::TPoint::x
Type x
Definition: point.h:30
impeller::TextureDescriptor::size
ISize size
Definition: texture_descriptor.h:42
impeller::ScaledFont::scale
Scalar scale
Definition: font_glyph_pair.h:35
impeller::Join::kBevel
@ kBevel
command_buffer.h
typeface_skia.h
allocator.h
impeller::BufferView
Definition: buffer_view.h:15
impeller::GlyphAtlas
A texture containing the bitmap representation of glyphs in different fonts along with the ability to...
Definition: glyph_atlas.h:27
impeller::FontGlyphAtlas::FindGlyphBounds
std::optional< std::pair< Rect, Rect > > FindGlyphBounds(const SubpixelGlyph &glyph) const
Find the location of a glyph in the atlas.
Definition: glyph_atlas.cc:119
impeller::TypographerContextSkia::CreateGlyphAtlasContext
std::shared_ptr< GlyphAtlasContext > CreateGlyphAtlasContext(GlyphAtlas::Type type) const override
Definition: typographer_context_skia.cc:84
impeller::Join
Join
Definition: path.h:24
impeller::TSize::Area
constexpr Type Area() const
Definition: size.h:102
impeller::Context
To do anything rendering related with Impeller, you need a context.
Definition: context.h:46
impeller::TRect::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150
buffer_view.h
impeller::TypographerContextSkia::~TypographerContextSkia
~TypographerContextSkia() override
rect.h
impeller::GlyphAtlas::FindFontGlyphBounds
std::optional< std::pair< Rect, Rect > > FindFontGlyphBounds(const FontGlyphPair &pair) const
Find the location of a specific font-glyph pair in the atlas.
Definition: glyph_atlas.cc:73
impeller::TPoint
Definition: point.h:27
impeller::BackendCast< TypefaceSkia, Typeface >::Cast
static TypefaceSkia & Cast(Typeface &base)
Definition: backend_cast.h:13
impeller::IPoint16
Definition: rectangle_packer.h:15
impeller::TextureUsage::kShaderRead
@ kShaderRead
scale
const Scalar scale
Definition: stroke_path_geometry.cc:301
impeller::TypographerContextSkia::CreateGlyphAtlas
std::shared_ptr< GlyphAtlas > CreateGlyphAtlas(Context &context, GlyphAtlas::Type type, HostBuffer &host_buffer, const std::shared_ptr< GlyphAtlasContext > &atlas_context, const FontGlyphMap &font_glyph_map) const override
Definition: typographer_context_skia.cc:446
impeller::ComputeGlyphSize
static Rect ComputeGlyphSize(const SkFont &font, const SubpixelGlyph &glyph, Scalar scale)
Definition: typographer_context_skia.cc:381
impeller::TextureDescriptor::storage_mode
StorageMode storage_mode
Definition: texture_descriptor.h:39
impeller::TSize::height
Type height
Definition: size.h:23
impeller::TRect< Scalar >::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
glyph_atlas.h
impeller::TextureDescriptor
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
Definition: texture_descriptor.h:38
impeller::TSize::IsEmpty
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition: size.h:105
render_target.h
impeller::AppendToExistingAtlas
static size_t AppendToExistingAtlas(const std::shared_ptr< GlyphAtlas > &atlas, const std::vector< FontGlyphPair > &extra_pairs, std::vector< Rect > &glyph_positions, const std::vector< Rect > &glyph_sizes, ISize atlas_size, int64_t height_adjustment, const std::shared_ptr< RectanglePacker > &rect_packer)
Definition: typographer_context_skia.cc:101
impeller
Definition: allocation.cc:12
impeller::Context::GetResourceAllocator
virtual std::shared_ptr< Allocator > GetResourceAllocator() const =0
Returns the allocator used to create textures and buffers on the device.
impeller::TRect::GetTop
constexpr auto GetTop() const
Definition: rect.h:347
impeller::PairsFitInAtlasOfSize
static size_t PairsFitInAtlasOfSize(const std::vector< FontGlyphPair > &pairs, const ISize &atlas_size, std::vector< Rect > &glyph_positions, const std::vector< Rect > &glyph_sizes, int64_t height_adjustment, const std::shared_ptr< RectanglePacker > &rect_packer, size_t start_index)
Definition: typographer_context_skia.cc:135
impeller::TypographerContextSkia::Make
static std::shared_ptr< TypographerContext > Make()
Definition: typographer_context_skia.cc:75
impeller::TRect
Definition: rect.h:122
impeller::GetImageInfo
static SkImageInfo GetImageInfo(const GlyphAtlas &atlas, Size size)
Definition: typographer_context_skia.cc:88
impeller::ScaledFont
A font and a scale. Used as a key that represents a typeface within a glyph atlas.
Definition: font_glyph_pair.h:33
size.h
impeller::TypographerContext::IsValid
virtual bool IsValid() const
Definition: typographer_context.cc:17
impeller::Cap
Cap
Definition: path.h:18