From 75752cc8d28e9fec7738b763e02a7eb126cd0a5f Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Tue, 6 Jun 2017 11:08:00 -0700 Subject: [PATCH] Support for 'fake bold' text and additional tests Change-Id: Ic9863052365316ea188fcf79b15378be90f440f6 --- engine/src/flutter/src/BUILD.gn | 1 + engine/src/flutter/src/font_collection.cc | 8 +- engine/src/flutter/src/font_collection.h | 12 ++ engine/src/flutter/src/paragraph.cc | 3 +- engine/src/flutter/src/text_style.h | 1 + .../tests/txt/font_collection_unittests.cc | 36 +++++- .../flutter/tests/txt/paragraph_unittests.cc | 113 ++++++++++++++++-- 7 files changed, 160 insertions(+), 14 deletions(-) diff --git a/engine/src/flutter/src/BUILD.gn b/engine/src/flutter/src/BUILD.gn index e8520ec113..2d5792f88a 100644 --- a/engine/src/flutter/src/BUILD.gn +++ b/engine/src/flutter/src/BUILD.gn @@ -40,5 +40,6 @@ source_set("src") { deps = [ "//lib/txt/libs/minikin", "//third_party/skia", + "//third_party/gtest", ] } diff --git a/engine/src/flutter/src/font_collection.cc b/engine/src/flutter/src/font_collection.cc index dfbfbc14b2..6763617d71 100644 --- a/engine/src/flutter/src/font_collection.cc +++ b/engine/src/flutter/src/font_collection.cc @@ -36,6 +36,10 @@ FontCollection::FontCollection() = default; FontCollection::~FontCollection() = default; +const std::string FontCollection::ProcessFamilyName(const std::string& family) { + return family.length() == 0 ? DEFAULT_FAMILY_NAME : family; +} + std::shared_ptr FontCollection::GetMinikinFontCollectionForFamily(const std::string& family, const std::string& dir) { @@ -51,8 +55,8 @@ FontCollection::GetMinikinFontCollectionForFamily(const std::string& family, // crashes when passed a null string. This seems to be a bug in Skia as // SkFontMgr explicitly says passing in nullptr gives the default font. - auto font_style_set = skia_font_manager->matchFamily( - family.length() == 0 ? "Roboto" : family.c_str()); + auto font_style_set = + skia_font_manager->matchFamily(ProcessFamilyName(family).c_str()); FTL_DCHECK(font_style_set != nullptr); std::vector minikin_fonts; diff --git a/engine/src/flutter/src/font_collection.h b/engine/src/flutter/src/font_collection.h index a85963a6bf..b78de954d8 100644 --- a/engine/src/flutter/src/font_collection.h +++ b/engine/src/flutter/src/font_collection.h @@ -17,11 +17,14 @@ #ifndef LIB_TXT_SRC_FONT_COLLECTION_H_ #define LIB_TXT_SRC_FONT_COLLECTION_H_ +#define DEFAULT_FAMILY_NAME "Roboto" + #include #include #include #include "lib/ftl/macros.h" +#include "lib/txt/tests/txt/render_test.h" #include "minikin/FontCollection.h" #include "minikin/FontFamily.h" @@ -38,8 +41,17 @@ class FontCollection { std::shared_ptr GetMinikinFontCollectionForFamily( const std::string& family, const std::string& dir = ""); + // Temporarily public. + const std::string ProcessFamilyName(const std::string& family); + + // For Testing. Temporarily public. + static const std::string GetDefaultFamilyName() { + return DEFAULT_FAMILY_NAME; + }; private: + friend RenderTest; + // TODO(chinmaygarde): Caches go here. FTL_DISALLOW_COPY_AND_ASSIGN(FontCollection); }; diff --git a/engine/src/flutter/src/paragraph.cc b/engine/src/flutter/src/paragraph.cc index 705a137921..44caeada36 100644 --- a/engine/src/flutter/src/paragraph.cc +++ b/engine/src/flutter/src/paragraph.cc @@ -90,11 +90,12 @@ void GetFontAndMinikinPaint(const TextStyle& style, *font = minikin::FontStyle(GetWeight(style), GetItalic(style)); paint->size = style.font_size; paint->letterSpacing = style.letter_spacing; - // TODO(abarth): font_family, word_spacing. + // TODO(abarth): word_spacing. } void GetPaint(const TextStyle& style, SkPaint* paint) { paint->setTextSize(style.font_size); + paint->setFakeBoldText(style.fake_bold); } } // namespace diff --git a/engine/src/flutter/src/text_style.h b/engine/src/flutter/src/text_style.h index 2b6c2cc632..21c122abfe 100644 --- a/engine/src/flutter/src/text_style.h +++ b/engine/src/flutter/src/text_style.h @@ -33,6 +33,7 @@ class TextStyle { // TextDecorationStyle decoration_style FontWeight font_weight = FontWeight::w400; FontStyle font_style = FontStyle::normal; + bool fake_bold = false; // TextBaseline text_baseline; std::string font_family = ""; double font_size = 14.0; diff --git a/engine/src/flutter/tests/txt/font_collection_unittests.cc b/engine/src/flutter/tests/txt/font_collection_unittests.cc index 1be73be10f..1851f04af9 100644 --- a/engine/src/flutter/tests/txt/font_collection_unittests.cc +++ b/engine/src/flutter/tests/txt/font_collection_unittests.cc @@ -21,9 +21,43 @@ #include "lib/txt/tests/txt/utils.h" TEST(FontCollection, HasDefaultRegistrations) { + std::string defaultFamilyName = txt::FontCollection::GetDefaultFamilyName(); + auto collection = txt::FontCollection::GetDefaultFontCollection() .GetMinikinFontCollectionForFamily("", txt::GetFontDir()); - + ASSERT_EQ( + defaultFamilyName, + txt::FontCollection::GetDefaultFontCollection().ProcessFamilyName("")); + ASSERT_NE(defaultFamilyName, + txt::FontCollection::GetDefaultFontCollection().ProcessFamilyName( + "NotARealFont!")); + ASSERT_EQ("NotARealFont!", + txt::FontCollection::GetDefaultFontCollection().ProcessFamilyName( + "NotARealFont!")); ASSERT_NE(collection.get(), nullptr); } + +TEST(FontCollection, GetMinikinFontCollections) { + std::string defaultFamilyName = txt::FontCollection::GetDefaultFamilyName(); + + auto collectionDef = + txt::FontCollection::GetDefaultFontCollection() + .GetMinikinFontCollectionForFamily("", txt::GetFontDir()); + auto collectionRoboto = + txt::FontCollection::GetDefaultFontCollection() + .GetMinikinFontCollectionForFamily("Roboto", txt::GetFontDir()); + auto collectionHomemadeApple = txt::FontCollection::GetDefaultFontCollection() + .GetMinikinFontCollectionForFamily( + "Homemade Apple", txt::GetFontDir()); + for (size_t base = 0; base < 50; base++) { + for (size_t variation = 0; variation < 50; variation++) { + ASSERT_EQ(collectionDef->hasVariationSelector(base, variation), + collectionRoboto->hasVariationSelector(base, variation)); + } + } + + ASSERT_NE(collectionDef, collectionHomemadeApple); + ASSERT_NE(collectionHomemadeApple, collectionRoboto); + ASSERT_NE(collectionDef.get(), nullptr); +} diff --git a/engine/src/flutter/tests/txt/paragraph_unittests.cc b/engine/src/flutter/tests/txt/paragraph_unittests.cc index dd98be7ea2..9aa842ee28 100644 --- a/engine/src/flutter/tests/txt/paragraph_unittests.cc +++ b/engine/src/flutter/tests/txt/paragraph_unittests.cc @@ -15,6 +15,8 @@ */ #include "lib/ftl/logging.h" +#include "lib/txt/src/font_style.h" +#include "lib/txt/src/font_weight.h" #include "lib/txt/tests/txt/utils.h" #include "paragraph.h" #include "paragraph_builder.h" @@ -42,7 +44,7 @@ TEST_F(RenderTest, SimpleParagraph) { paragraph->Layout(txt::ParagraphConstraints{GetTestCanvasWidth()}, txt::GetFontDir()); - paragraph->Paint(GetCanvas(), 10.0, 10.0); + paragraph->Paint(GetCanvas(), 10.0, 15.0); ASSERT_TRUE(Snapshot()); } @@ -68,25 +70,25 @@ TEST_F(RenderTest, SimpleRedParagraph) { paragraph->Layout(txt::ParagraphConstraints{GetTestCanvasWidth()}, txt::GetFontDir()); - paragraph->Paint(GetCanvas(), 10.0, 10.0); + paragraph->Paint(GetCanvas(), 10.0, 15.0); ASSERT_TRUE(Snapshot()); } -TEST_F(RenderTest, LongParagraph) { - const char* text1 = "RedRoboto"; +TEST_F(RenderTest, RainbowParagraph) { + const char* text1 = "RedRoboto "; auto icu_text1 = icu::UnicodeString::fromUTF8(text1); std::u16string u16_text1(icu_text1.getBuffer(), icu_text1.getBuffer() + icu_text1.length()); - const char* text2 = "BigGreenDefault"; + const char* text2 = "BigGreenDefault "; auto icu_text2 = icu::UnicodeString::fromUTF8(text2); std::u16string u16_text2(icu_text2.getBuffer(), icu_text2.getBuffer() + icu_text2.length()); - const char* text3 = "DefcolorHomemadeApple"; + const char* text3 = "DefcolorHomemadeApple "; auto icu_text3 = icu::UnicodeString::fromUTF8(text3); std::u16string u16_text3(icu_text3.getBuffer(), icu_text3.getBuffer() + icu_text3.length()); - const char* text4 = "SmallBlueRoboto"; + const char* text4 = "SmallBlueRoboto "; auto icu_text4 = icu::UnicodeString::fromUTF8(text4); std::u16string u16_text4(icu_text4.getBuffer(), icu_text4.getBuffer() + icu_text4.length()); @@ -108,7 +110,9 @@ TEST_F(RenderTest, LongParagraph) { txt::TextStyle text_style2; text_style2.font_size = 30; // Letter spacing not yet implemented - text_style2.letter_spacing = 10; + text_style2.letter_spacing = 100; + text_style2.font_weight = txt::FontWeight::w600; + text_style2.fake_bold = true; text_style2.color = SK_ColorGREEN; builder.PushStyle(text_style2); @@ -128,7 +132,8 @@ TEST_F(RenderTest, LongParagraph) { builder.AddText(u16_text4); - // extra text to see if it goes to default + // Extra text to see if it goes to default when there is more text chunks than + // styles. builder.AddText(u16_text5); builder.Pop(); @@ -142,6 +147,7 @@ TEST_F(RenderTest, LongParagraph) { ASSERT_TRUE(Snapshot()); } +// Currently, this should render nothing without a supplied TextStyle. TEST_F(RenderTest, DefaultStyleParagraph) { const char* text = "No TextStyle! Uh Oh!"; auto icu_text = icu::UnicodeString::fromUTF8(text); @@ -162,7 +168,94 @@ TEST_F(RenderTest, DefaultStyleParagraph) { paragraph->Layout(txt::ParagraphConstraints{GetTestCanvasWidth()}, txt::GetFontDir()); - paragraph->Paint(GetCanvas(), 10.0, 10.0); + paragraph->Paint(GetCanvas(), 10.0, 15.0); + + ASSERT_TRUE(Snapshot()); +} + +TEST_F(RenderTest, 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::ParagraphBuilder builder(paragraph_style); + + txt::TextStyle text_style; + text_style.font_size = 60; + // Letter spacing not yet implemented + text_style.letter_spacing = 10; + text_style.font_weight = txt::FontWeight::w900; + text_style.fake_bold = true; + text_style.color = SK_ColorRED; + builder.PushStyle(text_style); + + builder.AddText(u16_text); + + builder.Pop(); + + auto paragraph = builder.Build(); + paragraph->Layout(txt::ParagraphConstraints{GetTestCanvasWidth()}, + txt::GetFontDir()); + + paragraph->Paint(GetCanvas(), 10.0, 60.0); + + ASSERT_TRUE(Snapshot()); +} + +TEST_F(RenderTest, LinebreakParagraph) { + const char* text = + "This is a very long sentence to test if the text will properly wrap " + "around and go to the next line. Sometimes, short sentence. Longer " + "sentences are okay too because they are nessecary. Very short." + "This is a very long sentence to test if the text will properly wrap " + "around and go to the next line. Sometimes, short sentence. Longer " + "sentences are okay too because they are nessecary. Very short." + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod " + "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim " + "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea " + "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate " + "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint " + "occaecat cupidatat non proident, sunt in culpa qui officia deserunt " + "mollit anim id est laborum." + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod " + "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim " + "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea " + "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate " + "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint " + "occaecat cupidatat non proident, sunt in culpa qui officia deserunt " + "mollit anim id est laborum." + "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; + txt::ParagraphBuilder builder(paragraph_style); + + txt::TextStyle text_style; + text_style.font_size = 26; + // Letter spacing not yet implemented + text_style.letter_spacing = 10; + text_style.color = SK_ColorBLACK; + builder.PushStyle(text_style); + + builder.AddText(u16_text); + + builder.Pop(); + + auto paragraph = builder.Build(); + paragraph->Layout(txt::ParagraphConstraints{GetTestCanvasWidth()}, + txt::GetFontDir()); + + paragraph->Paint(GetCanvas(), 5.0, 30.0); ASSERT_TRUE(Snapshot()); } \ No newline at end of file