Render glyphs at the correct resolution with respect to the current transform (flutter/engine#101)

This commit is contained in:
Brandon DeRosier 2022-03-24 23:13:24 -07:00 committed by Dan Field
parent 951cb1c1ee
commit 458ab4ebb2
12 changed files with 93 additions and 24 deletions

View File

@ -247,7 +247,8 @@ void DisplayListDispatcher::setMaskFilter(const flutter::DlMaskFilter* filter) {
}
// |flutter::Dispatcher|
void DisplayListDispatcher::setImageFilter(const flutter::DlImageFilter* filter) {
void DisplayListDispatcher::setImageFilter(
const flutter::DlImageFilter* filter) {
UNIMPLEMENTED;
}
@ -609,9 +610,10 @@ void DisplayListDispatcher::drawDisplayList(
void DisplayListDispatcher::drawTextBlob(const sk_sp<SkTextBlob> blob,
SkScalar x,
SkScalar y) {
canvas_.DrawTextFrame(TextFrameFromTextBlob(blob), //
impeller::Point{x, y}, //
paint_ //
Scalar scale = canvas_.GetCurrentTransformation().GetMaxBasisLength();
canvas_.DrawTextFrame(TextFrameFromTextBlob(blob, scale), //
impeller::Point{x, y}, //
paint_ //
);
}

View File

@ -43,4 +43,7 @@ constexpr float kSqrt2 = 1.41421356237309504880;
// 1/sqrt(2)
constexpr float k1OverSqrt2 = 0.70710678118654752440;
// 0.001
constexpr float kEhCloseEnough = 1e-3;
} // namespace impeller

View File

@ -212,6 +212,21 @@ TEST(GeometryTest, MatrixTransformDirection) {
}
}
TEST(GeometryTest, MatrixGetMaxBasisLength) {
{
auto m = Matrix::MakeScale({3, 1, 1});
ASSERT_EQ(m.GetMaxBasisLength(), 3);
m = m * Matrix::MakeSkew(0, 4);
ASSERT_EQ(m.GetMaxBasisLength(), 5);
}
{
auto m = Matrix::MakeScale({-3, 4, 2});
ASSERT_EQ(m.GetMaxBasisLength(), 4);
}
}
TEST(GeometryTest, QuaternionLerp) {
auto q1 = Quaternion{{0.0, 0.0, 1.0}, 0.0};
auto q2 = Quaternion{{0.0, 0.0, 1.0}, M_PI_4};
@ -570,6 +585,21 @@ TEST(GeometryTest, CanUsePointAssignmentOperators) {
ASSERT_EQ(p.x, 1u);
ASSERT_EQ(p.y, 2u);
}
// Arithmetic type on RHS
{
IPoint p(1, 2);
p *= 3;
ASSERT_EQ(p.x, 3u);
ASSERT_EQ(p.y, 6u);
}
{
IPoint p(3, 6);
p /= 3;
ASSERT_EQ(p.x, 1u);
ASSERT_EQ(p.y, 2u);
}
}
TEST(GeometryTest, PointDotProduct) {

View File

@ -193,6 +193,15 @@ Scalar Matrix::GetDeterminant() const {
return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
}
Scalar Matrix::GetMaxBasisLength() const {
Scalar max = 0;
for (int i = 0; i < 3; i++) {
max = std::max(max,
e[i][0] * e[i][0] + e[i][1] * e[i][1] + e[i][2] * e[i][2]);
}
return std::sqrt(max);
}
/*
* Adapted for Impeller from Graphics Gems:
* http://www.realtimerendering.com/resources/GraphicsGems/gemsii/unmatrix.c

View File

@ -219,6 +219,8 @@ struct Matrix {
Scalar GetDeterminant() const;
Scalar GetMaxBasisLength() const;
constexpr bool IsAffine() const {
return (m[2] == 0 && m[3] == 0 && m[6] == 0 && m[7] == 0 && m[8] == 0 &&
m[9] == 0 && m[10] == 1 && m[11] == 0 && m[14] == 0 && m[15] == 1);

View File

@ -88,6 +88,13 @@ struct TPoint {
return *this;
}
template <class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
inline TPoint operator*=(U scale) {
x *= static_cast<Type>(scale);
y *= static_cast<Type>(scale);
return *this;
}
template <class U>
inline TPoint operator/=(const TPoint<U>& p) {
x /= static_cast<Type>(p.x);
@ -102,6 +109,13 @@ struct TPoint {
return *this;
}
template <class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
inline TPoint operator/=(U scale) {
x /= static_cast<Type>(scale);
y /= static_cast<Type>(scale);
return *this;
}
constexpr TPoint operator-() const { return {-x, -y}; }
constexpr TPoint operator+(const TPoint& p) const {

View File

@ -14,8 +14,6 @@ namespace impeller {
using Scalar = float;
constexpr Scalar kEhCloseEnough = 1e-3f;
template <class T, class = std::enable_if_t<std::is_arithmetic_v<T>>>
constexpr T Absolute(const T& val) {
return val >= T{} ? val : -val;

View File

@ -12,13 +12,14 @@
namespace impeller {
static Font ToFont(const SkFont& font) {
static Font ToFont(const SkFont& font, Scalar scale) {
auto typeface = std::make_shared<TypefaceSkia>(font.refTypefaceOrDefault());
SkFontMetrics sk_metrics;
font.getMetrics(&sk_metrics);
Font::Metrics metrics;
metrics.scale = scale;
metrics.point_size = font.getSize();
metrics.ascent = sk_metrics.fAscent;
metrics.descent = sk_metrics.fDescent;
@ -28,7 +29,8 @@ static Font ToFont(const SkFont& font) {
return Font{std::move(typeface), std::move(metrics)};
}
TextFrame TextFrameFromTextBlob(sk_sp<SkTextBlob> blob) {
TextFrame TextFrameFromTextBlob(sk_sp<SkTextBlob> blob,
Scalar scale) {
if (!blob) {
return {};
}
@ -36,7 +38,7 @@ TextFrame TextFrameFromTextBlob(sk_sp<SkTextBlob> blob) {
TextFrame frame;
for (SkTextBlobRunIterator run(blob.get()); !run.done(); run.next()) {
TextRun text_run(ToFont(run.font()));
TextRun text_run(ToFont(run.font(), scale));
const auto glyph_count = run.glyphCount();
const auto* glyphs = run.glyphs();
switch (run.positioning()) {

View File

@ -10,6 +10,6 @@
namespace impeller {
TextFrame TextFrameFromTextBlob(sk_sp<SkTextBlob> blob);
TextFrame TextFrameFromTextBlob(sk_sp<SkTextBlob> blob, Scalar scale = 1.0f);
} // namespace impeller

View File

@ -65,7 +65,8 @@ static bool PairsFitInAtlasOfSize(const FontGlyphPair::Vector& pairs,
for (const auto& pair : pairs) {
const auto glyph_size =
ISize::Ceil(pair.font.GetMetrics().GetBoundingBox().size);
ISize::Ceil(pair.font.GetMetrics().GetBoundingBox().size *
pair.font.GetMetrics().scale);
SkIPoint16 location_in_atlas;
if (!rect_packer->addRect(glyph_size.width, //
glyph_size.height, //
@ -125,7 +126,8 @@ static std::optional<SkBitmap> CreateAtlasBitmap(const GlyphAtlas& atlas,
SkFont sk_font(
TypefaceSkia::Cast(*font_glyph.font.GetTypeface()).GetSkiaTypeface(),
font_glyph.font.GetMetrics().point_size);
font_glyph.font.GetMetrics().point_size *
font_glyph.font.GetMetrics().scale);
const auto& metrics = font_glyph.font.GetMetrics();
@ -133,13 +135,14 @@ static std::optional<SkBitmap> CreateAtlasBitmap(const GlyphAtlas& atlas,
SkPaint glyph_paint;
glyph_paint.setColor(glyph_color);
canvas->drawGlyphs(1u, // count
&glyph_id, // glyphs
&position, // positions
SkPoint::Make(-metrics.min_extent.x,
-metrics.ascent), // origin
sk_font, // font
glyph_paint // paint
canvas->drawGlyphs(
1u, // count
&glyph_id, // glyphs
&position, // positions
SkPoint::Make(-metrics.min_extent.x * metrics.scale,
-metrics.ascent * metrics.scale), // origin
sk_font, // font
glyph_paint // paint
);
return true;
});

View File

@ -28,6 +28,12 @@ class Font : public Comparable<Font> {
/// the baseline with an upper-left-origin coordinate system.
///
struct Metrics {
//--------------------------------------------------------------------------
/// The scaling factor that should be used when rendering this font to an
/// atlas. This should normally be set in accordance with the transformation
/// matrix that will be used to position glyph geometry.
///
Scalar scale = 1.0f;
//--------------------------------------------------------------------------
/// The point size of the font.
///
@ -69,9 +75,9 @@ class Font : public Comparable<Font> {
}
constexpr bool operator==(const Metrics& o) const {
return point_size == o.point_size && ascent == o.ascent &&
descent == o.descent && min_extent == o.min_extent &&
max_extent == o.max_extent;
return scale == o.scale && point_size == o.point_size &&
ascent == o.ascent && descent == o.descent &&
min_extent == o.min_extent && max_extent == o.max_extent;
}
};
@ -107,6 +113,6 @@ class Font : public Comparable<Font> {
template <>
struct std::hash<impeller::Font::Metrics> {
constexpr std::size_t operator()(const impeller::Font::Metrics& m) const {
return fml::HashCombine(m.point_size, m.ascent, m.descent);
return fml::HashCombine(m.scale, m.point_size, m.ascent, m.descent);
}
};

View File

@ -47,7 +47,7 @@ class GlyphAtlas {
const std::shared_ptr<Texture>& GetTexture() const;
//----------------------------------------------------------------------------
/// @brief Record there location of a specific font-glyph pair within the
/// @brief Record the location of a specific font-glyph pair within the
/// atlas.
///
/// @param[in] pair The font-glyph pair