skia2/tests/SkParagraphTest.cpp
Kevin Lubick 7aeabcfa6a [SkParagraph] Require len if using addText(const char*)
Bug: skia:9469
Change-Id: Ie3ae11db9be4b1cf1645e8db0bf29dc8e59bc4cd
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/244877
Reviewed-by: Ben Wagner <bungeman@google.com>
2019-09-29 11:39:34 +00:00

4814 lines
216 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2019 Google LLC.
#include "src/utils/SkOSPath.h"
#include <sstream>
#include "modules/skparagraph/include/TypefaceFontProvider.h"
#include "modules/skparagraph/src/ParagraphBuilderImpl.h"
#include "modules/skparagraph/src/ParagraphImpl.h"
#include "src/core/SkOSFile.h"
#include "src/utils/SkShaperJSONWriter.h"
#include "tests/CodecPriv.h"
#include "tests/Test.h"
#include "tools/Resources.h"
#include "tools/ToolUtils.h"
#define VeryLongCanvasWidth 1000000
#define TestCanvasWidth 1000
#define TestCanvasHeight 600
using namespace skia::textlayout;
namespace {
SkScalar EPSILON100 = 0.01f;
SkScalar EPSILON50 = 0.02f;
SkScalar EPSILON20 = 0.05f;
SkScalar EPSILON10 = 0.1f;
SkScalar EPSILON5 = 0.20f;
SkScalar EPSILON2 = 0.50f;
bool equal(const char* base, TextRange a, const char* b) {
return std::strncmp(b, base + a.start, a.width()) == 0;
}
class TestFontCollection : public FontCollection {
public:
TestFontCollection()
: fFontsFound(false)
, fResolvedFonts(0)
, fResourceDir(GetResourcePath("fonts").c_str())
, fFontProvider(sk_make_sp<TypefaceFontProvider>()) {
std::vector<SkString> fonts;
SkOSFile::Iter iter(fResourceDir.c_str());
SkString path;
while (iter.next(&path)) {
if (path.endsWith("Roboto-Italic.ttf")) {
fFontsFound = true;
}
fonts.emplace_back(path);
}
if (!fFontsFound) {
return;
}
// Only register fonts if we have to
for (auto& font : fonts) {
SkString file_path;
file_path.printf("%s/%s", fResourceDir.c_str(), font.c_str());
fFontProvider->registerTypeface(SkTypeface::MakeFromFile(file_path.c_str()));
}
this->setTestFontManager(std::move(fFontProvider));
this->disableFontFallback();
if (!fFontsFound) SkDebugf("Fonts not found, skipping all the tests\n");
}
~TestFontCollection() = default;
size_t resolvedFonts() const { return fResolvedFonts; }
// TODO: temp solution until we check in fonts
bool fontsFound() const { return fFontsFound; }
private:
bool fFontsFound;
size_t fResolvedFonts;
std::string fResourceDir;
sk_sp<TypefaceFontProvider> fFontProvider;
};
class TestCanvas {
public:
TestCanvas(const char* testName) : name(testName) {
bits.allocN32Pixels(TestCanvasWidth, TestCanvasHeight);
canvas = new SkCanvas(bits);
canvas->clear(SK_ColorWHITE);
}
~TestCanvas() {
SkString tmpDir = skiatest::GetTmpDir();
if (!tmpDir.isEmpty()) {
SkString path = SkOSPath::Join(tmpDir.c_str(), name);
SkFILEWStream file(path.c_str());
if (!SkEncodeImage(&file, bits, SkEncodedImageFormat::kPNG, 100)) {
SkDebugf("Cannot write a picture %s\n", name);
}
}
delete canvas;
}
void drawRects(SkColor color, std::vector<TextBox>& result, bool fill = false) {
SkPaint paint;
if (!fill) {
paint.setStyle(SkPaint::kStroke_Style);
paint.setAntiAlias(true);
paint.setStrokeWidth(1);
}
paint.setColor(color);
for (auto& r : result) {
canvas->drawRect(r.rect, paint);
}
}
void drawLine(SkColor color, SkRect rect, bool vertical = true) {
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
paint.setAntiAlias(true);
paint.setStrokeWidth(1);
paint.setColor(color);
if (vertical) {
canvas->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint);
} else {
canvas->drawLine(rect.fLeft, rect.fTop, rect.fRight, rect.fTop, paint);
}
}
void drawLines(SkColor color, std::vector<TextBox>& result) {
for (auto& r : result) {
drawLine(color, r.rect);
}
}
SkCanvas* get() { return canvas; }
private:
SkBitmap bits;
SkCanvas* canvas;
const char* name;
};
} // namespace
// Checked: NO DIFF
DEF_TEST(SkParagraph_SimpleParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
const char* text = "Hello World Text Dialog";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
REPORTER_ASSERT(reporter, impl->styles().size() == 1); // paragraph style does not count
REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
size_t index = 0;
for (auto& line : impl->lines()) {
line.scanStyles(StyleType::kDecorations,
[&index, reporter]
(TextRange textRange, const TextStyle& style, const TextLine::ClipContext& context) {
REPORTER_ASSERT(reporter, index == 0);
REPORTER_ASSERT(reporter, style.getColor() == SK_ColorBLACK);
++index;
});
}
}
// Checked: DIFF+ (half of the letter spacing before the text???)
DEF_TEST(SkParagraph_InlinePlaceholderParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
TestCanvas canvas("SkParagraph_InlinePlaceholderParagraph.png");
if (!fontCollection->fontsFound()) return;
const char* text = "012 34";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setMaxLines(14);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorBLACK);
text_style.setFontSize(26);
text_style.setWordSpacing(5);
text_style.setLetterSpacing(1);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
PlaceholderStyle placeholder1(50, 50, PlaceholderAlignment::kBaseline, TextBaseline::kAlphabetic, 0);
builder.addPlaceholder(placeholder1);
builder.addText(text, len);
builder.addPlaceholder(placeholder1);
PlaceholderStyle placeholder2(5, 50, PlaceholderAlignment::kBaseline, TextBaseline::kAlphabetic, 50);
builder.addPlaceholder(placeholder2);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder2);
builder.addText(text, len);
builder.addPlaceholder(placeholder2);
builder.addText(text, len);
builder.addText(text, len);
builder.addPlaceholder(placeholder2);
builder.addPlaceholder(placeholder2);
builder.addPlaceholder(placeholder2);
builder.addPlaceholder(placeholder2);
builder.addPlaceholder(placeholder2);
builder.addPlaceholder(placeholder1);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addPlaceholder(placeholder2);
builder.addPlaceholder(placeholder1);
builder.addText(text, len);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle rect_height_style = RectHeightStyle::kTight;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
auto boxes = paragraph->getRectsForRange(0, 3, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
boxes = paragraph->getRectsForRange(0, 3, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorGREEN, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
boxes = paragraph->GetRectsForPlaceholders();
canvas.drawRects(SK_ColorRED, boxes);
boxes = paragraph->getRectsForRange(4, 17, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorBLUE, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 7);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.left(), 90.921f - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.top(), 50, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.right(), 90.921f + 50 - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.bottom(), 100, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[3].rect.left(), 231.343f - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[3].rect.top(), 50, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[3].rect.right(), 231.343f + 50 - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[3].rect.bottom(), 100, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[4].rect.left(), 281.343f - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[4].rect.top(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[4].rect.right(), 281.343f + 5 - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[4].rect.bottom(), 50, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[6].rect.left(), 336.343f - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[6].rect.top(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[6].rect.right(), 336.343f + 5 - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[6].rect.bottom(), 50, EPSILON100));
}
// Checked: DIFF+ (half of the letter spacing before the text???)
DEF_TEST(SkParagraph_InlinePlaceholderBaselineParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
TestCanvas canvas("SkParagraph_InlinePlaceholderBaselineParagraph.png");
if (!fontCollection->fontsFound()) return;
const char* text = "012 34";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setMaxLines(14);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorBLACK);
text_style.setFontSize(26);
text_style.setWordSpacing(5);
text_style.setLetterSpacing(1);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
PlaceholderStyle placeholder(55, 50, PlaceholderAlignment::kBaseline, TextBaseline::kAlphabetic, 38.347f);
builder.addPlaceholder(placeholder);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 0, 0);
auto boxes = paragraph->GetRectsForPlaceholders();
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 90.921f - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 90.921f + 55 - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 50, EPSILON100));
RectHeightStyle rect_height_style = RectHeightStyle::kTight;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
boxes = paragraph->getRectsForRange(5, 6, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorBLUE, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 75.324f - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 14.226f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 90.921f - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 44.694f, EPSILON100));
}
// Checked: DIFF+ (half of the letter spacing before the text???)
DEF_TEST(SkParagraph_InlinePlaceholderAboveBaselineParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
TestCanvas canvas("SkParagraph_InlinePlaceholderAboveBaselineParagraph.png");
if (!fontCollection->fontsFound()) return;
const char* text = "012 34";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setMaxLines(14);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorBLACK);
text_style.setFontSize(26);
text_style.setWordSpacing(5);
text_style.setLetterSpacing(1);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
PlaceholderStyle placeholder(55, 50, PlaceholderAlignment::kAboveBaseline, TextBaseline::kAlphabetic, 903129.129308f);
builder.addPlaceholder(placeholder);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 0, 0);
auto boxes = paragraph->GetRectsForPlaceholders();
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 90.921f - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), -0.347f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 90.921f + 55 - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 49.652f, EPSILON100));
RectHeightStyle rect_height_style = RectHeightStyle::kTight;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
boxes = paragraph->getRectsForRange(5, 6, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorBLUE, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 75.324f - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 25.531f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 90.921f - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 56, EPSILON100));
}
// Checked: DIFF+ (half of the letter spacing before the text???)
DEF_TEST(SkParagraph_InlinePlaceholderBelowBaselineParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
TestCanvas canvas("SkParagraph_InlinePlaceholderBelowBaselineParagraph.png");
if (!fontCollection->fontsFound()) return;
const char* text = "012 34";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setMaxLines(14);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorBLACK);
text_style.setFontSize(26);
text_style.setWordSpacing(5);
text_style.setLetterSpacing(1);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
PlaceholderStyle placeholder(55, 50, PlaceholderAlignment::kBelowBaseline, TextBaseline::kAlphabetic, 903129.129308f);
builder.addPlaceholder(placeholder);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 0, 0);
auto boxes = paragraph->GetRectsForPlaceholders();
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 90.921f - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 24, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 90.921f + 55 - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 74, EPSILON100));
RectHeightStyle rect_height_style = RectHeightStyle::kTight;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
boxes = paragraph->getRectsForRange(5, 6, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorBLUE, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 75.324f - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), -0.121f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 90.921f - 0.5f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 30.347f, EPSILON100));
}
// Checked: DIFF+ (half of the letter spacing before the text???)
DEF_TEST(SkParagraph_InlinePlaceholderBottomParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
TestCanvas canvas("SkParagraph_InlinePlaceholderBottomParagraph.png");
if (!fontCollection->fontsFound()) return;
const char* text = "012 34";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setMaxLines(14);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorBLACK);
text_style.setFontSize(26);
text_style.setWordSpacing(5);
text_style.setLetterSpacing(1);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
PlaceholderStyle placeholder(55, 50, PlaceholderAlignment::kBottom, TextBaseline::kAlphabetic, 0);
builder.addPlaceholder(placeholder);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle rect_height_style = RectHeightStyle::kTight;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
auto boxes = paragraph->GetRectsForPlaceholders();
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 90.921f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 90.921f + 55 - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 50, EPSILON100));
boxes = paragraph->getRectsForRange(0, 1, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorBLUE, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0.5f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 19.531f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 16.097f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 50, EPSILON100));
}
// Checked: DIFF+ (half of the letter spacing before the text???)
DEF_TEST(SkParagraph_InlinePlaceholderTopParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
TestCanvas canvas("SkParagraph_InlinePlaceholderTopParagraph.png");
if (!fontCollection->fontsFound()) return;
const char* text = "012 34";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setMaxLines(14);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorBLACK);
text_style.setFontSize(26);
text_style.setWordSpacing(5);
text_style.setLetterSpacing(1);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
PlaceholderStyle placeholder(55, 50, PlaceholderAlignment::kTop, TextBaseline::kAlphabetic, 0);
builder.addPlaceholder(placeholder);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle rect_height_style = RectHeightStyle::kTight;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
auto boxes = paragraph->GetRectsForPlaceholders();
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 90.921f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 90.921f + 55 - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 50, EPSILON100));
boxes = paragraph->getRectsForRange(0, 1, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorBLUE, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0.5f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 16.097f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 30.468f, EPSILON100));
}
// Checked: DIFF+ (half of the letter spacing before the text???)
DEF_TEST(SkParagraph_InlinePlaceholderMiddleParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
TestCanvas canvas("SkParagraph_InlinePlaceholderMiddleParagraph.png");
if (!fontCollection->fontsFound()) return;
const char* text = "012 34";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setMaxLines(14);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorBLACK);
text_style.setFontSize(26);
text_style.setWordSpacing(5);
text_style.setLetterSpacing(1);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
PlaceholderStyle placeholder(55, 50, PlaceholderAlignment::kMiddle, TextBaseline::kAlphabetic, 0);
builder.addPlaceholder(placeholder);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle rect_height_style = RectHeightStyle::kTight;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
auto boxes = paragraph->GetRectsForPlaceholders();
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 90.921f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 90.921f + 55 - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 50, EPSILON100));
boxes = paragraph->getRectsForRange(5, 6, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorBLUE, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 75.324f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 9.765f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 90.921f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 40.234f, EPSILON100));
}
// Checked: DIFF+ (half of the letter spacing before the text???)
DEF_TEST(SkParagraph_InlinePlaceholderIdeographicBaselineParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
TestCanvas canvas("SkParagraph_InlinePlaceholderIdeographicBaselineParagraph.png");
if (!fontCollection->fontsFound()) return;
const char* text = "給能上目秘使";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setMaxLines(14);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Source Han Serif CN")});
text_style.setColor(SK_ColorBLACK);
text_style.setFontSize(26);
text_style.setWordSpacing(5);
text_style.setLetterSpacing(1);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
PlaceholderStyle placeholder(55, 50, PlaceholderAlignment::kBaseline, TextBaseline::kIdeographic, 38.347f);
builder.addPlaceholder(placeholder);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle rect_height_style = RectHeightStyle::kTight;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
auto boxes = paragraph->GetRectsForPlaceholders();
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 162.5f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 162.5f + 55 - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 50, EPSILON100));
boxes = paragraph->getRectsForRange(5, 6, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorBLUE, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 135.5f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 4.703f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 162.5f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 42.065f, EPSILON100));
}
// Checked: DIFF+ (half of the letter spacing before the text???)
DEF_TEST(SkParagraph_InlinePlaceholderBreakParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
TestCanvas canvas("SkParagraph_InlinePlaceholderBreakParagraph.png");
if (!fontCollection->fontsFound()) return;
const char* text = "012 34";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setMaxLines(14);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorBLACK);
text_style.setFontSize(26);
text_style.setWordSpacing(5);
text_style.setLetterSpacing(1);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
PlaceholderStyle placeholder1(50, 50, PlaceholderAlignment::kBaseline, TextBaseline::kAlphabetic, 50);
PlaceholderStyle placeholder2(25, 25, PlaceholderAlignment::kBaseline, TextBaseline::kAlphabetic, 12.5f);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder2);
builder.addPlaceholder(placeholder1);
builder.addText(text, len);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder2); // 4 + 1
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder2); // 6 + 1
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder2); // 7 + 1
builder.addPlaceholder(placeholder1);
builder.addText(text, len);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder2);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addPlaceholder(placeholder2);
builder.addPlaceholder(placeholder1);
builder.addText(text, len);
builder.addPlaceholder(placeholder2);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth - 100);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle rect_height_style = RectHeightStyle::kTight;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
auto boxes = paragraph->getRectsForRange(0, 3, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
boxes = paragraph->getRectsForRange(175, 176, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorGREEN, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 31.695f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 218.531f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 47.292f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 249, EPSILON100));
boxes = paragraph->GetRectsForPlaceholders();
canvas.drawRects(SK_ColorRED, boxes);
boxes = paragraph->getRectsForRange(4, 45, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorBLUE, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 30);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 59.726f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 26.378f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 90.921f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 56.847f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[11].rect.left(), 606.343f - 0.5f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[11].rect.top(), 38, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[11].rect.right(), 631.343f - 0.5f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[11].rect.bottom(), 63, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[17].rect.left(), 0.5f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[17].rect.top(), 63.5f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[17].rect.right(), 50.5f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[17].rect.bottom(), 113.5f, EPSILON100));
}
// Checked: DIFF+ (half of the letter spacing before the text???)
DEF_TEST(SkParagraph_InlinePlaceholderGetRectsParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
TestCanvas canvas("SkParagraph_InlinePlaceholderGetRectsParagraph.png");
if (!fontCollection->fontsFound()) return;
const char* text = "012 34";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setMaxLines(14);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorBLACK);
text_style.setFontSize(26);
text_style.setWordSpacing(5);
text_style.setLetterSpacing(1);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
PlaceholderStyle placeholder1(50, 50, PlaceholderAlignment::kBaseline, TextBaseline::kAlphabetic, 50);
PlaceholderStyle placeholder2(5, 20, PlaceholderAlignment::kBaseline, TextBaseline::kAlphabetic, 10);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder2); // 8 + 1
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder2); // 5 + 1
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder1); // 8 + 0
builder.addText(text, len);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder2);
builder.addPlaceholder(placeholder2); // 1 + 2
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder2);
builder.addPlaceholder(placeholder2); // 1 + 2
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len);
builder.addText(text, len); // 11
builder.addPlaceholder(placeholder2);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder2);
builder.addPlaceholder(placeholder1);
builder.addPlaceholder(placeholder2);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle rect_height_style = RectHeightStyle::kMax;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
auto boxes = paragraph->GetRectsForPlaceholders();
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 34);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 90.921f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 140.921f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 50, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[16].rect.left(), 800.921f - 0.5f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[16].rect.top(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[16].rect.right(), 850.921f - 0.5f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[16].rect.bottom(), 50, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[33].rect.left(), 503.382f - 0.5f, EPSILON10));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[33].rect.top(), 160, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[33].rect.right(), 508.382f - 0.5f, EPSILON10));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[33].rect.bottom(), 180, EPSILON100));
boxes = paragraph->getRectsForRange(30, 50, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorBLUE, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 8);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 216.097f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 60, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 290.921f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 120, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.left(), 290.921f - 0.5f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.top(), 60, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.right(), 340.921f - 0.5f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.bottom(), 120, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[2].rect.left(), 340.921f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[2].rect.top(), 60, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[2].rect.right(), 345.921f - 0.5f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[2].rect.bottom(), 120, EPSILON100));
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_SimpleRedParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
const char* text = "I am RED";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorRED);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
REPORTER_ASSERT(reporter, impl->styles().size() == 1); // paragraph style does not count
REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
size_t index = 0;
for (auto& line : impl->lines()) {
line.scanStyles(StyleType::kDecorations,
[reporter, &index](TextRange textRange, const TextStyle& style, const TextLine::ClipContext& context) {
REPORTER_ASSERT(reporter, index == 0);
REPORTER_ASSERT(reporter, style.getColor() == SK_ColorRED);
++index;
return true;
});
}
}
// Checked: DIFF+ (Space between 1 & 2 style blocks)
DEF_TEST(SkParagraph_RainbowParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
TestCanvas canvas("SkParagraph_RainbowParagraph.png");
if (!fontCollection->fontsFound()) return;
const char* text1 = "Red Roboto"; // [0:10)
const char* text2 = "big Greeen Default"; // [10:28)
const char* text3 = "Defcolor Homemade Apple"; // [28:51)
const char* text4 = "Small Blue Roboto"; // [51:68)
const char* text41 = "Small Blue ";
const char* text5 =
"Continue Last Style With lots of words to check if it overlaps "
"properly or not"; // [68:)
const char* text42 =
"Roboto"
"Continue Last Style With lots of words to check if it overlaps "
"properly or not";
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setTextAlign(TextAlign::kLeft);
paragraph_style.setMaxLines(2);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style1;
text_style1.setFontFamilies({SkString("Roboto")});
text_style1.setColor(SK_ColorRED);
builder.pushStyle(text_style1);
builder.addText(text1, strlen(text1));
TextStyle text_style2;
text_style2.setFontFamilies({SkString("Roboto")});
text_style2.setFontSize(50);
text_style2.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
SkFontStyle::kUpright_Slant));
text_style2.setLetterSpacing(10);
text_style2.setDecorationColor(SK_ColorBLACK);
text_style2.setDecoration((TextDecoration)(
TextDecoration::kUnderline | TextDecoration::kOverline | TextDecoration::kLineThrough));
text_style2.setWordSpacing(30);
text_style2.setColor(SK_ColorGREEN);
builder.pushStyle(text_style2);
builder.addText(text2, strlen(text2));
TextStyle text_style3;
text_style3.setFontFamilies({SkString("Homemade Apple")});
text_style3.setColor(SK_ColorBLACK);
builder.pushStyle(text_style3);
builder.addText(text3, strlen(text3));
TextStyle text_style4;
text_style4.setFontFamilies({SkString("Roboto")});
text_style4.setFontSize(14);
text_style4.setDecorationColor(SK_ColorBLACK);
text_style4.setDecoration((TextDecoration)(
TextDecoration::kUnderline | TextDecoration::kOverline | TextDecoration::kLineThrough));
text_style4.setColor(SK_ColorBLUE);
builder.pushStyle(text_style4);
builder.addText(text4, strlen(text4));
builder.addText(text5, strlen(text5));
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(1000);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->runs().size() == 4);
REPORTER_ASSERT(reporter, impl->styles().size() == 4);
REPORTER_ASSERT(reporter, impl->lines().size() == 2);
auto rects = paragraph->getRectsForRange(0, impl->text().size(), RectHeightStyle::kMax, RectWidthStyle::kTight);
canvas.drawRects(SK_ColorMAGENTA, rects);
size_t index = 0;
impl->lines()[0].scanStyles(
StyleType::kAllAttributes,
[&](TextRange textRange, const TextStyle& style, const TextLine::ClipContext& context) {
switch (index) {
case 0:
REPORTER_ASSERT(reporter, style.equals(text_style1));
REPORTER_ASSERT(reporter, equal(impl->text().begin(), textRange, text1));
break;
case 1:
REPORTER_ASSERT(reporter, style.equals(text_style2));
REPORTER_ASSERT(reporter, equal(impl->text().begin(), textRange, text2));
break;
case 2:
REPORTER_ASSERT(reporter, style.equals(text_style3));
REPORTER_ASSERT(reporter, equal(impl->text().begin(), textRange, text3));
break;
case 3:
REPORTER_ASSERT(reporter, style.equals(text_style4));
REPORTER_ASSERT(reporter, equal(impl->text().begin(), textRange, text41));
break;
default:
REPORTER_ASSERT(reporter, false);
break;
}
++index;
return true;
});
impl->lines()[1].scanStyles(
StyleType::kAllAttributes,
[&](TextRange textRange, const TextStyle& style, const TextLine::ClipContext& context) {
switch (index) {
case 4:
REPORTER_ASSERT(reporter, style.equals(text_style4));
REPORTER_ASSERT(reporter, equal(impl->text().begin(), textRange, text42));
break;
default:
REPORTER_ASSERT(reporter, false);
break;
}
++index;
return true;
});
REPORTER_ASSERT(reporter, index == 5);
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_DefaultStyleParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_DefaultStyleParagraph.png");
const char* text = "No TextStyle! Uh Oh!";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
TextStyle defaultStyle;
defaultStyle.setFontFamilies({SkString("Roboto")});
paragraph_style.setTextStyle(defaultStyle);
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
builder.addText(text, len);
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 10.0, 15.0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
REPORTER_ASSERT(reporter, impl->styles().size() == 1);
REPORTER_ASSERT(reporter, impl->lines().size() == 1);
size_t index = 0;
impl->lines()[0].scanStyles(
StyleType::kAllAttributes,
[&](TextRange textRange, const TextStyle& style, const TextLine::ClipContext& context) {
REPORTER_ASSERT(reporter, style.equals(paragraph_style.getTextStyle()));
REPORTER_ASSERT(reporter, equal(impl->text().begin(), textRange, text));
++index;
return true;
});
REPORTER_ASSERT(reporter, index == 1);
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_BoldParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_BoldParagraph.png");
const char* text = "This is Red max bold text!";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorRED);
text_style.setFontSize(60);
text_style.setLetterSpacing(0);
text_style.setFontStyle(SkFontStyle(SkFontStyle::kBlack_Weight, SkFontStyle::kNormal_Width,
SkFontStyle::kUpright_Slant));
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(VeryLongCanvasWidth);
paragraph->paint(canvas.get(), 10.0, 60.0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
REPORTER_ASSERT(reporter, impl->styles().size() == 1);
REPORTER_ASSERT(reporter, impl->lines().size() == 1);
size_t index = 0;
impl->lines()[0].scanStyles(
StyleType::kAllAttributes,
[&](TextRange textRange, const TextStyle& style, const TextLine::ClipContext& context) {
REPORTER_ASSERT(reporter, style.equals(text_style));
REPORTER_ASSERT(reporter, equal(impl->text().begin(), textRange, text));
++index;
return true;
});
REPORTER_ASSERT(reporter, index == 1);
}
// Checked: NO DIFF (line height rounding error)
DEF_TEST(SkParagraph_HeightOverrideParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_HeightOverrideParagraph.png");
const char* text = "01234満毎冠行来昼本可\nabcd\n満毎冠行来昼本可";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setMaxLines(10);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setFontSize(20);
text_style.setColor(SK_ColorBLACK);
text_style.setHeight(3.6345f);
text_style.setHeightOverride(true);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->runs().size() == 3);
REPORTER_ASSERT(reporter, impl->styles().size() == 1); // paragraph style does not count
REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
paragraph->paint(canvas.get(), 0, 0);
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
paint.setAntiAlias(true);
paint.setStrokeWidth(1);
// Tests for GetRectsForRange()
RectHeightStyle rect_height_style = RectHeightStyle::kIncludeLineSpacingMiddle;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
paint.setColor(SK_ColorRED);
std::vector<TextBox> boxes = paragraph->getRectsForRange(0, 0, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 0ull);
boxes = paragraph->getRectsForRange(0, 40, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorBLUE, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 3ull);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.top(), 92.805f, EPSILON5));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.right(), 43.843f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[1].rect.bottom(), 165.495f, EPSILON5));
}
// Checked: DIFF+
DEF_TEST(SkParagraph_LeftAlignParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_LeftAlignParagraph.png");
const char* text =
"This is a very long sentence to test if the text will properly wrap "
"around and go to the next line. Sometimes, short sentence. Longer "
"sentences are okay too because they are nessecary. Very short. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
"veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
"velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
"occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
"mollit anim id est laborum. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
"veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
"velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
"occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
"mollit anim id est laborum.";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.setMaxLines(14);
paragraph_style.setTextAlign(TextAlign::kLeft);
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setFontSize(26);
text_style.setLetterSpacing(1);
text_style.setWordSpacing(5);
text_style.setColor(SK_ColorBLACK);
text_style.setHeight(1);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth - 100);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->text().size() == std::string{text}.length());
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
REPORTER_ASSERT(reporter, impl->styles().size() == 1);
REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
REPORTER_ASSERT(reporter, impl->lines().size() == paragraph_style.getMaxLines());
double expected_y = 0;
double epsilon = 0.01f;
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[0].baseline(), 24.121f, epsilon));
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[0].offset().fY, expected_y, epsilon));
expected_y += 30;
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[1].offset().fY, expected_y, epsilon));
expected_y += 30;
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[2].offset().fY, expected_y, epsilon));
expected_y += 30;
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[3].offset().fY, expected_y, epsilon));
expected_y += 30 * 10;
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[13].offset().fY, expected_y, epsilon));
REPORTER_ASSERT(reporter,
paragraph_style.getTextAlign() == impl->paragraphStyle().getTextAlign());
// Tests for GetGlyphPositionAtCoordinate()
REPORTER_ASSERT(reporter, impl->getGlyphPositionAtCoordinate(0, 0).position == 0);
REPORTER_ASSERT(reporter, impl->getGlyphPositionAtCoordinate(1, 1).position == 0);
REPORTER_ASSERT(reporter, impl->getGlyphPositionAtCoordinate(1, 35).position == 68);
REPORTER_ASSERT(reporter, impl->getGlyphPositionAtCoordinate(1, 70).position == 134);
REPORTER_ASSERT(reporter, impl->getGlyphPositionAtCoordinate(2000, 35).position == 134);
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_RightAlignParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_RightAlignParagraph.png");
const char* text =
"This is a very long sentence to test if the text will properly wrap "
"around and go to the next line. Sometimes, short sentence. Longer "
"sentences are okay too because they are nessecary. Very short. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
"veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
"velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
"occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
"mollit anim id est laborum. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
"veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
"velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
"occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
"mollit anim id est laborum.";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.setMaxLines(14);
paragraph_style.setTextAlign(TextAlign::kRight);
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setFontSize(26);
text_style.setLetterSpacing(1);
text_style.setWordSpacing(5);
text_style.setColor(SK_ColorBLACK);
text_style.setHeight(1);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth - 100);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
REPORTER_ASSERT(reporter, impl->styles().size() == 1);
REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
REPORTER_ASSERT(reporter, impl->lines().size() == paragraph_style.getMaxLines());
double expected_y = 0;
double epsilon = 0.01f;
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[0].baseline(), 24.121f, epsilon));
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[0].offset().fY, expected_y, epsilon));
expected_y += 30;
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[1].offset().fY, expected_y, epsilon));
expected_y += 30;
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[2].offset().fY, expected_y, epsilon));
expected_y += 30;
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[3].offset().fY, expected_y, epsilon));
expected_y += 30 * 10;
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[13].offset().fY, expected_y, epsilon));
auto calculate = [](const TextLine& line) -> SkScalar {
return TestCanvasWidth - 100 - line.offset().fX - line.width();
};
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[0]), 0, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[1]), 0, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[2]), 0, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[3]), 0, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[13]), 0, epsilon));
REPORTER_ASSERT(reporter,
paragraph_style.getTextAlign() == impl->paragraphStyle().getTextAlign());
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_CenterAlignParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_CenterAlignParagraph.png");
const char* text =
"This is a very long sentence to test if the text will properly wrap "
"around and go to the next line. Sometimes, short sentence. Longer "
"sentences are okay too because they are nessecary. Very short. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
"veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
"velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
"occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
"mollit anim id est laborum. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
"veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
"velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
"occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
"mollit anim id est laborum.";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.setMaxLines(14);
paragraph_style.setTextAlign(TextAlign::kCenter);
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setFontSize(26);
text_style.setLetterSpacing(1);
text_style.setWordSpacing(5);
text_style.setColor(SK_ColorBLACK);
text_style.setHeight(1);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth - 100);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->text().size() == std::string{text}.length());
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
REPORTER_ASSERT(reporter, impl->styles().size() == 1);
REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
REPORTER_ASSERT(reporter, impl->lines().size() == paragraph_style.getMaxLines());
double expected_y = 0;
double epsilon = 0.01f;
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[0].baseline(), 24.121f, epsilon));
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[0].offset().fY, expected_y, epsilon));
expected_y += 30;
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[1].offset().fY, expected_y, epsilon));
expected_y += 30;
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[2].offset().fY, expected_y, epsilon));
expected_y += 30;
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[3].offset().fY, expected_y, epsilon));
expected_y += 30 * 10;
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[13].offset().fY, expected_y, epsilon));
auto calculate = [](const TextLine& line) -> SkScalar {
return TestCanvasWidth - 100 - (line.offset().fX * 2 + line.width());
};
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[0]), 0, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[1]), 0, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[2]), 0, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[3]), 0, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[13]), 0, epsilon));
REPORTER_ASSERT(reporter,
paragraph_style.getTextAlign() == impl->paragraphStyle().getTextAlign());
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_JustifyAlignParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_JustifyAlignParagraph.png");
const char* text =
"This is a very long sentence to test if the text will properly wrap "
"around and go to the next line. Sometimes, short sentence. Longer "
"sentences are okay too because they are nessecary. Very short. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
"veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
"velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
"occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
"mollit anim id est laborum. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
"veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
"velit esse cillum dolore eu fugiat.";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.setMaxLines(14);
paragraph_style.setTextAlign(TextAlign::kJustify);
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setFontSize(26);
text_style.setLetterSpacing(0);
text_style.setWordSpacing(5);
text_style.setColor(SK_ColorBLACK);
text_style.setHeight(1);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth - 100);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle rect_height_style = RectHeightStyle::kMax;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
auto boxes = paragraph->getRectsForRange(0, 100, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->text().size() == std::string{text}.length());
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
REPORTER_ASSERT(reporter, impl->styles().size() == 1);
REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
double expected_y = 0;
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[0].baseline(), 24.121f, EPSILON100));
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[0].offset().fY, expected_y, EPSILON100));
expected_y += 30;
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[1].offset().fY, expected_y, EPSILON100));
expected_y += 30;
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[2].offset().fY, expected_y, EPSILON100));
expected_y += 30;
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[3].offset().fY, expected_y, EPSILON100));
expected_y += 30 * 9;
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(impl->lines()[12].offset().fY, expected_y, EPSILON100));
auto calculate = [](const TextLine& line) -> SkScalar {
return TestCanvasWidth - 100 - (line.offset().fX + line.width());
};
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[0]), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[1]), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[2]), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(impl->lines()[3]), 0, EPSILON100));
REPORTER_ASSERT(reporter, calculate(impl->lines()[13]) > 0);
REPORTER_ASSERT(reporter,
paragraph_style.getTextAlign() == impl->paragraphStyle().getTextAlign());
}
// Checked: DIFF (ghost spaces as a separate box in TxtLib)
DEF_TEST(SkParagraph_JustifyRTL, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_JustifyRTL.png");
const char* text =
"אאא בּבּבּבּ אאאא בּבּ אאא בּבּבּ אאאאא בּבּבּבּ אאאא בּבּבּבּבּ "
"אאאאא בּבּבּבּבּ אאאבּבּבּבּבּבּאאאאא בּבּבּבּבּבּאאאאאבּבּבּבּבּבּ אאאאא בּבּבּבּבּ "
"אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.setMaxLines(14);
paragraph_style.setTextAlign(TextAlign::kJustify);
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Ahem")});
text_style.setFontSize(26);
text_style.setColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth - 100);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
auto calculate = [](const TextLine& line) -> SkScalar {
return TestCanvasWidth - 100 - line.width();
};
for (auto& line : impl->lines()) {
if (&line == &impl->lines().back()) {
REPORTER_ASSERT(reporter, calculate(line) > EPSILON100);
} else {
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(line), 0, EPSILON100));
}
}
// Just make sure the the text is actually RTL
for (auto& run : impl->runs()) {
REPORTER_ASSERT(reporter, !run.leftToRight());
}
// Tests for GetRectsForRange()
RectHeightStyle rect_height_style = RectHeightStyle::kMax;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
auto boxes = paragraph->getRectsForRange(0, 100, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 3); // DIFF
boxes = paragraph->getRectsForRange(240, 250, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorBLUE, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 588, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 130, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 640, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 156, EPSILON100));
}
// Checked: NO DIFF (some minor decoration differences, probably)
DEF_TEST(SkParagraph_DecorationsParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_DecorationsParagraph.png");
const char* text1 = "This text should be";
const char* text2 = " decorated even when";
const char* text3 = " wrapped around to";
const char* text4 = " the next line.";
const char* text5 = " Otherwise, bad things happen.";
ParagraphStyle paragraph_style;
paragraph_style.setMaxLines(14);
paragraph_style.setTextAlign(TextAlign::kLeft);
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setFontSize(26);
text_style.setLetterSpacing(0);
text_style.setWordSpacing(5);
text_style.setColor(SK_ColorBLACK);
text_style.setHeight(2);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
text_style.setDecoration((TextDecoration)(
TextDecoration::kUnderline | TextDecoration::kOverline | TextDecoration::kLineThrough));
text_style.setDecorationStyle(TextDecorationStyle::kSolid);
text_style.setDecorationColor(SK_ColorBLACK);
text_style.setDecorationThicknessMultiplier(2.0);
builder.pushStyle(text_style);
builder.addText(text1, strlen(text1));
text_style.setDecorationStyle(TextDecorationStyle::kDouble);
text_style.setDecorationColor(SK_ColorBLUE);
text_style.setDecorationThicknessMultiplier(1.0);
builder.pushStyle(text_style);
builder.addText(text2, strlen(text2));
text_style.setDecorationStyle(TextDecorationStyle::kDotted);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text3, strlen(text3));
text_style.setDecorationStyle(TextDecorationStyle::kDashed);
text_style.setDecorationColor(SK_ColorBLACK);
text_style.setDecorationThicknessMultiplier(3.0);
builder.pushStyle(text_style);
builder.addText(text4, strlen(text4));
text_style.setDecorationStyle(TextDecorationStyle::kWavy);
text_style.setDecorationColor(SK_ColorRED);
text_style.setDecorationThicknessMultiplier(1.0);
builder.pushStyle(text_style);
builder.addText(text5, strlen(text5));
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth - 100);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
size_t index = 0;
for (auto& line : impl->lines()) {
line.scanStyles(
StyleType::kDecorations,
[&](TextRange textRange, const TextStyle& style, const TextLine::ClipContext& context) {
auto decoration = (TextDecoration)(TextDecoration::kUnderline |
TextDecoration::kOverline |
TextDecoration::kLineThrough);
REPORTER_ASSERT(reporter, style.getDecorationType() == decoration);
switch (index) {
case 0:
REPORTER_ASSERT(reporter, style.getDecorationStyle() ==
TextDecorationStyle::kSolid);
REPORTER_ASSERT(reporter, style.getDecorationColor() == SK_ColorBLACK);
REPORTER_ASSERT(reporter,
style.getDecorationThicknessMultiplier() == 2.0);
break;
case 1: // The style appears on 2 lines so it has 2 pieces
REPORTER_ASSERT(reporter, style.getDecorationStyle() ==
TextDecorationStyle::kDouble);
REPORTER_ASSERT(reporter, style.getDecorationColor() == SK_ColorBLUE);
REPORTER_ASSERT(reporter,
style.getDecorationThicknessMultiplier() == 1.0);
break;
case 2:
REPORTER_ASSERT(reporter, style.getDecorationStyle() ==
TextDecorationStyle::kDotted);
REPORTER_ASSERT(reporter, style.getDecorationColor() == SK_ColorBLACK);
REPORTER_ASSERT(reporter,
style.getDecorationThicknessMultiplier() == 1.0);
break;
case 3:
case 4:
REPORTER_ASSERT(reporter, style.getDecorationStyle() ==
TextDecorationStyle::kDashed);
REPORTER_ASSERT(reporter, style.getDecorationColor() == SK_ColorBLACK);
REPORTER_ASSERT(reporter,
style.getDecorationThicknessMultiplier() == 3.0);
break;
case 5:
REPORTER_ASSERT(reporter, style.getDecorationStyle() ==
TextDecorationStyle::kWavy);
REPORTER_ASSERT(reporter, style.getDecorationColor() == SK_ColorRED);
REPORTER_ASSERT(reporter,
style.getDecorationThicknessMultiplier() == 1.0);
break;
default:
REPORTER_ASSERT(reporter, false);
break;
}
++index;
return true;
});
}
}
DEF_TEST(SkParagraph_WavyDecorationParagraph, reporter) {
SkDebugf("TODO: Fix decorations\n");
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_ItalicsParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_ItalicsParagraph.png");
const char* text1 = "No italic ";
const char* text2 = "Yes Italic ";
const char* text3 = "No Italic again.";
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setFontSize(10);
text_style.setColor(SK_ColorRED);
builder.pushStyle(text_style);
builder.addText(text1, strlen(text1));
text_style.setFontStyle(SkFontStyle(SkFontStyle::kNormal_Weight, SkFontStyle::kNormal_Width,
SkFontStyle::kItalic_Slant));
builder.pushStyle(text_style);
builder.addText(text2, strlen(text2));
builder.pop();
builder.addText(text3, strlen(text3));
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->runs().size() == 3);
REPORTER_ASSERT(reporter, impl->styles().size() == 3);
REPORTER_ASSERT(reporter, impl->lines().size() == 1);
auto& line = impl->lines()[0];
size_t index = 0;
line.scanStyles(
StyleType::kForeground,
[&](TextRange textRange, const TextStyle& style, const TextLine::ClipContext& context) {
switch (index) {
case 0:
REPORTER_ASSERT(
reporter,
style.getFontStyle().slant() == SkFontStyle::kUpright_Slant);
break;
case 1:
REPORTER_ASSERT(reporter,
style.getFontStyle().slant() == SkFontStyle::kItalic_Slant);
break;
case 2:
REPORTER_ASSERT(
reporter,
style.getFontStyle().slant() == SkFontStyle::kUpright_Slant);
break;
default:
REPORTER_ASSERT(reporter, false);
break;
}
++index;
return true;
});
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_ChineseParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_ChineseParagraph.png");
const char* text =
"左線読設重説切後碁給能上目秘使約。満毎冠行来昼本可必図将発確年。今属場育"
"図情闘陰野高備込制詩西校客。審対江置講今固残必託地集済決維駆年策。立得庭"
"際輝求佐抗蒼提夜合逃表。注統天言件自謙雅載報紙喪。作画稿愛器灯女書利変探"
"訃第金線朝開化建。子戦年帝励害表月幕株漠新期刊人秘。図的海力生禁挙保天戦"
"聞条年所在口。";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.setMaxLines(14);
paragraph_style.setTextAlign(TextAlign::kJustify);
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
auto decoration = (TextDecoration)(TextDecoration::kUnderline | TextDecoration::kOverline |
TextDecoration::kLineThrough);
TextStyle text_style;
text_style.setFontFamilies({SkString("Source Han Serif CN")});
text_style.setFontSize(35);
text_style.setColor(SK_ColorBLACK);
text_style.setLetterSpacing(2);
text_style.setHeight(1);
text_style.setDecoration(decoration);
text_style.setDecorationColor(SK_ColorBLACK);
text_style.setDecorationStyle(TextDecorationStyle::kSolid);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth - 100);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
REPORTER_ASSERT(reporter, impl->lines().size() == 7);
REPORTER_ASSERT(reporter, impl->styles().size() == 1);
REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
}
// Checked: NO DIFF (disabled)
DEF_TEST(SkParagraph_ArabicParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_ArabicParagraph.png");
const char* text =
"من أسر وإعلان الخاصّة وهولندا،, عل قائمة الضغوط بالمطالبة تلك. الصفحة "
"بمباركة التقليدية قام عن. تصفح";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.setMaxLines(14);
paragraph_style.setTextAlign(TextAlign::kJustify);
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
auto decoration = (TextDecoration)(TextDecoration::kUnderline | TextDecoration::kOverline |
TextDecoration::kLineThrough);
TextStyle text_style;
text_style.setFontFamilies({SkString("Katibeh")});
text_style.setFontSize(35);
text_style.setColor(SK_ColorBLACK);
text_style.setLetterSpacing(2);
text_style.setDecoration(decoration);
text_style.setDecorationColor(SK_ColorBLACK);
text_style.setDecorationStyle(TextDecorationStyle::kSolid);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth - 100);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
REPORTER_ASSERT(reporter, impl->lines().size() == 2);
REPORTER_ASSERT(reporter, impl->styles().size() == 1);
REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
}
// Checked: DIFF (2 boxes and each space is a word)
DEF_TEST(SkParagraph_ArabicRectsParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_ArabicRectsParagraph.png");
const char* text = "بمباركة التقليدية قام عن. تصفح يد ";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setMaxLines(14);
paragraph_style.setTextAlign(TextAlign::kRight);
paragraph_style.setTextDirection(TextDirection::kRtl);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Noto Naskh Arabic")});
text_style.setFontSize(26);
text_style.setWordSpacing(5);
text_style.setColor(SK_ColorBLACK);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth - 100);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle rect_height_style = RectHeightStyle::kMax;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
std::vector<TextBox> boxes = paragraph->getRectsForRange(0, 100, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1ull);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 538.548f, EPSILON100)); // DIFF: 510.09375
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), -0.268f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 900, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 44, EPSILON100));
}
// Checked DIFF+
DEF_TEST(SkParagraph_ArabicRectsLTRLeftAlignParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_ArabicRectsLTRLeftAlignParagraph.png");
const char* text = "Helloبمباركة التقليدية قام عن. تصفح يد ";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setMaxLines(14);
paragraph_style.setTextAlign(TextAlign::kLeft);
paragraph_style.setTextDirection(TextDirection::kLtr);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Noto Naskh Arabic")});
text_style.setFontSize(26);
text_style.setWordSpacing(5);
text_style.setColor(SK_ColorBLACK);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth - 100);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->runs().size() == 3);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle rect_height_style = RectHeightStyle::kMax;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
std::vector<TextBox> boxes = paragraph->getRectsForRange(36, 40, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1ull);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 83.916f, EPSILON100)); // DIFF: 89.40625
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), -0.268f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 115.893f, EPSILON100)); // DIFF: 121.87891
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 44, EPSILON100));
}
// Checked DIFF+
DEF_TEST(SkParagraph_ArabicRectsLTRRightAlignParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_ArabicRectsLTRRightAlignParagraph.png");
const char* text = "Helloبمباركة التقليدية قام عن. تصفح يد ";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setMaxLines(14);
paragraph_style.setTextAlign(TextAlign::kRight);
paragraph_style.setTextDirection(TextDirection::kLtr);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Noto Naskh Arabic")});
text_style.setFontSize(26);
text_style.setWordSpacing(5);
text_style.setColor(SK_ColorBLACK);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth - 100);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->runs().size() == 3);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle rect_height_style = RectHeightStyle::kMax;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
std::vector<TextBox> boxes =
paragraph->getRectsForRange(36, 40, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1ull); // DIFF
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 561.501f, EPSILON100)); // DIFF
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), -0.268f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 593.479f, EPSILON100)); // DIFF
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 44, EPSILON100));
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_GetGlyphPositionAtCoordinateParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_GetGlyphPositionAtCoordinateParagraph.png");
const char* text =
"12345 67890 12345 67890 12345 67890 12345 67890 12345 67890 12345 "
"67890 12345";
const size_t len = strlen(text);
ParagraphStyle paragraphStyle;
paragraphStyle.setTextAlign(TextAlign::kLeft);
paragraphStyle.setMaxLines(10);
paragraphStyle.turnHintingOff();
TextStyle textStyle;
textStyle.setFontFamilies({SkString("Roboto")});
textStyle.setFontStyle(SkFontStyle(SkFontStyle::kNormal_Weight, SkFontStyle::kNormal_Width,
SkFontStyle::kUpright_Slant));
textStyle.setFontSize(50);
textStyle.setLetterSpacing(1);
textStyle.setWordSpacing(5);
textStyle.setHeight(1);
textStyle.setColor(SK_ColorBLACK);
ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
builder.pushStyle(textStyle);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
// Tests for getGlyphPositionAtCoordinate()
// NOTE: resulting values can be a few off from their respective positions in
// the original text because the final trailing whitespaces are sometimes not
// drawn (namely, when using "justify" alignment) and therefore are not active
// glyphs.
REPORTER_ASSERT(reporter,
paragraph->getGlyphPositionAtCoordinate(-10000, -10000).position == 0);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(-1, -1).position == 0);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(0, 0).position == 0);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(3, 3).position == 0);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(35, 1).position == 1);
REPORTER_ASSERT(reporter,
paragraph->getGlyphPositionAtCoordinate(300, 2).position == 11);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(301, 2.2f).position == 11);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(302, 2.6f).position == 11);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(301, 2.1f).position == 11);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(100000, 20).position == 18);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(450, 20).position == 16);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(100000, 90).position == 36);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(-100000, 90).position == 18);
REPORTER_ASSERT(reporter,
paragraph->getGlyphPositionAtCoordinate(20, -80).position == 1);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(1, 90).position == 18);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(1, 170).position == 36);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(10000, 180).position == 72);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(70, 180).position == 56);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(1, 270).position == 72);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(35, 90).position == 19);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(10000, 10000).position == 77);
REPORTER_ASSERT(reporter, paragraph->getGlyphPositionAtCoordinate(85, 10000).position == 75);
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_GetRectsForRangeParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_GetRectsForRangeParagraph.png");
const char* text =
"12345, \"67890\" 12345 67890 12345 67890 12345 67890 12345 67890 12345 "
"67890 12345";
const size_t len = strlen(text);
ParagraphStyle paragraphStyle;
paragraphStyle.setTextAlign(TextAlign::kLeft);
paragraphStyle.setMaxLines(10);
paragraphStyle.turnHintingOff();
TextStyle textStyle;
textStyle.setFontFamilies({SkString("Roboto")});
textStyle.setFontSize(50);
textStyle.setColor(SK_ColorBLACK);
textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
SkFontStyle::kUpright_Slant));
ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
builder.pushStyle(textStyle);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle heightStyle = RectHeightStyle::kMax;
RectWidthStyle widthStyle = RectWidthStyle::kTight;
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
paint.setAntiAlias(true);
paint.setStrokeWidth(1);
{
auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, result.empty());
}
{
auto result = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
canvas.drawRects(SK_ColorRED, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 28.417f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(2, 8, heightStyle, widthStyle);
canvas.drawRects(SK_ColorBLUE, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 56.835f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 177.97f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(8, 21, heightStyle, widthStyle);
canvas.drawRects(SK_ColorGREEN, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 177.97f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 507.031f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(30, 100, heightStyle, widthStyle);
canvas.drawRects(SK_ColorRED, result);
REPORTER_ASSERT(reporter, result.size() == 4);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 211.375f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 59.40625f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 463.623f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 118, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.top(), 236.406f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.right(), 142.089f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.bottom(), 295, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(19, 22, heightStyle, widthStyle);
canvas.drawRects(SK_ColorBLUE, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 450.1875f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 519.47266f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, result.empty());
}
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_GetRectsForRangeTight, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_GetRectsForRangeTight.png");
const char* text =
"( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
" ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
" ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
const size_t len = strlen(text);
ParagraphStyle paragraphStyle;
paragraphStyle.setTextAlign(TextAlign::kLeft);
paragraphStyle.setMaxLines(10);
paragraphStyle.turnHintingOff();
TextStyle textStyle;
textStyle.setFontFamilies({SkString("Noto Sans CJK JP")});
textStyle.setFontSize(50);
textStyle.setColor(SK_ColorBLACK);
textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
SkFontStyle::kUpright_Slant));
ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
builder.pushStyle(textStyle);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle heightStyle = RectHeightStyle::kTight;
RectWidthStyle widthStyle = RectWidthStyle::kTight;
{
auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, result.empty());
}
{
auto result = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
canvas.drawRects(SK_ColorRED, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 16.898f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 74, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(2, 8, heightStyle, widthStyle);
canvas.drawRects(SK_ColorBLUE, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 66.899f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 264.099f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 74, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(8, 21, heightStyle, widthStyle);
canvas.drawRects(SK_ColorGREEN, result);
REPORTER_ASSERT(reporter, result.size() == 2);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 264.099f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 595.085f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 74, EPSILON100));
}
}
// Checked: DIFF+
DEF_TEST(SkParagraph_GetRectsForRangeIncludeLineSpacingMiddle, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_GetRectsForRangeIncludeLineSpacingMiddle.png");
const char* text =
"( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
" ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
" ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
const size_t len = strlen(text);
ParagraphStyle paragraphStyle;
paragraphStyle.setTextAlign(TextAlign::kLeft);
paragraphStyle.setMaxLines(10);
paragraphStyle.turnHintingOff();
TextStyle textStyle;
textStyle.setFontFamilies({SkString("Roboto")});
textStyle.setFontSize(50);
textStyle.setHeight(1.6f);
textStyle.setHeightOverride(true);
textStyle.setColor(SK_ColorBLACK);
textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
SkFontStyle::kUpright_Slant));
ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
builder.pushStyle(textStyle);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle heightStyle = RectHeightStyle::kIncludeLineSpacingMiddle;
RectWidthStyle widthStyle = RectWidthStyle::kMax;
{
auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, result.empty());
}
{
auto result = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
canvas.drawRects(SK_ColorRED, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946615f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 17.4296889f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 88.473305f, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(2, 8, heightStyle, widthStyle);
canvas.drawRects(SK_ColorBLUE, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 67.429688f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946615f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 190.00781f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 88.473305f, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(8, 21, heightStyle, widthStyle);
canvas.drawRects(SK_ColorGREEN, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 190.00781f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946615f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 508.0625f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 88.473305f, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(30, 150, heightStyle, widthStyle);
canvas.drawRects(SK_ColorRED, result);
REPORTER_ASSERT(reporter, result.size() == 8);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 190.00781f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 88.473305f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 525.687f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 168.47331f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.left(), 525.687f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.top(), 88.473305f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.right(), 570.02344f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.bottom(), 168.47331f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.top(), 168.47331f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.right(), 531.574f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.bottom(), 248.47331f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.left(), 531.574f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.top(), 168.47331f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.right(), 570.02344f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.bottom(), 248.47331f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.top(), 248.47331f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.right(), 570.02344f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.bottom(), 328.47333f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.top(), 328.47333f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.right(), 570.02344f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.bottom(), 408.4733f, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(19, 22, heightStyle, widthStyle);
canvas.drawRects(SK_ColorBLUE, result);
REPORTER_ASSERT(reporter, result.size() == 2); // DIFF
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 463.72656f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946615f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 530.23047f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 88.473305f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.left(), 530.23047f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.top(), 16.946615f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.right(), 570.02344f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.bottom(), 88.473305f, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, result.empty());
}
}
// Checked: NO DIFF+
DEF_TEST(SkParagraph_GetRectsForRangeIncludeLineSpacingTop, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_GetRectsForRangeIncludeLineSpacingTop.png");
const char* text =
"( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
" ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
" ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
const size_t len = strlen(text);
ParagraphStyle paragraphStyle;
paragraphStyle.setTextAlign(TextAlign::kLeft);
paragraphStyle.setMaxLines(10);
paragraphStyle.turnHintingOff();
TextStyle textStyle;
textStyle.setFontFamilies({SkString("Roboto")});
textStyle.setFontSize(50);
textStyle.setHeight(1.6f);
textStyle.setHeightOverride(true);
textStyle.setColor(SK_ColorBLACK);
textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
SkFontStyle::kUpright_Slant));
ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
builder.pushStyle(textStyle);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle heightStyle = RectHeightStyle::kIncludeLineSpacingTop;
RectWidthStyle widthStyle = RectWidthStyle::kMax;
{
auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, result.empty());
}
{
auto result = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
canvas.drawRects(SK_ColorRED, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946615f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 17.4296889f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 80, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(2, 8, heightStyle, widthStyle);
canvas.drawRects(SK_ColorBLUE, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 67.429688f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946615f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 190.00781f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 80, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(8, 21, heightStyle, widthStyle);
canvas.drawRects(SK_ColorGREEN, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 190.00781f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946615f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 508.0625f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 80, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(30, 150, heightStyle, widthStyle);
canvas.drawRects(SK_ColorMAGENTA, result);
REPORTER_ASSERT(reporter, result.size() == 8);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 190.00781f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 80, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 525.687f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 160, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.left(), 525.687f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.top(), 80, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.right(), 570.02344f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.bottom(), 160, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.top(), 160, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.right(), 531.574f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.bottom(), 240, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.left(), 531.574f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.top(), 160, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.right(), 570.02344f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.bottom(), 240, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.top(), 240, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.right(), 570.02344f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.bottom(), 320, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.top(), 320, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.right(), 570.02344f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.bottom(), 400, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(19, 22, heightStyle, widthStyle);
canvas.drawRects(SK_ColorBLACK, result);
REPORTER_ASSERT(reporter, result.size() == 2); // DIFF
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 463.72656f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946615f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 530.23047f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 80, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.left(), 530.23047f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.top(), 16.946615f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.right(), 570.02344f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.bottom(), 80, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, result.empty());
}
}
// Checked: NO DIFF+
DEF_TEST(SkParagraph_GetRectsForRangeIncludeLineSpacingBottom, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_GetRectsForRangeIncludeLineSpacingBottom.png");
const char* text =
"( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
" ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
" ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
const size_t len = strlen(text);
ParagraphStyle paragraphStyle;
paragraphStyle.setTextAlign(TextAlign::kLeft);
paragraphStyle.setMaxLines(10);
paragraphStyle.turnHintingOff();
TextStyle textStyle;
textStyle.setFontFamilies({SkString("Roboto")});
textStyle.setFontSize(50);
textStyle.setHeight(1.6f);
textStyle.setHeightOverride(true);
textStyle.setColor(SK_ColorBLACK);
textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
SkFontStyle::kUpright_Slant));
ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
builder.pushStyle(textStyle);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle heightStyle = RectHeightStyle::kIncludeLineSpacingBottom;
RectWidthStyle widthStyle = RectWidthStyle::kMax;
{
auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, result.empty());
}
{
auto result = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
canvas.drawRects(SK_ColorRED, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 17.429f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 96.946f, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(2, 8, heightStyle, widthStyle);
canvas.drawRects(SK_ColorBLUE, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 67.4298f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 190.007f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 96.946f, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(8, 21, heightStyle, widthStyle);
canvas.drawRects(SK_ColorGREEN, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 190.007f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 508.062f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 96.946f, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(30, 150, heightStyle, widthStyle);
canvas.drawRects(SK_ColorMAGENTA, result);
REPORTER_ASSERT(reporter, result.size() == 8);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 190.007f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 96.946f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 525.687f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 176.946f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.left(), 525.687f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.top(), 96.946f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.right(), 570.023f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.bottom(), 176.946f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.top(), 176.946f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.right(), 531.574f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[2].rect.bottom(), 256.946f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.left(), 531.574f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.top(), 176.946f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.right(), 570.023f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.bottom(), 256.946f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.top(), 256.946f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.right(), 570.023f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[4].rect.bottom(), 336.946f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.top(), 336.946f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.right(), 570.023f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[5].rect.bottom(), 416.946f, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(19, 22, heightStyle, widthStyle);
canvas.drawRects(SK_ColorBLACK, result);
REPORTER_ASSERT(reporter, result.size() == 2); // DIFF
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 463.726f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 16.946f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 530.230f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 96.946f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.left(), 530.230f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.top(), 16.946f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.right(), 570.023f, EPSILON20));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.bottom(), 96.946f, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, result.empty());
}
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_GetRectsForRangeIncludeCombiningCharacter, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_GetRectsForRangeIncludeCombiningCharacter.png");
const char* text = "ดีสวัสดีชาวโลกที่น่ารัก";
const size_t len = strlen(text);
ParagraphStyle paragraphStyle;
paragraphStyle.setTextAlign(TextAlign::kLeft);
paragraphStyle.setMaxLines(10);
paragraphStyle.turnHintingOff();
ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
TextStyle textStyle;
textStyle.setFontFamilies({SkString("Roboto")});
textStyle.setFontSize(50);
textStyle.setLetterSpacing(1);
textStyle.setWordSpacing(5);
textStyle.setHeight(1);
textStyle.setColor(SK_ColorBLACK);
builder.pushStyle(textStyle);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth - 100);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->lines().size() == 1);
RectHeightStyle heightStyle = RectHeightStyle::kTight;
RectWidthStyle widthStyle = RectWidthStyle::kTight;
{
auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, result.empty());
}
{
auto first = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
auto second = paragraph->getRectsForRange(1, 2, heightStyle, widthStyle);
auto last = paragraph->getRectsForRange(0, 2, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, first.size() == 0 && second.size() == 1 && last.size() == 1);
REPORTER_ASSERT(reporter, second[0].rect == last[0].rect);
}
{
auto first = paragraph->getRectsForRange(3, 4, heightStyle, widthStyle);
auto second = paragraph->getRectsForRange(4, 5, heightStyle, widthStyle);
auto last = paragraph->getRectsForRange(3, 5, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, first.size() == 0 && second.size() == 1 && last.size() == 1);
REPORTER_ASSERT(reporter, second[0].rect == last[0].rect);
}
{
auto first = paragraph->getRectsForRange(14, 15, heightStyle, widthStyle);
auto second = paragraph->getRectsForRange(15, 16, heightStyle, widthStyle);
auto third = paragraph->getRectsForRange(16, 17, heightStyle, widthStyle);
auto last = paragraph->getRectsForRange(14, 17, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, first.size() == 0 && second.size() == 0 &&
third.size() == 1 && last.size() == 1);
REPORTER_ASSERT(reporter, third[0].rect == last[0].rect);
}
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_GetRectsForRangeCenterParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_GetRectsForRangeCenterParagraph.png");
// Minikin uses a hard coded list of unicode characters that he treats as invisible - as spaces.
// It's absolutely wrong - invisibility is a glyph attribute, not character/grapheme.
// Any attempt to substitute one for another leads to errors
// (for instance, some fonts can use these hard coded characters for something that is visible)
const char* text = "01234   "; // includes ideographic space and english space.
const size_t len = strlen(text);
ParagraphStyle paragraphStyle;
paragraphStyle.setTextAlign(TextAlign::kCenter);
paragraphStyle.setMaxLines(10);
paragraphStyle.turnHintingOff();
ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
TextStyle textStyle;
textStyle.setFontFamilies({SkString("Roboto")});
textStyle.setFontSize(50);
textStyle.setHeight(1);
textStyle.setColor(SK_ColorBLACK);
textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
SkFontStyle::kUpright_Slant));
builder.pushStyle(textStyle);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
// Some of the formatting lazily done on paint
RectHeightStyle heightStyle = RectHeightStyle::kMax;
RectWidthStyle widthStyle = RectWidthStyle::kTight;
{
auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, result.empty());
}
{
auto result = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
canvas.drawRects(SK_ColorRED, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 203.955f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 232.373f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(2, 4, heightStyle, widthStyle);
canvas.drawRects(SK_ColorBLUE, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 260.791f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 317.626f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(4, 5, heightStyle, widthStyle);
canvas.drawRects(SK_ColorGREEN, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 317.626f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 346.044f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(4, 6, heightStyle, widthStyle);
canvas.drawRects(SK_ColorBLACK, result);
REPORTER_ASSERT(reporter, result.size() == 1); // DIFF
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 317.626f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 358.494f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(5, 6, heightStyle, widthStyle);
canvas.drawRects(SK_ColorRED, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 346.044f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 358.494f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, result.empty());
}
}
// Checked DIFF+
DEF_TEST(SkParagraph_GetRectsForRangeCenterParagraphNewlineCentered, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_GetRectsForRangeCenterParagraphNewlineCentered.png");
const char* text = "01234\n";
const size_t len = strlen(text);
ParagraphStyle paragraphStyle;
paragraphStyle.setTextAlign(TextAlign::kCenter);
paragraphStyle.setMaxLines(10);
paragraphStyle.turnHintingOff();
ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
TextStyle textStyle;
textStyle.setFontFamilies({SkString("Roboto")});
textStyle.setFontSize(50);
textStyle.setHeight(1);
textStyle.setColor(SK_ColorBLACK);
textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
SkFontStyle::kUpright_Slant));
builder.pushStyle(textStyle);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->lines().size() == 2);
RectHeightStyle heightStyle = RectHeightStyle::kMax;
RectWidthStyle widthStyle = RectWidthStyle::kTight;
{
auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, result.empty());
}
{
auto result = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
canvas.drawRects(SK_ColorRED, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 203.955f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 232.373f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, EPSILON100));
}
{
auto result = paragraph->getRectsForRange(6, 7, heightStyle, widthStyle);
canvas.drawRects(SK_ColorBLUE, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 275.0f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 59.406f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 275.0f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 118, EPSILON100));
}
}
// Checked NO DIFF
DEF_TEST(SkParagraph_GetRectsForRangeCenterMultiLineParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_GetRectsForRangeCenterMultiLineParagraph.png");
const char* text = "01234   \n0123  "; // includes ideographic space and english space.
const size_t len = strlen(text);
ParagraphStyle paragraphStyle;
paragraphStyle.setTextAlign(TextAlign::kCenter);
paragraphStyle.setMaxLines(10);
paragraphStyle.turnHintingOff();
ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
TextStyle textStyle;
textStyle.setFontFamilies({SkString("Roboto")});
textStyle.setFontSize(50);
textStyle.setHeight(1);
textStyle.setColor(SK_ColorBLACK);
textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
SkFontStyle::kUpright_Slant));
builder.pushStyle(textStyle);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->lines().size() == 2);
RectHeightStyle heightStyle = RectHeightStyle::kMax;
RectWidthStyle widthStyle = RectWidthStyle::kTight;
SkScalar epsilon = 0.01f;
{
auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, result.empty());
}
{
auto result = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle);
canvas.drawRects(SK_ColorRED, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 203.955f, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 232.373f, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon));
}
{
auto result = paragraph->getRectsForRange(2, 4, heightStyle, widthStyle);
canvas.drawRects(SK_ColorBLUE, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 260.791f, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 317.626f, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon));
}
{
auto result = paragraph->getRectsForRange(4, 6, heightStyle, widthStyle);
canvas.drawRects(SK_ColorGREEN, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 317.626f, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 358.494f, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon));
}
{
auto result = paragraph->getRectsForRange(5, 6, heightStyle, widthStyle);
canvas.drawRects(SK_ColorYELLOW, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 346.044f, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 358.494f, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon));
}
{
auto result = paragraph->getRectsForRange(10, 12, heightStyle, widthStyle);
canvas.drawRects(SK_ColorCYAN, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 218.164f, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 59.40625f, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 275, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 118, epsilon));
}
{
auto result = paragraph->getRectsForRange(14, 18, heightStyle, widthStyle);
canvas.drawRects(SK_ColorBLACK, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 331.835f, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 59.40625f, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 419.189f, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 118, epsilon));
}
{
auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle);
REPORTER_ASSERT(reporter, result.empty());
}
}
// Checked: DIFF (line height rounding error)
DEF_TEST(SkParagraph_GetRectsForRangeStrut, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_GetRectsForRangeStrut.png");
const char* text = "Chinese 字典";
const size_t len = strlen(text);
StrutStyle strutStyle;
strutStyle.setStrutEnabled(true);
strutStyle.setFontFamilies({SkString("Roboto")});
strutStyle.setFontSize(14.0);
ParagraphStyle paragraphStyle;
paragraphStyle.setStrutStyle(strutStyle);
TextStyle textStyle;
textStyle.setFontFamilies({SkString("Noto Sans CJK JP")});
textStyle.setFontSize(20);
textStyle.setColor(SK_ColorBLACK);
ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
builder.pushStyle(textStyle);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
{
auto result = paragraph->getRectsForRange(0, 10, RectHeightStyle::kTight, RectWidthStyle::kMax);
canvas.drawRects(SK_ColorGREEN, result);
REPORTER_ASSERT(reporter, result.size() == 1);
}
{
auto result = paragraph->getRectsForRange(0, 10, RectHeightStyle::kStrut, RectWidthStyle::kMax);
canvas.drawRects(SK_ColorRED, result);
REPORTER_ASSERT(reporter, result.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 10.611f, EPSILON2));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 118.605f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 27.017f, EPSILON2));
}
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_GetRectsForRangeStrutFallback, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_GetRectsForRangeStrutFallback.png");
const char* text = "Chinese 字典";
const size_t len = strlen(text);
StrutStyle strutStyle;
strutStyle.setStrutEnabled(false);
ParagraphStyle paragraphStyle;
paragraphStyle.setStrutStyle(strutStyle);
TextStyle textStyle;
textStyle.setFontFamilies({SkString("Noto Sans CJK JP")});
textStyle.setFontSize(20);
textStyle.setColor(SK_ColorBLACK);
ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
builder.pushStyle(textStyle);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
auto result1 = paragraph->getRectsForRange(0, 10, RectHeightStyle::kTight, RectWidthStyle::kMax);
canvas.drawRects(SK_ColorGREEN, result1);
REPORTER_ASSERT(reporter, result1.size() == 1);
auto result2 = paragraph->getRectsForRange(0, 10, RectHeightStyle::kStrut, RectWidthStyle::kMax);
canvas.drawRects(SK_ColorRED, result2);
REPORTER_ASSERT(reporter, result2.size() == 1);
REPORTER_ASSERT(reporter, result1[0].rect == result2[0].rect);
}
// Checked: DIFF (small in numbers)
DEF_TEST(SkParagraph_GetWordBoundaryParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_GetWordBoundaryParagraph.png");
const char* text = "12345 67890 12345 67890 12345 67890 12345 "
"67890 12345 67890 12345 67890 12345";
const size_t len = strlen(text);
ParagraphStyle paragraphStyle;
paragraphStyle.setTextAlign(TextAlign::kLeft);
paragraphStyle.setMaxLines(10);
paragraphStyle.turnHintingOff();
TextStyle textStyle;
textStyle.setFontFamilies({SkString("Roboto")});
textStyle.setFontSize(52);
textStyle.setLetterSpacing(1.19039f);
textStyle.setWordSpacing(5);
textStyle.setHeight(1.5);
textStyle.setHeightOverride(true);
textStyle.setColor(SK_ColorBLACK);
ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
builder.pushStyle(textStyle);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
REPORTER_ASSERT(reporter, paragraph->getWordBoundary(0) == SkRange<size_t>(0, 5));
REPORTER_ASSERT(reporter, paragraph->getWordBoundary(1) == SkRange<size_t>(0, 5));
REPORTER_ASSERT(reporter, paragraph->getWordBoundary(2) == SkRange<size_t>(0, 5));
REPORTER_ASSERT(reporter, paragraph->getWordBoundary(3) == SkRange<size_t>(0, 5));
REPORTER_ASSERT(reporter, paragraph->getWordBoundary(4) == SkRange<size_t>(0, 5));
auto boxes = paragraph->getRectsForRange(5, 6, RectHeightStyle::kMax, RectWidthStyle::kTight);
canvas.drawLines(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, paragraph->getWordBoundary(5) == SkRange<size_t>(5, 7));
boxes = paragraph->getRectsForRange(6, 7, RectHeightStyle::kMax, RectWidthStyle::kTight);
canvas.drawLines(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, paragraph->getWordBoundary(6) == SkRange<size_t>(5, 7));
boxes = paragraph->getRectsForRange(7, 8, RectHeightStyle::kMax, RectWidthStyle::kTight);
canvas.drawLines(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, paragraph->getWordBoundary(7) == SkRange<size_t>(7, 12));
REPORTER_ASSERT(reporter, paragraph->getWordBoundary(8) == SkRange<size_t>(7, 12));
REPORTER_ASSERT(reporter, paragraph->getWordBoundary(9) == SkRange<size_t>(7, 12));
REPORTER_ASSERT(reporter, paragraph->getWordBoundary(10) == SkRange<size_t>(7, 12));
REPORTER_ASSERT(reporter, paragraph->getWordBoundary(11) == SkRange<size_t>(7, 12));
REPORTER_ASSERT(reporter, paragraph->getWordBoundary(12) == SkRange<size_t>(12, 13));
REPORTER_ASSERT(reporter, paragraph->getWordBoundary(13) == SkRange<size_t>(13, 18));
REPORTER_ASSERT(reporter, paragraph->getWordBoundary(30) == SkRange<size_t>(30, 31));
boxes = paragraph->getRectsForRange(12, 13, RectHeightStyle::kMax, RectWidthStyle::kTight);
canvas.drawLines(SK_ColorRED, boxes);
boxes = paragraph->getRectsForRange(13, 14, RectHeightStyle::kMax, RectWidthStyle::kTight);
canvas.drawLines(SK_ColorRED, boxes);
boxes = paragraph->getRectsForRange(18, 19, RectHeightStyle::kMax, RectWidthStyle::kTight);
canvas.drawLines(SK_ColorRED, boxes);
boxes = paragraph->getRectsForRange(19, 20, RectHeightStyle::kMax, RectWidthStyle::kTight);
canvas.drawLines(SK_ColorRED, boxes);
boxes = paragraph->getRectsForRange(24, 25, RectHeightStyle::kMax, RectWidthStyle::kTight);
canvas.drawLines(SK_ColorRED, boxes);
boxes = paragraph->getRectsForRange(25, 26, RectHeightStyle::kMax, RectWidthStyle::kTight);
canvas.drawLines(SK_ColorRED, boxes);
boxes = paragraph->getRectsForRange(30, 31, RectHeightStyle::kMax, RectWidthStyle::kTight);
canvas.drawLines(SK_ColorRED, boxes);
boxes = paragraph->getRectsForRange(31, 32, RectHeightStyle::kMax, RectWidthStyle::kTight);
canvas.drawLines(SK_ColorRED, boxes);
auto outLen = static_cast<ParagraphImpl*>(paragraph.get())->text().size();
REPORTER_ASSERT(reporter, paragraph->getWordBoundary(outLen - 1) == SkRange<size_t>(outLen - 5, outLen));
}
// Checked: DIFF (unclear)
DEF_TEST(SkParagraph_SpacingParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_SpacingParagraph.png");
ParagraphStyle paragraph_style;
paragraph_style.setMaxLines(10);
paragraph_style.setTextAlign(TextAlign::kLeft);
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setFontSize(50);
text_style.setLetterSpacing(20);
text_style.setWordSpacing(0);
text_style.setColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText("H", 1);
builder.pop();
text_style.setLetterSpacing(10);
text_style.setWordSpacing(0);
builder.pushStyle(text_style);
builder.addText("H", 1);
builder.pop();
text_style.setLetterSpacing(20);
text_style.setWordSpacing(0);
builder.pushStyle(text_style);
builder.addText("H", 1);
builder.pop();
text_style.setLetterSpacing(0);
text_style.setWordSpacing(0);
builder.pushStyle(text_style);
builder.addText("|", 1);
builder.pop();
const char* hSpace = "H ";
const size_t len = strlen(hSpace);
text_style.setLetterSpacing(0);
text_style.setWordSpacing(20);
builder.pushStyle(text_style);
builder.addText(hSpace, len);
builder.pop();
text_style.setLetterSpacing(0);
text_style.setWordSpacing(0);
builder.pushStyle(text_style);
builder.addText(hSpace, len);
builder.pop();
text_style.setLetterSpacing(0);
text_style.setLetterSpacing(0);
text_style.setWordSpacing(20);
builder.pushStyle(text_style);
builder.addText(hSpace, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->lines().size() == 1);
size_t index = 0;
impl->lines().begin()->scanStyles(StyleType::kLetterSpacing,
[&](TextRange textRange, const TextStyle& style, const TextLine::ClipContext& context) {
++index;
return true;
});
REPORTER_ASSERT(reporter, index == 4);
index = 0;
impl->lines().begin()->scanStyles(StyleType::kWordSpacing,
[&](TextRange textRange, const TextStyle& style, const TextLine::ClipContext& context) {
++index;
return true;
});
REPORTER_ASSERT(reporter, index == 4);
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_LongWordParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_LongWordParagraph.png");
const char* text =
"A "
"veryverylongwordtoseewherethiswillwraporifitwillatallandifitdoesthenthat"
"wouldbeagoodthingbecausethebreakingisworking.";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorRED);
text_style.setFontSize(31);
text_style.setLetterSpacing(0);
text_style.setWordSpacing(0);
text_style.setColor(SK_ColorBLACK);
text_style.setHeight(1);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth / 2);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->text().size() == std::string{text}.length());
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
REPORTER_ASSERT(reporter, impl->styles().size() == 1);
REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
REPORTER_ASSERT(reporter, impl->lines().size() == 4);
REPORTER_ASSERT(reporter, impl->lines()[0].width() > TestCanvasWidth / 2 - 20);
REPORTER_ASSERT(reporter, impl->lines()[1].width() > TestCanvasWidth / 2 - 20);
REPORTER_ASSERT(reporter, impl->lines()[2].width() > TestCanvasWidth / 2 - 20);
}
// Checked: DIFF?
DEF_TEST(SkParagraph_KernScaleParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_KernScaleParagraph.png");
const char* text1 = "AVAVAWAH A0 V0 VA To The Lo";
const char* text2 = " Dialog Text List lots of words to see "
"if kerning works on a bigger set of characters AVAVAW";
float scale = 3.0f;
ParagraphStyle paragraph_style;
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Droid Serif")});
text_style.setFontSize(100 / scale);
text_style.setColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text1, strlen(text1));
builder.pushStyle(text_style);
builder.addText("A", 1);
builder.pushStyle(text_style);
builder.addText("V", 1);
text_style.setFontSize(14 / scale);
builder.pushStyle(text_style);
builder.addText(text2, strlen(text2));
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth / scale);
canvas.get()->scale(scale, scale);
paragraph->paint(canvas.get(), 0, 0);
canvas.get()->scale(1, 1);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
// First and second lines must have the same width, the third one must be bigger
REPORTER_ASSERT(reporter, impl->lines().size() == 3);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[0].width(), 285.858f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[1].width(), 329.709f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[2].width(), 120.619f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[0].height(), 39.00f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[1].height(), 39.00f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[2].height(), 05.00f, EPSILON100));
}
// Checked: DIFF+
DEF_TEST(SkParagraph_NewlineParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_NewlineParagraph.png");
const char* text =
"line1\nline2 test1 test2 test3 test4 test5 test6 test7\nline3\n\nline4 "
"test1 test2 test3 test4";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorRED);
text_style.setFontSize(60);
text_style.setColor(SK_ColorBLACK);
text_style.setHeight(1);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth - 300);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
// Minikin does not count empty lines but SkParagraph does
REPORTER_ASSERT(reporter, impl->lines().size() == 7);
REPORTER_ASSERT(reporter, impl->lines()[0].offset().fY == 0);
REPORTER_ASSERT(reporter, impl->lines()[1].offset().fY == 70);
REPORTER_ASSERT(reporter, impl->lines()[2].offset().fY == 140);
REPORTER_ASSERT(reporter, impl->lines()[3].offset().fY == 210);
REPORTER_ASSERT(reporter, impl->lines()[4].offset().fY == 280); // Empty line
REPORTER_ASSERT(reporter, impl->lines()[5].offset().fY == 350);
REPORTER_ASSERT(reporter, impl->lines()[6].offset().fY == 420);
}
// TODO: Fix underline
DEF_TEST(SkParagraph_EmojiParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_EmojiParagraph.png");
const char* text =
"😀😃😄😁😆😅😂🤣☺😇🙂😍😡😟😢😻👽💩👍👎🙏👌👋👄👁👦👼👨‍🚀👨‍🚒🙋‍♂️👳👨‍👨‍👧‍👧\
💼👡👠☂🐶🐰🐻🐼🐷🐒🐵🐔🐧🐦🐋🐟🐡🕸🐌🐴🐊🐄🐪🐘🌸🌏🔥🌟🌚🌝💦💧\
❄🍕🍔🍟🥝🍱🕶🎩🏈⚽🚴‍♀️🎻🎼🎹🚨🚎🚐⚓🛳🚀🚁🏪🏢🖱⏰📱💾💉📉🛏🔑🔓\
📁🗓📊❤💯🚫🔻♠♣🕓❗🏳🏁🏳️‍🌈🇮🇹🇱🇷🇺🇸🇬🇧🇨🇳🇧🇴";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Noto Color Emoji")});
text_style.setFontSize(50);
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->lines().size() == 8);
for (auto& line : impl->lines()) {
if (&line != impl->lines().end() - 1) {
REPORTER_ASSERT(reporter, line.width() == 998.25f);
} else {
REPORTER_ASSERT(reporter, line.width() < 998.25f);
}
REPORTER_ASSERT(reporter, line.height() == 59);
}
}
// Checked: DIFF+
DEF_TEST(SkParagraph_EmojiMultiLineRectsParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_EmojiMultiLineRectsParagraph.png");
const char* text =
"👩👩👦👩👩👧👧🇺🇸👩👩👦👩👩👧👧i🇺🇸👩👩👦👩👩👧👧🇺🇸👩👩👦👩👩👧👧🇺🇸"
"👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸"
"👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸"
"👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸"
"❄🍕🍔🍟🥝🍱🕶🎩🏈⚽🚴‍♀️🎻🎼🎹🚨🚎🚐⚓🛳🚀🚁🏪🏢🖱⏰📱💾💉📉🛏🔑🔓"
"📁🗓📊❤💯🚫🔻♠♣🕓❗🏳🏁🏳️‍🌈🇮🇹🇱🇷🇺🇸🇬🇧🇨🇳🇧🇴";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Noto Color Emoji")});
text_style.setFontSize(50);
text_style.setColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth - 300);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle rect_height_style = RectHeightStyle::kTight;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
auto result = paragraph->getRectsForRange(0, 0, rect_height_style, rect_width_style);
REPORTER_ASSERT(reporter, result.size() == 0);
result = paragraph->getRectsForRange(0, 119, rect_height_style, rect_width_style);
REPORTER_ASSERT(reporter, result.size() == 2);
canvas.drawRects(SK_ColorRED, result);
result = paragraph->getRectsForRange(122, 132, rect_height_style, rect_width_style);
REPORTER_ASSERT(reporter, result.size() == 1);
canvas.drawRects(SK_ColorBLUE, result);
auto pos = paragraph->getGlyphPositionAtCoordinate(610, 100).position;
result = paragraph->getRectsForRange(0, pos, rect_height_style, rect_width_style);
REPORTER_ASSERT(reporter, result.size() == 2);
canvas.drawRects(SK_ColorGREEN, result);
pos = paragraph->getGlyphPositionAtCoordinate(580, 100).position;
result = paragraph->getRectsForRange(0, pos, rect_height_style, rect_width_style);
REPORTER_ASSERT(reporter, result.size() == 2);
canvas.drawRects(SK_ColorGREEN, result);
pos = paragraph->getGlyphPositionAtCoordinate(560, 100).position;
result = paragraph->getRectsForRange(0, pos, rect_height_style, rect_width_style);
REPORTER_ASSERT(reporter, result.size() == 2);
canvas.drawRects(SK_ColorGREEN, result);
}
DEF_TEST(SkParagraph_HyphenBreakParagraph, reporter) {
SkDebugf("Hyphens are not implemented, and will not be implemented soon.\n");
}
// Checked: DIFF (line breaking)
DEF_TEST(SkParagraph_RepeatLayoutParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_RepeatLayoutParagraph.png");
const char* text =
"Sentence to layout at diff widths to get diff line counts. short words "
"short words short words short words short words short words short words "
"short words short words short words short words short words short words "
"end";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setFontSize(31);
text_style.setColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(300);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
// Some of the formatting lazily done on paint
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
REPORTER_ASSERT(reporter, impl->styles().size() == 1);
REPORTER_ASSERT(reporter, impl->lines().size() == 12);
paragraph->layout(600);
paragraph->paint(canvas.get(), 0, 0);
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
REPORTER_ASSERT(reporter, impl->styles().size() == 1);
REPORTER_ASSERT(reporter, impl->lines().size() == 6);
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_Ellipsize, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_Ellipsize.png");
const char* text =
"This is a very long sentence to test if the text will properly wrap "
"around and go to the next line. Sometimes, short sentence. Longer "
"sentences are okay too because they are nessecary. Very short. ";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.setMaxLines(1);
paragraph_style.setEllipsis(u"\u2026");
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
// Check that the ellipsizer limited the text to one line and did not wrap to a second line.
REPORTER_ASSERT(reporter, impl->lines().size() == 1);
auto& line = impl->lines()[0];
REPORTER_ASSERT(reporter, line.ellipsis() != nullptr);
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_UnderlineShiftParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_UnderlineShiftParagraph.png");
const char* text1 = "fluttser ";
const char* text2 = "mdje";
const char* text3 = "fluttser mdje";
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setTextAlign(TextAlign::kLeft);
paragraph_style.setMaxLines(2);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text1, strlen(text1));
text_style.setDecoration(TextDecoration::kUnderline);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text2, strlen(text2));
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
ParagraphBuilderImpl builder1(paragraph_style, fontCollection);
text_style.setDecoration(TextDecoration::kNoDecoration);
builder1.pushStyle(text_style);
builder1.addText(text3, strlen(text3));
builder1.pop();
auto paragraph1 = builder1.Build();
paragraph1->layout(TestCanvasWidth);
paragraph1->paint(canvas.get(), 0, 25);
auto impl1 = static_cast<ParagraphImpl*>(paragraph1.get());
REPORTER_ASSERT(reporter, impl->lines().size() == 1);
REPORTER_ASSERT(reporter, impl1->lines().size() == 1);
auto rect = paragraph->getRectsForRange(0, 12, RectHeightStyle::kMax, RectWidthStyle::kTight)
.front()
.rect;
auto rect1 = paragraph1->getRectsForRange(0, 12, RectHeightStyle::kMax, RectWidthStyle::kTight)
.front()
.rect;
REPORTER_ASSERT(reporter, rect.fLeft == rect1.fLeft);
REPORTER_ASSERT(reporter, rect.fRight == rect1.fRight);
for (size_t i = 0; i < 12; ++i) {
auto r =
paragraph->getRectsForRange(i, i + 1, RectHeightStyle::kMax, RectWidthStyle::kTight)
.front()
.rect;
auto r1 =
paragraph1
->getRectsForRange(i, i + 1, RectHeightStyle::kMax, RectWidthStyle::kTight)
.front()
.rect;
REPORTER_ASSERT(reporter, r.fLeft == r1.fLeft);
REPORTER_ASSERT(reporter, r.fRight == r1.fRight);
}
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_SimpleShadow, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_SimpleShadow.png");
const char* text = "Hello World Text Dialog";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorBLACK);
text_style.addShadow(TextShadow(SK_ColorBLACK, SkPoint::Make(2.0f, 2.0f), 1.0));
builder.pushStyle(text_style);
builder.addText(text, len);
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 10.0, 15.0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
REPORTER_ASSERT(reporter, impl->styles().size() == 1);
size_t index = 0;
for (auto& line : impl->lines()) {
line.scanStyles(StyleType::kShadow,
[&](TextRange textRange, const TextStyle& style, const TextLine::ClipContext& context) {
REPORTER_ASSERT(reporter, index == 0 && style.equals(text_style));
++index;
return true;
});
}
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_ComplexShadow, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_ComplexShadow.png");
const char* text = "Text Chunk ";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorBLACK);
text_style.addShadow(TextShadow(SK_ColorBLACK, SkPoint::Make(2.0f, 2.0f), 1.0f));
builder.pushStyle(text_style);
builder.addText(text, len);
text_style.addShadow(TextShadow(SK_ColorRED, SkPoint::Make(2.0f, 2.0f), 5.0f));
text_style.addShadow(TextShadow(SK_ColorGREEN, SkPoint::Make(10.0f, -5.0f), 3.0f));
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
builder.addText(text, len);
text_style.addShadow(TextShadow(SK_ColorRED, SkPoint::Make(0.0f, 1.0f), 0.0f));
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
builder.addText(text, len);
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 10.0, 15.0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
size_t index = 0;
for (auto& line : impl->lines()) {
line.scanStyles(StyleType::kShadow,
[&](TextRange textRange, const TextStyle& style, const TextLine::ClipContext& context) {
++index;
switch (index) {
case 1:
REPORTER_ASSERT(reporter, style.getShadowNumber() == 1);
break;
case 2:
REPORTER_ASSERT(reporter, style.getShadowNumber() == 3);
break;
case 3:
REPORTER_ASSERT(reporter, style.getShadowNumber() == 1);
break;
case 4:
REPORTER_ASSERT(reporter, style.getShadowNumber() == 4);
REPORTER_ASSERT(reporter, style.equals(text_style));
break;
case 5:
REPORTER_ASSERT(reporter, style.getShadowNumber() == 1);
break;
default:
REPORTER_ASSERT(reporter, false);
}
return true;
});
}
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_BaselineParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_BaselineParagraph.png");
const char* text =
"左線読設Byg後碁給能上目秘使約。満毎冠行来昼本可必図将発確年。今属場育"
"図情闘陰野高備込制詩西校客。審対江置講今固残必託地集済決維駆年策。立得";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setMaxLines(14);
paragraph_style.setTextAlign(TextAlign::kJustify);
paragraph_style.setHeight(1.5);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Source Han Serif CN")});
text_style.setColor(SK_ColorBLACK);
text_style.setFontSize(55);
text_style.setLetterSpacing(2);
text_style.setDecorationStyle(TextDecorationStyle::kSolid);
text_style.setDecorationColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth - 100);
paragraph->paint(canvas.get(), 0, 0);
SkRect rect1 = SkRect::MakeXYWH(0, paragraph->getIdeographicBaseline(),
paragraph->getMaxWidth(),
paragraph->getIdeographicBaseline());
SkRect rect2 = SkRect::MakeXYWH(0, paragraph->getAlphabeticBaseline(),
paragraph->getMaxWidth(),
paragraph->getAlphabeticBaseline());
canvas.drawLine(SK_ColorRED, rect1, false);
canvas.drawLine(SK_ColorGREEN, rect2, false);
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(paragraph->getIdeographicBaseline(), 79.035f, EPSILON100));
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(paragraph->getAlphabeticBaseline(), 63.305f, EPSILON100));
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_FontFallbackParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_FontFallbackParagraph.png");
const char* text1 = "Roboto 字典 "; // Roboto + unresolved
const char* text2 = "Homemade Apple 字典"; // Homemade Apple + Noto Sans...
const char* text3 = "Chinese 字典"; // Homemade Apple + Source Han
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({
SkString("Not a real font"),
SkString("Also a fake font"),
SkString("So fake it is obvious"),
SkString("Next one should be a real font..."),
SkString("Roboto"),
SkString("another fake one in between"),
SkString("Homemade Apple"),
});
text_style.setColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text1, strlen(text1));
text_style.setFontFamilies({
SkString("Not a real font"),
SkString("Also a fake font"),
SkString("So fake it is obvious"),
SkString("Homemade Apple"),
SkString("Next one should be a real font..."),
SkString("Roboto"),
SkString("another fake one in between"),
SkString("Noto Sans CJK JP"),
SkString("Source Han Serif CN"),
});
builder.pushStyle(text_style);
builder.addText(text2, strlen(text2));
text_style.setFontFamilies({
SkString("Not a real font"),
SkString("Also a fake font"),
SkString("So fake it is obvious"),
SkString("Homemade Apple"),
SkString("Next one should be a real font..."),
SkString("Roboto"),
SkString("another fake one in between"),
SkString("Source Han Serif CN"),
SkString("Noto Sans CJK JP"),
});
builder.pushStyle(text_style);
builder.addText(text3, strlen(text3));
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 10.0, 15.0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
// Font resolution in Skia produces 6 runs because 2 parts of "Roboto 字典 " have different
// script (Minikin merges the first 2 into one because of unresolved) [Apple + Unresolved ]
// [Apple + Noto] [Apple + Han]
REPORTER_ASSERT(reporter, impl->runs().size() == 6);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[0].advance().fX, 48.330f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[1].advance().fX, 15.879f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[2].advance().fX, 139.125f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[3].advance().fX, 27.999f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[4].advance().fX, 62.248f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[5].advance().fX, 27.999f, EPSILON100));
// When a different font is resolved, then the metrics are different.
REPORTER_ASSERT(reporter, impl->runs()[1].correctAscent() != impl->runs()[3].correctAscent());
REPORTER_ASSERT(reporter, impl->runs()[1].correctDescent() != impl->runs()[3].correctDescent());
REPORTER_ASSERT(reporter, impl->runs()[3].correctAscent() != impl->runs()[5].correctAscent());
REPORTER_ASSERT(reporter, impl->runs()[3].correctDescent() != impl->runs()[5].correctDescent());
REPORTER_ASSERT(reporter, impl->runs()[1].correctAscent() != impl->runs()[5].correctAscent());
REPORTER_ASSERT(reporter, impl->runs()[1].correctDescent() != impl->runs()[5].correctDescent());
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_StrutParagraph1, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_StrutParagraph1.png");
// The chinese extra height should be absorbed by the strut.
const char* text = "01234満毎冠p来É本可\nabcd\n満毎É行p昼本可";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.setMaxLines(10);
paragraph_style.setTextAlign(TextAlign::kLeft);
paragraph_style.turnHintingOff();
StrutStyle strut_style;
strut_style.setStrutEnabled(true);
strut_style.setFontFamilies({SkString("BlahFake"), SkString("Ahem")});
strut_style.setFontSize(50);
strut_style.setHeight(1.8f);
strut_style.setHeightOverride(true);
strut_style.setLeading(0.1f);
paragraph_style.setStrutStyle(strut_style);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Ahem")});
text_style.setFontSize(50);
text_style.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width, SkFontStyle::kUpright_Slant));
text_style.setColor(SK_ColorBLACK);
text_style.setHeight(0.5f);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->lines().size() == 4);
RectHeightStyle rect_height_style = RectHeightStyle::kTight;
RectHeightStyle rect_height_max_style = RectHeightStyle::kMax;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
{
auto boxes = paragraph->getRectsForRange(0, 0, rect_height_style, rect_width_style);
REPORTER_ASSERT(reporter, boxes.empty());
}
{
auto boxes = paragraph->getRectsForRange(0, 1, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 34.5f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 50, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 84.5f, EPSILON100));
}
{
auto boxes = paragraph->getRectsForRange(0, 1, rect_height_max_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 34.5f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 50, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 95, EPSILON100));
}
{
auto boxes = paragraph->getRectsForRange(6, 10, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 300, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 34.5f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 500, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 84.5f, EPSILON100));
}
{
auto boxes = paragraph->getRectsForRange(6, 10, rect_height_max_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 300, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 34.5f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 500, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 95, EPSILON100));
}
{
auto boxes = paragraph->getRectsForRange(14, 16, rect_height_max_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 224.5f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 100, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 285, EPSILON100));
}
{
auto boxes = paragraph->getRectsForRange(20, 25, rect_height_max_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 50, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 319.5f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 300, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 380, EPSILON100));
}
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_StrutParagraph2, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_StrutParagraph2.png");
// The chinese extra height should be absorbed by the strut.
const char* text = "01234ABCDEFGH\nabcd\nABCDEFGH";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.setMaxLines(10);
paragraph_style.setTextAlign(TextAlign::kLeft);
paragraph_style.turnHintingOff();
StrutStyle strut_style;
strut_style.setStrutEnabled(true);
strut_style.setFontFamilies({SkString("Ahem")});
strut_style.setFontSize(50);
strut_style.setHeight(1.6f);
strut_style.setHeightOverride(true);
paragraph_style.setStrutStyle(strut_style);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Ahem")});
text_style.setFontSize(50);
text_style.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
SkFontStyle::kUpright_Slant));
text_style.setColor(SK_ColorBLACK);
text_style.setHeight(1);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
// Font is not resolved and the first line does not fit
REPORTER_ASSERT(reporter, impl->lines().size() == 4);
RectHeightStyle rect_height_style = RectHeightStyle::kTight;
RectHeightStyle rect_height_max_style = RectHeightStyle::kMax;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
{
auto boxes = paragraph->getRectsForRange(0, 0, rect_height_style, rect_width_style);
REPORTER_ASSERT(reporter, boxes.empty());
}
{
auto boxes = paragraph->getRectsForRange(0, 1, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 24, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 50, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 74, EPSILON100));
}
{
auto boxes = paragraph->getRectsForRange(0, 1, rect_height_max_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 24, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 50, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 80, EPSILON100));
}
{
auto boxes = paragraph->getRectsForRange(6, 10, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 300, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 24, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 500, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 74, EPSILON100));
}
{
auto boxes = paragraph->getRectsForRange(6, 10, rect_height_max_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 300, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 24, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 500, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 80, EPSILON100));
}
{
auto boxes = paragraph->getRectsForRange(14, 16, rect_height_max_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 184, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 100, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 240, EPSILON100));
}
{
auto boxes = paragraph->getRectsForRange(20, 25, rect_height_max_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 50, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 264, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 300, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 320, EPSILON100));
}
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_StrutParagraph3, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_StrutParagraph3.png");
// The chinese extra height should be absorbed by the strut.
const char* text = "01234満毎p行来昼本可\nabcd\n満毎冠行来昼本可";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.setMaxLines(10);
paragraph_style.setTextAlign(TextAlign::kLeft);
paragraph_style.turnHintingOff();
StrutStyle strut_style;
strut_style.setStrutEnabled(true);
strut_style.setFontFamilies({SkString("Ahem")});
strut_style.setFontSize(50);
strut_style.setHeight(1.2f);
strut_style.setHeightOverride(true);
paragraph_style.setStrutStyle(strut_style);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Ahem")});
text_style.setFontSize(50);
text_style.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
SkFontStyle::kUpright_Slant));
text_style.setColor(SK_ColorBLACK);
text_style.setHeight(1);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
// Font is not resolved and the first line does not fit
REPORTER_ASSERT(reporter, impl->lines().size() == 4);
RectHeightStyle rect_height_style = RectHeightStyle::kTight;
RectHeightStyle rect_height_max_style = RectHeightStyle::kMax;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
SkScalar epsilon = 0.001f;
{
auto boxes = paragraph->getRectsForRange(0, 0, rect_height_style, rect_width_style);
REPORTER_ASSERT(reporter, boxes.empty());
}
{
auto boxes = paragraph->getRectsForRange(0, 1, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 8, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 50, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 58, epsilon));
}
{
auto boxes = paragraph->getRectsForRange(0, 1, rect_height_max_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 8, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 50, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 60, epsilon));
}
{
auto boxes = paragraph->getRectsForRange(6, 10, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 300, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 8, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 500, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 58, epsilon));
}
{
auto boxes = paragraph->getRectsForRange(6, 10, rect_height_max_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 300, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 8, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 500, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 60, epsilon));
}
{
auto boxes = paragraph->getRectsForRange(14, 16, rect_height_max_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 128, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 100, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 180, epsilon));
}
{
auto boxes = paragraph->getRectsForRange(20, 25, rect_height_max_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 50, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 188, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 300, epsilon));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 240, epsilon));
}
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_StrutForceParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_StrutForceParagraph.png");
const char* text = "01234満毎冠行来昼本可\nabcd\n満毎冠行来昼本可";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.setMaxLines(10);
paragraph_style.setTextAlign(TextAlign::kLeft);
paragraph_style.turnHintingOff();
StrutStyle strut_style;
strut_style.setStrutEnabled(true);
strut_style.setFontFamilies({SkString("Ahem")});
strut_style.setFontSize(50);
strut_style.setHeight(1.5f);
strut_style.setHeightOverride(true);
strut_style.setLeading(0.1f);
strut_style.setForceStrutHeight(true);
paragraph_style.setStrutStyle(strut_style);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Ahem")});
text_style.setFontSize(50);
text_style.setLetterSpacing(0);
text_style.setColor(SK_ColorBLACK);
text_style.setHeight(1);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
// Font is not resolved and the first line does not fit
REPORTER_ASSERT(reporter, impl->lines().size() == 4);
RectHeightStyle rect_height_style = RectHeightStyle::kTight;
RectHeightStyle rect_height_max_style = RectHeightStyle::kMax;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
auto boxes1 = paragraph->getRectsForRange(0, 0, rect_height_style, rect_width_style);
REPORTER_ASSERT(reporter, boxes1.empty());
auto boxes2 = paragraph->getRectsForRange(0, 1, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes2);
REPORTER_ASSERT(reporter, boxes2.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes2[0].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes2[0].rect.top(), 22.5f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes2[0].rect.right(), 50, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes2[0].rect.bottom(), 72.5f, EPSILON100));
auto boxes3 = paragraph->getRectsForRange(0, 1, rect_height_max_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes3);
REPORTER_ASSERT(reporter, boxes3.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes3[0].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes3[0].rect.top(), 22.5f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes3[0].rect.right(), 50, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes3[0].rect.bottom(), 80, EPSILON100));
auto boxes4 = paragraph->getRectsForRange(6, 10, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes4);
REPORTER_ASSERT(reporter, boxes4.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes4[0].rect.left(), 300, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes4[0].rect.top(), 22.5f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes4[0].rect.right(), 500, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes4[0].rect.bottom(), 72.5f, EPSILON100));
auto boxes5 = paragraph->getRectsForRange(6, 10, rect_height_max_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes5);
REPORTER_ASSERT(reporter, boxes5.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes5[0].rect.left(), 300, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes5[0].rect.top(), 22.5f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes5[0].rect.right(), 500, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes5[0].rect.bottom(), 80, EPSILON100));
auto boxes6 = paragraph->getRectsForRange(14, 16, rect_height_max_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes6);
REPORTER_ASSERT(reporter, boxes6.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes6[0].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes6[0].rect.top(), 182.5f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes6[0].rect.right(), 100, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes6[0].rect.bottom(), 240, EPSILON100));
auto boxes7 = paragraph->getRectsForRange(20, 25, rect_height_max_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes7);
REPORTER_ASSERT(reporter, boxes7.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes7[0].rect.left(), 50, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes7[0].rect.top(), 262.5f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes7[0].rect.right(), 300, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes7[0].rect.bottom(), 320, EPSILON100));
}
// Checked: NO DIFF
DEF_TEST(SkParagraph_StrutDefaultParagraph, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_StrutDefaultParagraph.png");
const char* text = "01234満毎冠行来昼本可\nabcd\n満毎冠行来昼本可";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.setMaxLines(10);
paragraph_style.setTextAlign(TextAlign::kLeft);
paragraph_style.turnHintingOff();
StrutStyle strut_style;
strut_style.setStrutEnabled(true);
strut_style.setFontFamilies({SkString("Ahem")});
strut_style.setFontSize(50);
strut_style.setHeight(1.5f);
strut_style.setLeading(0.1f);
strut_style.setForceStrutHeight(false);
paragraph_style.setStrutStyle(strut_style);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Ahem")});
text_style.setFontSize(20);
text_style.setColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(550);
paragraph->paint(canvas.get(), 0, 0);
RectHeightStyle rect_height_style = RectHeightStyle::kTight;
RectHeightStyle rect_height_strut_style = RectHeightStyle::kStrut;
RectWidthStyle rect_width_style = RectWidthStyle::kTight;
{
auto boxes = paragraph->getRectsForRange(0, 0, rect_height_style, rect_width_style);
REPORTER_ASSERT(reporter, boxes.empty());
}
{
auto boxes = paragraph->getRectsForRange(0, 1, rect_height_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 26.5f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 20, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 46.5f, EPSILON100));
}
{
auto boxes = paragraph->getRectsForRange(0, 2, rect_height_strut_style, rect_width_style);
canvas.drawRects(SK_ColorRED, boxes);
REPORTER_ASSERT(reporter, boxes.size() == 1);
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 2.5f, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 40, EPSILON100));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 52.5f, EPSILON100));
}
}
// TODO: Implement font features
DEF_TEST(SkParagraph_FontFeaturesParagraph, reporter) {
SkDebugf("TODO: Font features\n");
}
// Not in Minikin
DEF_TEST(SkParagraph_WhitespacesInMultipleFonts, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
const char* text = "English English 字典 字典 😀😃😄 😀😃😄";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies(
{SkString("Roboto"), SkString("Noto Color Emoji"), SkString("Source Han Serif CN")});
text_style.setFontSize(60);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
SkDEBUGCODE(auto impl = static_cast<ParagraphImpl*>(paragraph.get());)
SkASSERT(impl->runs().size() == 3);
SkASSERT(impl->runs()[0].textRange().end == impl->runs()[1].textRange().start);
SkASSERT(impl->runs()[1].textRange().end == impl->runs()[2].textRange().start);
}
DEF_TEST(SkParagraph_JSON1, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
const char* text = "👨‍👩‍👧‍👦";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Noto Color Emoji")});
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
auto run = impl->runs().front();
auto cluster = 0;
SkShaperJSONWriter::VisualizeClusters(
text, 0, std::strlen(text), run.glyphs(), run.clusterIndexes(),
[&](int codePointCount, SkSpan<const char> utf1to1, SkSpan<const SkGlyphID> glyph1to1) {
if (cluster == 0) {
std::string toCheckUtf8{utf1to1.data(), utf1to1.size()};
SkASSERT(std::strcmp(text, utf1to1.data()) == 0);
SkASSERT(glyph1to1.size() == 1);
SkASSERT(*glyph1to1.begin() == 1611);
}
++cluster;
});
SkASSERT(cluster <= 2);
}
DEF_TEST(SkParagraph_JSON2, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
const char* text = "p〠q";
const size_t len = strlen(text);
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Noto Sans CJK JP")});
text_style.setColor(SK_ColorBLACK);
text_style.setFontSize(50);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
auto run = impl->runs().front();
auto cluster = 0;
for (auto& run : impl->runs()) {
SkShaperJSONWriter::VisualizeClusters(
impl->text().begin() + run.textRange().start, 0, run.textRange().width(),
run.glyphs(), run.clusterIndexes(),
[&](int codePointCount, SkSpan<const char> utf1to1,
SkSpan<const SkGlyphID> glyph1to1) {
if (cluster == 0) {
std::string toCheckUtf8{utf1to1.data(), utf1to1.size()};
SkASSERT(std::strcmp(text, utf1to1.data()) == 0);
SkASSERT(glyph1to1.size() == 3);
}
++cluster;
});
}
SkASSERT(cluster <= 2);
}
DEF_TEST(SkParagraph_CacheText, reporter) {
ParagraphCache cache;
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorBLACK);
auto test = [&](const char* text, int count, bool expectedToBeFound) {
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
builder.pushStyle(text_style);
builder.addText(text, strlen(text));
builder.pop();
auto paragraph = builder.Build();
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
REPORTER_ASSERT(reporter, count == cache.count());
auto found = cache.findParagraph(impl);
REPORTER_ASSERT(reporter, found == expectedToBeFound);
auto added = cache.updateParagraph(impl);
REPORTER_ASSERT(reporter, added != expectedToBeFound);
};
test("text1", 0, false);
test("text1", 1, true);
test("text2", 1, false);
test("text2", 2, true);
test("text3", 2, false);
}
DEF_TEST(SkParagraph_CacheFonts, reporter) {
ParagraphCache cache;
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
TextStyle text_style;
text_style.setColor(SK_ColorBLACK);
const char* text = "text";
const size_t len = strlen(text);
auto test = [&](int count, bool expectedToBeFound) {
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
impl->getResolver().findAllFontsForAllStyledBlocks(impl);
REPORTER_ASSERT(reporter, count == cache.count());
auto found = cache.findParagraph(impl);
REPORTER_ASSERT(reporter, found == expectedToBeFound);
auto added = cache.updateParagraph(impl);
REPORTER_ASSERT(reporter, added != expectedToBeFound);
};
text_style.setFontFamilies({SkString("Roboto")});
test(0, false);
test(1, true);
text_style.setFontFamilies({SkString("Homemade Apple")});
test(1, false);
test(2, true);
text_style.setFontFamilies({SkString("Noto Color Emoji")});
test(2, false);
}
DEF_TEST(SkParagraph_CacheFontRanges, reporter) {
ParagraphCache cache;
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorBLACK);
auto test = [&](const char* text1,
const char* text2,
const char* font1,
const char* font2,
int count,
bool expectedToBeFound) {
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
text_style.setFontFamilies({SkString(font1)});
builder.pushStyle(text_style);
builder.addText(text1, strlen(text1));
builder.pop();
text_style.setFontFamilies({SkString(font2)});
builder.pushStyle(text_style);
builder.addText(text2, strlen(text2));
builder.pop();
auto paragraph = builder.Build();
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
impl->getResolver().findAllFontsForAllStyledBlocks(impl);
REPORTER_ASSERT(reporter, count == cache.count());
auto found = cache.findParagraph(impl);
REPORTER_ASSERT(reporter, found == expectedToBeFound);
auto added = cache.updateParagraph(impl);
REPORTER_ASSERT(reporter, added != expectedToBeFound);
};
test("text", "", "Roboto", "Homemade Apple", 0, false);
test("t", "ext", "Roboto", "Homemade Apple", 1, false);
test("te", "xt", "Roboto", "Homemade Apple", 2, false);
test("tex", "t", "Roboto", "Homemade Apple", 3, false);
test("text", "", "Roboto", "Homemade Apple", 4, true);
}
DEF_TEST(SkParagraph_CacheStyles, reporter) {
ParagraphCache cache;
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
TextStyle text_style;
text_style.setFontFamilies({SkString("Roboto")});
text_style.setColor(SK_ColorBLACK);
const char* text = "text";
const size_t len = strlen(text);
auto test = [&](int count, bool expectedToBeFound) {
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
builder.pushStyle(text_style);
builder.addText(text, len);
builder.pop();
auto paragraph = builder.Build();
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
impl->getResolver().findAllFontsForAllStyledBlocks(impl);
REPORTER_ASSERT(reporter, count == cache.count());
auto found = cache.findParagraph(impl);
REPORTER_ASSERT(reporter, found == expectedToBeFound);
auto added = cache.updateParagraph(impl);
REPORTER_ASSERT(reporter, added != expectedToBeFound);
};
test(0, false);
test(1, true);
text_style.setLetterSpacing(10);
test(1, false);
test(2, true);
text_style.setWordSpacing(10);
test(2, false);
}
DEF_TEST(SkParagraph_EmptyParagraphWithLineBreak, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
TestCanvas canvas("SkParagraph_EmptyParagraphWithLineBreak.png");
ParagraphStyle paragraph_style;
TextStyle text_style;
text_style.setFontSize(16);
text_style.setFontFamilies({SkString("Roboto")});
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
builder.addText("\n", 1);
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 0, 0);
auto result = paragraph->GetRectsForPlaceholders();
}
DEF_TEST(SkParagraph_NullInMiddleOfText, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
TestCanvas canvas("SkParagraph_NullInMiddleOfText.png");
const SkString text("null terminator ->\u0000<- on purpose did you see it?");
ParagraphStyle paragraph_style;
TextStyle text_style;
text_style.setFontSize(16);
text_style.setFontFamilies({SkString("Roboto")});
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
builder.addText(text.c_str(), text.size());
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 0, 0);
}
DEF_TEST(SkParagraph_PlaceholderOnly, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
TestCanvas canvas("SkParagraph_PlaceholderOnly.png");
ParagraphStyle paragraph_style;
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
PlaceholderStyle placeholder(0, 0, PlaceholderAlignment::kBaseline, TextBaseline::kAlphabetic, 0);
builder.addPlaceholder(placeholder);
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
auto result = paragraph->GetRectsForPlaceholders();
paragraph->paint(canvas.get(), 0, 0);
}
DEF_TEST(SkParagraph_Fallbacks, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
fontCollection->setDefaultFontManager(SkFontMgr::RefDefault(), "Arial");
TestCanvas canvas("SkParagraph_Fallbacks.png");
const char* multiScript = "A1!aÀàĀāƁƀḂⱠꜲꬰəͲἀἏЀЖԠꙐꙮՁخࡔࠇܦআਉઐଘஇఘಧൺඣᭆᯔᮯ᳇ꠈᜅᩌꪈ༇ꥄꡙꫤ᧰៘꧁꧂ᜰᨏᯤᢆᣭᗗꗃⵞ𐒎߷ጩꬤ𖠺‡₩℻Ⅷ↹⋇⏳ⓖ╋▒◛⚧⑆שׁ🅕㊼龜ポ䷤🂡\n";
const size_t len = strlen(multiScript);
const char* androidFonts[] = {
"sans-serif",
"sans-serif-condensed",
"serif",
"monospace",
"serif-monospace",
"casual",
"cursive",
"sans-serif-smallcaps",
};
for (auto& font : androidFonts) {
ParagraphStyle paragraph_style;
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setColor(SK_ColorBLACK);
text_style.setLocale(SkString("en_US"));
text_style.setFontSize(20);
text_style.setFontFamilies({ SkString(font) });
builder.pushStyle(text_style);
builder.addText(multiScript, len);
builder.pop();
auto paragraph = builder.Build();
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 0, 0);
canvas.get()->translate(0, paragraph.get()->getHeight() + 10);
}
}
DEF_TEST(SkParagraph_Bidi1, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
TestCanvas canvas("SkParagraph_Bidi1.png");
std::u16string abc = u"\u202Dabc";
std::u16string DEF = u"\u202EDEF";
std::u16string ghi = u"\u202Dghi";
std::u16string JKL = u"\u202EJKL";
std::u16string mno = u"\u202Dmno";
std::u16string abcDEFghiJKLmno = u"\u202Dabc\u202EDEF\u202Dghi\u202EJKL\u202Dmno";
ParagraphStyle paragraph_style;
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({ SkString("sans-serif")});
text_style.setFontSize(40);
text_style.setColor(SK_ColorCYAN);
text_style.setFontStyle(SkFontStyle(SkFontStyle::kThin_Weight, SkFontStyle::kNormal_Width, SkFontStyle::kUpright_Slant));
builder.pushStyle(text_style);
builder.addText(abc);
text_style.setColor(SK_ColorGREEN);
text_style.setFontStyle(SkFontStyle(SkFontStyle::kLight_Weight, SkFontStyle::kNormal_Width, SkFontStyle::kUpright_Slant));
builder.pushStyle(text_style);
builder.addText(DEF);
text_style.setColor(SK_ColorYELLOW);
text_style.setFontStyle(SkFontStyle(SkFontStyle::kNormal_Weight, SkFontStyle::kNormal_Width, SkFontStyle::kUpright_Slant));
builder.pushStyle(text_style);
builder.addText(ghi);
text_style.setColor(SK_ColorMAGENTA);
text_style.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width, SkFontStyle::kUpright_Slant));
builder.pushStyle(text_style);
builder.addText(JKL);
text_style.setColor(SK_ColorBLUE);
text_style.setFontStyle(SkFontStyle(SkFontStyle::kBlack_Weight, SkFontStyle::kNormal_Width, SkFontStyle::kUpright_Slant));
builder.pushStyle(text_style);
builder.addText(mno);
auto paragraph = builder.Build();
paragraph->layout(400);
paragraph->paint(canvas.get(), 0, 0);
}
DEF_TEST(SkParagraph_Bidi2, reporter) {
sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>();
if (!fontCollection->fontsFound()) return;
fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
TestCanvas canvas("SkParagraph_Bidi2.png");
std::u16string abcD = u"\u202Dabc\u202ED";
std::u16string EFgh = u"EF\u202Dgh";
std::u16string iJKLmno = u"i\u202EJKL\u202Dmno";
std::u16string abcDEFghiJKLmno = u"\u202Dabc\u202EDEF\u202Dghi\u202EJKL\u202Dmno";
ParagraphStyle paragraph_style;
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({ SkString("sans-serif")});
text_style.setFontSize(40);
text_style.setColor(SK_ColorBLACK);
text_style.setColor(SK_ColorYELLOW);
text_style.setFontSize(40);
text_style.setFontStyle(SkFontStyle(SkFontStyle::kThin_Weight, SkFontStyle::kNormal_Width, SkFontStyle::kUpright_Slant));
builder.pushStyle(text_style);
builder.addText(abcD);
text_style.setColor(SK_ColorRED);
text_style.setFontSize(50);
text_style.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width, SkFontStyle::kUpright_Slant));
builder.pushStyle(text_style);
builder.addText(EFgh);
text_style.setColor(SK_ColorMAGENTA);
text_style.setFontSize(60);
text_style.setFontStyle(SkFontStyle(SkFontStyle::kExtraBold_Weight, SkFontStyle::kNormal_Width, SkFontStyle::kUpright_Slant));
builder.pushStyle(text_style);
builder.addText(iJKLmno);
auto paragraph = builder.Build();
paragraph->layout(360);
paragraph->paint(canvas.get(), 0, 0);
}