[Impeller] backfilling TextContents unit tests (#161625)
issue: https://github.com/flutter/flutter/issues/149652 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
parent
bdecbaec9d
commit
52cfc8b073
@ -160,6 +160,7 @@
|
||||
../../../flutter/impeller/entity/contents/filters/matrix_filter_contents_unittests.cc
|
||||
../../../flutter/impeller/entity/contents/host_buffer_unittests.cc
|
||||
../../../flutter/impeller/entity/contents/test
|
||||
../../../flutter/impeller/entity/contents/text_contents_unittests.cc
|
||||
../../../flutter/impeller/entity/contents/tiled_texture_contents_unittests.cc
|
||||
../../../flutter/impeller/entity/draw_order_resolver_unittests.cc
|
||||
../../../flutter/impeller/entity/entity_pass_target_unittests.cc
|
||||
|
@ -248,6 +248,7 @@ impeller_component("entity_unittests") {
|
||||
"contents/filters/inputs/filter_input_unittests.cc",
|
||||
"contents/filters/matrix_filter_contents_unittests.cc",
|
||||
"contents/host_buffer_unittests.cc",
|
||||
"contents/text_contents_unittests.cc",
|
||||
"contents/tiled_texture_contents_unittests.cc",
|
||||
"draw_order_resolver_unittests.cc",
|
||||
"entity_pass_target_unittests.cc",
|
||||
@ -266,5 +267,6 @@ impeller_component("entity_unittests") {
|
||||
"../playground:playground_test",
|
||||
"//flutter/display_list/testing:display_list_testing",
|
||||
"//flutter/impeller/typographer/backends/skia:typographer_skia_backend",
|
||||
"//flutter/third_party/txt",
|
||||
]
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "impeller/core/buffer_view.h"
|
||||
#include "impeller/core/formats.h"
|
||||
#include "impeller/core/sampler_descriptor.h"
|
||||
#include "impeller/entity/contents/content_context.h"
|
||||
#include "impeller/entity/entity.h"
|
||||
#include "impeller/geometry/color.h"
|
||||
#include "impeller/geometry/point.h"
|
||||
@ -20,6 +19,9 @@
|
||||
|
||||
namespace impeller {
|
||||
|
||||
using VS = GlyphAtlasPipeline::VertexShader;
|
||||
using FS = GlyphAtlasPipeline::FragmentShader;
|
||||
|
||||
TextContents::TextContents() = default;
|
||||
|
||||
TextContents::~TextContents() = default;
|
||||
@ -72,6 +74,130 @@ void TextContents::SetTextProperties(Color color,
|
||||
}
|
||||
}
|
||||
|
||||
void TextContents::ComputeVertexData(
|
||||
VS::PerVertexData* vtx_contents,
|
||||
const std::shared_ptr<TextFrame>& frame,
|
||||
Scalar scale,
|
||||
const Matrix& entity_transform,
|
||||
Vector2 offset,
|
||||
std::optional<GlyphProperties> glyph_properties,
|
||||
const std::shared_ptr<GlyphAtlas>& atlas) {
|
||||
// Common vertex information for all glyphs.
|
||||
// All glyphs are given the same vertex information in the form of a
|
||||
// unit-sized quad. The size of the glyph is specified in per instance data
|
||||
// and the vertex shader uses this to size the glyph correctly. The
|
||||
// interpolated vertex information is also used in the fragment shader to
|
||||
// sample from the glyph atlas.
|
||||
|
||||
constexpr std::array<Point, 6> unit_points = {Point{0, 0}, Point{1, 0},
|
||||
Point{0, 1}, Point{1, 0},
|
||||
Point{0, 1}, Point{1, 1}};
|
||||
|
||||
ISize atlas_size = atlas->GetTexture()->GetSize();
|
||||
bool is_translation_scale = entity_transform.IsTranslationScaleOnly();
|
||||
Matrix basis_transform = entity_transform.Basis();
|
||||
|
||||
VS::PerVertexData vtx;
|
||||
size_t i = 0u;
|
||||
size_t bounds_offset = 0u;
|
||||
for (const TextRun& run : frame->GetRuns()) {
|
||||
const Font& font = run.GetFont();
|
||||
Scalar rounded_scale = TextFrame::RoundScaledFontSize(scale);
|
||||
FontGlyphAtlas* font_atlas = nullptr;
|
||||
|
||||
// Adjust glyph position based on the subpixel rounding
|
||||
// used by the font.
|
||||
Point subpixel_adjustment(0.5, 0.5);
|
||||
switch (font.GetAxisAlignment()) {
|
||||
case AxisAlignment::kNone:
|
||||
break;
|
||||
case AxisAlignment::kX:
|
||||
subpixel_adjustment.x = 0.125;
|
||||
break;
|
||||
case AxisAlignment::kY:
|
||||
subpixel_adjustment.y = 0.125;
|
||||
break;
|
||||
case AxisAlignment::kAll:
|
||||
subpixel_adjustment.x = 0.125;
|
||||
subpixel_adjustment.y = 0.125;
|
||||
break;
|
||||
}
|
||||
|
||||
Point screen_offset = (entity_transform * Point(0, 0));
|
||||
for (const TextRun::GlyphPosition& glyph_position :
|
||||
run.GetGlyphPositions()) {
|
||||
const FrameBounds& frame_bounds = frame->GetFrameBounds(bounds_offset);
|
||||
bounds_offset++;
|
||||
auto atlas_glyph_bounds = frame_bounds.atlas_bounds;
|
||||
auto glyph_bounds = frame_bounds.glyph_bounds;
|
||||
|
||||
// If frame_bounds.is_placeholder is true, this is the first frame
|
||||
// the glyph has been rendered and so its atlas position was not
|
||||
// known when the glyph was recorded. Perform a slow lookup into the
|
||||
// glyph atlas hash table.
|
||||
if (frame_bounds.is_placeholder) {
|
||||
if (!font_atlas) {
|
||||
font_atlas =
|
||||
atlas->GetOrCreateFontGlyphAtlas(ScaledFont{font, rounded_scale});
|
||||
}
|
||||
|
||||
if (!font_atlas) {
|
||||
VALIDATION_LOG << "Could not find font in the atlas.";
|
||||
continue;
|
||||
}
|
||||
Point subpixel = TextFrame::ComputeSubpixelPosition(
|
||||
glyph_position, font.GetAxisAlignment(), offset, rounded_scale);
|
||||
|
||||
std::optional<FrameBounds> maybe_atlas_glyph_bounds =
|
||||
font_atlas->FindGlyphBounds(SubpixelGlyph{
|
||||
glyph_position.glyph, //
|
||||
subpixel, //
|
||||
glyph_properties //
|
||||
});
|
||||
if (!maybe_atlas_glyph_bounds.has_value()) {
|
||||
VALIDATION_LOG << "Could not find glyph position in the atlas.";
|
||||
continue;
|
||||
}
|
||||
atlas_glyph_bounds = maybe_atlas_glyph_bounds.value().atlas_bounds;
|
||||
}
|
||||
|
||||
Rect scaled_bounds = glyph_bounds.Scale(1.0 / rounded_scale);
|
||||
// For each glyph, we compute two rectangles. One for the vertex
|
||||
// positions and one for the texture coordinates (UVs). The atlas
|
||||
// glyph bounds are used to compute UVs in cases where the
|
||||
// destination and source sizes may differ due to clamping the sizes
|
||||
// of large glyphs.
|
||||
Point uv_origin =
|
||||
(atlas_glyph_bounds.GetLeftTop() - Point(0.5, 0.5)) / atlas_size;
|
||||
Point uv_size = (atlas_glyph_bounds.GetSize() + Point(1, 1)) / atlas_size;
|
||||
|
||||
Point unrounded_glyph_position =
|
||||
basis_transform *
|
||||
(glyph_position.position + scaled_bounds.GetLeftTop());
|
||||
|
||||
Point screen_glyph_position =
|
||||
(screen_offset + unrounded_glyph_position + subpixel_adjustment)
|
||||
.Floor();
|
||||
|
||||
for (const Point& point : unit_points) {
|
||||
Point position;
|
||||
if (is_translation_scale) {
|
||||
position = (screen_glyph_position +
|
||||
(basis_transform * point * scaled_bounds.GetSize()))
|
||||
.Round();
|
||||
} else {
|
||||
position = entity_transform *
|
||||
(glyph_position.position + scaled_bounds.GetLeftTop() +
|
||||
point * scaled_bounds.GetSize());
|
||||
}
|
||||
vtx.uv = uv_origin + (uv_size * point);
|
||||
vtx.position = position;
|
||||
vtx_contents[i++] = vtx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TextContents::Render(const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
RenderPass& pass) const {
|
||||
@ -100,17 +226,12 @@ bool TextContents::Render(const ContentContext& renderer,
|
||||
opts.primitive_type = PrimitiveType::kTriangle;
|
||||
pass.SetPipeline(renderer.GetGlyphAtlasPipeline(opts));
|
||||
|
||||
using VS = GlyphAtlasPipeline::VertexShader;
|
||||
using FS = GlyphAtlasPipeline::FragmentShader;
|
||||
|
||||
// Common vertex uniforms for all glyphs.
|
||||
VS::FrameInfo frame_info;
|
||||
frame_info.mvp =
|
||||
Entity::GetShaderTransform(entity.GetShaderClipDepth(), pass, Matrix());
|
||||
ISize atlas_size = atlas->GetTexture()->GetSize();
|
||||
bool is_translation_scale = entity.GetTransform().IsTranslationScaleOnly();
|
||||
Matrix entity_transform = entity.GetTransform();
|
||||
Matrix basis_transform = entity_transform.Basis();
|
||||
|
||||
VS::BindFrameInfo(pass,
|
||||
renderer.GetTransientsBuffer().EmplaceUniform(frame_info));
|
||||
@ -147,17 +268,6 @@ bool TextContents::Render(const ContentContext& renderer,
|
||||
sampler_desc) // sampler
|
||||
);
|
||||
|
||||
// Common vertex information for all glyphs.
|
||||
// All glyphs are given the same vertex information in the form of a
|
||||
// unit-sized quad. The size of the glyph is specified in per instance data
|
||||
// and the vertex shader uses this to size the glyph correctly. The
|
||||
// interpolated vertex information is also used in the fragment shader to
|
||||
// sample from the glyph atlas.
|
||||
|
||||
constexpr std::array<Point, 6> unit_points = {Point{0, 0}, Point{1, 0},
|
||||
Point{0, 1}, Point{1, 0},
|
||||
Point{0, 1}, Point{1, 1}};
|
||||
|
||||
auto& host_buffer = renderer.GetTransientsBuffer();
|
||||
size_t vertex_count = 0;
|
||||
for (const auto& run : frame_->GetRuns()) {
|
||||
@ -168,112 +278,11 @@ bool TextContents::Render(const ContentContext& renderer,
|
||||
BufferView buffer_view = host_buffer.Emplace(
|
||||
vertex_count * sizeof(VS::PerVertexData), alignof(VS::PerVertexData),
|
||||
[&](uint8_t* contents) {
|
||||
VS::PerVertexData vtx;
|
||||
VS::PerVertexData* vtx_contents =
|
||||
reinterpret_cast<VS::PerVertexData*>(contents);
|
||||
size_t i = 0u;
|
||||
size_t bounds_offset = 0u;
|
||||
for (const TextRun& run : frame_->GetRuns()) {
|
||||
const Font& font = run.GetFont();
|
||||
Scalar rounded_scale = TextFrame::RoundScaledFontSize(scale_);
|
||||
FontGlyphAtlas* font_atlas = nullptr;
|
||||
|
||||
// Adjust glyph position based on the subpixel rounding
|
||||
// used by the font.
|
||||
Point subpixel_adjustment(0.5, 0.5);
|
||||
switch (font.GetAxisAlignment()) {
|
||||
case AxisAlignment::kNone:
|
||||
break;
|
||||
case AxisAlignment::kX:
|
||||
subpixel_adjustment.x = 0.125;
|
||||
break;
|
||||
case AxisAlignment::kY:
|
||||
subpixel_adjustment.y = 0.125;
|
||||
break;
|
||||
case AxisAlignment::kAll:
|
||||
subpixel_adjustment.x = 0.125;
|
||||
subpixel_adjustment.y = 0.125;
|
||||
break;
|
||||
}
|
||||
|
||||
Point screen_offset = (entity_transform * Point(0, 0));
|
||||
for (const TextRun::GlyphPosition& glyph_position :
|
||||
run.GetGlyphPositions()) {
|
||||
const FrameBounds& frame_bounds =
|
||||
frame_->GetFrameBounds(bounds_offset);
|
||||
bounds_offset++;
|
||||
auto atlas_glyph_bounds = frame_bounds.atlas_bounds;
|
||||
auto glyph_bounds = frame_bounds.glyph_bounds;
|
||||
|
||||
// If frame_bounds.is_placeholder is true, this is the first frame
|
||||
// the glyph has been rendered and so its atlas position was not
|
||||
// known when the glyph was recorded. Perform a slow lookup into the
|
||||
// glyph atlas hash table.
|
||||
if (frame_bounds.is_placeholder) {
|
||||
if (!font_atlas) {
|
||||
font_atlas = atlas->GetOrCreateFontGlyphAtlas(
|
||||
ScaledFont{font, rounded_scale});
|
||||
}
|
||||
|
||||
if (!font_atlas) {
|
||||
VALIDATION_LOG << "Could not find font in the atlas.";
|
||||
continue;
|
||||
}
|
||||
Point subpixel = TextFrame::ComputeSubpixelPosition(
|
||||
glyph_position, font.GetAxisAlignment(), offset_,
|
||||
rounded_scale);
|
||||
|
||||
std::optional<FrameBounds> maybe_atlas_glyph_bounds =
|
||||
font_atlas->FindGlyphBounds(SubpixelGlyph{
|
||||
glyph_position.glyph, //
|
||||
subpixel, //
|
||||
GetGlyphProperties() //
|
||||
});
|
||||
if (!maybe_atlas_glyph_bounds.has_value()) {
|
||||
VALIDATION_LOG << "Could not find glyph position in the atlas.";
|
||||
continue;
|
||||
}
|
||||
atlas_glyph_bounds =
|
||||
maybe_atlas_glyph_bounds.value().atlas_bounds;
|
||||
}
|
||||
|
||||
Rect scaled_bounds = glyph_bounds.Scale(1.0 / rounded_scale);
|
||||
// For each glyph, we compute two rectangles. One for the vertex
|
||||
// positions and one for the texture coordinates (UVs). The atlas
|
||||
// glyph bounds are used to compute UVs in cases where the
|
||||
// destination and source sizes may differ due to clamping the sizes
|
||||
// of large glyphs.
|
||||
Point uv_origin =
|
||||
(atlas_glyph_bounds.GetLeftTop() - Point(0.5, 0.5)) /
|
||||
atlas_size;
|
||||
Point uv_size =
|
||||
(atlas_glyph_bounds.GetSize() + Point(1, 1)) / atlas_size;
|
||||
|
||||
Point unrounded_glyph_position =
|
||||
basis_transform *
|
||||
(glyph_position.position + scaled_bounds.GetLeftTop());
|
||||
|
||||
Point screen_glyph_position =
|
||||
(screen_offset + unrounded_glyph_position + subpixel_adjustment)
|
||||
.Floor();
|
||||
|
||||
for (const Point& point : unit_points) {
|
||||
Point position;
|
||||
if (is_translation_scale) {
|
||||
position = (screen_glyph_position +
|
||||
(basis_transform * point * scaled_bounds.GetSize()))
|
||||
.Round();
|
||||
} else {
|
||||
position = entity_transform * (glyph_position.position +
|
||||
scaled_bounds.GetLeftTop() +
|
||||
point * scaled_bounds.GetSize());
|
||||
}
|
||||
vtx.uv = uv_origin + (uv_size * point);
|
||||
vtx.position = position;
|
||||
vtx_contents[i++] = vtx;
|
||||
}
|
||||
}
|
||||
}
|
||||
ComputeVertexData(vtx_contents, frame_, scale_,
|
||||
/*entity_transform=*/entity_transform, offset_,
|
||||
GetGlyphProperties(), atlas);
|
||||
});
|
||||
|
||||
pass.SetVertexBuffer(std::move(buffer_view));
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "impeller/entity/contents/content_context.h"
|
||||
#include "impeller/entity/contents/contents.h"
|
||||
#include "impeller/geometry/color.h"
|
||||
#include "impeller/typographer/font_glyph_pair.h"
|
||||
@ -61,6 +62,15 @@ class TextContents final : public Contents {
|
||||
const Entity& entity,
|
||||
RenderPass& pass) const override;
|
||||
|
||||
static void ComputeVertexData(
|
||||
GlyphAtlasPipeline::VertexShader::PerVertexData* vtx_contents,
|
||||
const std::shared_ptr<TextFrame>& frame,
|
||||
Scalar scale,
|
||||
const Matrix& entity_transform,
|
||||
Vector2 offset,
|
||||
std::optional<GlyphProperties> glyph_properties,
|
||||
const std::shared_ptr<GlyphAtlas>& atlas);
|
||||
|
||||
private:
|
||||
std::optional<GlyphProperties> GetGlyphProperties() const;
|
||||
|
||||
|
@ -0,0 +1,167 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/impeller/geometry/geometry_asserts.h"
|
||||
#include "flutter/impeller/renderer/testing/mocks.h"
|
||||
#include "flutter/testing/testing.h"
|
||||
#include "impeller/entity/contents/text_contents.h"
|
||||
#include "impeller/playground/playground_test.h"
|
||||
#include "impeller/typographer/backends/skia/text_frame_skia.h"
|
||||
#include "impeller/typographer/backends/skia/typographer_context_skia.h"
|
||||
#include "third_party/googletest/googletest/include/gtest/gtest.h"
|
||||
#include "txt/platform.h"
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wunreachable-code"
|
||||
|
||||
namespace impeller {
|
||||
namespace testing {
|
||||
|
||||
using TextContentsTest = PlaygroundTest;
|
||||
INSTANTIATE_PLAYGROUND_SUITE(TextContentsTest);
|
||||
|
||||
using ::testing::Return;
|
||||
|
||||
namespace {
|
||||
std::shared_ptr<TextFrame> MakeTextFrame(const std::string& text,
|
||||
const std::string_view& font_fixture,
|
||||
Scalar font_size) {
|
||||
auto c_font_fixture = std::string(font_fixture);
|
||||
auto mapping = flutter::testing::OpenFixtureAsSkData(c_font_fixture.c_str());
|
||||
if (!mapping) {
|
||||
return nullptr;
|
||||
}
|
||||
sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager();
|
||||
SkFont sk_font(font_mgr->makeFromData(mapping), font_size);
|
||||
auto blob = SkTextBlob::MakeFromString(text.c_str(), sk_font);
|
||||
if (!blob) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return MakeTextFrameFromTextBlobSkia(blob);
|
||||
}
|
||||
|
||||
std::shared_ptr<GlyphAtlas> CreateGlyphAtlas(
|
||||
Context& context,
|
||||
const TypographerContext* typographer_context,
|
||||
HostBuffer& host_buffer,
|
||||
GlyphAtlas::Type type,
|
||||
Scalar scale,
|
||||
const std::shared_ptr<GlyphAtlasContext>& atlas_context,
|
||||
const std::shared_ptr<TextFrame>& frame) {
|
||||
frame->SetPerFrameData(scale, /*offset=*/{0, 0},
|
||||
/*properties=*/std::nullopt);
|
||||
return typographer_context->CreateGlyphAtlas(context, type, host_buffer,
|
||||
atlas_context, {frame});
|
||||
}
|
||||
|
||||
Rect PerVertexDataPositionToRect(
|
||||
GlyphAtlasPipeline::VertexShader::PerVertexData data[6]) {
|
||||
Scalar right = FLT_MIN;
|
||||
Scalar left = FLT_MAX;
|
||||
Scalar top = FLT_MAX;
|
||||
Scalar bottom = FLT_MIN;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
right = std::max(right, data[i].position.x);
|
||||
left = std::min(left, data[i].position.x);
|
||||
top = std::min(top, data[i].position.y);
|
||||
bottom = std::max(bottom, data[i].position.y);
|
||||
}
|
||||
|
||||
return Rect::MakeLTRB(left, top, right, bottom);
|
||||
}
|
||||
|
||||
Rect PerVertexDataUVToRect(
|
||||
GlyphAtlasPipeline::VertexShader::PerVertexData data[6],
|
||||
ISize texture_size) {
|
||||
Scalar right = FLT_MIN;
|
||||
Scalar left = FLT_MAX;
|
||||
Scalar top = FLT_MAX;
|
||||
Scalar bottom = FLT_MIN;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
right = std::max(right, data[i].uv.x * texture_size.width);
|
||||
left = std::min(left, data[i].uv.x * texture_size.width);
|
||||
top = std::min(top, data[i].uv.y * texture_size.height);
|
||||
bottom = std::max(bottom, data[i].uv.y * texture_size.height);
|
||||
}
|
||||
|
||||
return Rect::MakeLTRB(left, top, right, bottom);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_P(TextContentsTest, SimpleComputeVertexData) {
|
||||
#ifndef FML_OS_MACOSX
|
||||
GTEST_SKIP() << "Results aren't stable across linux and macos.";
|
||||
#endif
|
||||
|
||||
GlyphAtlasPipeline::VertexShader::PerVertexData data[6];
|
||||
|
||||
std::shared_ptr<TextFrame> text_frame =
|
||||
MakeTextFrame("1", "ahem.ttf", /*font_size=*/50);
|
||||
|
||||
std::shared_ptr<TypographerContext> context = TypographerContextSkia::Make();
|
||||
std::shared_ptr<GlyphAtlasContext> atlas_context =
|
||||
context->CreateGlyphAtlasContext(GlyphAtlas::Type::kAlphaBitmap);
|
||||
std::shared_ptr<HostBuffer> host_buffer = HostBuffer::Create(
|
||||
GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter());
|
||||
ASSERT_TRUE(context && context->IsValid());
|
||||
std::shared_ptr<GlyphAtlas> atlas =
|
||||
CreateGlyphAtlas(*GetContext(), context.get(), *host_buffer,
|
||||
GlyphAtlas::Type::kAlphaBitmap, /*scale=*/1.0f,
|
||||
atlas_context, text_frame);
|
||||
|
||||
ISize texture_size = atlas->GetTexture()->GetSize();
|
||||
TextContents::ComputeVertexData(data, text_frame, /*scale=*/1.0,
|
||||
/*entity_transform=*/Matrix(),
|
||||
/*offset=*/Vector2(0, 0),
|
||||
/*glyph_properties=*/std::nullopt, atlas);
|
||||
|
||||
Rect position_rect = PerVertexDataPositionToRect(data);
|
||||
Rect uv_rect = PerVertexDataUVToRect(data, texture_size);
|
||||
// The -1 offset comes from Skia in `ComputeGlyphSize`. So since the font size
|
||||
// is 50, the math appears to be to get back a 50x50 rect and apply 1 pixel
|
||||
// of padding.
|
||||
EXPECT_RECT_NEAR(position_rect, Rect::MakeXYWH(-1, -41, 52, 52));
|
||||
// (0.5, 0.5) gets us sampling from the exact middle of the first pixel, the
|
||||
// extra width takes us 0.5 past the end of the glyph too to sample fully the
|
||||
// last pixel.
|
||||
EXPECT_RECT_NEAR(uv_rect, Rect::MakeXYWH(0.5, 0.5, 53, 53));
|
||||
}
|
||||
|
||||
TEST_P(TextContentsTest, SimpleComputeVertexData2x) {
|
||||
#ifndef FML_OS_MACOSX
|
||||
GTEST_SKIP() << "Results aren't stable across linux and macos.";
|
||||
#endif
|
||||
|
||||
GlyphAtlasPipeline::VertexShader::PerVertexData data[6];
|
||||
|
||||
std::shared_ptr<TextFrame> text_frame =
|
||||
MakeTextFrame("1", "ahem.ttf", /*font_size=*/50);
|
||||
|
||||
std::shared_ptr<TypographerContext> context = TypographerContextSkia::Make();
|
||||
std::shared_ptr<GlyphAtlasContext> atlas_context =
|
||||
context->CreateGlyphAtlasContext(GlyphAtlas::Type::kAlphaBitmap);
|
||||
std::shared_ptr<HostBuffer> host_buffer = HostBuffer::Create(
|
||||
GetContext()->GetResourceAllocator(), GetContext()->GetIdleWaiter());
|
||||
ASSERT_TRUE(context && context->IsValid());
|
||||
Scalar font_scale = 2.f;
|
||||
std::shared_ptr<GlyphAtlas> atlas = CreateGlyphAtlas(
|
||||
*GetContext(), context.get(), *host_buffer,
|
||||
GlyphAtlas::Type::kAlphaBitmap, font_scale, atlas_context, text_frame);
|
||||
|
||||
ISize texture_size = atlas->GetTexture()->GetSize();
|
||||
TextContents::ComputeVertexData(
|
||||
data, text_frame, font_scale,
|
||||
/*entity_transform=*/Matrix::MakeScale({font_scale, font_scale, 1}),
|
||||
/*offset=*/Vector2(0, 0),
|
||||
/*glyph_properties=*/std::nullopt, atlas);
|
||||
|
||||
Rect position_rect = PerVertexDataPositionToRect(data);
|
||||
Rect uv_rect = PerVertexDataUVToRect(data, texture_size);
|
||||
EXPECT_RECT_NEAR(position_rect, Rect::MakeXYWH(-1, -81, 102, 102));
|
||||
EXPECT_RECT_NEAR(uv_rect, Rect::MakeXYWH(0.5, 0.5, 103, 103));
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace impeller
|
@ -102,6 +102,7 @@ impellerc("runtime_stages") {
|
||||
|
||||
test_fixtures("file_fixtures") {
|
||||
fixtures = [
|
||||
"//flutter/third_party/txt/third_party/fonts/ahem.ttf",
|
||||
"//flutter/third_party/txt/third_party/fonts/HomemadeApple.ttf",
|
||||
"//flutter/third_party/txt/third_party/fonts/NotoColorEmoji.ttf",
|
||||
"//flutter/third_party/txt/third_party/fonts/Roboto-Medium.ttf",
|
||||
|
@ -141,6 +141,7 @@ bool TextFrame::IsFrameComplete() const {
|
||||
}
|
||||
|
||||
const FrameBounds& TextFrame::GetFrameBounds(size_t index) const {
|
||||
FML_DCHECK(index < bound_values_.size());
|
||||
return bound_values_[index];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user