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 // TODO(bdero): We might be able to remove this per-glyph padding if we fix
48 // the underlying causes of the overlap.
49 // https://github.com/flutter/flutter/issues/114563
50 constexpr auto kPadding = 2;
51 
52 namespace {
53 SkPaint::Cap ToSkiaCap(Cap cap) {
54  switch (cap) {
55  case Cap::kButt:
56  return SkPaint::Cap::kButt_Cap;
57  case Cap::kRound:
58  return SkPaint::Cap::kRound_Cap;
59  case Cap::kSquare:
60  return SkPaint::Cap::kSquare_Cap;
61  }
62  FML_UNREACHABLE();
63 }
64 
65 SkPaint::Join ToSkiaJoin(Join join) {
66  switch (join) {
67  case Join::kMiter:
68  return SkPaint::Join::kMiter_Join;
69  case Join::kRound:
70  return SkPaint::Join::kRound_Join;
71  case Join::kBevel:
72  return SkPaint::Join::kBevel_Join;
73  }
74  FML_UNREACHABLE();
75 }
76 } // namespace
77 
78 std::shared_ptr<TypographerContext> TypographerContextSkia::Make() {
79  return std::make_shared<TypographerContextSkia>();
80 }
81 
83 
85 
86 std::shared_ptr<GlyphAtlasContext>
88  return std::make_shared<GlyphAtlasContext>(type);
89 }
90 
91 static SkImageInfo GetImageInfo(const GlyphAtlas& atlas, Size size) {
92  switch (atlas.GetType()) {
94  return SkImageInfo::MakeA8(SkISize{static_cast<int32_t>(size.width),
95  static_cast<int32_t>(size.height)});
97  return SkImageInfo::MakeN32Premul(size.width, size.height);
98  }
99  FML_UNREACHABLE();
100 }
101 
102 /// Append as many glyphs to the texture as will fit, and return the first index
103 /// of [extra_pairs] that did not fit.
104 static size_t AppendToExistingAtlas(
105  const std::shared_ptr<GlyphAtlas>& atlas,
106  const std::vector<FontGlyphPair>& extra_pairs,
107  std::vector<Rect>& glyph_positions,
108  const std::vector<Rect>& glyph_sizes,
109  ISize atlas_size,
110  int64_t height_adjustment,
111  const std::shared_ptr<RectanglePacker>& rect_packer) {
112  TRACE_EVENT0("impeller", __FUNCTION__);
113  if (!rect_packer || atlas_size.IsEmpty()) {
114  return 0;
115  }
116 
117  for (size_t i = 0; i < extra_pairs.size(); i++) {
118  ISize glyph_size = ISize::Ceil(glyph_sizes[i].GetSize());
119  IPoint16 location_in_atlas;
120  if (!rect_packer->AddRect(glyph_size.width + kPadding, //
121  glyph_size.height + kPadding, //
122  &location_in_atlas //
123  )) {
124  return i;
125  }
126  // Position the glyph in the center of the 1px padding.
127  glyph_positions.push_back(Rect::MakeXYWH(
128  location_in_atlas.x() + 1, //
129  location_in_atlas.y() + height_adjustment + 1, //
130  glyph_size.width, //
131  glyph_size.height //
132  ));
133  }
134 
135  return extra_pairs.size();
136 }
137 
138 static size_t PairsFitInAtlasOfSize(
139  const std::vector<FontGlyphPair>& pairs,
140  const ISize& atlas_size,
141  std::vector<Rect>& glyph_positions,
142  const std::vector<Rect>& glyph_sizes,
143  int64_t height_adjustment,
144  const std::shared_ptr<RectanglePacker>& rect_packer,
145  size_t start_index) {
146  FML_DCHECK(!atlas_size.IsEmpty());
147 
148  for (size_t i = start_index; i < pairs.size(); i++) {
149  ISize glyph_size = ISize::Ceil(glyph_sizes[i].GetSize());
150  IPoint16 location_in_atlas;
151  if (!rect_packer->AddRect(glyph_size.width + kPadding, //
152  glyph_size.height + kPadding, //
153  &location_in_atlas //
154  )) {
155  return i;
156  }
157  glyph_positions.push_back(Rect::MakeXYWH(
158  location_in_atlas.x() + 1, //
159  location_in_atlas.y() + height_adjustment + 1, //
160  glyph_size.width, //
161  glyph_size.height //
162  ));
163  }
164 
165  return pairs.size();
166 }
167 
169  const std::shared_ptr<GlyphAtlasContext>& atlas_context,
170  const std::vector<FontGlyphPair>& extra_pairs,
171  std::vector<Rect>& glyph_positions,
172  const std::vector<Rect>& glyph_sizes,
173  size_t glyph_index_start,
174  int64_t max_texture_height) {
175  // Because we can't grow the skyline packer horizontally, pick a reasonable
176  // large width for all atlases.
177  static constexpr int64_t kAtlasWidth = 4096;
178  static constexpr int64_t kMinAtlasHeight = 1024;
179 
180  ISize current_size = ISize(kAtlasWidth, kMinAtlasHeight);
181  if (atlas_context->GetAtlasSize().height > current_size.height) {
182  current_size.height = atlas_context->GetAtlasSize().height * 2;
183  }
184 
185  auto height_adjustment = atlas_context->GetAtlasSize().height;
186  while (current_size.height <= max_texture_height) {
187  std::shared_ptr<RectanglePacker> rect_packer;
188  if (atlas_context->GetRectPacker() || glyph_index_start) {
189  rect_packer = RectanglePacker::Factory(
190  kAtlasWidth,
191  current_size.height - atlas_context->GetAtlasSize().height);
192  } else {
193  rect_packer = RectanglePacker::Factory(kAtlasWidth, current_size.height);
194  }
195  glyph_positions.erase(glyph_positions.begin() + glyph_index_start,
196  glyph_positions.end());
197  atlas_context->UpdateRectPacker(rect_packer);
198  auto next_index = PairsFitInAtlasOfSize(
199  extra_pairs, current_size, glyph_positions, glyph_sizes,
200  height_adjustment, rect_packer, glyph_index_start);
201  if (next_index == extra_pairs.size()) {
202  return current_size;
203  }
204  current_size = ISize(current_size.width, current_size.height * 2);
205  }
206  return {};
207 }
208 
209 static void DrawGlyph(SkCanvas* canvas,
210  const ScaledFont& scaled_font,
211  const SubpixelGlyph& glyph,
212  const Rect& scaled_bounds,
213  const GlyphProperties& prop,
214  bool has_color) {
215  const auto& metrics = scaled_font.font.GetMetrics();
216  SkPoint position = SkPoint::Make(1, 1);
217  SkGlyphID glyph_id = glyph.glyph.index;
218 
219  SkFont sk_font(
221  metrics.point_size, metrics.scaleX, metrics.skewX);
222  sk_font.setEdging(SkFont::Edging::kAntiAlias);
223  sk_font.setHinting(SkFontHinting::kSlight);
224  sk_font.setEmbolden(metrics.embolden);
225  sk_font.setSubpixel(true);
226  sk_font.setSize(sk_font.getSize() * scaled_font.scale);
227 
228  auto glyph_color =
229  has_color ? glyph.properties.color.ToARGB() : SK_ColorBLACK;
230 
231  SkPaint glyph_paint;
232  glyph_paint.setColor(glyph_color);
233  glyph_paint.setBlendMode(SkBlendMode::kSrc);
234  if (prop.stroke) {
235  glyph_paint.setStroke(true);
236  glyph_paint.setStrokeWidth(prop.stroke_width * scaled_font.scale);
237  glyph_paint.setStrokeCap(ToSkiaCap(glyph.properties.stroke_cap));
238  glyph_paint.setStrokeJoin(ToSkiaJoin(glyph.properties.stroke_join));
239  glyph_paint.setStrokeMiter(prop.stroke_miter * scaled_font.scale);
240  }
241  canvas->translate(glyph.subpixel_offset.x, glyph.subpixel_offset.y);
242  canvas->drawGlyphs(1u, // count
243  &glyph_id, // glyphs
244  &position, // positions
245  SkPoint::Make(-scaled_bounds.GetLeft(),
246  -scaled_bounds.GetTop()), // origin
247  sk_font, // font
248  glyph_paint // paint
249  );
250 }
251 
252 static bool UpdateAtlasBitmap(const GlyphAtlas& atlas,
253  std::shared_ptr<BlitPass>& blit_pass,
254  HostBuffer& host_buffer,
255  const std::shared_ptr<Texture>& texture,
256  const std::vector<FontGlyphPair>& new_pairs,
257  size_t start_index,
258  size_t end_index) {
259  TRACE_EVENT0("impeller", __FUNCTION__);
260 
261  bool has_color = atlas.GetType() == GlyphAtlas::Type::kColorBitmap;
262 
263  for (size_t i = start_index; i < end_index; i++) {
264  const FontGlyphPair& pair = new_pairs[i];
265  auto data = atlas.FindFontGlyphBounds(pair);
266  if (!data.has_value()) {
267  continue;
268  }
269  auto [pos, bounds] = data.value();
270  Size size = pos.GetSize();
271  if (size.IsEmpty()) {
272  continue;
273  }
274  // The uploaded bitmap is expanded by 1px of padding
275  // on each side.
276  size.width += 2;
277  size.height += 2;
278 
279  SkBitmap bitmap;
280  bitmap.setInfo(GetImageInfo(atlas, size));
281  if (!bitmap.tryAllocPixels()) {
282  return false;
283  }
284 
285  auto surface = SkSurfaces::WrapPixels(bitmap.pixmap());
286  if (!surface) {
287  return false;
288  }
289  auto canvas = surface->getCanvas();
290  if (!canvas) {
291  return false;
292  }
293 
294  DrawGlyph(canvas, pair.scaled_font, pair.glyph, bounds,
295  pair.glyph.properties, has_color);
296 
297  // Writing to a malloc'd buffer and then copying to the staging buffers
298  // benchmarks as substantially faster on a number of Android devices.
299  BufferView buffer_view = host_buffer.Emplace(
300  bitmap.getAddr(0, 0),
302  atlas.GetTexture()->GetTextureDescriptor().format),
304 
305  // convert_to_read is set to false so that the texture remains in a transfer
306  // dst layout until we finish writing to it below. This only has an impact
307  // on Vulkan where we are responsible for managing image layouts.
308  if (!blit_pass->AddCopy(std::move(buffer_view), //
309  texture, //
310  IRect::MakeXYWH(pos.GetLeft() - 1, pos.GetTop() - 1,
311  size.width, size.height), //
312  /*label=*/"", //
313  /*slice=*/0, //
314  /*convert_to_read=*/false //
315  )) {
316  return false;
317  }
318  }
319  return blit_pass->ConvertTextureToShaderRead(texture);
320 }
321 
322 static Rect ComputeGlyphSize(const SkFont& font,
323  const SubpixelGlyph& glyph,
324  Scalar scale) {
325  SkRect scaled_bounds;
326  SkPaint glyph_paint;
327  if (glyph.properties.stroke) {
328  glyph_paint.setStroke(true);
329  glyph_paint.setStrokeWidth(glyph.properties.stroke_width * scale);
330  glyph_paint.setStrokeCap(ToSkiaCap(glyph.properties.stroke_cap));
331  glyph_paint.setStrokeJoin(ToSkiaJoin(glyph.properties.stroke_join));
332  glyph_paint.setStrokeMiter(glyph.properties.stroke_miter * scale);
333  }
334  font.getBounds(&glyph.glyph.index, 1, &scaled_bounds, &glyph_paint);
335 
336  // Expand the bounds of glyphs at subpixel offsets by 2 in the x direction.
337  Scalar adjustment = 0.0;
338  if (glyph.subpixel_offset != Point(0, 0)) {
339  adjustment = 1.0;
340  }
341  return Rect::MakeLTRB(scaled_bounds.fLeft - adjustment, scaled_bounds.fTop,
342  scaled_bounds.fRight + adjustment,
343  scaled_bounds.fBottom);
344 };
345 
346 std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
347  Context& context,
349  HostBuffer& host_buffer,
350  const std::shared_ptr<GlyphAtlasContext>& atlas_context,
351  const FontGlyphMap& font_glyph_map) const {
352  TRACE_EVENT0("impeller", __FUNCTION__);
353  if (!IsValid()) {
354  return nullptr;
355  }
356  std::shared_ptr<GlyphAtlas> last_atlas = atlas_context->GetGlyphAtlas();
357  FML_DCHECK(last_atlas->GetType() == type);
358 
359  if (font_glyph_map.empty()) {
360  return last_atlas;
361  }
362 
363  // ---------------------------------------------------------------------------
364  // Step 1: Determine if the atlas type and font glyph pairs are compatible
365  // with the current atlas and reuse if possible. For each new font and
366  // glyph pair, compute the glyph size at scale.
367  // ---------------------------------------------------------------------------
368  std::vector<Rect> glyph_sizes;
369  std::vector<FontGlyphPair> new_glyphs;
370  for (const auto& font_value : font_glyph_map) {
371  const ScaledFont& scaled_font = font_value.first;
372  const FontGlyphAtlas* font_glyph_atlas =
373  last_atlas->GetFontGlyphAtlas(scaled_font.font, scaled_font.scale);
374 
375  auto metrics = scaled_font.font.GetMetrics();
376 
377  SkFont sk_font(
379  metrics.point_size, metrics.scaleX, metrics.skewX);
380  sk_font.setEdging(SkFont::Edging::kAntiAlias);
381  sk_font.setHinting(SkFontHinting::kSlight);
382  sk_font.setEmbolden(metrics.embolden);
383  // Rather than computing the bounds at the requested point size and scaling
384  // up the bounds, we scale up the font size and request the bounds. This
385  // seems to give more accurate bounds information.
386  sk_font.setSize(sk_font.getSize() * scaled_font.scale);
387  sk_font.setSubpixel(true);
388 
389  if (font_glyph_atlas) {
390  for (const SubpixelGlyph& glyph : font_value.second) {
391  if (!font_glyph_atlas->FindGlyphBounds(glyph)) {
392  new_glyphs.emplace_back(scaled_font, glyph);
393  glyph_sizes.push_back(
394  ComputeGlyphSize(sk_font, glyph, scaled_font.scale));
395  }
396  }
397  } else {
398  for (const SubpixelGlyph& glyph : font_value.second) {
399  new_glyphs.emplace_back(scaled_font, glyph);
400  glyph_sizes.push_back(
401  ComputeGlyphSize(sk_font, glyph, scaled_font.scale));
402  }
403  }
404  }
405  if (new_glyphs.size() == 0) {
406  return last_atlas;
407  }
408 
409  // ---------------------------------------------------------------------------
410  // Step 2: Determine if the additional missing glyphs can be appended to the
411  // existing bitmap without recreating the atlas.
412  // ---------------------------------------------------------------------------
413  std::vector<Rect> glyph_positions;
414  glyph_positions.reserve(new_glyphs.size());
415  size_t first_missing_index = 0;
416 
417  if (last_atlas->GetTexture()) {
418  // Append all glyphs that fit into the current atlas.
419  first_missing_index = AppendToExistingAtlas(
420  last_atlas, new_glyphs, glyph_positions, glyph_sizes,
421  atlas_context->GetAtlasSize(), atlas_context->GetHeightAdjustment(),
422  atlas_context->GetRectPacker());
423 
424  // ---------------------------------------------------------------------------
425  // Step 3a: Record the positions in the glyph atlas of the newly added
426  // glyphs.
427  // ---------------------------------------------------------------------------
428  for (size_t i = 0; i < first_missing_index; i++) {
429  last_atlas->AddTypefaceGlyphPositionAndBounds(
430  new_glyphs[i], glyph_positions[i], glyph_sizes[i]);
431  }
432 
433  std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
434  std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
435 
436  fml::ScopedCleanupClosure closure([&]() {
437  blit_pass->EncodeCommands(context.GetResourceAllocator());
438  context.GetCommandQueue()->Submit({std::move(cmd_buffer)});
439  });
440 
441  // ---------------------------------------------------------------------------
442  // Step 4a: Draw new font-glyph pairs into the a host buffer and encode
443  // the uploads into the blit pass.
444  // ---------------------------------------------------------------------------
445  if (!UpdateAtlasBitmap(*last_atlas, blit_pass, host_buffer,
446  last_atlas->GetTexture(), new_glyphs, 0,
447  first_missing_index)) {
448  return nullptr;
449  }
450 
451  // If all glyphs fit, just return the old atlas.
452  if (first_missing_index == new_glyphs.size()) {
453  return last_atlas;
454  }
455  }
456 
457  int64_t height_adjustment = atlas_context->GetAtlasSize().height;
458  const int64_t max_texture_height =
459  context.GetResourceAllocator()->GetMaxTextureSizeSupported().height;
460 
461  // IF the current atlas size is as big as it can get, then "GC" and create an
462  // atlas with only the required glyphs. OpenGLES cannot reliably perform the
463  // blit required here, as 1) it requires attaching textures as read and write
464  // framebuffers which has substantially smaller size limits that max textures
465  // and 2) is missing a GLES 2.0 implementation and cap check.
466  bool blit_old_atlas = true;
467  std::shared_ptr<GlyphAtlas> new_atlas = last_atlas;
468  if (atlas_context->GetAtlasSize().height >= max_texture_height ||
470  blit_old_atlas = false;
471  first_missing_index = 0;
472  glyph_positions.clear();
473  height_adjustment = 0;
474  new_atlas = std::make_shared<GlyphAtlas>(type);
475  atlas_context->UpdateRectPacker(nullptr);
476  atlas_context->UpdateGlyphAtlas(new_atlas, {0, 0}, 0);
477  }
478 
479  // A new glyph atlas must be created.
480  ISize atlas_size = ComputeNextAtlasSize(atlas_context, //
481  new_glyphs, //
482  glyph_positions, //
483  glyph_sizes, //
484  first_missing_index, //
485  max_texture_height //
486  );
487 
488  atlas_context->UpdateGlyphAtlas(new_atlas, atlas_size, height_adjustment);
489  if (atlas_size.IsEmpty()) {
490  return nullptr;
491  }
492  FML_DCHECK(new_glyphs.size() == glyph_positions.size());
493 
494  TextureDescriptor descriptor;
495  switch (type) {
497  descriptor.format =
498  context.GetCapabilities()->GetDefaultGlyphAtlasFormat();
499  break;
502  break;
503  }
504  descriptor.size = atlas_size;
506  descriptor.usage = TextureUsage::kShaderRead;
507  std::shared_ptr<Texture> new_texture =
508  context.GetResourceAllocator()->CreateTexture(descriptor);
509  if (!new_texture) {
510  return nullptr;
511  }
512 
513  new_texture->SetLabel("GlyphAtlas");
514 
515  std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
516  std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
517 
518  // The R8/A8 textures used for certain glyphs is not supported as color
519  // attachments in most graphics drivers. For other textures, most framebuffer
520  // attachments have a much smaller size limit than the max texture size.
521  {
522  TRACE_EVENT0("flutter", "ClearGlyphAtlas");
523  size_t byte_size =
524  new_texture->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
526  host_buffer.Emplace(nullptr, byte_size, DefaultUniformAlignment());
527 
528  ::memset(buffer_view.buffer->OnGetContents() + buffer_view.range.offset, 0,
529  byte_size);
530  buffer_view.buffer->Flush();
531  blit_pass->AddCopy(buffer_view, new_texture);
532  }
533 
534  fml::ScopedCleanupClosure closure([&]() {
535  blit_pass->EncodeCommands(context.GetResourceAllocator());
536  context.GetCommandQueue()->Submit({std::move(cmd_buffer)});
537  });
538 
539  // Blit the old texture to the top left of the new atlas.
540  if (new_atlas->GetTexture() && blit_old_atlas) {
541  blit_pass->AddCopy(new_atlas->GetTexture(), new_texture,
542  IRect::MakeSize(new_atlas->GetTexture()->GetSize()),
543  {0, 0});
544  }
545 
546  // Now append all remaining glyphs. This should never have any missing data...
547  new_atlas->SetTexture(std::move(new_texture));
548 
549  // ---------------------------------------------------------------------------
550  // Step 3a: Record the positions in the glyph atlas of the newly added
551  // glyphs.
552  // ---------------------------------------------------------------------------
553  for (size_t i = first_missing_index; i < glyph_positions.size(); i++) {
554  new_atlas->AddTypefaceGlyphPositionAndBounds(
555  new_glyphs[i], glyph_positions[i], glyph_sizes[i]);
556  }
557 
558  // ---------------------------------------------------------------------------
559  // Step 4a: Draw new font-glyph pairs into the a host buffer and encode
560  // the uploads into the blit pass.
561  // ---------------------------------------------------------------------------
562  if (!UpdateAtlasBitmap(*new_atlas, blit_pass, host_buffer,
563  new_atlas->GetTexture(), new_glyphs,
564  first_missing_index, new_glyphs.size())) {
565  return nullptr;
566  }
567  // ---------------------------------------------------------------------------
568  // Step 8b: Record the texture in the glyph atlas.
569  // ---------------------------------------------------------------------------
570 
571  return new_atlas;
572 }
573 
574 } // 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::DefaultUniformAlignment
constexpr size_t DefaultUniformAlignment()
Definition: platform.h:14
impeller::GlyphAtlas::Type::kAlphaBitmap
@ kAlphaBitmap
impeller::GlyphProperties
Definition: font_glyph_pair.h:19
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:252
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:200
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:42
impeller::TextureDescriptor::format
PixelFormat format
Definition: texture_descriptor.h:41
impeller::ScaledFont::font
Font font
Definition: font_glyph_pair.h:33
impeller::PixelFormat::kR8G8B8A8UNormInt
@ kR8G8B8A8UNormInt
texture_descriptor.h
impeller::SubpixelGlyph
A glyph and its subpixel position.
Definition: font_glyph_pair.h:40
formats.h
impeller::TSize::Ceil
constexpr TSize Ceil() const
Definition: size.h:96
impeller::Color::ToARGB
constexpr uint32_t ToARGB() const
Convert to ARGB 32 bit color.
Definition: color.h:261
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:127
impeller::GlyphProperties::stroke_miter
Scalar stroke_miter
Definition: font_glyph_pair.h:24
impeller::Cap::kButt
@ kButt
impeller::TextureDescriptor::usage
TextureUsageMask usage
Definition: texture_descriptor.h:44
impeller::GlyphProperties::color
Color color
Definition: font_glyph_pair.h:20
impeller::IPoint16::y
int16_t y() const
Definition: rectangle_packer.h:17
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::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:168
impeller::FontGlyphPair::glyph
const SubpixelGlyph & glyph
Definition: font_glyph_pair.h:64
render_pass.h
impeller::TRect::GetLeft
constexpr auto GetLeft() const
Definition: rect.h:341
impeller::BytesPerPixelForPixelFormat
constexpr size_t BytesPerPixelForPixelFormat(PixelFormat format)
Definition: formats.h:460
glyph.h
impeller::Context::BackendType::kOpenGLES
@ kOpenGLES
rectangle_packer.h
impeller::FontGlyphPair::scaled_font
const ScaledFont & scaled_font
Definition: font_glyph_pair.h:63
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
impeller::FontGlyphMap
std::unordered_map< ScaledFont, std::unordered_set< SubpixelGlyph > > FontGlyphMap
Definition: font_glyph_pair.h:54
font_glyph_pair.h
type
GLenum type
Definition: blit_command_gles.cc:126
impeller::SubpixelGlyph::glyph
Glyph glyph
Definition: font_glyph_pair.h:41
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::SubpixelGlyph::properties
GlyphProperties properties
Definition: font_glyph_pair.h:43
impeller::GlyphProperties::stroke_join
Join stroke_join
Definition: font_glyph_pair.h:23
impeller::Glyph::index
uint16_t index
Definition: glyph.h:22
impeller::GlyphProperties::stroke
bool stroke
Definition: font_glyph_pair.h:25
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:60
impeller::Font::GetMetrics
const Metrics & GetMetrics() const
Definition: font.cc:45
platform.h
impeller::kPadding
constexpr auto kPadding
Definition: typographer_context_skia.cc:50
impeller::TSize::width
Type width
Definition: size.h:22
impeller::TPoint::x
Type x
Definition: point.h:30
impeller::GlyphProperties::stroke_width
Scalar stroke_width
Definition: font_glyph_pair.h:21
impeller::TextureDescriptor::size
ISize size
Definition: texture_descriptor.h:42
impeller::ScaledFont::scale
Scalar scale
Definition: font_glyph_pair.h:34
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:87
impeller::GlyphProperties::stroke_cap
Cap stroke_cap
Definition: font_glyph_pair.h:22
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:45
impeller::TRect::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:146
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:308
impeller::DrawGlyph
static void DrawGlyph(SkCanvas *canvas, const ScaledFont &scaled_font, const SubpixelGlyph &glyph, const Rect &scaled_bounds, const GlyphProperties &prop, bool has_color)
Definition: typographer_context_skia.cc:209
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:346
impeller::ComputeGlyphSize
static Rect ComputeGlyphSize(const SkFont &font, const SubpixelGlyph &glyph, Scalar scale)
Definition: typographer_context_skia.cc:322
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:104
impeller
Definition: aiks_blend_unittests.cc:18
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:343
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:138
impeller::TypographerContextSkia::Make
static std::shared_ptr< TypographerContext > Make()
Definition: typographer_context_skia.cc:78
impeller::TRect< Scalar >
impeller::GetImageInfo
static SkImageInfo GetImageInfo(const GlyphAtlas &atlas, Size size)
Definition: typographer_context_skia.cc:91
impeller::ScaledFont
A font and a scale. Used as a key that represents a typeface within a glyph atlas.
Definition: font_glyph_pair.h:32
size.h
impeller::TypographerContext::IsValid
virtual bool IsValid() const
Definition: typographer_context.cc:17
impeller::Cap
Cap
Definition: path.h:18