blob: ec06ce702512e3403b980afa5b32606c6d8b36db [file] [log] [blame]
// 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 <memory>
#include "display_list/utils/dl_receiver_utils.h"
#include "gtest/gtest.h"
#include "runtime/test_font_data.h"
#include "skia/paragraph_builder_skia.h"
#include "testing/canvas_test.h"
namespace flutter {
namespace testing {
//------------------------------------------------------------------------------
/// @brief A custom |DlOpReceiver| that records some |DlOps| it receives.
class DlOpRecorder final : public virtual DlOpReceiver,
private IgnoreAttributeDispatchHelper,
private IgnoreClipDispatchHelper,
private IgnoreDrawDispatchHelper,
private IgnoreTransformDispatchHelper {
public:
int lineCount() const { return lines_.size(); }
int rectCount() const { return rects_.size(); }
int pathCount() const { return paths_.size(); }
bool hasPathEffect() const { return path_effect_ != nullptr; }
private:
void drawLine(const SkPoint& p0, const SkPoint& p1) override {
lines_.emplace_back(p0, p1);
}
void drawRect(const SkRect& rect) override { rects_.push_back(rect); }
void drawPath(const SkPath& path) override { paths_.push_back(path); }
void setPathEffect(const DlPathEffect* effect) override {
path_effect_ = effect;
}
std::vector<std::pair<SkPoint, SkPoint>> lines_;
std::vector<SkRect> rects_;
std::vector<SkPath> paths_;
const DlPathEffect* path_effect_;
};
template <typename T>
class PainterTestBase : public CanvasTestBase<T> {
public:
PainterTestBase() = default;
void PretendImpellerIsEnabled(bool impeller) { impeller_ = impeller; }
protected:
sk_sp<DisplayList> draw(txt::TextDecorationStyle style) const {
auto t_style = makeDecoratedStyle(style);
auto pb_skia = makeParagraphBuilder();
pb_skia.PushStyle(t_style);
pb_skia.AddText(u"Hello World!");
pb_skia.Pop();
auto builder = DisplayListBuilder();
auto paragraph = pb_skia.Build();
paragraph->Layout(10000);
paragraph->Paint(&builder, 0, 0);
return builder.Build();
}
private:
std::shared_ptr<txt::FontCollection> makeFontCollection() const {
auto f_collection = std::make_shared<txt::FontCollection>();
auto font_provider = std::make_unique<txt::TypefaceFontAssetProvider>();
for (auto& font : GetTestFontData()) {
font_provider->RegisterTypeface(font);
}
auto manager = sk_make_sp<txt::AssetFontManager>(std::move(font_provider));
f_collection->SetAssetFontManager(manager);
return f_collection;
}
txt::ParagraphBuilderSkia makeParagraphBuilder() const {
auto p_style = txt::ParagraphStyle();
auto f_collection = makeFontCollection();
return txt::ParagraphBuilderSkia(p_style, f_collection, impeller_);
}
txt::TextStyle makeDecoratedStyle(txt::TextDecorationStyle style) const {
auto t_style = txt::TextStyle();
t_style.color = SK_ColorBLACK; // default
t_style.font_weight = txt::FontWeight::w400; // normal
t_style.font_size = 14; // default
t_style.decoration = txt::TextDecoration::kUnderline;
t_style.decoration_style = style;
t_style.decoration_color = SK_ColorBLACK;
t_style.font_families.push_back("ahem");
return t_style;
}
bool impeller_ = false;
};
using PainterTest = PainterTestBase<::testing::Test>;
TEST_F(PainterTest, DrawsSolidLineSkia) {
PretendImpellerIsEnabled(false);
auto recorder = DlOpRecorder();
draw(txt::TextDecorationStyle::kSolid)->Dispatch(recorder);
// Skia may draw a solid underline as a filled rectangle:
// https://skia.googlesource.com/skia/+/refs/heads/main/modules/skparagraph/src/Decorations.cpp#91
EXPECT_EQ(recorder.rectCount(), 1);
EXPECT_FALSE(recorder.hasPathEffect());
}
TEST_F(PainterTest, DrawsSolidLineImpeller) {
PretendImpellerIsEnabled(true);
auto recorder = DlOpRecorder();
draw(txt::TextDecorationStyle::kSolid)->Dispatch(recorder);
// Skia may draw a solid underline as a filled rectangle:
// https://skia.googlesource.com/skia/+/refs/heads/main/modules/skparagraph/src/Decorations.cpp#91
EXPECT_EQ(recorder.rectCount(), 1);
EXPECT_FALSE(recorder.hasPathEffect());
}
TEST_F(PainterTest, DrawDashedLineSkia) {
PretendImpellerIsEnabled(false);
auto recorder = DlOpRecorder();
draw(txt::TextDecorationStyle::kDashed)->Dispatch(recorder);
// Skia draws a dashed underline as a filled rectangle with a path effect.
EXPECT_EQ(recorder.lineCount(), 1);
EXPECT_TRUE(recorder.hasPathEffect());
}
TEST_F(PainterTest, DrawDashedLineImpeller) {
PretendImpellerIsEnabled(true);
auto recorder = DlOpRecorder();
draw(txt::TextDecorationStyle::kDashed)->Dispatch(recorder);
// Impeller draws a dashed underline as a path.
EXPECT_EQ(recorder.pathCount(), 1);
EXPECT_FALSE(recorder.hasPathEffect());
}
} // namespace testing
} // namespace flutter