/* * Copyright 2017 Google, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "flutter/fml/logging.h" #include "render_test.h" #include "third_party/icu/source/common/unicode/unistr.h" #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkPath.h" #include "txt/font_style.h" #include "txt/font_weight.h" #include "txt/paragraph_builder_txt.h" #include "txt/paragraph_txt.h" #include "txt/placeholder_run.h" #include "txt_test_utils.h" #define DISABLE_ON_WINDOWS(TEST) DISABLE_TEST_WINDOWS(TEST) namespace txt { using ParagraphTest = RenderTest; TEST_F(ParagraphTest, SimpleParagraph) { const char* text = "Hello World Text Dialog"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; // We must supply a font here, as the default is Arial, and we do not // include Arial in our test fonts as it is proprietary. We want it to // be Arial default though as it is one of the most common fonts on host // platforms. On real devices/apps, Arial should be able to be resolved. text_style.font_families = std::vector(1, "Roboto"); text_style.color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 10.0, 15.0); ASSERT_EQ(paragraph->text_.size(), std::string{text}.length()); for (size_t i = 0; i < u16_text.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text[i]); } ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull); ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull); ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style)); ASSERT_EQ(paragraph->records_[0].style().color, text_style.color); ASSERT_TRUE(Snapshot()); } // It is possible for the line_metrics_ vector in paragraph to have an empty // line at the end as a result of the line breaking algorithm. This causes // the final_line_count_ to be one less than line metrics. This tests that we // properly handle this case and do not segfault. TEST_F(ParagraphTest, GetGlyphPositionAtCoordinateSegfault) { const char* text = "Hello World\nText Dialog"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; // We must supply a font here, as the default is Arial, and we do not // include Arial in our test fonts as it is proprietary. We want it to // be Arial default though as it is one of the most common fonts on host // platforms. On real devices/apps, Arial should be able to be resolved. text_style.font_families = std::vector(1, "Roboto"); text_style.color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 10.0, 15.0); ASSERT_EQ(paragraph->final_line_count_, paragraph->line_metrics_.size()); ASSERT_EQ(paragraph->final_line_count_, 2ull); ASSERT_EQ(paragraph->GetLineCount(), 2ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(0.2, 0.2).position, 0ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(20.2, 0.2).position, 3ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(0.2, 20.2).position, 12ull); // We artificially reproduce the conditions that cause segfaults in very // specific circumstances in the wild. By adding this empty un-laid-out // LineMetrics at the end, we force the case where final_line_count_ // represents the true number of lines whereas line_metrics_ has one // extra empty one. paragraph->line_metrics_.emplace_back(23, 24, 24, 24, true); ASSERT_EQ(paragraph->final_line_count_, paragraph->line_metrics_.size() - 1); ASSERT_EQ(paragraph->final_line_count_, 2ull); ASSERT_EQ(paragraph->GetLineCount(), 2ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(0.2, 20.2).position, 12ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(0.2, 0.2).position, 0ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(20.2, 0.2).position, 3ull); paragraph->line_metrics_.emplace_back(24, 25, 25, 25, true); ASSERT_EQ(paragraph->final_line_count_, paragraph->line_metrics_.size() - 2); ASSERT_EQ(paragraph->final_line_count_, 2ull); ASSERT_EQ(paragraph->GetLineCount(), 2ull); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, LineMetricsParagraph1) { const char* text = "Hello! What is going on?\nSecond line \nthirdline"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; // We must supply a font here, as the default is Arial, and we do not // include Arial in our test fonts as it is proprietary. We want it to // be Arial default though as it is one of the most common fonts on host // platforms. On real devices/apps, Arial should be able to be resolved. text_style.font_families = std::vector(1, "Roboto"); text_style.color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_TRUE(Snapshot()); ASSERT_EQ(paragraph->GetLineMetrics().size(), 3ull); ASSERT_EQ(paragraph->GetLineMetrics()[0].start_index, 0ull); ASSERT_EQ(paragraph->GetLineMetrics()[0].end_index, 24ull); ASSERT_EQ(paragraph->GetLineMetrics()[0].end_including_newline, 25ull); ASSERT_EQ(paragraph->GetLineMetrics()[0].end_excluding_whitespace, 24ull); ASSERT_EQ(paragraph->GetLineMetrics()[0].hard_break, true); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].ascent, 12.988281); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].descent, 3.4179688); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].width, 149.67578); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].left, 0.0); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].baseline, 12.582031); ASSERT_EQ(paragraph->GetLineMetrics()[0].line_number, 0ull); ASSERT_EQ(paragraph->GetLineMetrics()[0].run_metrics.size(), 1ull); ASSERT_EQ( paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(paragraph->GetLineMetrics()[0].start_index) ->second.text_style->color, SK_ColorBLACK); ASSERT_EQ( paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(paragraph->GetLineMetrics()[0].start_index) ->second.text_style->font_families, std::vector(1, "Roboto")); ASSERT_FLOAT_EQ( paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(paragraph->GetLineMetrics()[0].start_index) ->second.font_metrics.fAscent, -12.988281); ASSERT_FLOAT_EQ( paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(paragraph->GetLineMetrics()[0].start_index) ->second.font_metrics.fDescent, 3.4179688); ASSERT_FLOAT_EQ( paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(paragraph->GetLineMetrics()[0].start_index) ->second.font_metrics.fXHeight, 7.3964844); ASSERT_FLOAT_EQ( paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(paragraph->GetLineMetrics()[0].start_index) ->second.font_metrics.fLeading, 0); ASSERT_FLOAT_EQ( paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(paragraph->GetLineMetrics()[0].start_index) ->second.font_metrics.fTop, -14.786133); ASSERT_FLOAT_EQ( paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(paragraph->GetLineMetrics()[0].start_index) ->second.font_metrics.fUnderlinePosition, 1.0253906); ASSERT_EQ(paragraph->GetLineMetrics()[1].start_index, 25ull); ASSERT_EQ(paragraph->GetLineMetrics()[1].end_index, 37ull); ASSERT_EQ(paragraph->GetLineMetrics()[1].end_including_newline, 38ull); ASSERT_EQ(paragraph->GetLineMetrics()[1].end_excluding_whitespace, 36ull); ASSERT_EQ(paragraph->GetLineMetrics()[1].hard_break, true); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].ascent, 12.988281); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].descent, 3.4179688); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].width, 72.039062); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].left, 0.0); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].baseline, 28.582031); ASSERT_EQ(paragraph->GetLineMetrics()[1].line_number, 1ull); ASSERT_EQ(paragraph->GetLineMetrics()[1].run_metrics.size(), 1ull); ASSERT_EQ( paragraph->GetLineMetrics()[1] .run_metrics.lower_bound(paragraph->GetLineMetrics()[1].start_index) ->second.text_style->color, SK_ColorBLACK); ASSERT_EQ( paragraph->GetLineMetrics()[1] .run_metrics.lower_bound(paragraph->GetLineMetrics()[1].start_index) ->second.text_style->font_families, std::vector(1, "Roboto")); ASSERT_FLOAT_EQ( paragraph->GetLineMetrics()[1] .run_metrics.lower_bound(paragraph->GetLineMetrics()[1].start_index) ->second.font_metrics.fAscent, -12.988281); ASSERT_FLOAT_EQ( paragraph->GetLineMetrics()[1] .run_metrics.lower_bound(paragraph->GetLineMetrics()[1].start_index) ->second.font_metrics.fDescent, 3.4179688); ASSERT_FLOAT_EQ( paragraph->GetLineMetrics()[1] .run_metrics.lower_bound(paragraph->GetLineMetrics()[1].start_index) ->second.font_metrics.fXHeight, 7.3964844); ASSERT_FLOAT_EQ( paragraph->GetLineMetrics()[1] .run_metrics.lower_bound(paragraph->GetLineMetrics()[1].start_index) ->second.font_metrics.fLeading, 0); ASSERT_FLOAT_EQ( paragraph->GetLineMetrics()[1] .run_metrics.lower_bound(paragraph->GetLineMetrics()[1].start_index) ->second.font_metrics.fTop, -14.786133); ASSERT_FLOAT_EQ( paragraph->GetLineMetrics()[1] .run_metrics.lower_bound(paragraph->GetLineMetrics()[1].start_index) ->second.font_metrics.fUnderlinePosition, 1.0253906); } TEST_F(ParagraphTest, LineMetricsParagraph2) { const char* text = "test string alphabetic"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string alphabetic(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); const char* text2 = "测试中文日本語한국어"; auto icu_text2 = icu::UnicodeString::fromUTF8(text2); std::u16string cjk(icu_text2.getBuffer(), icu_text2.getBuffer() + icu_text2.length()); txt::ParagraphStyle paragraph_style; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_families.push_back("Noto Sans CJK JP"); text_style.font_size = 27; text_style.color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(alphabetic); text_style.font_size = 24; builder.PushStyle(text_style); builder.AddText(cjk); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(350); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_TRUE(Snapshot()); ASSERT_EQ(paragraph->GetLineMetrics().size(), 2ull); ASSERT_EQ(paragraph->GetLineMetrics()[0].start_index, 0ull); ASSERT_EQ(paragraph->GetLineMetrics()[0].end_index, 26ull); ASSERT_EQ(paragraph->GetLineMetrics()[0].end_including_newline, 26ull); ASSERT_EQ(paragraph->GetLineMetrics()[0].end_excluding_whitespace, 26ull); ASSERT_EQ(paragraph->GetLineMetrics()[0].hard_break, false); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].ascent, 27.84); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].descent, 7.6799998); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].width, 349.22266); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].left, 0.0); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0].baseline, 28.32); ASSERT_EQ(paragraph->GetLineMetrics()[0].line_number, 0ull); ASSERT_EQ(paragraph->GetLineMetrics()[0].run_metrics.size(), 2ull); // First run ASSERT_EQ(paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(2) ->second.text_style->font_size, 27); ASSERT_EQ(paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(2) ->second.text_style->font_families, text_style.font_families); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(2) ->second.font_metrics.fAscent, -25.048828); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(2) ->second.font_metrics.fDescent, 6.5917969); ASSERT_EQ(paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(21) ->second.text_style->font_size, 27); ASSERT_EQ(paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(21) ->second.text_style->font_families, text_style.font_families); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(21) ->second.font_metrics.fAscent, -25.048828); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(21) ->second.font_metrics.fDescent, 6.5917969); // Second run ASSERT_EQ(paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(22) ->second.text_style->font_size, 24); ASSERT_EQ(paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(22) ->second.text_style->font_families, text_style.font_families); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(22) ->second.font_metrics.fAscent, -27.84); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(22) ->second.font_metrics.fDescent, 7.6799998); ASSERT_EQ(paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(24) ->second.text_style->font_size, 24); ASSERT_EQ(paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(24) ->second.text_style->font_families, text_style.font_families); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(24) ->second.font_metrics.fAscent, -27.84); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[0] .run_metrics.lower_bound(24) ->second.font_metrics.fDescent, 7.6799998); ASSERT_EQ(paragraph->GetLineMetrics()[1].start_index, 26ull); ASSERT_EQ(paragraph->GetLineMetrics()[1].end_index, 32ull); ASSERT_EQ(paragraph->GetLineMetrics()[1].end_including_newline, 32ull); ASSERT_EQ(paragraph->GetLineMetrics()[1].end_excluding_whitespace, 32ull); ASSERT_EQ(paragraph->GetLineMetrics()[1].hard_break, true); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].ascent, 27.84); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].descent, 7.6799998); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].width, 138.23438); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].left, 0.0); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1].baseline, 64.32); ASSERT_EQ(paragraph->GetLineMetrics()[1].line_number, 1ull); ASSERT_EQ(paragraph->GetLineMetrics()[1].run_metrics.size(), 1ull); // Indexing below the line will just resolve to the first run in the line. ASSERT_EQ(paragraph->GetLineMetrics()[1] .run_metrics.lower_bound(3) ->second.text_style->font_size, 24); ASSERT_EQ(paragraph->GetLineMetrics()[1] .run_metrics.lower_bound(3) ->second.text_style->font_families, text_style.font_families); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1] .run_metrics.lower_bound(3) ->second.font_metrics.fAscent, -27.84); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1] .run_metrics.lower_bound(3) ->second.font_metrics.fDescent, 7.6799998); // Indexing within the line ASSERT_EQ(paragraph->GetLineMetrics()[1] .run_metrics.lower_bound(31) ->second.text_style->font_size, 24); ASSERT_EQ(paragraph->GetLineMetrics()[1] .run_metrics.lower_bound(31) ->second.text_style->font_families, text_style.font_families); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1] .run_metrics.lower_bound(31) ->second.font_metrics.fAscent, -27.84); ASSERT_FLOAT_EQ(paragraph->GetLineMetrics()[1] .run_metrics.lower_bound(31) ->second.font_metrics.fDescent, 7.6799998); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderParagraph)) { const char* text = "012 34"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 26; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); txt::PlaceholderRun placeholder_run(50, 50, PlaceholderAlignment::kBaseline, TextBaseline::kAlphabetic, 0); builder.AddPlaceholder(placeholder_run); builder.AddText(u16_text); builder.AddPlaceholder(placeholder_run); txt::PlaceholderRun placeholder_run2(5, 50, PlaceholderAlignment::kBaseline, TextBaseline::kAlphabetic, 50); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run2); builder.AddText(u16_text); builder.AddPlaceholder(placeholder_run2); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run); builder.AddText(u16_text); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kTight; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 3, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } // ASSERT_TRUE(Snapshot()); EXPECT_EQ(boxes.size(), 1ull); paint.setColor(SK_ColorGREEN); boxes = paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); paint.setColor(SK_ColorRED); boxes = paragraph->GetRectsForPlaceholders(); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(4, 17, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 7ull); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 90.921875); EXPECT_FLOAT_EQ(boxes[1].rect.top(), 50); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 140.92188); EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 100); EXPECT_FLOAT_EQ(boxes[3].rect.left(), 231.34375); EXPECT_FLOAT_EQ(boxes[3].rect.top(), 50); EXPECT_FLOAT_EQ(boxes[3].rect.right(), 231.34375 + 50); EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 100); EXPECT_FLOAT_EQ(boxes[4].rect.left(), 281.34375); EXPECT_FLOAT_EQ(boxes[4].rect.top(), 0); EXPECT_FLOAT_EQ(boxes[4].rect.right(), 281.34375 + 5); EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 50); EXPECT_FLOAT_EQ(boxes[6].rect.left(), 336.34375); EXPECT_FLOAT_EQ(boxes[6].rect.top(), 0); EXPECT_FLOAT_EQ(boxes[6].rect.right(), 336.34375 + 5); EXPECT_FLOAT_EQ(boxes[6].rect.bottom(), 50); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderBaselineParagraph)) { const char* text = "012 34"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 26; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); txt::PlaceholderRun placeholder_run(55, 50, PlaceholderAlignment::kBaseline, TextBaseline::kAlphabetic, 38.34734); builder.AddPlaceholder(placeholder_run); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kTight; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForPlaceholders(); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); // Verify the box is in the right place EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.921875); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.92188); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); // Verify the other text didn't just shift to accomodate it. EXPECT_FLOAT_EQ(boxes[0].rect.left(), 75.324219); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 14.226246); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.921875); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 44.694996); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderAboveBaselineParagraph)) { const char* text = "012 34"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 26; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); txt::PlaceholderRun placeholder_run(55, 50, PlaceholderAlignment::kAboveBaseline, TextBaseline::kAlphabetic, 903129.129308); builder.AddPlaceholder(placeholder_run); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kTight; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForPlaceholders(); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); // Verify the box is in the right place EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.921875); EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.34765625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.92188); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 49.652344); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); // Verify the other text didn't just shift to accomodate it. EXPECT_FLOAT_EQ(boxes[0].rect.left(), 75.324219); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 25.53125); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.921875); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 56); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderBelowBaselineParagraph)) { const char* text = "012 34"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 26; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); txt::PlaceholderRun placeholder_run(55, 50, PlaceholderAlignment::kBelowBaseline, TextBaseline::kAlphabetic, 903129.129308); builder.AddPlaceholder(placeholder_run); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kTight; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForPlaceholders(); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); // Verify the box is in the right place EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.921875); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 24); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.92188); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 74); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); // Verify the other text didn't just shift to accomodate it. EXPECT_FLOAT_EQ(boxes[0].rect.left(), 75.324219); EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.12109375); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.921875); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 30.347656); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderBottomParagraph)) { const char* text = "012 34"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 26; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); txt::PlaceholderRun placeholder_run(55, 50, PlaceholderAlignment::kBottom, TextBaseline::kAlphabetic, 0); builder.AddPlaceholder(placeholder_run); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kTight; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForPlaceholders(); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); // Verify the box is in the right place EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.921875); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.92188); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); // Verify the other text didn't just shift to accomodate it. EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0.5); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 19.53125); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 16.097656); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderTopParagraph)) { const char* text = "012 34"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 26; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); txt::PlaceholderRun placeholder_run(55, 50, PlaceholderAlignment::kTop, TextBaseline::kAlphabetic, 0); builder.AddPlaceholder(placeholder_run); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kTight; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForPlaceholders(); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); // Verify the box is in the right place EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.921875); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.92188); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); // Verify the other text didn't just shift to accomodate it. EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0.5); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 16.097656); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 30.46875); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderMiddleParagraph)) { const char* text = "012 34"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 26; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); txt::PlaceholderRun placeholder_run(55, 50, PlaceholderAlignment::kMiddle, TextBaseline::kAlphabetic, 0); builder.AddPlaceholder(placeholder_run); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kTight; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForPlaceholders(); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); // Verify the box is in the right place EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.921875); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.92188); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); // Verify the other text didn't just shift to accomodate it. EXPECT_FLOAT_EQ(boxes[0].rect.left(), 75.324219); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 9.765625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.921875); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 40.234375); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderIdeographicBaselineParagraph)) { const char* text = "給能上目秘使"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Source Han Serif CN"); text_style.font_size = 26; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); txt::PlaceholderRun placeholder_run(55, 50, PlaceholderAlignment::kBaseline, TextBaseline::kIdeographic, 38.34734); builder.AddPlaceholder(placeholder_run); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kTight; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForPlaceholders(); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); // Verify the box is in the right place EXPECT_FLOAT_EQ(boxes[0].rect.left(), 162.5); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 217.5); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); // Verify the other text didn't just shift to accomodate it. EXPECT_FLOAT_EQ(boxes[0].rect.left(), 135.5); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 4.7033391); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 162.5); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 42.065342); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderBreakParagraph)) { const char* text = "012 34"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 26; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); txt::PlaceholderRun placeholder_run(50, 50, PlaceholderAlignment::kBaseline, TextBaseline::kAlphabetic, 50); txt::PlaceholderRun placeholder_run2(25, 25, PlaceholderAlignment::kBaseline, TextBaseline::kAlphabetic, 12.5); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run); builder.AddText(u16_text); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run); builder.AddText(u16_text); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run2); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run); builder.AddText(u16_text); builder.AddPlaceholder(placeholder_run2); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() - 100); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kTight; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 3, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); paint.setColor(SK_ColorGREEN); boxes = paragraph->GetRectsForRange(175, 176, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 31.695312); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 218.53125); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 47.292969); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 249); paint.setColor(SK_ColorRED); boxes = paragraph->GetRectsForPlaceholders(); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(4, 45, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 30ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 59.726562); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 26.378906); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.921875); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 56.847656); EXPECT_FLOAT_EQ(boxes[11].rect.left(), 606.34375); EXPECT_FLOAT_EQ(boxes[11].rect.top(), 38); EXPECT_FLOAT_EQ(boxes[11].rect.right(), 631.34375); EXPECT_FLOAT_EQ(boxes[11].rect.bottom(), 63); EXPECT_FLOAT_EQ(boxes[17].rect.left(), 0.5); EXPECT_FLOAT_EQ(boxes[17].rect.top(), 63.5); EXPECT_FLOAT_EQ(boxes[17].rect.right(), 50.5); EXPECT_FLOAT_EQ(boxes[17].rect.bottom(), 113.5); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderGetRectsParagraph)) { const char* text = "012 34"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 26; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); txt::PlaceholderRun placeholder_run(50, 50, PlaceholderAlignment::kBaseline, TextBaseline::kAlphabetic, 50); txt::PlaceholderRun placeholder_run2(5, 20, PlaceholderAlignment::kBaseline, TextBaseline::kAlphabetic, 10); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run); builder.AddText(u16_text); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run2); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddText(u16_text); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run2); builder.AddPlaceholder(placeholder_run); builder.AddPlaceholder(placeholder_run2); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForPlaceholders(); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 34ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 90.921875); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 140.92188); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50); EXPECT_FLOAT_EQ(boxes[16].rect.left(), 800.92188); EXPECT_FLOAT_EQ(boxes[16].rect.top(), 0); EXPECT_FLOAT_EQ(boxes[16].rect.right(), 850.92188); EXPECT_FLOAT_EQ(boxes[16].rect.bottom(), 50); EXPECT_FLOAT_EQ(boxes[33].rect.left(), 503.38281); EXPECT_FLOAT_EQ(boxes[33].rect.top(), 160); EXPECT_FLOAT_EQ(boxes[33].rect.right(), 508.38281); EXPECT_FLOAT_EQ(boxes[33].rect.bottom(), 180); Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kMax; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(30, 50, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 8ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 216.09766); // Top should be taller than "tight" EXPECT_FLOAT_EQ(boxes[0].rect.top(), 60); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 290.92188); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 120); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 290.92188); EXPECT_FLOAT_EQ(boxes[1].rect.top(), 60); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 340.92188); EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 120); EXPECT_FLOAT_EQ(boxes[2].rect.left(), 340.92188); EXPECT_FLOAT_EQ(boxes[2].rect.top(), 60); EXPECT_FLOAT_EQ(boxes[2].rect.right(), 345.92188); EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 120); ASSERT_TRUE(Snapshot()); } #if OS_LINUX // Tests if manually inserted 0xFFFC characters are replaced to 0xFFFD in order // to not interfere with the placeholder box layout. TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholder0xFFFCParagraph)) { const char* text = "ab\uFFFCcd"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); // Used to generate the replaced version. const char* text2 = "ab\uFFFDcd"; auto icu_text2 = icu::UnicodeString::fromUTF8(text2); std::u16string u16_text2(icu_text2.getBuffer(), icu_text2.getBuffer() + icu_text2.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 26; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); std::vector truth_text; builder.AddText(u16_text); truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end()); builder.AddText(u16_text); truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end()); txt::PlaceholderRun placeholder_run(50, 50, PlaceholderAlignment::kBaseline, TextBaseline::kAlphabetic, 25); builder.AddPlaceholder(placeholder_run); truth_text.push_back(0xFFFC); builder.AddText(u16_text); truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end()); builder.AddText(u16_text); truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end()); builder.AddPlaceholder(placeholder_run); truth_text.push_back(0xFFFC); builder.AddPlaceholder(placeholder_run); truth_text.push_back(0xFFFC); builder.AddText(u16_text); truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end()); builder.AddText(u16_text); truth_text.insert(truth_text.end(), u16_text2.begin(), u16_text2.end()); builder.AddPlaceholder(placeholder_run); truth_text.push_back(0xFFFC); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 0, 0); for (size_t i = 0; i < truth_text.size(); ++i) { EXPECT_EQ(paragraph->text_[i], truth_text[i]); } SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); paint.setColor(SK_ColorRED); paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForPlaceholders(); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 4ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 177.83594); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 227.83594); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50); EXPECT_FLOAT_EQ(boxes[3].rect.left(), 682.50781); EXPECT_FLOAT_EQ(boxes[3].rect.top(), 0); EXPECT_FLOAT_EQ(boxes[3].rect.right(), 732.50781); EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 50); ASSERT_TRUE(Snapshot()); } #endif TEST_F(ParagraphTest, SimpleRedParagraph) { const char* text = "I am RED"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.color = SK_ColorRED; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 10.0, 15.0); ASSERT_EQ(paragraph->text_.size(), std::string{text}.length()); for (size_t i = 0; i < u16_text.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text[i]); } ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull); ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull); ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style)); ASSERT_EQ(paragraph->records_[0].style().color, text_style.color); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, RainbowParagraph) { const char* text1 = "Red Roboto"; auto icu_text1 = icu::UnicodeString::fromUTF8(text1); std::u16string u16_text1(icu_text1.getBuffer(), icu_text1.getBuffer() + icu_text1.length()); const char* text2 = "big Greeen Default"; auto icu_text2 = icu::UnicodeString::fromUTF8(text2); std::u16string u16_text2(icu_text2.getBuffer(), icu_text2.getBuffer() + icu_text2.length()); const char* text3 = "Defcolor Homemade Apple"; auto icu_text3 = icu::UnicodeString::fromUTF8(text3); std::u16string u16_text3(icu_text3.getBuffer(), icu_text3.getBuffer() + icu_text3.length()); const char* text4 = "Small Blue Roboto"; auto icu_text4 = icu::UnicodeString::fromUTF8(text4); std::u16string u16_text4(icu_text4.getBuffer(), icu_text4.getBuffer() + icu_text4.length()); const char* text5 = "Continue Last Style With lots of words to check if it overlaps " "properly or not"; auto icu_text5 = icu::UnicodeString::fromUTF8(text5); std::u16string u16_text5(icu_text5.getBuffer(), icu_text5.getBuffer() + icu_text5.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 2; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style1; text_style1.font_families = std::vector(1, "Roboto"); text_style1.color = SK_ColorRED; builder.PushStyle(text_style1); builder.AddText(u16_text1); txt::TextStyle text_style2; text_style2.font_size = 50; text_style2.letter_spacing = 10; text_style2.word_spacing = 30; text_style2.font_weight = txt::FontWeight::w600; text_style2.color = SK_ColorGREEN; text_style2.font_families = std::vector(1, "Roboto"); text_style2.decoration = TextDecoration::kUnderline | TextDecoration::kOverline | TextDecoration::kLineThrough; text_style2.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style2); builder.AddText(u16_text2); txt::TextStyle text_style3; text_style3.font_families = std::vector(1, "Homemade Apple"); builder.PushStyle(text_style3); builder.AddText(u16_text3); txt::TextStyle text_style4; text_style4.font_size = 14; text_style4.color = SK_ColorBLUE; text_style4.font_families = std::vector(1, "Roboto"); text_style4.decoration = TextDecoration::kUnderline | TextDecoration::kOverline | TextDecoration::kLineThrough; text_style4.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style4); builder.AddText(u16_text4); // Extra text to see if it goes to default when there is more text chunks than // styles. builder.AddText(u16_text5); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 0, 0); u16_text1 += u16_text2 + u16_text3 + u16_text4; for (size_t i = 0; i < u16_text1.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text1[i]); } ASSERT_TRUE(Snapshot()); ASSERT_EQ(paragraph->runs_.runs_.size(), 4ull); ASSERT_EQ(paragraph->runs_.styles_.size(), 5ull); ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style1)); ASSERT_TRUE(paragraph->runs_.styles_[2].equals(text_style2)); ASSERT_TRUE(paragraph->runs_.styles_[3].equals(text_style3)); ASSERT_TRUE(paragraph->runs_.styles_[4].equals(text_style4)); ASSERT_EQ(paragraph->records_[0].style().color, text_style1.color); ASSERT_EQ(paragraph->records_[1].style().color, text_style2.color); ASSERT_EQ(paragraph->records_[2].style().color, text_style3.color); ASSERT_EQ(paragraph->records_[3].style().color, text_style4.color); } // Currently, this should render nothing without a supplied TextStyle. TEST_F(ParagraphTest, DefaultStyleParagraph) { const char* text = "No TextStyle! Uh Oh!"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.font_family = "Roboto"; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 10.0, 15.0); ASSERT_EQ(paragraph->text_.size(), std::string{text}.length()); for (size_t i = 0; i < u16_text.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text[i]); } ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull); ASSERT_EQ(paragraph->runs_.styles_.size(), 1ull); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, BoldParagraph) { const char* text = "This is Red max bold text!"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 60; text_style.letter_spacing = 0; text_style.font_weight = txt::FontWeight::w900; text_style.color = SK_ColorRED; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 10.0, 60.0); ASSERT_EQ(paragraph->text_.size(), std::string{text}.length()); for (size_t i = 0; i < u16_text.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text[i]); } ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull); ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull); ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style)); ASSERT_EQ(paragraph->records_[0].style().color, text_style.color); ASSERT_TRUE(Snapshot()); // width_ takes the full available space, but longest_line_ is only the width // of the text, which is less than one line. ASSERT_DOUBLE_EQ(paragraph->width_, GetTestCanvasWidth()); ASSERT_TRUE(paragraph->longest_line_ < paragraph->width_); Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kMax; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; std::vector boxes = paragraph->GetRectsForRange( 0, strlen(text), rect_height_style, rect_width_style); ASSERT_DOUBLE_EQ(paragraph->longest_line_, boxes[boxes.size() - 1].rect.right() - boxes[0].rect.left()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(HeightOverrideParagraph)) { const char* text = "01234満毎冠行来昼本可\nabcd\n満毎冠行来昼本可"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 20; text_style.letter_spacing = 0; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 3.6345; text_style.has_height_override = true; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kIncludeLineSpacingMiddle; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(0, 40, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 3ull); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 0); EXPECT_NEAR(boxes[1].rect.top(), 92.805778503417969, 0.0001); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 43.84375); EXPECT_NEAR(boxes[1].rect.bottom(), 165.49578857421875, 0.0001); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(LeftAlignParagraph)) { 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 necessary. 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."; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 26; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() - 100); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_TRUE(Snapshot()); ASSERT_EQ(paragraph->text_.size(), std::string{text}.length()); for (size_t i = 0; i < u16_text.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text[i]); } ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull); ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull); ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style)); ASSERT_EQ(paragraph->records_.size(), paragraph_style.max_lines); double expected_y = 24; ASSERT_TRUE(paragraph->records_[0].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().y(), expected_y); expected_y += 30; ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().x(), 0); ASSERT_TRUE(paragraph->records_[1].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[1].offset().y(), expected_y); expected_y += 30; ASSERT_DOUBLE_EQ(paragraph->records_[1].offset().x(), 0); ASSERT_TRUE(paragraph->records_[2].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().y(), expected_y); expected_y += 30; ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().x(), 0); ASSERT_TRUE(paragraph->records_[3].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[3].offset().y(), expected_y); expected_y += 30 * 10; ASSERT_DOUBLE_EQ(paragraph->records_[3].offset().x(), 0); ASSERT_TRUE(paragraph->records_[13].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[13].offset().y(), expected_y); ASSERT_DOUBLE_EQ(paragraph->records_[13].offset().x(), 0); ASSERT_EQ(paragraph_style.text_align, paragraph->GetParagraphStyle().text_align); // Tests for GetGlyphPositionAtCoordinate() ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(0, 0).position, 0ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 1).position, 0ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 35).position, 68ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 70).position, 134ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(2000, 35).position, 134ull); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(RightAlignParagraph)) { 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 necessary. 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."; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; paragraph_style.text_align = TextAlign::right; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 26; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); int available_width = GetTestCanvasWidth() - 100; paragraph->Layout(available_width); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_TRUE(Snapshot()); ASSERT_EQ(paragraph->text_.size(), std::string{text}.length()); for (size_t i = 0; i < u16_text.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text[i]); } ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull); ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull); ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style)); // Two records for each due to 'ghost' trailing whitespace run. ASSERT_EQ(paragraph->records_.size(), paragraph_style.max_lines * 2); double expected_y = 24; ASSERT_TRUE(paragraph->records_[0].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().y(), expected_y); expected_y += 30; ASSERT_NEAR( paragraph->records_[0].offset().x(), paragraph->width_ - paragraph->breaker_.getWidths()[paragraph->records_[0].line()], 2.0); // width_ takes the full available space, while longest_line_ wraps the glyphs // as tightly as possible. Even though this text is more than one line long, // no line perfectly spans the width of the full line, so longest_line_ is // less than width_. ASSERT_DOUBLE_EQ(paragraph->width_, available_width); ASSERT_TRUE(paragraph->longest_line_ < available_width); ASSERT_DOUBLE_EQ(paragraph->longest_line_, 880.765625); ASSERT_TRUE(paragraph->records_[2].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().y(), expected_y); expected_y += 30; ASSERT_NEAR( paragraph->records_[2].offset().x(), paragraph->width_ - paragraph->breaker_.getWidths()[paragraph->records_[2].line()], 2.0); ASSERT_TRUE(paragraph->records_[4].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[4].offset().y(), expected_y); expected_y += 30; ASSERT_NEAR( paragraph->records_[4].offset().x(), paragraph->width_ - paragraph->breaker_.getWidths()[paragraph->records_[4].line()], 2.0); ASSERT_TRUE(paragraph->records_[6].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[6].offset().y(), expected_y); expected_y += 30 * 10; ASSERT_NEAR( paragraph->records_[6].offset().x(), paragraph->width_ - paragraph->breaker_.getWidths()[paragraph->records_[6].line()], 2.0); ASSERT_TRUE(paragraph->records_[26].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[26].offset().y(), expected_y); ASSERT_NEAR( paragraph->records_[26].offset().x(), paragraph->width_ - paragraph->breaker_.getWidths()[paragraph->records_[26].line()], 2.0); ASSERT_EQ(paragraph_style.text_align, paragraph->GetParagraphStyle().text_align); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(CenterAlignParagraph)) { 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 necessary. 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."; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; paragraph_style.text_align = TextAlign::center; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 26; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() - 100); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_TRUE(Snapshot()); ASSERT_EQ(paragraph->text_.size(), std::string{text}.length()); for (size_t i = 0; i < u16_text.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text[i]); } ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull); ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull); ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style)); // Two records for each due to 'ghost' trailing whitespace run. ASSERT_EQ(paragraph->records_.size(), paragraph_style.max_lines * 2); double expected_y = 24; ASSERT_TRUE(paragraph->records_[0].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().y(), expected_y); expected_y += 30; ASSERT_NEAR(paragraph->records_[0].offset().x(), (paragraph->width_ - paragraph->breaker_.getWidths()[paragraph->records_[0].line()]) / 2, 2.0); ASSERT_TRUE(paragraph->records_[2].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().y(), expected_y); expected_y += 30; ASSERT_NEAR(paragraph->records_[2].offset().x(), (paragraph->width_ - paragraph->breaker_.getWidths()[paragraph->records_[2].line()]) / 2, 2.0); ASSERT_TRUE(paragraph->records_[4].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[4].offset().y(), expected_y); expected_y += 30; ASSERT_NEAR(paragraph->records_[4].offset().x(), (paragraph->width_ - paragraph->breaker_.getWidths()[paragraph->records_[4].line()]) / 2, 2.0); ASSERT_TRUE(paragraph->records_[6].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[6].offset().y(), expected_y); expected_y += 30 * 10; ASSERT_NEAR(paragraph->records_[6].offset().x(), (paragraph->width_ - paragraph->breaker_.getWidths()[paragraph->records_[6].line()]) / 2, 2.0); ASSERT_TRUE(paragraph->records_[26].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[26].offset().y(), expected_y); ASSERT_NEAR( paragraph->records_[26].offset().x(), (paragraph->width_ - paragraph->breaker_.getWidths()[paragraph->records_[26].line()]) / 2, 2.0); ASSERT_EQ(paragraph_style.text_align, paragraph->GetParagraphStyle().text_align); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(JustifyAlignParagraph)) { 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 necessary. 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."; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; paragraph_style.text_align = TextAlign::justify; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 26; text_style.letter_spacing = 0; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() - 100); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_TRUE(Snapshot()); ASSERT_EQ(paragraph->text_.size(), std::string{text}.length()); for (size_t i = 0; i < u16_text.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text[i]); } ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull); ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull); ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style)); ASSERT_EQ(paragraph->records_.size(), 27ull); double expected_y = 24; ASSERT_TRUE(paragraph->records_[0].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().y(), expected_y); expected_y += 30; ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().x(), 0); ASSERT_TRUE(paragraph->records_[2].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().y(), expected_y); expected_y += 30; ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().x(), 0); ASSERT_TRUE(paragraph->records_[4].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[4].offset().y(), expected_y); expected_y += 30; ASSERT_DOUBLE_EQ(paragraph->records_[4].offset().x(), 0); ASSERT_TRUE(paragraph->records_[6].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[6].offset().y(), expected_y); expected_y += 30 * 10; ASSERT_DOUBLE_EQ(paragraph->records_[6].offset().x(), 0); ASSERT_TRUE(paragraph->records_[26].style().equals(text_style)); ASSERT_DOUBLE_EQ(paragraph->records_[26].offset().y(), expected_y); ASSERT_DOUBLE_EQ(paragraph->records_[26].offset().x(), 0); ASSERT_EQ(paragraph_style.text_align, paragraph->GetParagraphStyle().text_align); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(JustifyRTL)) { const char* text = "אאא בּבּבּבּ אאאא בּבּ אאא בּבּבּ אאאאא בּבּבּבּ אאאא בּבּבּבּבּ " "אאאאא בּבּבּבּבּ אאאבּבּבּבּבּבּאאאאא בּבּבּבּבּבּאאאאאבּבּבּבּבּבּ אאאאא בּבּבּבּבּ " "אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; paragraph_style.text_align = TextAlign::justify; paragraph_style.text_direction = TextDirection::rtl; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Ahem"); text_style.font_size = 26; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); size_t paragraph_width = GetTestCanvasWidth() - 100; paragraph->Layout(paragraph_width); paragraph->Paint(GetCanvas(), 0, 0); auto glyph_line_width = [¶graph](int index) { size_t second_to_last_position_index = paragraph->glyph_lines_[index].positions.size() - 1; return paragraph->glyph_lines_[index] .positions[second_to_last_position_index] .x_pos.end; }; SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kMax; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 100, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } ASSERT_EQ(boxes.size(), 5ull); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(240, 250, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } ASSERT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 588); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 130); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 640); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 156); ASSERT_TRUE(Snapshot()); // All lines should be justified to the width of the // paragraph. for (size_t i = 0; i < paragraph->glyph_lines_.size(); ++i) { ASSERT_EQ(glyph_line_width(i), paragraph_width); } } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(JustifyRTLNewLine)) { const char* text = "אאא בּבּבּבּ אאאא\nבּבּ אאא בּבּבּ אאאאא בּבּבּבּ אאאא בּבּבּבּבּ " "אאאאא בּבּבּבּבּ אאאבּבּבּבּבּבּאאאאא בּבּבּבּבּבּאאאאאבּבּבּבּבּבּ אאאאא בּבּבּבּבּ " "אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ אאאאא בּבּבּבּבּבּ"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; paragraph_style.text_align = TextAlign::justify; paragraph_style.text_direction = TextDirection::rtl; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Ahem"); text_style.font_size = 26; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); size_t paragraph_width = GetTestCanvasWidth() - 100; paragraph->Layout(paragraph_width); paragraph->Paint(GetCanvas(), 0, 0); auto glyph_line_width = [¶graph](int index) { size_t second_to_last_position_index = paragraph->glyph_lines_[index].positions.size() - 1; return paragraph->glyph_lines_[index] .positions[second_to_last_position_index] .x_pos.end; }; SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); ASSERT_TRUE(Snapshot()); // Tests for GetRectsForRange() Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kMax; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 30, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } ASSERT_EQ(boxes.size(), 2ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 562); EXPECT_FLOAT_EQ(boxes[0].rect.top(), -1.4305115e-06); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 900); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 26); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(240, 250, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } ASSERT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 68); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 130); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 120); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 156); ASSERT_TRUE(Snapshot()); // All lines should be justified to the width of the // paragraph. for (size_t i = 0; i < paragraph->glyph_lines_.size(); ++i) { ASSERT_EQ(glyph_line_width(i), paragraph_width); } } TEST_F(ParagraphTest, DecorationsParagraph) { txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 26; text_style.letter_spacing = 0; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 2; text_style.decoration = TextDecoration::kUnderline | TextDecoration::kOverline | TextDecoration::kLineThrough; text_style.decoration_style = txt::TextDecorationStyle::kSolid; text_style.decoration_color = SK_ColorBLACK; text_style.decoration_thickness_multiplier = 2.0; builder.PushStyle(text_style); builder.AddText(u"This text should be"); text_style.decoration_style = txt::TextDecorationStyle::kDouble; text_style.decoration_color = SK_ColorBLUE; text_style.decoration_thickness_multiplier = 1.0; builder.PushStyle(text_style); builder.AddText(u" decorated even when"); text_style.decoration_style = txt::TextDecorationStyle::kDotted; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u" wrapped around to"); text_style.decoration_style = txt::TextDecorationStyle::kDashed; text_style.decoration_color = SK_ColorBLACK; text_style.decoration_thickness_multiplier = 3.0; builder.PushStyle(text_style); builder.AddText(u" the next line."); text_style.decoration_style = txt::TextDecorationStyle::kWavy; text_style.decoration_color = SK_ColorRED; text_style.decoration_thickness_multiplier = 1.0; builder.PushStyle(text_style); builder.AddText(u" Otherwise, bad things happen."); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() - 100); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_TRUE(Snapshot()); ASSERT_EQ(paragraph->runs_.size(), 5ull); ASSERT_EQ(paragraph->records_.size(), 6ull); for (size_t i = 0; i < 6; ++i) { ASSERT_EQ(paragraph->records_[i].style().decoration, TextDecoration::kUnderline | TextDecoration::kOverline | TextDecoration::kLineThrough); } ASSERT_EQ(paragraph->records_[0].style().decoration_style, txt::TextDecorationStyle::kSolid); ASSERT_EQ(paragraph->records_[1].style().decoration_style, txt::TextDecorationStyle::kDouble); ASSERT_EQ(paragraph->records_[2].style().decoration_style, txt::TextDecorationStyle::kDotted); ASSERT_EQ(paragraph->records_[3].style().decoration_style, txt::TextDecorationStyle::kDashed); ASSERT_EQ(paragraph->records_[4].style().decoration_style, txt::TextDecorationStyle::kDashed); ASSERT_EQ(paragraph->records_[5].style().decoration_style, txt::TextDecorationStyle::kWavy); ASSERT_EQ(paragraph->records_[0].style().decoration_color, SK_ColorBLACK); ASSERT_EQ(paragraph->records_[1].style().decoration_color, SK_ColorBLUE); ASSERT_EQ(paragraph->records_[2].style().decoration_color, SK_ColorBLACK); ASSERT_EQ(paragraph->records_[3].style().decoration_color, SK_ColorBLACK); ASSERT_EQ(paragraph->records_[4].style().decoration_color, SK_ColorBLACK); ASSERT_EQ(paragraph->records_[5].style().decoration_color, SK_ColorRED); ASSERT_EQ(paragraph->records_[0].style().decoration_thickness_multiplier, 2.0); ASSERT_EQ(paragraph->records_[1].style().decoration_thickness_multiplier, 1.0); ASSERT_EQ(paragraph->records_[2].style().decoration_thickness_multiplier, 1.0); ASSERT_EQ(paragraph->records_[3].style().decoration_thickness_multiplier, 3.0); ASSERT_EQ(paragraph->records_[4].style().decoration_thickness_multiplier, 3.0); ASSERT_EQ(paragraph->records_[5].style().decoration_thickness_multiplier, 1.0); } TEST_F(ParagraphTest, WavyDecorationParagraph) { txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 26; text_style.letter_spacing = 0; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 2; text_style.decoration = TextDecoration::kUnderline | TextDecoration::kOverline | TextDecoration::kLineThrough; text_style.decoration_style = txt::TextDecorationStyle::kWavy; text_style.decoration_color = SK_ColorRED; text_style.decoration_thickness_multiplier = 1.0; builder.PushStyle(text_style); builder.AddText(u" Otherwise, bad things happen."); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() - 100); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_TRUE(Snapshot()); ASSERT_EQ(paragraph->runs_.size(), 1ull); ASSERT_EQ(paragraph->records_.size(), 1ull); for (size_t i = 0; i < 1; ++i) { ASSERT_EQ(paragraph->records_[i].style().decoration, TextDecoration::kUnderline | TextDecoration::kOverline | TextDecoration::kLineThrough); } ASSERT_EQ(paragraph->records_[0].style().decoration_style, txt::TextDecorationStyle::kWavy); ASSERT_EQ(paragraph->records_[0].style().decoration_color, SK_ColorRED); ASSERT_EQ(paragraph->records_[0].style().decoration_thickness_multiplier, 1.0); SkPath path0; SkPath canonical_path0; paragraph->ComputeWavyDecoration(path0, 1, 1, 9.56, 1); canonical_path0.moveTo(1, 1); canonical_path0.rQuadTo(1, -1, 2, 0); canonical_path0.rQuadTo(1, 1, 2, 0); canonical_path0.rQuadTo(1, -1, 2, 0); canonical_path0.rQuadTo(1, 1, 2, 0); canonical_path0.rQuadTo(0.78, -0.78, 1.56, -0.3432); ASSERT_EQ(path0.countPoints(), canonical_path0.countPoints()); for (int i = 0; i < canonical_path0.countPoints(); ++i) { ASSERT_EQ(path0.getPoint(i).x(), canonical_path0.getPoint(i).x()); ASSERT_EQ(path0.getPoint(i).y(), canonical_path0.getPoint(i).y()); } SkPath path1; SkPath canonical_path1; paragraph->ComputeWavyDecoration(path1, 1, 1, 8.35, 1); canonical_path1.moveTo(1, 1); canonical_path1.rQuadTo(1, -1, 2, 0); canonical_path1.rQuadTo(1, 1, 2, 0); canonical_path1.rQuadTo(1, -1, 2, 0); canonical_path1.rQuadTo(1, 1, 2, 0); canonical_path1.rQuadTo(0.175, -0.175, 0.35, -0.28875); ASSERT_EQ(path1.countPoints(), canonical_path1.countPoints()); for (int i = 0; i < canonical_path1.countPoints(); ++i) { ASSERT_EQ(path1.getPoint(i).x(), canonical_path1.getPoint(i).x()); ASSERT_EQ(path1.getPoint(i).y(), canonical_path1.getPoint(i).y()); } SkPath path2; SkPath canonical_path2; paragraph->ComputeWavyDecoration(path2, 1, 1, 10.59, 1); canonical_path2.moveTo(1, 1); canonical_path2.rQuadTo(1, -1, 2, 0); canonical_path2.rQuadTo(1, 1, 2, 0); canonical_path2.rQuadTo(1, -1, 2, 0); canonical_path2.rQuadTo(1, 1, 2, 0); canonical_path2.rQuadTo(1, -1, 2, 0); canonical_path2.rQuadTo(0.295, 0.295, 0.59, 0.41595); ASSERT_EQ(path2.countPoints(), canonical_path2.countPoints()); for (int i = 0; i < canonical_path2.countPoints(); ++i) { ASSERT_EQ(path2.getPoint(i).x(), canonical_path2.getPoint(i).x()); ASSERT_EQ(path2.getPoint(i).y(), canonical_path2.getPoint(i).y()); } SkPath path3; SkPath canonical_path3; paragraph->ComputeWavyDecoration(path3, 1, 1, 11.2, 1); canonical_path3.moveTo(1, 1); canonical_path3.rQuadTo(1, -1, 2, 0); canonical_path3.rQuadTo(1, 1, 2, 0); canonical_path3.rQuadTo(1, -1, 2, 0); canonical_path3.rQuadTo(1, 1, 2, 0); canonical_path3.rQuadTo(1, -1, 2, 0); canonical_path3.rQuadTo(0.6, 0.6, 1.2, 0.48); ASSERT_EQ(path3.countPoints(), canonical_path3.countPoints()); for (int i = 0; i < canonical_path3.countPoints(); ++i) { ASSERT_EQ(path3.getPoint(i).x(), canonical_path3.getPoint(i).x()); ASSERT_EQ(path3.getPoint(i).y(), canonical_path3.getPoint(i).y()); } SkPath path4; SkPath canonical_path4; paragraph->ComputeWavyDecoration(path4, 1, 1, 12, 1); canonical_path4.moveTo(1, 1); canonical_path4.rQuadTo(1, -1, 2, 0); canonical_path4.rQuadTo(1, 1, 2, 0); canonical_path4.rQuadTo(1, -1, 2, 0); canonical_path4.rQuadTo(1, 1, 2, 0); canonical_path4.rQuadTo(1, -1, 2, 0); canonical_path4.rQuadTo(1, 1, 2, 0); ASSERT_EQ(path4.countPoints(), canonical_path4.countPoints()); for (int i = 0; i < canonical_path4.countPoints(); ++i) { ASSERT_EQ(path4.getPoint(i).x(), canonical_path4.getPoint(i).x()); ASSERT_EQ(path4.getPoint(i).y(), canonical_path4.getPoint(i).y()); } } TEST_F(ParagraphTest, ItalicsParagraph) { txt::ParagraphStyle paragraph_style; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.color = SK_ColorRED; text_style.font_size = 10; builder.PushStyle(text_style); builder.AddText(u"No italic "); text_style.font_style = txt::FontStyle::italic; builder.PushStyle(text_style); builder.AddText(u"Yes Italic "); builder.Pop(); builder.AddText(u"No Italic again."); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_EQ(paragraph->runs_.runs_.size(), 3ull); ASSERT_EQ(paragraph->runs_.styles_.size(), 3ull); ASSERT_EQ(paragraph->records_[1].style().color, text_style.color); ASSERT_EQ(paragraph->records_[1].style().font_style, txt::FontStyle::italic); ASSERT_EQ(paragraph->records_[2].style().font_style, txt::FontStyle::normal); ASSERT_EQ(paragraph->records_[0].style().font_style, txt::FontStyle::normal); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, ChineseParagraph) { const char* text = "左線読設重説切後碁給能上目秘使約。満毎冠行来昼本可必図将発確年。今属場育" "図情闘陰野高備込制詩西校客。審対江置講今固残必託地集済決維駆年策。立得庭" "際輝求佐抗蒼提夜合逃表。注統天言件自謙雅載報紙喪。作画稿愛器灯女書利変探" "訃第金線朝開化建。子戦年帝励害表月幕株漠新期刊人秘。図的海力生禁挙保天戦" "聞条年所在口。"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; paragraph_style.text_align = TextAlign::justify; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.color = SK_ColorBLACK; text_style.font_size = 35; text_style.letter_spacing = 2; text_style.font_families = std::vector(1, "Source Han Serif CN"); text_style.decoration = TextDecoration::kUnderline | TextDecoration::kOverline | TextDecoration::kLineThrough; text_style.decoration_style = txt::TextDecorationStyle::kSolid; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() - 100); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull); ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull); ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style)); ASSERT_EQ(paragraph->records_[0].style().color, text_style.color); ASSERT_EQ(paragraph->records_.size(), 7ull); ASSERT_TRUE(Snapshot()); } // TODO(garyq): Support RTL languages. TEST_F(ParagraphTest, DISABLED_ArabicParagraph) { const char* text = "من أسر وإعلان الخاصّة وهولندا،, عل قائمة الضغوط بالمطالبة تلك. الصفحة " "بمباركة التقليدية قام عن. تصفح"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; paragraph_style.text_align = TextAlign::right; paragraph_style.text_direction = TextDirection::rtl; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.color = SK_ColorBLACK; text_style.font_size = 35; text_style.letter_spacing = 2; text_style.font_families = std::vector(1, "Katibeh"); text_style.decoration = TextDecoration::kUnderline | TextDecoration::kOverline | TextDecoration::kLineThrough; text_style.decoration_style = txt::TextDecorationStyle::kSolid; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() - 100); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_EQ(paragraph->text_.size(), std::string{text}.length()); ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull); ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull); ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style)); ASSERT_EQ(paragraph->records_[0].style().color, text_style.color); ASSERT_EQ(paragraph->records_.size(), 2ull); ASSERT_EQ(paragraph->paragraph_style_.text_direction, TextDirection::rtl); for (size_t i = 0; i < u16_text.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text[u16_text.length() - i]); } ASSERT_TRUE(Snapshot()); } // Checks if the rects are in the correct positions after typing spaces in // Arabic. TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(ArabicRectsParagraph)) { const char* text = "بمباركة التقليدية قام عن. تصفح يد "; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; paragraph_style.text_align = TextAlign::right; paragraph_style.text_direction = TextDirection::rtl; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Noto Naskh Arabic"); text_style.font_size = 26; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() - 100); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kMax; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 100, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 2ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 556.54688); EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.26855469); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 900); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 44); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 510.09375); EXPECT_FLOAT_EQ(boxes[1].rect.top(), -0.26855469); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 557.04688); EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 44); ASSERT_EQ(paragraph_style.text_align, paragraph->GetParagraphStyle().text_align); ASSERT_TRUE(Snapshot()); } // Trailing space at the end of the arabic rtl run should be at the left end of // the arabic run. TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(ArabicRectsLTRLeftAlignParagraph)) { const char* text = "Helloبمباركة التقليدية قام عن. تصفح يد "; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; paragraph_style.text_align = TextAlign::left; paragraph_style.text_direction = TextDirection::ltr; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Noto Naskh Arabic"); text_style.font_size = 26; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() - 100); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kMax; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(36, 40, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 89.40625); EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.26855469); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 121.87891); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 44); ASSERT_EQ(paragraph_style.text_align, paragraph->GetParagraphStyle().text_align); ASSERT_TRUE(Snapshot()); } // Trailing space at the end of the arabic rtl run should be at the left end of // the arabic run and be a ghost space. TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(ArabicRectsLTRRightAlignParagraph)) { const char* text = "Helloبمباركة التقليدية قام عن. تصفح يد "; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; paragraph_style.text_align = TextAlign::right; paragraph_style.text_direction = TextDirection::ltr; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Noto Naskh Arabic"); text_style.font_size = 26; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; text_style.decoration = TextDecoration::kUnderline; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() - 100); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kMax; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(36, 40, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 2ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 556.54688); EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.26855469); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 577.78125); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 44); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 545.30859); EXPECT_FLOAT_EQ(boxes[1].rect.top(), -0.26855469); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 557.04688); EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 44); ASSERT_EQ(paragraph_style.text_align, paragraph->GetParagraphStyle().text_align); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, GetGlyphPositionAtCoordinateParagraph) { const char* text = "12345 67890 12345 67890 12345 67890 12345 67890 12345 67890 12345 " "67890 12345"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 50; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_TRUE(Snapshot()); // 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. ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(-10000, -10000).position, 0ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(-1, -1).position, 0ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(0, 0).position, 0ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(3, 3).position, 0ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(35, 1).position, 1ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(300, 2).position, 11ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(301, 2.2).position, 11ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(302, 2.6).position, 11ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(301, 2.1).position, 11ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(100000, 20).position, 18ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(450, 20).position, 16ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(100000, 90).position, 36ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(-100000, 90).position, 18ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(20, -80).position, 1ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 90).position, 18ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 170).position, 36ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(10000, 180).position, 72ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(70, 180).position, 56ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 270).position, 72ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(35, 90).position, 19ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(10000, 10000).position, 77ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(85, 10000).position, 75ull); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) { const char* text = "12345, \"67890\" 12345 67890 12345 67890 12345 67890 12345 67890 12345 " "67890 12345"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 50; text_style.letter_spacing = 0; text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() // NOTE: The base truth values may still need adjustment as the specifics // are adjusted. Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kMax; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 28.417969); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(2, 8, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 56.835938); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 177.97266); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); paint.setColor(SK_ColorGREEN); boxes = paragraph->GetRectsForRange(8, 21, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 177.97266); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 507.02344); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); paint.setColor(SK_ColorRED); boxes = paragraph->GetRectsForRange(30, 100, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 4ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 211.375); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 59.40625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 463.61719); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 118); // TODO(garyq): The following set of vals are definitely wrong and // end of paragraph handling needs to be fixed in a later patch. EXPECT_FLOAT_EQ(boxes[3].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[3].rect.top(), 236.40625); EXPECT_FLOAT_EQ(boxes[3].rect.right(), 142.08984); EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 295); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(19, 22, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 450.1875); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 519.47266); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); paint.setColor(SK_ColorRED); boxes = paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeTight)) { const char* text = "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Noto Sans CJK JP"); text_style.font_size = 50; text_style.letter_spacing = 0; text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() // NOTE: The base truth values may still need adjustment as the specifics // are adjusted. Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kTight; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 16.898438); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 74); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(2, 8, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 264.09375); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 74); paint.setColor(SK_ColorGREEN); boxes = paragraph->GetRectsForRange(8, 21, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 2ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 264.09375); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 595.08594); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 74); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeIncludeLineSpacingMiddle)) { const char* text = "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 50; text_style.letter_spacing = 0; text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1.6; text_style.has_height_override = true; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() // NOTE: The base truth values may still need adjustment as the specifics // are adjusted. Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kIncludeLineSpacingMiddle; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kMax; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.429688); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 88.473305); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(2, 8, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 67.429688); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 88.473305); paint.setColor(SK_ColorGREEN); boxes = paragraph->GetRectsForRange(8, 21, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 88.473312); paint.setColor(SK_ColorRED); boxes = paragraph->GetRectsForRange(30, 150, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 8ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 88.473312); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 168.47331); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875); EXPECT_FLOAT_EQ(boxes[1].rect.top(), 88.473312); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344); EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 168.4733); EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[2].rect.top(), 168.4733); EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422); EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 248.47331); EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422); EXPECT_FLOAT_EQ(boxes[3].rect.top(), 168.4733); EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344); EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 248.47331); EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[4].rect.top(), 248.47331); EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344); EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 328.4733); EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[5].rect.top(), 328.47333); EXPECT_FLOAT_EQ(boxes[5].rect.right(), 570.02344); EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 408.4733); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(19, 22, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 463.72656); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 88.473305); paint.setColor(SK_ColorRED); boxes = paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeIncludeLineSpacingTop)) { const char* text = "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 50; text_style.letter_spacing = 0; text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1.6; text_style.has_height_override = true; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() // NOTE: The base truth values may still need adjustment as the specifics // are adjusted. Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kIncludeLineSpacingTop; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kMax; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.429688); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(2, 8, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 67.429688); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80); paint.setColor(SK_ColorGREEN); boxes = paragraph->GetRectsForRange(8, 21, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80); paint.setColor(SK_ColorRED); boxes = paragraph->GetRectsForRange(30, 150, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 8ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 80); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 160); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875); EXPECT_FLOAT_EQ(boxes[1].rect.top(), 80); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344); EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 160); EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[2].rect.top(), 160); EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422); EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 240); EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422); EXPECT_FLOAT_EQ(boxes[3].rect.top(), 160); EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344); EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 240); EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[4].rect.top(), 240); EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344); EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 320); EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[5].rect.top(), 320); EXPECT_FLOAT_EQ(boxes[5].rect.right(), 570.02344); EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 400); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(19, 22, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 463.72656); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80); paint.setColor(SK_ColorRED); boxes = paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeIncludeLineSpacingBottom)) { const char* text = "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 50; text_style.letter_spacing = 0; text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1.6; text_style.has_height_override = true; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() // NOTE: The base truth values may still need adjustment as the specifics // are adjusted. Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kIncludeLineSpacingBottom; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kMax; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.429688); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 96.946609); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(2, 8, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 67.429688); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 96.946609); paint.setColor(SK_ColorGREEN); boxes = paragraph->GetRectsForRange(8, 21, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 96.946609); paint.setColor(SK_ColorRED); boxes = paragraph->GetRectsForRange(30, 150, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 8ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 96.946617); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 176.94661); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875); EXPECT_FLOAT_EQ(boxes[1].rect.top(), 96.946617); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344); EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 176.94661); EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[2].rect.top(), 176.94661); EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422); EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 256.94662); EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422); EXPECT_FLOAT_EQ(boxes[3].rect.top(), 176.94661); EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344); EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 256.94662); EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[4].rect.top(), 256.94662); EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344); EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 336.94662); EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[5].rect.top(), 336.94662); EXPECT_FLOAT_EQ(boxes[5].rect.right(), 570.02344); EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 416.94662); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(19, 22, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 463.72656); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 96.946609); paint.setColor(SK_ColorRED); boxes = paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, GetRectsForRangeIncludeCombiningCharacter) { const char* text = "ดีสวัสดีชาวโลกที่น่ารัก"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 50; text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() - 100); paragraph->Paint(GetCanvas(), 0, 0); Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kTight; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; std::vector boxes = paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); EXPECT_EQ(boxes.size(), 0ull); // Case when the sentence starts with a combining character // We should get 0 box for ด because it's already been combined to ดี boxes = paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(1, 2, rect_height_style, rect_width_style); EXPECT_EQ(boxes.size(), 1ull); boxes = paragraph->GetRectsForRange(0, 2, rect_height_style, rect_width_style); EXPECT_EQ(boxes.size(), 1ull); // Case when the sentence contains a combining character // We should get 0 box for ว because it's already been combined to วั boxes = paragraph->GetRectsForRange(3, 4, rect_height_style, rect_width_style); EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(4, 5, rect_height_style, rect_width_style); EXPECT_EQ(boxes.size(), 1ull); boxes = paragraph->GetRectsForRange(3, 5, rect_height_style, rect_width_style); EXPECT_EQ(boxes.size(), 1ull); // Case when the sentence contains a combining character that contain 3 // characters We should get 0 box for ท and ที because it's already been // combined to ที่ boxes = paragraph->GetRectsForRange(14, 15, rect_height_style, rect_width_style); EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(15, 16, rect_height_style, rect_width_style); EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(16, 17, rect_height_style, rect_width_style); EXPECT_EQ(boxes.size(), 1ull); boxes = paragraph->GetRectsForRange(14, 17, rect_height_style, rect_width_style); EXPECT_EQ(boxes.size(), 1ull); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeCenterParagraph)) { const char* text = "01234   "; // includes ideographic space // and english space. auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; paragraph_style.text_align = TextAlign::center; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 50; text_style.letter_spacing = 0; text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kMax; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 203.95508); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 232.37305); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(2, 4, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 260.79102); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 317.62695); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); paint.setColor(SK_ColorGREEN); boxes = paragraph->GetRectsForRange(4, 6, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 2ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 317.62695); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 346.04492); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); paint.setColor(SK_ColorBLACK); boxes = paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 346.04492); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 358.49414); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); paint.setColor(SK_ColorRED); boxes = paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeCenterParagraphNewlineCentered)) { const char* text = "01234\n"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; paragraph_style.text_align = TextAlign::center; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 50; text_style.letter_spacing = 0; text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kMax; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 203.95508); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 232.37305); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); paint.setColor(SK_ColorGREEN); boxes = paragraph->GetRectsForRange(6, 7, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 275); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 275); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 75); // TODO(garyq): This value can be improved... Should be // taller, but we need a good way to obtain a height // without any glyphs on the line. ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeCenterMultiLineParagraph)) { const char* text = "01234   \n0123  "; // includes ideographic // space and english space. auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; paragraph_style.text_align = TextAlign::center; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 50; text_style.letter_spacing = 0; text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kMax; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 203.95508); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 232.37305); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); paint.setColor(SK_ColorBLUE); boxes = paragraph->GetRectsForRange(2, 4, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 260.79102); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 317.62695); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); paint.setColor(SK_ColorGREEN); boxes = paragraph->GetRectsForRange(4, 6, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 2ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 317.62695); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 346.04492); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); paint.setColor(SK_ColorBLACK); boxes = paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 346.04492); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 358.49414); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); paint.setColor(SK_ColorBLACK); boxes = paragraph->GetRectsForRange(10, 12, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 218.16406); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 59.40625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 275); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 118); paint.setColor(SK_ColorBLACK); boxes = paragraph->GetRectsForRange(14, 18, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 331.83594); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 59.40625); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 419.18359); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 118); paint.setColor(SK_ColorRED); boxes = paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeStrut)) { const char* text = "Chinese 字典"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.strut_enabled = true; paragraph_style.strut_font_families.push_back("Roboto"); paragraph_style.strut_font_size = 14; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families.push_back("Noto Sans CJK JP"); text_style.font_size = 20; text_style.color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); std::vector strut_boxes = paragraph->GetRectsForRange(0, 10, Paragraph::RectHeightStyle::kStrut, Paragraph::RectWidthStyle::kMax); ASSERT_EQ(strut_boxes.size(), 1ull); const SkRect& strut_rect = strut_boxes.front().rect; paint.setColor(SK_ColorRED); GetCanvas()->drawRect(strut_rect, paint); std::vector tight_boxes = paragraph->GetRectsForRange(0, 10, Paragraph::RectHeightStyle::kTight, Paragraph::RectWidthStyle::kMax); ASSERT_EQ(tight_boxes.size(), 1ull); const SkRect& tight_rect = tight_boxes.front().rect; paint.setColor(SK_ColorGREEN); GetCanvas()->drawRect(tight_rect, paint); EXPECT_FLOAT_EQ(strut_rect.left(), 0); EXPECT_FLOAT_EQ(strut_rect.top(), 10.611719); EXPECT_FLOAT_EQ(strut_rect.right(), 118.60547); EXPECT_FLOAT_EQ(strut_rect.bottom(), 27.017969); ASSERT_TRUE(tight_rect.contains(strut_rect)); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeStrutFallback)) { const char* text = "Chinese 字典"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.strut_enabled = false; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families.push_back("Noto Sans CJK JP"); text_style.font_size = 20; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); std::vector strut_boxes = paragraph->GetRectsForRange(0, 10, Paragraph::RectHeightStyle::kStrut, Paragraph::RectWidthStyle::kMax); std::vector tight_boxes = paragraph->GetRectsForRange(0, 10, Paragraph::RectHeightStyle::kTight, Paragraph::RectWidthStyle::kMax); ASSERT_EQ(strut_boxes.size(), 1ull); ASSERT_EQ(tight_boxes.size(), 1ull); ASSERT_EQ(strut_boxes.front().rect, tight_boxes.front().rect); } SkRect GetCoordinatesForGlyphPosition(txt::Paragraph& paragraph, size_t pos) { std::vector boxes = paragraph.GetRectsForRange(pos, pos + 1, Paragraph::RectHeightStyle::kMax, Paragraph::RectWidthStyle::kTight); return !boxes.empty() ? boxes.front().rect : SkRect::MakeEmpty(); } TEST_F(ParagraphTest, GetWordBoundaryParagraph) { const char* text = "12345 67890 12345 67890 12345 67890 12345 67890 12345 67890 12345 " "67890 12345"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 52; text_style.letter_spacing = 1.19039; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1.5; text_style.has_height_override = true; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); paint.setColor(SK_ColorRED); SkRect rect = GetCoordinatesForGlyphPosition(*paragraph, 0); GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint); EXPECT_EQ(paragraph->GetWordBoundary(0), txt::Paragraph::Range(0, 5)); EXPECT_EQ(paragraph->GetWordBoundary(1), txt::Paragraph::Range(0, 5)); EXPECT_EQ(paragraph->GetWordBoundary(2), txt::Paragraph::Range(0, 5)); EXPECT_EQ(paragraph->GetWordBoundary(3), txt::Paragraph::Range(0, 5)); EXPECT_EQ(paragraph->GetWordBoundary(4), txt::Paragraph::Range(0, 5)); rect = GetCoordinatesForGlyphPosition(*paragraph, 5); GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint); EXPECT_EQ(paragraph->GetWordBoundary(5), txt::Paragraph::Range(5, 7)); rect = GetCoordinatesForGlyphPosition(*paragraph, 6); GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint); EXPECT_EQ(paragraph->GetWordBoundary(6), txt::Paragraph::Range(5, 7)); rect = GetCoordinatesForGlyphPosition(*paragraph, 7); GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint); EXPECT_EQ(paragraph->GetWordBoundary(7), txt::Paragraph::Range(7, 12)); EXPECT_EQ(paragraph->GetWordBoundary(8), txt::Paragraph::Range(7, 12)); EXPECT_EQ(paragraph->GetWordBoundary(9), txt::Paragraph::Range(7, 12)); EXPECT_EQ(paragraph->GetWordBoundary(10), txt::Paragraph::Range(7, 12)); EXPECT_EQ(paragraph->GetWordBoundary(11), txt::Paragraph::Range(7, 12)); rect = GetCoordinatesForGlyphPosition(*paragraph, 12); GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint); EXPECT_EQ(paragraph->GetWordBoundary(12), txt::Paragraph::Range(12, 13)); rect = GetCoordinatesForGlyphPosition(*paragraph, 13); GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint); EXPECT_EQ(paragraph->GetWordBoundary(13), txt::Paragraph::Range(13, 18)); rect = GetCoordinatesForGlyphPosition(*paragraph, 18); GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint); rect = GetCoordinatesForGlyphPosition(*paragraph, 19); GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint); rect = GetCoordinatesForGlyphPosition(*paragraph, 24); GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint); rect = GetCoordinatesForGlyphPosition(*paragraph, 25); GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint); rect = GetCoordinatesForGlyphPosition(*paragraph, 30); GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint); EXPECT_EQ(paragraph->GetWordBoundary(30), txt::Paragraph::Range(30, 31)); rect = GetCoordinatesForGlyphPosition(*paragraph, 31); GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint); rect = GetCoordinatesForGlyphPosition(*paragraph, icu_text.length() - 5); GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint); EXPECT_EQ( paragraph->GetWordBoundary(icu_text.length() - 1), txt::Paragraph::Range(icu_text.length() - 5, icu_text.length())); rect = GetCoordinatesForGlyphPosition(*paragraph, icu_text.length()); GetCanvas()->drawLine(rect.fLeft, rect.fTop, rect.fLeft, rect.fBottom, paint); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, SpacingParagraph) { const char* text = "H"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 50; text_style.letter_spacing = 20; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); text_style.font_size = 50; text_style.letter_spacing = 10; text_style.word_spacing = 0; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); text_style.font_size = 50; text_style.letter_spacing = 20; text_style.word_spacing = 0; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); text_style.font_size = 50; text_style.letter_spacing = 0; text_style.word_spacing = 0; builder.PushStyle(text_style); builder.AddText(u"|"); builder.Pop(); text_style.font_size = 50; text_style.letter_spacing = 0; text_style.word_spacing = 20; builder.PushStyle(text_style); builder.AddText(u"H "); builder.Pop(); text_style.font_size = 50; text_style.letter_spacing = 0; text_style.word_spacing = 0; builder.PushStyle(text_style); builder.AddText(u"H "); builder.Pop(); text_style.font_size = 50; text_style.letter_spacing = 0; text_style.word_spacing = 20; builder.PushStyle(text_style); builder.AddText(u"H "); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); paint.setColor(SK_ColorRED); ASSERT_TRUE(Snapshot()); ASSERT_EQ(paragraph->records_.size(), 7ull); ASSERT_EQ(paragraph->records_[0].style().letter_spacing, 20); ASSERT_EQ(paragraph->records_[1].style().letter_spacing, 10); ASSERT_EQ(paragraph->records_[2].style().letter_spacing, 20); ASSERT_EQ(paragraph->records_[4].style().word_spacing, 20); ASSERT_EQ(paragraph->records_[5].style().word_spacing, 0); ASSERT_EQ(paragraph->records_[6].style().word_spacing, 20); } TEST_F(ParagraphTest, LongWordParagraph) { const char* text = "A " "veryverylongwordtoseewherethiswillwraporifitwillatallandifitdoesthenthat" "wouldbeagoodthingbecausethebreakingisworking."; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.break_strategy = minikin::kBreakStrategy_HighQuality; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 31; text_style.letter_spacing = 0; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() / 2); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_TRUE(Snapshot()); ASSERT_EQ(paragraph->text_.size(), std::string{text}.length()); for (size_t i = 0; i < u16_text.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text[i]); } ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull); ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull); ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style)); ASSERT_EQ(paragraph->records_[0].style().color, text_style.color); ASSERT_EQ(paragraph->GetLineCount(), 4ull); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, KernScaleParagraph) { float scale = 3.0f; txt::ParagraphStyle paragraph_style; paragraph_style.break_strategy = minikin::kBreakStrategy_HighQuality; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Droid Serif"); text_style.font_size = 100 / scale; text_style.letter_spacing = 0; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u"AVAVAWAH A0 V0 VA To The Lo"); builder.PushStyle(text_style); builder.AddText(u"A"); builder.PushStyle(text_style); builder.AddText(u"V"); text_style.font_size = 14 / scale; builder.PushStyle(text_style); builder.AddText( u" Dialog Text List lots of words to see if kerning works on a bigger " u"set of characters AVAVAW"); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() / scale); GetCanvas()->scale(scale, scale); paragraph->Paint(GetCanvas(), 0, 0); GetCanvas()->scale(1.0, 1.0); ASSERT_TRUE(Snapshot()); EXPECT_DOUBLE_EQ(paragraph->records_[0].offset().x(), 0); EXPECT_DOUBLE_EQ(paragraph->records_[1].offset().x(), 0); EXPECT_DOUBLE_EQ(paragraph->records_[2].offset().x(), 207.37109375f); EXPECT_DOUBLE_EQ(paragraph->records_[3].offset().x(), 230.87109375f); EXPECT_DOUBLE_EQ(paragraph->records_[4].offset().x(), 253.36328125f); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(NewlineParagraph)) { txt::ParagraphStyle paragraph_style; paragraph_style.font_family = "Roboto"; paragraph_style.break_strategy = minikin::kBreakStrategy_HighQuality; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 60; text_style.letter_spacing = 0; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText( u"line1\nline2 test1 test2 test3 test4 test5 test6 test7\nline3\n\nline4 " "test1 test2 test3 test4"); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() - 300); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_TRUE(Snapshot()); ASSERT_EQ(paragraph->records_.size(), 6ull); EXPECT_DOUBLE_EQ(paragraph->records_[0].offset().x(), 0); EXPECT_DOUBLE_EQ(paragraph->records_[1].offset().x(), 0); EXPECT_DOUBLE_EQ(paragraph->records_[1].offset().y(), 126); EXPECT_DOUBLE_EQ(paragraph->records_[2].offset().x(), 0); EXPECT_DOUBLE_EQ(paragraph->records_[3].offset().x(), 0); EXPECT_DOUBLE_EQ(paragraph->records_[4].offset().x(), 0); EXPECT_DOUBLE_EQ(paragraph->records_[3].offset().y(), 266); EXPECT_DOUBLE_EQ(paragraph->records_[5].offset().x(), 0); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(EmojiParagraph)) { const char* text = "😀😃😄😁😆😅😂🤣☺😇🙂😍😡😟😢😻👽💩👍👎🙏👌👋👄👁👦👼👨‍🚀👨‍🚒🙋‍♂️👳👨‍👨‍👧‍👧\ 💼👡👠☂🐶🐰🐻🐼🐷🐒🐵🐔🐧🐦🐋🐟🐡🕸🐌🐴🐊🐄🐪🐘🌸🌏🔥🌟🌚🌝💦💧\ ❄🍕🍔🍟🥝🍱🕶🎩🏈⚽🚴‍♀️🎻🎼🎹🚨🚎🚐⚓🛳🚀🚁🏪🏢🖱⏰📱💾💉📉🛏🔑🔓\ 📁🗓📊❤💯🚫🔻♠♣🕓❗🏳🏁🏳️‍🌈🇮🇹🇱🇷🇺🇸🇬🇧🇨🇳🇧🇴"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.color = SK_ColorBLACK; text_style.font_families = std::vector(1, "Noto Color Emoji"); text_style.font_size = 50; text_style.decoration = TextDecoration::kUnderline; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_TRUE(Snapshot()); for (size_t i = 0; i < u16_text.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text[i]); } ASSERT_EQ(paragraph->records_.size(), 8ull); EXPECT_EQ(paragraph->records_[0].line(), 0ull); EXPECT_EQ(paragraph->records_[1].line(), 1ull); EXPECT_EQ(paragraph->records_[2].line(), 2ull); EXPECT_EQ(paragraph->records_[3].line(), 3ull); EXPECT_EQ(paragraph->records_[7].line(), 7ull); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(EmojiMultiLineRectsParagraph)) { // clang-format off const char* text = "👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧i🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸" "👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸" "👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸" "👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸👩‍👩‍👦👩‍👩‍👧‍👧🇺🇸" "❄🍕🍔🍟🥝🍱🕶🎩🏈⚽🚴‍♀️🎻🎼🎹🚨🚎🚐⚓🛳🚀🚁🏪🏢🖱⏰📱💾💉📉🛏🔑🔓" "📁🗓📊❤💯🚫🔻♠♣🕓❗🏳🏁🏳️‍🌈🇮🇹🇱🇷🇺🇸🇬🇧🇨🇳🇧🇴"; // clang-format on auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.color = SK_ColorBLACK; text_style.font_families = std::vector(1, "Noto Color Emoji"); text_style.font_size = 50; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() - 300); paragraph->Paint(GetCanvas(), 0, 0); for (size_t i = 0; i < u16_text.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text[i]); } ASSERT_EQ(paragraph->records_.size(), 10ull); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kTight; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); // Ligature style indexing. boxes = paragraph->GetRectsForRange(0, 119, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 2ull); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 334.61475); boxes = paragraph->GetRectsForRange(122, 132, rect_height_style, rect_width_style); paint.setColor(SK_ColorBLUE); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 357.95996); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 418.79901); // GetPositionForCoordinates should not return inter-emoji positions. boxes = paragraph->GetRectsForRange( 0, paragraph->GetGlyphPositionAtCoordinate(610, 100).position, rect_height_style, rect_width_style); paint.setColor(SK_ColorGREEN); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 2ull); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 0); // The following is expected to change to a higher value when // rounding up is added to getGlyphPositionForCoordinate. EXPECT_FLOAT_EQ(boxes[1].rect.right(), 560.28516); boxes = paragraph->GetRectsForRange( 0, paragraph->GetGlyphPositionAtCoordinate(580, 100).position, rect_height_style, rect_width_style); paint.setColor(SK_ColorGREEN); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 2ull); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 560.28516); boxes = paragraph->GetRectsForRange( 0, paragraph->GetGlyphPositionAtCoordinate(560, 100).position, rect_height_style, rect_width_style); paint.setColor(SK_ColorGREEN); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 2ull); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 0); // The following is expected to change to the 560.28516 value when // rounding up is added to getGlyphPositionForCoordinate. EXPECT_FLOAT_EQ(boxes[1].rect.right(), 498.03125); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, HyphenBreakParagraph) { const char* text = "A " "very-very-long-Hyphen-word-to-see-where-this-will-wrap-or-if-it-will-at-" "all-and-if-it-does-thent-hat-" "would-be-a-good-thing-because-the-breaking."; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.break_strategy = minikin::kBreakStrategy_HighQuality; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 31; text_style.letter_spacing = 0; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() / 2); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_TRUE(Snapshot()); ASSERT_EQ(paragraph->text_.size(), std::string{text}.length()); for (size_t i = 0; i < u16_text.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text[i]); } ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull); ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull); ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style)); ASSERT_EQ(paragraph->records_[0].style().color, text_style.color); ASSERT_EQ(paragraph->GetLineCount(), 5ull); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, RepeatLayoutParagraph) { 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"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.break_strategy = minikin::kBreakStrategy_HighQuality; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 31; text_style.letter_spacing = 0; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); // First Layout. auto paragraph = BuildParagraph(builder); paragraph->Layout(300); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_TRUE(Snapshot()); ASSERT_EQ(paragraph->text_.size(), std::string{text}.length()); for (size_t i = 0; i < u16_text.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text[i]); } ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull); ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull); ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style)); ASSERT_EQ(paragraph->records_[0].style().color, text_style.color); ASSERT_EQ(paragraph->GetLineCount(), 12ull); // Second Layout. SetUp(); paragraph->Layout(600); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_TRUE(Snapshot()); ASSERT_EQ(paragraph->text_.size(), std::string{text}.length()); for (size_t i = 0; i < u16_text.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text[i]); } ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull); ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull); ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style)); ASSERT_EQ(paragraph->records_[0].style().color, text_style.color); ASSERT_EQ(paragraph->GetLineCount(), 6ull); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, Ellipsize) { 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 necessary. Very short. "; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.ellipsis = u"\u2026"; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 0, 0); ASSERT_TRUE(Snapshot()); // Check that the ellipsizer limited the text to one line and did not wrap // to a second line. ASSERT_EQ(paragraph->records_.size(), 1ull); } // Test for shifting when identical runs of text are built as multiple runs. TEST_F(ParagraphTest, UnderlineShiftParagraph) { const char* text1 = "fluttser "; auto icu_text1 = icu::UnicodeString::fromUTF8(text1); std::u16string u16_text1(icu_text1.getBuffer(), icu_text1.getBuffer() + icu_text1.length()); const char* text2 = "mdje"; auto icu_text2 = icu::UnicodeString::fromUTF8(text2); std::u16string u16_text2(icu_text2.getBuffer(), icu_text2.getBuffer() + icu_text2.length()); const char* text3 = "fluttser mdje"; auto icu_text3 = icu::UnicodeString::fromUTF8(text3); std::u16string u16_text3(icu_text3.getBuffer(), icu_text3.getBuffer() + icu_text3.length()); // Construct multi-run paragraph. txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 2; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style1; text_style1.color = SK_ColorBLACK; text_style1.font_families = std::vector(1, "Roboto"); builder.PushStyle(text_style1); builder.AddText(u16_text1); txt::TextStyle text_style2; text_style2.color = SK_ColorBLACK; text_style2.font_families = std::vector(1, "Roboto"); text_style2.decoration = TextDecoration::kUnderline; text_style2.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style2); builder.AddText(u16_text2); builder.Pop(); // Construct single run paragraph. txt::ParagraphBuilderTxt builder2(paragraph_style, GetTestFontCollection()); builder2.PushStyle(text_style1); builder2.AddText(u16_text3); builder2.Pop(); // Build multi-run paragraph auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 0, 0); // Build single-run paragraph auto paragraph2 = BuildParagraph(builder2); paragraph2->Layout(GetTestCanvasWidth()); paragraph2->Paint(GetCanvas(), 0, 25); ASSERT_TRUE(Snapshot()); ASSERT_EQ(paragraph->records_[0].GetRunWidth() + paragraph->records_[1].GetRunWidth(), paragraph2->records_[0].GetRunWidth()); auto rects1 = paragraph->GetRectsForRange(0, 12, Paragraph::RectHeightStyle::kMax, Paragraph::RectWidthStyle::kTight); auto rects2 = paragraph2->GetRectsForRange(0, 12, Paragraph::RectHeightStyle::kMax, Paragraph::RectWidthStyle::kTight); for (size_t i = 0; i < 12; ++i) { auto r1 = GetCoordinatesForGlyphPosition(*paragraph, i); auto r2 = GetCoordinatesForGlyphPosition(*paragraph2, i); ASSERT_EQ(r1.fLeft, r2.fLeft); ASSERT_EQ(r1.fRight, r2.fRight); } } TEST_F(ParagraphTest, SimpleShadow) { const char* text = "Hello World Text Dialog"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.color = SK_ColorBLACK; text_style.text_shadows.emplace_back(SK_ColorBLACK, SkPoint::Make(2.0, 2.0), 1.0); builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 10.0, 15.0); ASSERT_EQ(paragraph->text_.size(), std::string{text}.length()); for (size_t i = 0; i < u16_text.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text[i]); } ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull); ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull); ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style)); ASSERT_EQ(paragraph->records_[0].style().color, text_style.color); ASSERT_EQ(paragraph->records_[0].style().text_shadows.size(), 1ull); ASSERT_EQ(paragraph->records_[0].style().text_shadows[0], text_style.text_shadows[0]); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, ComplexShadow) { const char* text = "Text Chunk "; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.color = SK_ColorBLACK; text_style.text_shadows.emplace_back(SK_ColorBLACK, SkPoint::Make(2.0, 2.0), 1.0); builder.PushStyle(text_style); builder.AddText(u16_text); text_style.text_shadows.emplace_back(SK_ColorRED, SkPoint::Make(2.0, 2.0), 5.0); text_style.text_shadows.emplace_back(SK_ColorGREEN, SkPoint::Make(10.0, -5.0), 3.0); builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); builder.AddText(u16_text); text_style.text_shadows.emplace_back(SK_ColorGREEN, SkPoint::Make(0.0, -1.0), 0.0); builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 10.0, 15.0); ASSERT_EQ(paragraph->text_.size(), std::string{text}.length() * 5); for (size_t i = 0; i < u16_text.length(); i++) { ASSERT_EQ(paragraph->text_[i], u16_text[i]); } ASSERT_EQ(paragraph->records_[0].style().text_shadows.size(), 1ull); ASSERT_EQ(paragraph->records_[1].style().text_shadows.size(), 3ull); ASSERT_EQ(paragraph->records_[2].style().text_shadows.size(), 1ull); ASSERT_EQ(paragraph->records_[3].style().text_shadows.size(), 4ull); ASSERT_EQ(paragraph->records_[4].style().text_shadows.size(), 1ull); for (size_t i = 0; i < 1; ++i) ASSERT_EQ(paragraph->records_[0].style().text_shadows[i], text_style.text_shadows[i]); for (size_t i = 0; i < 3; ++i) ASSERT_EQ(paragraph->records_[1].style().text_shadows[i], text_style.text_shadows[i]); for (size_t i = 0; i < 1; ++i) ASSERT_EQ(paragraph->records_[2].style().text_shadows[i], text_style.text_shadows[i]); for (size_t i = 0; i < 4; ++i) ASSERT_EQ(paragraph->records_[3].style().text_shadows[i], text_style.text_shadows[i]); for (size_t i = 0; i < 1; ++i) ASSERT_EQ(paragraph->records_[4].style().text_shadows[i], text_style.text_shadows[i]); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, BaselineParagraph) { const char* text = "左線読設Byg後碁給能上目秘使約。満毎冠行来昼本可必図将発確年。今属場育" "図情闘陰野高備込制詩西校客。審対江置講今固残必託地集済決維駆年策。立得"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 14; paragraph_style.text_align = TextAlign::justify; paragraph_style.height = 1.5; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.color = SK_ColorBLACK; text_style.font_size = 55; text_style.letter_spacing = 2; text_style.font_families = std::vector(1, "Source Han Serif CN"); text_style.decoration_style = txt::TextDecorationStyle::kSolid; text_style.decoration_color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth() - 100); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); paint.setColor(SK_ColorRED); GetCanvas()->drawLine(0, paragraph->GetIdeographicBaseline(), paragraph->GetMaxWidth(), paragraph->GetIdeographicBaseline(), paint); paint.setColor(SK_ColorGREEN); GetCanvas()->drawLine(0, paragraph->GetAlphabeticBaseline(), paragraph->GetMaxWidth(), paragraph->GetAlphabeticBaseline(), paint); ASSERT_DOUBLE_EQ(paragraph->GetIdeographicBaseline(), 79.035000801086426); ASSERT_DOUBLE_EQ(paragraph->GetAlphabeticBaseline(), 63.305000305175781); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, FontFallbackParagraph) { const char* text = "Roboto 字典 "; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); const char* text2 = "Homemade Apple 字典"; icu_text = icu::UnicodeString::fromUTF8(text2); std::u16string u16_text2(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); const char* text3 = "Chinese 字典"; icu_text = icu::UnicodeString::fromUTF8(text3); std::u16string u16_text3(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; // No chinese fallback provided, should not be able to render the chinese. text_style.font_families = std::vector(1, "Not a real font"); text_style.font_families.push_back("Also a fake font"); text_style.font_families.push_back("So fake it is obvious"); text_style.font_families.push_back("Next one should be a real font..."); text_style.font_families.push_back("Roboto"); text_style.font_families.push_back("another fake one in between"); text_style.font_families.push_back("Homemade Apple"); text_style.color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text); // Japanese version of the chinese should be rendered. text_style.font_families = std::vector(1, "Not a real font"); text_style.font_families.push_back("Also a fake font"); text_style.font_families.push_back("So fake it is obvious"); text_style.font_families.push_back("Homemade Apple"); text_style.font_families.push_back("Next one should be a real font..."); text_style.font_families.push_back("Roboto"); text_style.font_families.push_back("another fake one in between"); text_style.font_families.push_back("Noto Sans CJK JP"); text_style.font_families.push_back("Source Han Serif CN"); text_style.color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text2); // Chinese font defiend first text_style.font_families = std::vector(1, "Not a real font"); text_style.font_families.push_back("Also a fake font"); text_style.font_families.push_back("So fake it is obvious"); text_style.font_families.push_back("Homemade Apple"); text_style.font_families.push_back("Next one should be a real font..."); text_style.font_families.push_back("Roboto"); text_style.font_families.push_back("another fake one in between"); text_style.font_families.push_back("Source Han Serif CN"); text_style.font_families.push_back("Noto Sans CJK JP"); text_style.color = SK_ColorBLACK; builder.PushStyle(text_style); builder.AddText(u16_text3); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 10.0, 15.0); ASSERT_TRUE(Snapshot()); ASSERT_EQ(paragraph->records_.size(), 5ull); ASSERT_DOUBLE_EQ(paragraph->records_[0].GetRunWidth(), 64.19921875); ASSERT_DOUBLE_EQ(paragraph->records_[1].GetRunWidth(), 139.1171875); ASSERT_DOUBLE_EQ(paragraph->records_[2].GetRunWidth(), 28); ASSERT_DOUBLE_EQ(paragraph->records_[3].GetRunWidth(), 62.24609375); ASSERT_DOUBLE_EQ(paragraph->records_[4].GetRunWidth(), 28); // When a different font is resolved, then the metrics are different. ASSERT_TRUE(paragraph->records_[2].metrics().fTop - paragraph->records_[4].metrics().fTop != 0); ASSERT_TRUE(paragraph->records_[2].metrics().fAscent - paragraph->records_[4].metrics().fAscent != 0); ASSERT_TRUE(paragraph->records_[2].metrics().fDescent - paragraph->records_[4].metrics().fDescent != 0); ASSERT_TRUE(paragraph->records_[2].metrics().fBottom - paragraph->records_[4].metrics().fBottom != 0); ASSERT_TRUE(paragraph->records_[2].metrics().fAvgCharWidth - paragraph->records_[4].metrics().fAvgCharWidth != 0); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutParagraph1)) { // The chinese extra height should be absorbed by the strut. const char* text = "01234満毎冠p来É本可\nabcd\n満毎É行p昼本可"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; paragraph_style.strut_font_families = std::vector(1, "BlahFake"); paragraph_style.strut_font_families.push_back("ahem"); paragraph_style.strut_font_size = 50; paragraph_style.strut_height = 1.8; paragraph_style.strut_has_height_override = true; paragraph_style.strut_leading = 0.1; paragraph_style.strut_enabled = true; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "ahem"); text_style.font_families.push_back("ahem"); text_style.font_size = 50; text_style.letter_spacing = 0; text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = .5; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kTight; Paragraph::RectHeightStyle rect_height_max_style = Paragraph::RectHeightStyle::kMax; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_NEAR(boxes[0].rect.top(), 34.5, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50); EXPECT_NEAR(boxes[0].rect.bottom(), 84.5, 0.0001); boxes = paragraph->GetRectsForRange(0, 1, rect_height_max_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_NEAR(boxes[0].rect.top(), 34.5, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 95); boxes = paragraph->GetRectsForRange(6, 10, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300); EXPECT_NEAR(boxes[0].rect.top(), 34.5, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500); EXPECT_NEAR(boxes[0].rect.bottom(), 84.5, 0.0001); ; boxes = paragraph->GetRectsForRange(6, 10, rect_height_max_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300); EXPECT_NEAR(boxes[0].rect.top(), 34.5, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 95); boxes = paragraph->GetRectsForRange(14, 16, rect_height_max_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_NEAR(boxes[0].rect.top(), 224.5, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 100); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 285); boxes = paragraph->GetRectsForRange(20, 25, rect_height_max_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 50); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 319.5); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 300); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 380); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutParagraph2)) { // This string is all one size and smaller than the strut metrics. const char* text = "01234ABCDEFGH\nabcd\nABCDEFGH"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; paragraph_style.strut_font_families = std::vector(1, "ahem"); paragraph_style.strut_font_size = 50; paragraph_style.strut_height = 1.6; paragraph_style.strut_has_height_override = true; paragraph_style.strut_enabled = true; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "ahem"); text_style.font_families.push_back("ahem"); text_style.font_size = 50; text_style.letter_spacing = 0; text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kTight; Paragraph::RectHeightStyle rect_height_max_style = Paragraph::RectHeightStyle::kMax; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_NEAR(boxes[0].rect.top(), 24, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50); EXPECT_NEAR(boxes[0].rect.bottom(), 74, 0.0001); boxes = paragraph->GetRectsForRange(0, 1, rect_height_max_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_NEAR(boxes[0].rect.top(), 24, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80); boxes = paragraph->GetRectsForRange(6, 10, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300); EXPECT_NEAR(boxes[0].rect.top(), 24, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500); EXPECT_NEAR(boxes[0].rect.bottom(), 74, 0.0001); boxes = paragraph->GetRectsForRange(6, 10, rect_height_max_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300); EXPECT_NEAR(boxes[0].rect.top(), 24, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80); boxes = paragraph->GetRectsForRange(14, 16, rect_height_max_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_NEAR(boxes[0].rect.top(), 184, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 100); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 240); boxes = paragraph->GetRectsForRange(20, 25, rect_height_max_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 50); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 264); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 300); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 320); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutParagraph3)) { // The strut is too small to absorb the extra chinese height, but the english // second line height is increased due to strut. const char* text = "01234満毎p行来昼本可\nabcd\n満毎冠行来昼本可"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; paragraph_style.strut_font_families = std::vector(1, "ahem"); paragraph_style.strut_font_size = 50; paragraph_style.strut_height = 1.2; paragraph_style.strut_has_height_override = true; paragraph_style.strut_enabled = true; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "ahem"); text_style.font_families.push_back("ahem"); text_style.font_size = 50; text_style.letter_spacing = 0; text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kTight; Paragraph::RectHeightStyle rect_height_max_style = Paragraph::RectHeightStyle::kMax; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_NEAR(boxes[0].rect.top(), 8, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50); EXPECT_NEAR(boxes[0].rect.bottom(), 58, 0.0001); boxes = paragraph->GetRectsForRange(0, 1, rect_height_max_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_NEAR(boxes[0].rect.top(), 8, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 60); boxes = paragraph->GetRectsForRange(6, 10, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300); EXPECT_NEAR(boxes[0].rect.top(), 8, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500); EXPECT_NEAR(boxes[0].rect.bottom(), 58, 0.0001); boxes = paragraph->GetRectsForRange(6, 10, rect_height_max_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300); EXPECT_NEAR(boxes[0].rect.top(), 8, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 60); boxes = paragraph->GetRectsForRange(14, 16, rect_height_max_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 128); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 100); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 180); boxes = paragraph->GetRectsForRange(20, 25, rect_height_max_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 50); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 188); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 300); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 240); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutForceParagraph)) { // The strut is too small to absorb the extra chinese height, but the english // second line height is increased due to strut. const char* text = "01234満毎冠行来昼本可\nabcd\n満毎冠行来昼本可"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; paragraph_style.strut_font_families = std::vector(1, "ahem"); paragraph_style.strut_font_size = 50; paragraph_style.strut_height = 1.5; paragraph_style.strut_has_height_override = true; paragraph_style.strut_leading = 0.1; paragraph_style.force_strut_height = true; paragraph_style.strut_enabled = true; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "ahem"); text_style.font_families.push_back("ahem"); text_style.font_size = 50; text_style.letter_spacing = 0; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kTight; Paragraph::RectHeightStyle rect_height_max_style = Paragraph::RectHeightStyle::kMax; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_NEAR(boxes[0].rect.top(), 22.5, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50); EXPECT_NEAR(boxes[0].rect.bottom(), 72.5, 0.0001); boxes = paragraph->GetRectsForRange(0, 1, rect_height_max_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_NEAR(boxes[0].rect.top(), 22.5, 0.0001); ; EXPECT_FLOAT_EQ(boxes[0].rect.right(), 50); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80); boxes = paragraph->GetRectsForRange(6, 10, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300); EXPECT_NEAR(boxes[0].rect.top(), 22.5, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500); EXPECT_NEAR(boxes[0].rect.bottom(), 72.5, 0.0001); boxes = paragraph->GetRectsForRange(6, 10, rect_height_max_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 300); EXPECT_NEAR(boxes[0].rect.top(), 22.5, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 500); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80); boxes = paragraph->GetRectsForRange(14, 16, rect_height_max_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_NEAR(boxes[0].rect.top(), 182.5, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 100); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 240); boxes = paragraph->GetRectsForRange(20, 25, rect_height_max_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 50); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 262.5); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 300); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 320); ASSERT_TRUE(Snapshot()); } // The height override is disabled for this test. Direct metrics from the font. TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutDefaultParagraph)) { const char* text = "01234満毎冠行来昼本可\nabcd\n満毎冠行来昼本可"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; paragraph_style.strut_font_families = std::vector(1, "ahem"); paragraph_style.strut_font_size = 50; paragraph_style.strut_height = 1.5; paragraph_style.strut_leading = 0.1; paragraph_style.force_strut_height = false; paragraph_style.strut_enabled = true; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "ahem"); text_style.font_families.push_back("ahem"); text_style.font_size = 20; text_style.letter_spacing = 0; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(550); paragraph->Paint(GetCanvas(), 0, 0); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(1); // Tests for GetRectsForRange() Paragraph::RectHeightStyle rect_height_style = Paragraph::RectHeightStyle::kTight; Paragraph::RectHeightStyle rect_height_strut_style = Paragraph::RectHeightStyle::kStrut; Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 0ull); boxes = paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_NEAR(boxes[0].rect.top(), 26.5, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 20); EXPECT_NEAR(boxes[0].rect.bottom(), 46.5, 0.0001); boxes = paragraph->GetRectsForRange(0, 2, rect_height_strut_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_NEAR(boxes[0].rect.top(), 2.5, 0.0001); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 40); EXPECT_NEAR(boxes[0].rect.bottom(), 52.5, 0.0001); ASSERT_TRUE(Snapshot()); } TEST_F(ParagraphTest, FontFeaturesParagraph) { const char* text = "12ab\n"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); txt::ParagraphStyle paragraph_style; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); text_style.color = SK_ColorBLACK; text_style.font_features.SetFeature("tnum", 1); builder.PushStyle(text_style); builder.AddText(u16_text); text_style.font_features.SetFeature("tnum", 0); text_style.font_features.SetFeature("pnum", 1); builder.PushStyle(text_style); builder.AddText(u16_text); builder.Pop(); builder.Pop(); auto paragraph = BuildParagraph(builder); paragraph->Layout(GetTestCanvasWidth()); paragraph->Paint(GetCanvas(), 10.0, 15.0); ASSERT_EQ(paragraph->glyph_lines_.size(), 3ull); // Tabular numbers should have equal widths. const txt::ParagraphTxt::GlyphLine& tnum_line = paragraph->glyph_lines_[0]; ASSERT_EQ(tnum_line.positions.size(), 4ull); EXPECT_FLOAT_EQ(tnum_line.positions[0].x_pos.width(), tnum_line.positions[1].x_pos.width()); // Proportional numbers should have variable widths. const txt::ParagraphTxt::GlyphLine& pnum_line = paragraph->glyph_lines_[1]; ASSERT_EQ(pnum_line.positions.size(), 4ull); EXPECT_NE(pnum_line.positions[0].x_pos.width(), pnum_line.positions[1].x_pos.width()); // Alphabetic characters should be unaffected. EXPECT_FLOAT_EQ(tnum_line.positions[2].x_pos.width(), pnum_line.positions[2].x_pos.width()); ASSERT_TRUE(Snapshot()); } } // namespace txt