13 #include "flutter/fml/logging.h"
14 #include "flutter/fml/trace_event.h"
15 #include "fml/closure.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"
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"
53 return SkPaint::Cap::kButt_Cap;
55 return SkPaint::Cap::kRound_Cap;
57 return SkPaint::Cap::kSquare_Cap;
65 return SkPaint::Join::kMiter_Join;
67 return SkPaint::Join::kRound_Join;
69 return SkPaint::Join::kBevel_Join;
76 return std::make_shared<TypographerContextSkia>();
83 std::shared_ptr<GlyphAtlasContext>
85 return std::make_shared<GlyphAtlasContext>(
type);
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);
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,
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()) {
114 for (
size_t i = 0; i < extra_pairs.size(); i++) {
125 location_in_atlas.
x() + 1,
126 location_in_atlas.
y() + height_adjustment + 1,
132 return extra_pairs.size();
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());
145 for (
size_t i = start_index; i < pairs.size(); i++) {
155 location_in_atlas.
x() + 1,
156 location_in_atlas.
y() + height_adjustment + 1,
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) {
174 static constexpr int64_t kAtlasWidth = 4096;
175 static constexpr int64_t kMinAtlasHeight = 1024;
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;
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) {
188 current_size.
height - atlas_context->GetAtlasSize().height);
192 glyph_positions.erase(glyph_positions.begin() + glyph_index_start,
193 glyph_positions.end());
194 atlas_context->UpdateRectPacker(rect_packer);
196 extra_pairs, current_size, glyph_positions, glyph_sizes,
197 height_adjustment, rect_packer, glyph_index_start);
198 if (next_index == extra_pairs.size()) {
207 const SkPoint position,
210 const Rect& scaled_bounds,
211 const std::optional<GlyphProperties>& prop,
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);
225 auto glyph_color = prop.has_value() ? prop->color.ToARGB() : SK_ColorBLACK;
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);
239 canvas->drawGlyphs(1u,
242 SkPoint::Make(-scaled_bounds.
GetLeft(),
254 std::shared_ptr<BlitPass>& blit_pass,
256 const std::shared_ptr<Texture>& texture,
257 const std::vector<FontGlyphPair>& new_pairs,
260 TRACE_EVENT0(
"impeller", __FUNCTION__);
266 if (!bitmap.tryAllocPixels()) {
270 auto surface = SkSurfaces::WrapPixels(bitmap.pixmap());
274 auto canvas = surface->getCanvas();
279 for (
size_t i = start_index; i < end_index; i++) {
282 if (!
data.has_value()) {
285 auto [pos, bounds] =
data.value();
286 Size size = pos.GetSize();
291 DrawGlyph(canvas, SkPoint::Make(pos.GetLeft(), pos.GetTop()),
299 bitmap.getAddr(0, 0),
300 texture->GetSize().Area() *
302 atlas.
GetTexture()->GetTextureDescriptor().format),
308 texture->GetSize().height));
312 std::shared_ptr<BlitPass>& blit_pass,
314 const std::shared_ptr<Texture>& texture,
315 const std::vector<FontGlyphPair>& new_pairs,
318 TRACE_EVENT0(
"impeller", __FUNCTION__);
322 for (
size_t i = start_index; i < end_index; i++) {
325 if (!
data.has_value()) {
328 auto [pos, bounds] =
data.value();
329 Size size = pos.GetSize();
340 if (!bitmap.tryAllocPixels()) {
344 auto surface = SkSurfaces::WrapPixels(bitmap.pixmap());
348 auto canvas = surface->getCanvas();
359 bitmap.getAddr(0, 0),
361 atlas.
GetTexture()->GetTextureDescriptor().format),
378 return blit_pass->ConvertTextureToShaderRead(texture);
384 SkRect scaled_bounds;
387 glyph_paint.setStroke(
true);
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);
393 font.getBounds(&glyph.
glyph.
index, 1, &scaled_bounds, &glyph_paint);
400 return Rect::MakeLTRB(scaled_bounds.fLeft - adjustment, scaled_bounds.fTop,
401 scaled_bounds.fRight + adjustment,
402 scaled_bounds.fBottom);
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;
412 atlas->GetFontGlyphAtlas(scaled_font.
font, scaled_font.
scale);
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);
425 sk_font.setSize(sk_font.getSize() * scaled_font.
scale);
426 sk_font.setSubpixel(
true);
428 if (font_glyph_atlas) {
431 new_glyphs.emplace_back(scaled_font, glyph);
432 glyph_sizes.push_back(
438 new_glyphs.emplace_back(scaled_font, glyph);
439 glyph_sizes.push_back(
450 const std::shared_ptr<GlyphAtlasContext>& atlas_context,
452 TRACE_EVENT0(
"impeller", __FUNCTION__);
456 std::shared_ptr<GlyphAtlas> last_atlas = atlas_context->GetGlyphAtlas();
457 FML_DCHECK(last_atlas->GetType() ==
type);
459 if (font_glyph_map.empty()) {
468 std::vector<FontGlyphPair> new_glyphs;
469 std::vector<Rect> glyph_sizes;
471 if (new_glyphs.size() == 0) {
479 std::vector<Rect> glyph_positions;
480 glyph_positions.reserve(new_glyphs.size());
481 size_t first_missing_index = 0;
483 if (last_atlas->GetTexture()) {
486 last_atlas, new_glyphs, glyph_positions, glyph_sizes,
487 atlas_context->GetAtlasSize(), atlas_context->GetHeightAdjustment(),
488 atlas_context->GetRectPacker());
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]);
500 std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
502 fml::ScopedCleanupClosure closure([&]() {
512 last_atlas->GetTexture(), new_glyphs, 0,
513 first_missing_index)) {
518 if (first_missing_index == new_glyphs.size()) {
523 int64_t height_adjustment = atlas_context->GetAtlasSize().height;
524 const int64_t max_texture_height =
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);
542 glyph_positions.clear();
543 glyph_positions.reserve(new_glyphs.size());
544 first_missing_index = 0;
546 height_adjustment = 0;
547 atlas_context->UpdateRectPacker(
nullptr);
548 atlas_context->UpdateGlyphAtlas(new_atlas, {0, 0}, 0);
560 atlas_context->UpdateGlyphAtlas(new_atlas, atlas_size, height_adjustment);
564 FML_DCHECK(new_glyphs.size() == glyph_positions.size());
576 descriptor.
size = atlas_size;
579 std::shared_ptr<Texture> new_texture =
585 new_texture->SetLabel(
"GlyphAtlas");
588 std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
590 fml::ScopedCleanupClosure closure([&]() {
596 auto old_texture = new_atlas->GetTexture();
597 new_atlas->SetTexture(std::move(new_texture));
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]);
613 new_atlas->GetTexture(), new_glyphs,
614 first_missing_index, new_glyphs.size())) {
619 if (blit_old_atlas && old_texture) {
620 blit_pass->AddCopy(old_texture, new_atlas->GetTexture(),