| // Copyright 2019 Google LLC. |
| #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/Test.h" |
| #include "tools/Resources.h" |
| |
| #define VeryLongCanvasWidth 1000000 |
| #define TestCanvasWidth 1000 |
| #define TestCanvasHeight 600 |
| |
| using namespace skia::textlayout; |
| namespace { |
| |
| bool equal(SkSpan<const char> a, const char* b) { |
| return std::strncmp(b, a.data(), a.size()) == 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; |
| }; |
| } // namespace |
| |
| DEF_TEST(SkParagraph_SimpleParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* text = "Hello World Text Dialog"; |
| |
| 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); |
| 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].style().equals(text_style)); |
| |
| // Some of the formatting lazily done on paint |
| impl->formatLines(TestCanvasWidth - 100); |
| |
| size_t index = 0; |
| for (auto& line : impl->lines()) { |
| line.scanStyles(StyleType::kDecorations, |
| [&index, reporter](SkSpan<const char> text, TextStyle style, SkScalar) { |
| REPORTER_ASSERT(reporter, index == 0); |
| REPORTER_ASSERT(reporter, style.getColor() == SK_ColorBLACK); |
| ++index; |
| return true; |
| }); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_SimpleRedParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* text = "I am RED"; |
| |
| 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); |
| 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].style().equals(text_style)); |
| |
| // Some of the formatting lazily done on paint |
| impl->formatLines(TestCanvasWidth - 100); |
| |
| size_t index = 0; |
| for (auto& line : impl->lines()) { |
| line.scanStyles(StyleType::kDecorations, |
| [&index, reporter](SkSpan<const char> text, TextStyle style, SkScalar) { |
| REPORTER_ASSERT(reporter, index == 0); |
| REPORTER_ASSERT(reporter, style.getColor() == SK_ColorRED); |
| ++index; |
| return true; |
| }); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_RainbowParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* text1 = "Red Roboto"; |
| const char* text2 = "big Greeen Default"; |
| const char* text3 = "Defcolor Homemade Apple"; |
| const char* text4 = "Small Blue Roboto"; |
| const char* text5 = |
| "Continue Last Style With lots of words to check if it overlaps " |
| "properly or not"; |
| const char* text45 = |
| "Small Blue 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(1); |
| 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); |
| |
| 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); |
| |
| TextStyle text_style3; |
| text_style3.setFontFamilies({SkString("Homemade Apple")}); |
| builder.pushStyle(text_style3); |
| builder.addText(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); |
| |
| builder.addText(text5); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(VeryLongCanvasWidth); |
| |
| 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() == 1); |
| |
| // Some of the formatting lazily done on paint |
| impl->formatLines(VeryLongCanvasWidth); |
| |
| size_t index = 0; |
| impl->lines()[0].scanStyles(StyleType::kAllAttributes, |
| [&](SkSpan<const char> text, TextStyle style, SkScalar) { |
| switch (index) { |
| case 0: |
| REPORTER_ASSERT(reporter, style.equals(text_style1)); |
| REPORTER_ASSERT(reporter, equal(text, text1)); |
| break; |
| case 1: |
| REPORTER_ASSERT(reporter, style.equals(text_style2)); |
| REPORTER_ASSERT(reporter, equal(text, text2)); |
| break; |
| case 2: |
| REPORTER_ASSERT(reporter, style.equals(text_style3)); |
| REPORTER_ASSERT(reporter, equal(text, text3)); |
| break; |
| case 3: |
| REPORTER_ASSERT(reporter, style.equals(text_style4)); |
| REPORTER_ASSERT(reporter, equal(text, text45)); |
| break; |
| default: |
| REPORTER_ASSERT(reporter, false); |
| break; |
| } |
| ++index; |
| return true; |
| }); |
| REPORTER_ASSERT(reporter, index == 4); |
| } |
| |
| DEF_TEST(SkParagraph_DefaultStyleParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* text = "No TextStyle! Uh Oh!"; |
| |
| ParagraphStyle paragraph_style; |
| TextStyle defaultStyle; |
| defaultStyle.setFontFamilies({SkString("Roboto")}); |
| paragraph_style.setTextStyle(defaultStyle); |
| paragraph_style.turnHintingOff(); |
| ParagraphBuilderImpl builder(paragraph_style, fontCollection); |
| builder.addText(text); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(VeryLongCanvasWidth); |
| |
| 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); |
| |
| impl->formatLines(VeryLongCanvasWidth); |
| |
| size_t index = 0; |
| impl->lines()[0].scanStyles( |
| StyleType::kAllAttributes, [&](SkSpan<const char> text1, TextStyle style, SkScalar) { |
| REPORTER_ASSERT(reporter, style.equals(paragraph_style.getTextStyle())); |
| REPORTER_ASSERT(reporter, equal(text1, text)); |
| ++index; |
| return true; |
| }); |
| REPORTER_ASSERT(reporter, index == 1); |
| } |
| |
| DEF_TEST(SkParagraph_BoldParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* text = "This is Red max bold 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(VeryLongCanvasWidth); |
| |
| 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); |
| |
| impl->formatLines(VeryLongCanvasWidth); |
| |
| size_t index = 0; |
| impl->lines()[0].scanStyles(StyleType::kAllAttributes, |
| [&](SkSpan<const char> text1, TextStyle style, SkScalar) { |
| REPORTER_ASSERT(reporter, style.equals(text_style)); |
| REPORTER_ASSERT(reporter, equal(text1, text)); |
| ++index; |
| return true; |
| }); |
| REPORTER_ASSERT(reporter, index == 1); |
| } |
| |
| DEF_TEST(SkParagraph_LeftAlignParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| 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."; |
| |
| 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth - 100); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| // Some of the formatting lazily done on paint |
| impl->formatLines(TestCanvasWidth - 100); |
| |
| 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].style().equals(text_style)); |
| REPORTER_ASSERT(reporter, impl->lines().size() == paragraph_style.getMaxLines()); |
| |
| // Apparently, Minikin records start from the base line (24) |
| 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); |
| } |
| |
| DEF_TEST(SkParagraph_RightAlignParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| 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."; |
| |
| 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth - 100); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| // Some of the formatting lazily done on paint |
| impl->formatLines(TestCanvasWidth - 100); |
| |
| REPORTER_ASSERT(reporter, impl->runs().size() == 1); |
| REPORTER_ASSERT(reporter, impl->styles().size() == 1); |
| REPORTER_ASSERT(reporter, impl->styles()[0].style().equals(text_style)); |
| // Minikin has two records for each due to 'ghost' trailing whitespace run, SkParagraph - 1 |
| REPORTER_ASSERT(reporter, impl->lines().size() == paragraph_style.getMaxLines()); |
| |
| // Apparently, Minikin records start from the base line (24) |
| 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()); |
| } |
| |
| DEF_TEST(SkParagraph_CenterAlignParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| 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."; |
| |
| 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth - 100); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| // Some of the formatting lazily done on paint |
| impl->formatLines(TestCanvasWidth - 100); |
| |
| 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].style().equals(text_style)); |
| // Minikin has two records for each due to 'ghost' trailing whitespace run, SkParagraph - 1 |
| REPORTER_ASSERT(reporter, impl->lines().size() == paragraph_style.getMaxLines()); |
| |
| // Apparently, Minikin records start from the base line (24) |
| 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()); |
| } |
| |
| DEF_TEST(SkParagraph_JustifyAlignParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| 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."; |
| |
| 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth - 100); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| impl->formatLines(TestCanvasWidth - 100); |
| |
| 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].style().equals(text_style)); |
| |
| 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 * 9; |
| REPORTER_ASSERT(reporter, |
| SkScalarNearlyEqual(impl->lines()[12].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, calculate(impl->lines()[12]) > 0); |
| |
| REPORTER_ASSERT(reporter, |
| paragraph_style.getTextAlign() == impl->paragraphStyle().getTextAlign()); |
| } |
| |
| DEF_TEST(SkParagraph_JustifyRTL, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* 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); |
| text_style.setHeight(1); |
| text_style.setDecoration(TextDecoration::kUnderline); |
| text_style.setDecorationColor(SK_ColorBLACK); |
| builder.pushStyle(text_style); |
| builder.addText(text); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth - 100); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| impl->formatLines(TestCanvasWidth - 100); |
| |
| auto calculate = [](const TextLine& line) -> SkScalar { |
| return TestCanvasWidth - 100 - (line.offset().fX + line.width()); |
| }; |
| |
| SkScalar epsilon = 0.1f; |
| for (auto& line : impl->lines()) { |
| if (&line == impl->lines().end() - 1) { |
| REPORTER_ASSERT(reporter, calculate(line) > epsilon); |
| } else { |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(calculate(line), 0, epsilon)); |
| } |
| } |
| |
| // Just make sure the the text is actually RTL |
| for (auto& run : impl->runs()) { |
| REPORTER_ASSERT(reporter, !run.leftToRight()); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_DecorationsParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| 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("This text should be"); |
| |
| text_style.setDecorationStyle(TextDecorationStyle::kDouble); |
| text_style.setDecorationColor(SK_ColorBLUE); |
| text_style.setDecorationThicknessMultiplier(1.0); |
| builder.pushStyle(text_style); |
| builder.addText(" decorated even when"); |
| |
| text_style.setDecorationStyle(TextDecorationStyle::kDotted); |
| text_style.setDecorationColor(SK_ColorBLACK); |
| builder.pushStyle(text_style); |
| builder.addText(" wrapped around to"); |
| |
| text_style.setDecorationStyle(TextDecorationStyle::kDashed); |
| text_style.setDecorationColor(SK_ColorBLACK); |
| text_style.setDecorationThicknessMultiplier(3.0); |
| builder.pushStyle(text_style); |
| builder.addText(" the next line."); |
| |
| text_style.setDecorationStyle(TextDecorationStyle::kWavy); |
| text_style.setDecorationColor(SK_ColorRED); |
| text_style.setDecorationThicknessMultiplier(1.0); |
| builder.pushStyle(text_style); |
| builder.addText(" Otherwise, bad things happen."); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth - 100); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| impl->formatLines(TestCanvasWidth - 100); |
| |
| size_t index = 0; |
| for (auto& line : impl->lines()) { |
| line.scanStyles( |
| StyleType::kDecorations, |
| [&index, reporter](SkSpan<const char> text, TextStyle style, SkScalar) { |
| auto decoration = (TextDecoration)(TextDecoration::kUnderline | |
| TextDecoration::kOverline | |
| TextDecoration::kLineThrough); |
| REPORTER_ASSERT(reporter, style.getDecoration() == 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_ItalicsParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| 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("No italic "); |
| |
| text_style.setFontStyle(SkFontStyle(SkFontStyle::kNormal_Weight, SkFontStyle::kNormal_Width, |
| SkFontStyle::kItalic_Slant)); |
| builder.pushStyle(text_style); |
| builder.addText("Yes Italic "); |
| builder.pop(); |
| builder.addText("No Italic again."); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| // Some of the formatting lazily done on paint |
| impl->formatLines(TestCanvasWidth - 100); |
| |
| 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, |
| [&index, reporter](SkSpan<const char> text, TextStyle style, SkScalar) { |
| 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; |
| }); |
| } |
| |
| DEF_TEST(SkParagraph_ChineseParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth - 100); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| impl->formatLines(TestCanvasWidth - 100); |
| |
| 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].style().equals(text_style)); |
| } |
| |
| DEF_TEST(SkParagraph_ArabicParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* 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); |
| // TODO: turn off some font features for letter spacing (waiting on SkShaper) |
| // 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth - 100); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| impl->formatLines(TestCanvasWidth - 100); |
| |
| 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].style().equals(text_style)); |
| } |
| |
| DEF_TEST(SkParagraph_GetGlyphPositionAtCoordinateParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* text = |
| "12345 67890 12345 67890 12345 67890 12345 67890 12345 67890 12345 " |
| "67890 12345"; |
| |
| ParagraphStyle paragraphStyle; |
| paragraphStyle.setTextAlign(TextAlign::kLeft); |
| paragraphStyle.setMaxLines(10); |
| paragraphStyle.turnHintingOff(); |
| TextStyle textStyle; |
| textStyle.setFontFamilies({SkString("Roboto")}); |
| 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(550); |
| |
| // 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 == 10); // !!! 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 == 0); // !!! 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); |
| } |
| |
| DEF_TEST(SkParagraph_GetRectsForRangeParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* text = |
| "12345, \"67890\" 12345 67890 12345 67890 12345 67890 12345 67890 12345 " |
| "67890 12345"; |
| |
| 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(550); |
| |
| 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); |
| REPORTER_ASSERT(reporter, result.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 28.417f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(2, 8, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 56.835f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 177.97f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(8, 21, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 177.97f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 507.031f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(30, 100, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 4); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 211.375f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 59.40625f, epsilon)); |
| // This number does not match: 463.617 & 451.171 |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 451.171f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 118, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.top(), 236.406f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.right(), 142.089f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[3].rect.bottom(), 295, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(19, 22, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 450.1875f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0.40625f, epsilon)); |
| // This number does not match 519.472 & 507.031 |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 507.031f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.empty()); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_GetRectsForRangeTight, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(550); |
| |
| RectHeightStyle heightStyle = RectHeightStyle::kTight; |
| 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); |
| REPORTER_ASSERT(reporter, result.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 16.898f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 74, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(2, 8, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 66.899f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 264.099f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 74, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(8, 21, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 2); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 264.099f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 528.199f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.right(), 172.199f, epsilon)); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_GetRectsForRangeIncludeLineSpacingMiddle, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* 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.setHeight(1.3f); |
| 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(550); |
| |
| RectHeightStyle heightStyle = RectHeightStyle::kIncludeLineSpacingMiddle; |
| RectWidthStyle widthStyle = RectWidthStyle::kTight; |
| SkScalar epsilon = 0.01f; |
| // 16 glyphs per line 160/16 = 10 lines |
| { |
| auto result = paragraph->getRectsForRange(0, 0, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.empty()); |
| } |
| { |
| auto result = paragraph->getRectsForRange(0, 1, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 8.60f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 16.90f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 93.60f, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(2, 8, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 66.90f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 8.60f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 264.10f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 93.60f, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(8, 21, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 2); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 264.10f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 8.60f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 528.20f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 93.60f, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(30, 150, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 9); |
| SkScalar offsetY = 104.60f; |
| for (auto& box : result) { |
| if (&box != &result.back()) { |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(box.rect.right(), 528.20f, epsilon)); |
| } |
| if (&box != &result.front()) { |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(box.rect.left(), 0, epsilon)); |
| } |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(box.rect.top(), offsetY, epsilon)); |
| offsetY = box.rect.bottom() + 11; |
| } |
| } |
| { |
| auto result = paragraph->getRectsForRange(19, 22, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 97.20f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 104.60f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 197.20f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 189.60f, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.empty()); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_GetRectsForRangeIncludeLineSpacingTop, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* 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.setWordSpacing(0); |
| textStyle.setLetterSpacing(0); |
| textStyle.setHeight(1.3f); |
| 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(550); |
| |
| RectHeightStyle heightStyle = RectHeightStyle::kIncludeLineSpacingTop; |
| 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); |
| REPORTER_ASSERT(reporter, result.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 16.898f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 91.199f, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(2, 8, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 66.899f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 264.099f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 91.199f, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(8, 21, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 2); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 264.099f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 528.199f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 91.199f, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(30, 150, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 9); |
| SkScalar level = 96; |
| for (auto& box : result) { |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(box.rect.top(), level, epsilon)); |
| level += 96; |
| if (&box != &result.back()) { |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(box.rect.right(), 528.199f, epsilon)); |
| } |
| if (&box != &result.front()) { |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(box.rect.left(), 0, epsilon)); |
| } |
| } |
| } |
| { |
| auto result = paragraph->getRectsForRange(19, 22, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 97.199f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 96, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 197.199f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 187.199f, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.empty()); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_GetRectsForRangeIncludeLineSpacingBottom, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* 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.setWordSpacing(0); |
| textStyle.setLetterSpacing(0); |
| textStyle.setHeight(1.3f); |
| 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(550); |
| |
| RectHeightStyle heightStyle = RectHeightStyle::kIncludeLineSpacingBottom; |
| 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); |
| REPORTER_ASSERT(reporter, result.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 17.199f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 16.898f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 96, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(2, 8, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 66.899f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 17.199f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 264.099f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 96, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(8, 21, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 2); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 264.099f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 528.199f, epsilon)); |
| // It seems that Minikin does not take in account like breaks, but we do. |
| // SkParagraph returns 528.199 instead |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[1].rect.right(), 172.199f, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(30, 150, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 9); |
| SkScalar level = 17.199f + 96; |
| for (auto& box : result) { |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(box.rect.top(), level, epsilon)); |
| level += 96; |
| if (&box != &result.back()) { |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(box.rect.right(), 528.199f, epsilon)); |
| } |
| if (&box != &result.front()) { |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(box.rect.left(), 0, epsilon)); |
| } |
| } |
| } |
| { |
| auto result = paragraph->getRectsForRange(19, 22, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.left(), 97.199f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.top(), 113.199f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 197.199f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 192, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.empty()); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_GetRectsForRangeIncludeCombiningCharacter, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* 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.setLetterSpacing(1); |
| textStyle.setWordSpacing(5); |
| textStyle.setHeight(1); |
| textStyle.setColor(SK_ColorBLACK); |
| |
| builder.pushStyle(textStyle); |
| builder.addText(text); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth - 100); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| impl->formatLines(TestCanvasWidth - 100); |
| |
| 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() == 1 && second.size() == 1 && last.size() == 1); |
| REPORTER_ASSERT(reporter, |
| last[0].rect.fLeft = SkTMin(first[0].rect.fLeft, second[0].rect.fLeft)); |
| REPORTER_ASSERT(reporter, |
| last[0].rect.fRight = SkTMax(first[0].rect.fRight, second[0].rect.fRight)); |
| } |
| { |
| 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() == 1 && second.size() == 1 && last.size() == 1); |
| REPORTER_ASSERT(reporter, |
| last[0].rect.fLeft = SkTMin(first[0].rect.fLeft, second[0].rect.fLeft)); |
| REPORTER_ASSERT(reporter, |
| last[0].rect.fRight = SkTMax(first[0].rect.fRight, second[0].rect.fRight)); |
| } |
| { |
| 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() == 1 && second.size() == 1 && third.size() == 1 && |
| last.size() == 1); |
| REPORTER_ASSERT(reporter, |
| last[0].rect.fLeft = SkTMin(first[0].rect.fLeft, third[0].rect.fLeft)); |
| REPORTER_ASSERT(reporter, |
| last[0].rect.fRight = SkTMax(first[0].rect.fRight, third[0].rect.fRight)); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_GetRectsForRangeCenterParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| // 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 "; //"01234 ใ "; // includes ideographic space and english space. |
| |
| 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.setLetterSpacing(0); |
| textStyle.setWordSpacing(0); |
| 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(550); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| // Some of the formatting lazily done on paint |
| impl->formatLines(550); |
| |
| 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); |
| 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); |
| 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, 5, heightStyle, widthStyle); |
| 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(), 346.044f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon)); |
| } |
| |
| { |
| auto result = paragraph->getRectsForRange(4, 6, heightStyle, widthStyle); |
| 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(), 346.044f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon)); |
| } |
| |
| { |
| auto result = paragraph->getRectsForRange(5, 6, heightStyle, widthStyle); |
| 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(), 346.044f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon)); |
| } |
| |
| { |
| auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.empty()); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_GetRectsForRangeCenterParagraphNewlineCentered, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* text = "01234\n"; |
| |
| 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.setLetterSpacing(0); |
| textStyle.setWordSpacing(0); |
| 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(550); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| // Some of the formatting lazily done on paint |
| impl->formatLines(550); |
| |
| 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); |
| 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)); |
| } |
| |
| { |
| // Minikin has [6:7] not empty but I cannot imagine how and why |
| auto result = paragraph->getRectsForRange(5, 6, heightStyle, widthStyle); |
| 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.406f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.right(), 346.044f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon)); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_GetRectsForRangeCenterMultiLineParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* text = "01234 \n0123 "; |
| // "01234 ใ \n0123ใ "; // includes ideographic space and english space. |
| |
| 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.setLetterSpacing(0); |
| textStyle.setWordSpacing(0); |
| 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(550); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| // Some of the formatting lazily done on paint |
| impl->formatLines(550); |
| |
| 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); |
| 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); |
| 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, 5, heightStyle, widthStyle); |
| 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(), 346.044f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(4, 6, heightStyle, widthStyle); |
| 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(), 346.044f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(5, 6, heightStyle, widthStyle); |
| 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(), 346.044f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 59, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(10, 12, heightStyle, widthStyle); |
| 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)); |
| } |
| { |
| // Minikin counts all spaces but they really don't appear on the screen |
| // and the text even centered without them |
| auto result = paragraph->getRectsForRange(14, 18, heightStyle, widthStyle); |
| 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(), 331.835f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[0].rect.bottom(), 118, epsilon)); |
| } |
| { |
| auto result = paragraph->getRectsForRange(21, 21, heightStyle, widthStyle); |
| REPORTER_ASSERT(reporter, result.empty()); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_GetWordBoundaries, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| 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.setColor(SK_ColorBLACK); |
| textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width, |
| SkFontStyle::kUpright_Slant)); |
| |
| ParagraphBuilderImpl builder(paragraphStyle, fontCollection); |
| builder.pushStyle(textStyle); |
| builder.addText( |
| "12345 67890 12345 67890 12345 67890 12345 67890 12345 67890 12345 67890 12345"); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(550); |
| |
| 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)); |
| |
| REPORTER_ASSERT(reporter, paragraph->getWordBoundary(5) == SkRange<size_t>(5, 7)); |
| REPORTER_ASSERT(reporter, paragraph->getWordBoundary(6) == SkRange<size_t>(5, 7)); |
| |
| 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)); |
| |
| auto len = static_cast<ParagraphImpl*>(paragraph.get())->text().size(); |
| REPORTER_ASSERT(reporter, paragraph->getWordBoundary(len - 1) == SkRange<size_t>(len - 5, len)); |
| } |
| |
| DEF_TEST(SkParagraph_SpacingParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| 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); |
| text_style.setHeight(1); |
| builder.pushStyle(text_style); |
| builder.addText("H"); |
| builder.pop(); |
| |
| text_style.setLetterSpacing(10); |
| builder.pushStyle(text_style); |
| builder.addText("H"); |
| builder.pop(); |
| |
| text_style.setLetterSpacing(20); |
| builder.pushStyle(text_style); |
| builder.addText("H"); |
| builder.pop(); |
| |
| text_style.setLetterSpacing(0); |
| builder.pushStyle(text_style); |
| builder.addText("|"); |
| builder.pop(); |
| |
| text_style.setLetterSpacing(0); |
| text_style.setWordSpacing(20); |
| builder.pushStyle(text_style); |
| builder.addText("H "); |
| builder.pop(); |
| |
| text_style.setLetterSpacing(0); |
| text_style.setWordSpacing(0); |
| builder.pushStyle(text_style); |
| builder.addText("H "); |
| builder.pop(); |
| |
| text_style.setLetterSpacing(0); |
| text_style.setWordSpacing(20); |
| builder.pushStyle(text_style); |
| builder.addText("H "); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(550); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| REPORTER_ASSERT(reporter, impl->lines().size() == 1); |
| size_t index = 0; |
| impl->lines().begin()->scanStyles(StyleType::kLetterSpacing, |
| [&index](SkSpan<const char> text, TextStyle style, SkScalar) { |
| ++index; |
| return true; |
| }); |
| REPORTER_ASSERT(reporter, index == 4); |
| index = 0; |
| impl->lines().begin()->scanStyles(StyleType::kWordSpacing, |
| [&index](SkSpan<const char> text, TextStyle style, SkScalar) { |
| ++index; |
| return true; |
| }); |
| REPORTER_ASSERT(reporter, index == 4); |
| } |
| |
| DEF_TEST(SkParagraph_LongWordParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* text = |
| "A " |
| "veryverylongwordtoseewherethiswillwraporifitwillatallandifitdoesthenthat" |
| "wouldbeagoodthingbecausethebreakingisworking."; |
| |
| 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth / 2); |
| |
| 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].style().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); |
| } |
| |
| DEF_TEST(SkParagraph_KernScaleParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| 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.setWordSpacing(0); |
| text_style.setLetterSpacing(0); |
| text_style.setHeight(1); |
| text_style.setColor(SK_ColorBLACK); |
| |
| builder.pushStyle(text_style); |
| builder.addText("AV00\nVA00\nA0V0"); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth / scale); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| // Some of the formatting lazily done on paint |
| impl->formatLines(TestCanvasWidth); |
| |
| // First and second lines must have the same width, the third one must be bigger |
| SkScalar epsilon = 0.01f; |
| REPORTER_ASSERT(reporter, impl->lines().size() == 3); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[0].width(), 80.58f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[1].width(), 80.58f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[2].width(), 83.25f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[0].height(), 39.00f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[1].height(), 39.00f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[2].height(), 39.00f, epsilon)); |
| } |
| |
| DEF_TEST(SkParagraph_NewlineParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* text = |
| "line1\nline2 test1 test2 test3 test4 test5 test6 test7\nline3\n\nline4 " |
| "test1 test2 test3 test4"; |
| 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.setWordSpacing(0); |
| text_style.setColor(SK_ColorBLACK); |
| text_style.setHeight(1); |
| builder.pushStyle(text_style); |
| builder.addText(text); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth - 300); |
| |
| 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); |
| |
| SkScalar epsilon = 0.1f; |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[0].width(), 130.31f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[1].width(), 586.64f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[2].width(), 593.49f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[3].width(), 130.31f, epsilon)); |
| REPORTER_ASSERT(reporter, |
| SkScalarNearlyEqual(impl->lines()[4].width(), 0, epsilon)); // Empty line |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[5].width(), 586.64f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->lines()[6].width(), 137.16f, epsilon)); |
| |
| REPORTER_ASSERT(reporter, impl->lines()[0].shift() == 0); |
| } |
| |
| DEF_TEST(SkParagraph_EmojiParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| // Some of the formatting lazily done on paint |
| impl->formatLines(TestCanvasWidth); |
| |
| 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); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_RepeatLayoutParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| 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"; |
| |
| 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.setLetterSpacing(0); |
| text_style.setWordSpacing(0); |
| 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); |
| 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); |
| REPORTER_ASSERT(reporter, impl->runs().size() == 1); |
| REPORTER_ASSERT(reporter, impl->styles().size() == 1); |
| REPORTER_ASSERT(reporter, impl->lines().size() == 6); |
| } |
| |
| DEF_TEST(SkParagraph_Ellipsize, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| 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. "; |
| |
| 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.setDecorationColor(SK_ColorBLACK); |
| builder.pushStyle(text_style); |
| builder.addText(text); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| // Some of the formatting lazily done on paint |
| impl->formatLines(TestCanvasWidth); |
| |
| // 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); |
| size_t index = 0; |
| line.scanRuns([&index, &line, reporter](Run* run, int32_t, size_t, SkRect, SkScalar, bool) { |
| ++index; |
| if (index == 2) { |
| REPORTER_ASSERT(reporter, run->text() == line.ellipsis()->text()); |
| } |
| return true; |
| }); |
| REPORTER_ASSERT(reporter, index == 2); |
| } |
| |
| DEF_TEST(SkParagraph_UnderlineShiftParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| 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); |
| text_style.setDecoration(TextDecoration::kUnderline); |
| text_style.setDecorationColor(SK_ColorBLACK); |
| builder.pushStyle(text_style); |
| builder.addText(text2); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| |
| ParagraphBuilderImpl builder1(paragraph_style, fontCollection); |
| text_style.setDecoration(TextDecoration::kNoDecoration); |
| builder1.pushStyle(text_style); |
| builder1.addText(text3); |
| builder1.pop(); |
| |
| auto paragraph1 = builder1.Build(); |
| paragraph1->layout(TestCanvasWidth); |
| |
| auto impl1 = static_cast<ParagraphImpl*>(paragraph1.get()); |
| |
| REPORTER_ASSERT(reporter, impl->lines().size() == 1); |
| REPORTER_ASSERT(reporter, impl1->lines().size() == 1); |
| { |
| auto& line = impl->lines()[0]; |
| size_t index = 0; |
| line.scanStyles( |
| StyleType::kDecorations, |
| [&index, reporter](SkSpan<const char> text, TextStyle style, SkScalar) { |
| switch (index) { |
| case 0: |
| REPORTER_ASSERT(reporter, |
| style.getDecoration() == TextDecoration::kNoDecoration); |
| break; |
| case 1: |
| REPORTER_ASSERT(reporter, |
| style.getDecoration() == TextDecoration::kUnderline); |
| break; |
| default: |
| REPORTER_ASSERT(reporter, false); |
| break; |
| } |
| ++index; |
| return true; |
| }); |
| REPORTER_ASSERT(reporter, index == 2); |
| } |
| { |
| auto& line = impl1->lines()[0]; |
| size_t index = 0; |
| line.scanStyles(StyleType::kDecorations, |
| [&index, reporter](SkSpan<const char> text, TextStyle style, SkScalar) { |
| if (index == 0) { |
| REPORTER_ASSERT(reporter, style.getDecoration() == |
| TextDecoration::kNoDecoration); |
| } else { |
| REPORTER_ASSERT(reporter, false); |
| } |
| ++index; |
| return true; |
| }); |
| REPORTER_ASSERT(reporter, index == 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); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_SimpleShadow, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* text = "Hello World Text Dialog"; |
| |
| 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); |
| |
| 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); |
| size_t index = 0; |
| for (auto& line : impl->lines()) { |
| line.scanStyles( |
| StyleType::kShadow, |
| [&index, text_style, reporter](SkSpan<const char> text, TextStyle style, SkScalar) { |
| REPORTER_ASSERT(reporter, index == 0 && style.equals(text_style)); |
| ++index; |
| return true; |
| }); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_ComplexShadow, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* text = "Text Chunk "; |
| |
| 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); |
| |
| 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); |
| builder.pop(); |
| |
| builder.addText(text); |
| |
| text_style.addShadow(TextShadow(SK_ColorRED, SkPoint::Make(0.0f, 1.0f), 0.0f)); |
| builder.pushStyle(text_style); |
| builder.addText(text); |
| builder.pop(); |
| |
| builder.addText(text); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth); |
| |
| auto impl = static_cast<ParagraphImpl*>(paragraph.get()); |
| |
| size_t index = 0; |
| for (auto& line : impl->lines()) { |
| line.scanStyles( |
| StyleType::kShadow, |
| [&index, text_style, reporter](SkSpan<const char> text, TextStyle style, SkScalar) { |
| ++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; |
| }); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_BaselineParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* text = |
| "ๅทฆ็ท่ชญ่จญBygๅพ็ข็ตฆ่ฝไธ็ฎ็งไฝฟ็ดใๆบๆฏๅ ่กๆฅๆผๆฌๅฏๅฟ
ๅณๅฐ็บ็ขบๅนดใไปๅฑๅ ด่ฒ" |
| "ๅณๆ
้้ฐ้้ซๅ่พผๅถ่ฉฉ่ฅฟๆ กๅฎขใๅฏฉๅฏพๆฑ็ฝฎ่ฌไปๅบๆฎๅฟ
่จๅฐ้ๆธๆฑบ็ถญ้งๅนด็ญใ็ซๅพ"; |
| |
| 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth - 100); |
| |
| SkScalar epsilon = 0.01f; |
| REPORTER_ASSERT(reporter, |
| SkScalarNearlyEqual(paragraph->getIdeographicBaseline(), 79.035f, epsilon)); |
| REPORTER_ASSERT(reporter, |
| SkScalarNearlyEqual(paragraph->getAlphabeticBaseline(), 63.305f, epsilon)); |
| } |
| |
| DEF_TEST(SkParagraph_FontFallbackParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| |
| const char* text1 = "Roboto ๅญๅ
ธ "; |
| const char* text2 = "Homemade Apple ๅญๅ
ธ"; |
| const char* text3 = "Chinese ๅญๅ
ธ"; |
| |
| 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); |
| |
| 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); |
| |
| 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); |
| |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(TestCanvasWidth); |
| |
| 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); |
| |
| SkScalar epsilon = 0.01f; |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[0].advance().fX, 48.46f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[1].advance().fX, 15.90f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[2].advance().fX, 139.12f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[3].advance().fX, 27.99f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[4].advance().fX, 62.24f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[5].advance().fX, 27.99f, epsilon)); |
| |
| // When a different font is resolved, then the metrics are different. |
| REPORTER_ASSERT(reporter, impl->runs()[1].ascent() != impl->runs()[3].ascent()); |
| REPORTER_ASSERT(reporter, impl->runs()[1].descent() != impl->runs()[3].descent()); |
| REPORTER_ASSERT(reporter, impl->runs()[3].ascent() != impl->runs()[5].ascent()); |
| REPORTER_ASSERT(reporter, impl->runs()[3].descent() != impl->runs()[5].descent()); |
| REPORTER_ASSERT(reporter, impl->runs()[1].ascent() != impl->runs()[5].ascent()); |
| REPORTER_ASSERT(reporter, impl->runs()[1].descent() != impl->runs()[5].descent()); |
| } |
| |
| DEF_TEST(SkParagraph_StrutParagraph1, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| // The chinese extra height should be absorbed by the strut. |
| // const char* text = "01234ๆบๆฏๅ pๆฅรๆฌๅฏ\nabcd\nๆบๆฏร่กpๆผๆฌๅฏ"; |
| const char* text = "01234ๆบๆฏๅ ่กๆฅๆผๆฌๅฏ\nabcd\nๆบๆฏๅ ่กๆฅๆผๆฌๅฏ"; |
| |
| 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.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.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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(550); |
| |
| 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); |
| REPORTER_ASSERT(reporter, boxes.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 34.5f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 50, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 84.5f, epsilon)); |
| } |
| { |
| auto boxes = paragraph->getRectsForRange(0, 1, rect_height_max_style, rect_width_style); |
| REPORTER_ASSERT(reporter, boxes.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 50, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 95, epsilon)); |
| } |
| { |
| auto boxes = paragraph->getRectsForRange(6, 10, rect_height_style, rect_width_style); |
| REPORTER_ASSERT(reporter, boxes.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 300, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 34.5f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 500, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 84.5f, epsilon)); |
| } |
| { |
| auto boxes = paragraph->getRectsForRange(6, 10, rect_height_max_style, rect_width_style); |
| REPORTER_ASSERT(reporter, boxes.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 300, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 500, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 95, epsilon)); |
| } |
| { |
| auto boxes = paragraph->getRectsForRange(14, 16, rect_height_max_style, rect_width_style); |
| REPORTER_ASSERT(reporter, boxes.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 190, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 100, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 285, epsilon)); |
| } |
| { |
| auto boxes = paragraph->getRectsForRange(20, 25, rect_height_max_style, rect_width_style); |
| REPORTER_ASSERT(reporter, boxes.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 50, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 285, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 300, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 380, epsilon)); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_StrutParagraph2, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| // The chinese extra height should be absorbed by the strut. |
| const char* text = "01234ABCDEFGH\nabcd\nABCDEFGH"; |
| |
| 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); |
| 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(550); |
| |
| 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); |
| REPORTER_ASSERT(reporter, boxes.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 24, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 50, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 74, epsilon)); |
| } |
| { |
| auto boxes = paragraph->getRectsForRange(0, 1, rect_height_max_style, rect_width_style); |
| REPORTER_ASSERT(reporter, boxes.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 50, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 80, epsilon)); |
| } |
| { |
| auto boxes = paragraph->getRectsForRange(6, 10, rect_height_style, rect_width_style); |
| REPORTER_ASSERT(reporter, boxes.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 300, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 24, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 500, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 74, epsilon)); |
| } |
| { |
| auto boxes = paragraph->getRectsForRange(6, 10, rect_height_max_style, rect_width_style); |
| REPORTER_ASSERT(reporter, boxes.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 300, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 500, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 80, epsilon)); |
| } |
| { |
| auto boxes = paragraph->getRectsForRange(14, 16, rect_height_max_style, rect_width_style); |
| REPORTER_ASSERT(reporter, boxes.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 160, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 100, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 240, epsilon)); |
| } |
| { |
| auto boxes = paragraph->getRectsForRange(20, 25, rect_height_max_style, rect_width_style); |
| REPORTER_ASSERT(reporter, boxes.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 50, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 240, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 300, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 320, epsilon)); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_StrutParagraph3, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| // The chinese extra height should be absorbed by the strut. |
| // const char* text = "01234ๆบๆฏp่กๆฅๆผๆฌๅฏ\nabcd\nๆบๆฏๅ ่กๆฅๆผๆฌๅฏ"; |
| const char* text = "01234ๆบๆฏๅ ่กๆฅๆผๆฌๅฏ\nabcd\nๆบๆฏๅ ่กๆฅๆผๆฌๅฏ"; |
| |
| 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); |
| 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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(550); |
| |
| 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); |
| 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); |
| REPORTER_ASSERT(reporter, boxes.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 0, 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); |
| 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); |
| REPORTER_ASSERT(reporter, boxes.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 300, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 0, 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); |
| REPORTER_ASSERT(reporter, boxes.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 120, 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); |
| REPORTER_ASSERT(reporter, boxes.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.left(), 50, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.top(), 180, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.right(), 300, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes[0].rect.bottom(), 240, epsilon)); |
| } |
| } |
| |
| DEF_TEST(SkParagraph_StrutForceParagraph, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* text = "01234ๆบๆฏๅ ่กๆฅๆผๆฌๅฏ\nabcd\nๆบๆฏๅ ่กๆฅๆผๆฌๅฏ"; |
| |
| 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(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); |
| builder.pop(); |
| |
| auto paragraph = builder.Build(); |
| paragraph->layout(550); |
| |
| 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 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); |
| REPORTER_ASSERT(reporter, boxes2.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes2[0].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes2[0].rect.top(), 22.5f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes2[0].rect.right(), 50, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes2[0].rect.bottom(), 72.5f, epsilon)); |
| |
| auto boxes3 = paragraph->getRectsForRange(0, 1, rect_height_max_style, rect_width_style); |
| REPORTER_ASSERT(reporter, boxes3.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes3[0].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes3[0].rect.top(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes3[0].rect.right(), 50, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes3[0].rect.bottom(), 80, epsilon)); |
| |
| auto boxes4 = paragraph->getRectsForRange(6, 10, rect_height_style, rect_width_style); |
| REPORTER_ASSERT(reporter, boxes4.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes4[0].rect.left(), 300, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes4[0].rect.top(), 22.5f, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes4[0].rect.right(), 500, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes4[0].rect.bottom(), 72.5f, epsilon)); |
| |
| auto boxes5 = paragraph->getRectsForRange(6, 10, rect_height_max_style, rect_width_style); |
| REPORTER_ASSERT(reporter, boxes5.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes5[0].rect.left(), 300, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes5[0].rect.top(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes5[0].rect.right(), 500, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes5[0].rect.bottom(), 80, epsilon)); |
| |
| auto boxes6 = paragraph->getRectsForRange(14, 16, rect_height_max_style, rect_width_style); |
| REPORTER_ASSERT(reporter, boxes6.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes6[0].rect.left(), 0, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes6[0].rect.top(), 160, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes6[0].rect.right(), 100, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes6[0].rect.bottom(), 240, epsilon)); |
| |
| auto boxes7 = paragraph->getRectsForRange(20, 25, rect_height_max_style, rect_width_style); |
| REPORTER_ASSERT(reporter, boxes7.size() == 1); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes7[0].rect.left(), 50, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes7[0].rect.top(), 240, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes7[0].rect.right(), 300, epsilon)); |
| REPORTER_ASSERT(reporter, SkScalarNearlyEqual(boxes7[0].rect.bottom(), 320, epsilon)); |
| } |
| |
| // 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 ๅญๅ
ธ ๅญๅ
ธ ๐๐๐ ๐๐๐"; |
| 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); |
| 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].text().end() == impl->runs()[1].text().begin()); |
| SkASSERT(impl->runs()[1].text().end() == impl->runs()[2].text().begin()); |
| } |
| |
| // 4 to 1 |
| DEF_TEST(SkParagraph_JSON1, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* 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); |
| 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); |
| } |
| |
| // 5 to 3 |
| DEF_TEST(SkParagraph_JSON2, reporter) { |
| sk_sp<TestFontCollection> fontCollection = sk_make_sp<TestFontCollection>(); |
| if (!fontCollection->fontsFound()) return; |
| const char* text = "pใ q"; |
| |
| //icu::UnicodeString unicode(text, std::strlen(text)); |
| //std::string str; |
| //unicode.toUTF8String(str); |
| |
| 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); |
| 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( |
| run.text().data(), 0, run.text().size(), 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); |
| } |