diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 7d6275ae3408a..4bc31dd43629d 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -398,7 +398,6 @@ ../../../flutter/third_party/txt/.clang-format ../../../flutter/third_party/txt/.gitattributes ../../../flutter/third_party/txt/.gitignore -../../../flutter/third_party/txt/PATENTS ../../../flutter/third_party/txt/tests ../../../flutter/third_party/txt/third_party/fonts ../../../flutter/third_party/web_locale_keymap/CHANGELOG.md diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index d2468dfc5c775..c2433b64880dd 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1,48 +1,7 @@ ==================================================================================================== LIBRARY: txt -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/benchmarks/paint_record_benchmarks.cc -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/benchmarks/paragraph_benchmarks.cc -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/benchmarks/paragraph_builder_benchmarks.cc ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/benchmarks/skparagraph_benchmarks.cc ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/benchmarks/txt_run_all_benchmarks.cc -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/log/log.cc -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/log/log.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/CmapCoverage.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/CmapCoverage.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/Emoji.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/Emoji.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/FontCollection.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/FontCollection.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/FontFamily.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/FontFamily.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/FontLanguage.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/FontLanguage.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/FontLanguageListCache.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/FontLanguageListCache.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/FontUtils.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/FontUtils.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/GraphemeBreak.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/GraphemeBreak.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/HbFontCache.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/HbFontCache.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/Hyphenator.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/Hyphenator.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/Layout.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/Layout.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/LayoutUtils.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/LayoutUtils.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/LineBreaker.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/LineBreaker.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/Measurement.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/Measurement.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/MinikinFont.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/MinikinFont.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/MinikinInternal.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/MinikinInternal.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/SparseBitSet.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/SparseBitSet.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/WordBreaker.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/minikin/WordBreaker.h ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/skia/paragraph_builder_skia.cc ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/skia/paragraph_builder_skia.h ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/skia/paragraph_skia.cc @@ -55,27 +14,17 @@ ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutte ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/font_collection.h ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/font_features.cc ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/font_features.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/font_skia.cc -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/font_skia.h ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/font_style.h ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/font_weight.h ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/line_metrics.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/paint_record.cc -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/paint_record.h ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/paragraph.h ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/paragraph_builder.cc ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/paragraph_builder.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/paragraph_builder_txt.cc -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/paragraph_builder_txt.h ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/paragraph_style.cc ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/paragraph_style.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/paragraph_txt.cc -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/paragraph_txt.h ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/placeholder_run.cc ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/placeholder_run.h ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/run_metrics.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/styled_runs.cc -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/styled_runs.h ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/test_font_manager.cc ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/test_font_manager.h ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/text_baseline.h @@ -87,57 +36,9 @@ ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutte ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/text_style.h ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/typeface_font_asset_provider.cc ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/txt/typeface_font_asset_provider.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/utils/JenkinsHash.cpp -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/utils/JenkinsHash.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/utils/LinuxUtils.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/utils/LruCache.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/utils/MacUtils.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/utils/TypeHelpers.h -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/txt/src/utils/WindowsUtils.h TYPE: LicenseType.apache -FILE: ../../../flutter/third_party/txt/benchmarks/paint_record_benchmarks.cc -FILE: ../../../flutter/third_party/txt/benchmarks/paragraph_benchmarks.cc -FILE: ../../../flutter/third_party/txt/benchmarks/paragraph_builder_benchmarks.cc FILE: ../../../flutter/third_party/txt/benchmarks/skparagraph_benchmarks.cc FILE: ../../../flutter/third_party/txt/benchmarks/txt_run_all_benchmarks.cc -FILE: ../../../flutter/third_party/txt/src/log/log.cc -FILE: ../../../flutter/third_party/txt/src/log/log.h -FILE: ../../../flutter/third_party/txt/src/minikin/CmapCoverage.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/CmapCoverage.h -FILE: ../../../flutter/third_party/txt/src/minikin/Emoji.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/Emoji.h -FILE: ../../../flutter/third_party/txt/src/minikin/FontCollection.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/FontCollection.h -FILE: ../../../flutter/third_party/txt/src/minikin/FontFamily.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/FontFamily.h -FILE: ../../../flutter/third_party/txt/src/minikin/FontLanguage.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/FontLanguage.h -FILE: ../../../flutter/third_party/txt/src/minikin/FontLanguageListCache.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/FontLanguageListCache.h -FILE: ../../../flutter/third_party/txt/src/minikin/FontUtils.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/FontUtils.h -FILE: ../../../flutter/third_party/txt/src/minikin/GraphemeBreak.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/GraphemeBreak.h -FILE: ../../../flutter/third_party/txt/src/minikin/HbFontCache.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/HbFontCache.h -FILE: ../../../flutter/third_party/txt/src/minikin/Hyphenator.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/Hyphenator.h -FILE: ../../../flutter/third_party/txt/src/minikin/Layout.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/Layout.h -FILE: ../../../flutter/third_party/txt/src/minikin/LayoutUtils.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/LayoutUtils.h -FILE: ../../../flutter/third_party/txt/src/minikin/LineBreaker.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/LineBreaker.h -FILE: ../../../flutter/third_party/txt/src/minikin/Measurement.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/Measurement.h -FILE: ../../../flutter/third_party/txt/src/minikin/MinikinFont.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/MinikinFont.h -FILE: ../../../flutter/third_party/txt/src/minikin/MinikinInternal.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/MinikinInternal.h -FILE: ../../../flutter/third_party/txt/src/minikin/SparseBitSet.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/SparseBitSet.h -FILE: ../../../flutter/third_party/txt/src/minikin/WordBreaker.cpp -FILE: ../../../flutter/third_party/txt/src/minikin/WordBreaker.h FILE: ../../../flutter/third_party/txt/src/skia/paragraph_builder_skia.cc FILE: ../../../flutter/third_party/txt/src/skia/paragraph_builder_skia.h FILE: ../../../flutter/third_party/txt/src/skia/paragraph_skia.cc @@ -150,27 +51,17 @@ FILE: ../../../flutter/third_party/txt/src/txt/font_collection.cc FILE: ../../../flutter/third_party/txt/src/txt/font_collection.h FILE: ../../../flutter/third_party/txt/src/txt/font_features.cc FILE: ../../../flutter/third_party/txt/src/txt/font_features.h -FILE: ../../../flutter/third_party/txt/src/txt/font_skia.cc -FILE: ../../../flutter/third_party/txt/src/txt/font_skia.h FILE: ../../../flutter/third_party/txt/src/txt/font_style.h FILE: ../../../flutter/third_party/txt/src/txt/font_weight.h FILE: ../../../flutter/third_party/txt/src/txt/line_metrics.h -FILE: ../../../flutter/third_party/txt/src/txt/paint_record.cc -FILE: ../../../flutter/third_party/txt/src/txt/paint_record.h FILE: ../../../flutter/third_party/txt/src/txt/paragraph.h FILE: ../../../flutter/third_party/txt/src/txt/paragraph_builder.cc FILE: ../../../flutter/third_party/txt/src/txt/paragraph_builder.h -FILE: ../../../flutter/third_party/txt/src/txt/paragraph_builder_txt.cc -FILE: ../../../flutter/third_party/txt/src/txt/paragraph_builder_txt.h FILE: ../../../flutter/third_party/txt/src/txt/paragraph_style.cc FILE: ../../../flutter/third_party/txt/src/txt/paragraph_style.h -FILE: ../../../flutter/third_party/txt/src/txt/paragraph_txt.cc -FILE: ../../../flutter/third_party/txt/src/txt/paragraph_txt.h FILE: ../../../flutter/third_party/txt/src/txt/placeholder_run.cc FILE: ../../../flutter/third_party/txt/src/txt/placeholder_run.h FILE: ../../../flutter/third_party/txt/src/txt/run_metrics.h -FILE: ../../../flutter/third_party/txt/src/txt/styled_runs.cc -FILE: ../../../flutter/third_party/txt/src/txt/styled_runs.h FILE: ../../../flutter/third_party/txt/src/txt/test_font_manager.cc FILE: ../../../flutter/third_party/txt/src/txt/test_font_manager.h FILE: ../../../flutter/third_party/txt/src/txt/text_baseline.h @@ -182,13 +73,6 @@ FILE: ../../../flutter/third_party/txt/src/txt/text_style.cc FILE: ../../../flutter/third_party/txt/src/txt/text_style.h FILE: ../../../flutter/third_party/txt/src/txt/typeface_font_asset_provider.cc FILE: ../../../flutter/third_party/txt/src/txt/typeface_font_asset_provider.h -FILE: ../../../flutter/third_party/txt/src/utils/JenkinsHash.cpp -FILE: ../../../flutter/third_party/txt/src/utils/JenkinsHash.h -FILE: ../../../flutter/third_party/txt/src/utils/LinuxUtils.h -FILE: ../../../flutter/third_party/txt/src/utils/LruCache.h -FILE: ../../../flutter/third_party/txt/src/utils/MacUtils.h -FILE: ../../../flutter/third_party/txt/src/utils/TypeHelpers.h -FILE: ../../../flutter/third_party/txt/src/utils/WindowsUtils.h ---------------------------------------------------------------------------------------------------- Apache License Version 2.0, January 2004 diff --git a/common/config.gni b/common/config.gni index afb8f0b2b2c92..329f0bcdd0c2f 100644 --- a/common/config.gni +++ b/common/config.gni @@ -14,12 +14,6 @@ declare_args() { # The runtime mode ("debug", "profile", "release", or "jit_release") flutter_runtime_mode = "debug" - # Whether to link the Skia text shaper module into the engine - flutter_enable_skshaper = false - - # Whether to use the Skia text shaper module for all text rendering - flutter_always_use_skshaper = false - # Whether to use a prebuilt Dart SDK instead of building one. flutter_prebuilt_dart_sdk = false diff --git a/common/settings.h b/common/settings.h index 755621c0f6d9c..687822c6e0f90 100644 --- a/common/settings.h +++ b/common/settings.h @@ -205,9 +205,6 @@ struct Settings { // manager before creating the engine. bool prefetched_default_font_manager = false; - // Selects the SkParagraph implementation of the text layout engine. - bool enable_skparagraph = false; - // Enable the rendering of colors outside of the sRGB gamut. bool enable_wide_gamut = false; diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index b0c3ce3dfd4d1..3f12eed206863 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -182,12 +182,6 @@ source_set("ui") { if (!defined(defines)) { defines = [] } - if (flutter_enable_skshaper) { - defines += [ "FLUTTER_ENABLE_SKSHAPER" ] - } - if (flutter_always_use_skshaper) { - defines += [ "FLUTTER_ALWAYS_USE_SKSHAPER" ] - } if (is_win) { # Required for M_PI and others. defines += [ "_USE_MATH_DEFINES" ] diff --git a/lib/ui/text/paragraph.cc b/lib/ui/text/paragraph.cc index 4b3df6439186d..624ed145dcf38 100644 --- a/lib/ui/text/paragraph.cc +++ b/lib/ui/text/paragraph.cc @@ -65,13 +65,8 @@ void Paragraph::paint(Canvas* canvas, double x, double y) { } DisplayListBuilder* builder = canvas->builder(); - if (builder && m_paragraph->Paint(builder, x, y)) { - return; - } - // Fall back to SkCanvas if painting to DisplayListBuilder is not supported. - SkCanvas* sk_canvas = canvas->canvas(); - if (sk_canvas) { - m_paragraph->Paint(sk_canvas, x, y); + if (builder) { + m_paragraph->Paint(builder, x, y); } } diff --git a/lib/ui/text/paragraph_builder.cc b/lib/ui/text/paragraph_builder.cc index 82881ede24eda..4b1c07bc61712 100644 --- a/lib/ui/text/paragraph_builder.cc +++ b/lib/ui/text/paragraph_builder.cc @@ -297,23 +297,8 @@ ParagraphBuilder::ParagraphBuilder( ->client() ->GetFontCollection(); - typedef std::unique_ptr (*ParagraphBuilderFactory)( - const txt::ParagraphStyle& style, - std::shared_ptr font_collection); - ParagraphBuilderFactory factory = txt::ParagraphBuilder::CreateTxtBuilder; - -#if FLUTTER_ENABLE_SKSHAPER -#if FLUTTER_ALWAYS_USE_SKSHAPER - bool enable_skparagraph = true; -#else - bool enable_skparagraph = UIDartState::Current()->enable_skparagraph(); -#endif - if (enable_skparagraph) { - factory = txt::ParagraphBuilder::CreateSkiaBuilder; - } -#endif // FLUTTER_ENABLE_SKSHAPER - - m_paragraphBuilder = factory(style, font_collection.GetFontCollection()); + m_paragraphBuilder = txt::ParagraphBuilder::CreateSkiaBuilder( + style, font_collection.GetFontCollection()); } ParagraphBuilder::~ParagraphBuilder() = default; diff --git a/lib/ui/ui_dart_state.cc b/lib/ui/ui_dart_state.cc index 65cef346ec173..e66059fc515b3 100644 --- a/lib/ui/ui_dart_state.cc +++ b/lib/ui/ui_dart_state.cc @@ -60,7 +60,6 @@ UIDartState::UIDartState( LogMessageCallback log_message_callback, std::shared_ptr isolate_name_server, bool is_root_isolate, - bool enable_skparagraph, const UIDartState::Context& context) : add_callback_(std::move(add_callback)), remove_callback_(std::move(remove_callback)), @@ -69,7 +68,6 @@ UIDartState::UIDartState( unhandled_exception_callback_(std::move(unhandled_exception_callback)), log_message_callback_(std::move(log_message_callback)), isolate_name_server_(std::move(isolate_name_server)), - enable_skparagraph_(enable_skparagraph), context_(context) { AddOrRemoveTaskObserver(true /* add */); } @@ -234,10 +232,6 @@ void UIDartState::LogMessage(const std::string& tag, } } -bool UIDartState::enable_skparagraph() const { - return enable_skparagraph_; -} - Dart_Handle UIDartState::HandlePlatformMessage( std::unique_ptr message) { if (platform_configuration_) { diff --git a/lib/ui/ui_dart_state.h b/lib/ui/ui_dart_state.h index 6792d8471f9d5..c384cd420f1c3 100644 --- a/lib/ui/ui_dart_state.h +++ b/lib/ui/ui_dart_state.h @@ -153,8 +153,6 @@ class UIDartState : public tonic::DartState { // @param[in] message The message to be logged. void LogMessage(const std::string& tag, const std::string& message) const; - bool enable_skparagraph() const; - template static flutter::SkiaGPUObject CreateGPUObject(sk_sp object) { if (!object) { @@ -185,7 +183,6 @@ class UIDartState : public tonic::DartState { LogMessageCallback log_message_callback, std::shared_ptr isolate_name_server, bool is_root_isolate_, - bool enable_skparagraph, const UIDartState::Context& context); ~UIDartState() override; @@ -210,7 +207,6 @@ class UIDartState : public tonic::DartState { UnhandledExceptionCallback unhandled_exception_callback_; LogMessageCallback log_message_callback_; const std::shared_ptr isolate_name_server_; - const bool enable_skparagraph_; UIDartState::Context context_; void AddOrRemoveTaskObserver(bool add); diff --git a/runtime/dart_isolate.cc b/runtime/dart_isolate.cc index 6e4e3757cefc6..791ac03dbbf95 100644 --- a/runtime/dart_isolate.cc +++ b/runtime/dart_isolate.cc @@ -284,7 +284,6 @@ DartIsolate::DartIsolate(const Settings& settings, settings.log_message_callback, DartVMRef::GetIsolateNameServer(), is_root_isolate, - settings.enable_skparagraph, context), may_insecurely_connect_to_all_domains_( settings.may_insecurely_connect_to_all_domains), diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index 0bd2d9ee524ed..2d767835b696b 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -1425,36 +1425,6 @@ TEST_F(ShellTest, ReportTimingsIsCalledImmediatelyAfterTheFirstFrame) { ASSERT_EQ(timestamps.size(), FrameTiming::kCount); } -TEST_F(ShellTest, ReloadSystemFonts) { - auto settings = CreateSettingsForFixture(); - - fml::MessageLoop::EnsureInitializedForCurrentThread(); - auto task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); - TaskRunners task_runners("test", task_runner, task_runner, task_runner, - task_runner); - auto shell = CreateShell(settings, task_runners); - - auto fontCollection = GetFontCollection(shell.get()); - std::vector families(1, "Robotofake"); - auto font = - fontCollection->GetMinikinFontCollectionForFamilies(families, "en"); - if (font == nullptr) { - // The system does not have default font. Aborts this test. - return; - } - unsigned int id = font->getId(); - // The result should be cached. - font = fontCollection->GetMinikinFontCollectionForFamilies(families, "en"); - ASSERT_EQ(font->getId(), id); - bool result = shell->ReloadSystemFonts(); - - // The cache is cleared, and FontCollection will be assigned a new id. - font = fontCollection->GetMinikinFontCollectionForFamilies(families, "en"); - ASSERT_NE(font->getId(), id); - ASSERT_TRUE(result); - shell.reset(); -} - TEST_F(ShellTest, WaitForFirstFrame) { auto settings = CreateSettingsForFixture(); std::unique_ptr shell = CreateShell(settings); diff --git a/shell/common/switches.cc b/shell/common/switches.cc index 1aec89b79b170..6e8307ab4c936 100644 --- a/shell/common/switches.cc +++ b/shell/common/switches.cc @@ -443,10 +443,6 @@ Settings SettingsFromCommandLine(const fml::CommandLine& command_line) { settings.use_asset_fonts = !command_line.HasOption(FlagForSwitch(Switch::DisableAssetFonts)); - std::string enable_skparagraph = command_line.GetOptionValueWithDefault( - FlagForSwitch(Switch::EnableSkParagraph), ""); - settings.enable_skparagraph = enable_skparagraph != "false"; - settings.enable_impeller = command_line.HasOption(FlagForSwitch(Switch::EnableImpeller)); diff --git a/shell/common/switches.h b/shell/common/switches.h index ce27a02e0fa01..c6cb7f4d89cd3 100644 --- a/shell/common/switches.h +++ b/shell/common/switches.h @@ -257,9 +257,6 @@ DEF_SWITCH(OldGenHeapSize, DEF_SWITCH(ResourceCacheMaxBytesThreshold, "resource-cache-max-bytes-threshold", "The max bytes threshold of resource cache, or 0 for unlimited.") -DEF_SWITCH(EnableSkParagraph, - "enable-skparagraph", - "Selects the SkParagraph implementation of the text layout engine.") DEF_SWITCH(EnableImpeller, "enable-impeller", "Enable the Impeller renderer on supported platforms. Ignored if " diff --git a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java index b09be89e4b57f..5461838e7ad85 100644 --- a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java +++ b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java @@ -39,8 +39,6 @@ public class FlutterLoader { private static final String OLD_GEN_HEAP_SIZE_META_DATA_KEY = "io.flutter.embedding.android.OldGenHeapSize"; - private static final String ENABLE_SKPARAGRAPH_META_DATA_KEY = - "io.flutter.embedding.android.EnableSkParagraph"; private static final String ENABLE_IMPELLER_META_DATA_KEY = "io.flutter.embedding.android.EnableImpeller"; @@ -318,10 +316,6 @@ public void ensureInitializationComplete( shellArgs.add("--prefetched-default-font-manager"); - boolean enableSkParagraph = - metaData == null || metaData.getBoolean(ENABLE_SKPARAGRAPH_META_DATA_KEY, true); - shellArgs.add("--enable-skparagraph=" + enableSkParagraph); - if (metaData != null && metaData.getBoolean(ENABLE_IMPELLER_META_DATA_KEY, false)) { shellArgs.add("--enable-impeller"); } diff --git a/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java b/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java index 00518705ebef4..2e765dce06960 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java @@ -197,44 +197,6 @@ public void itSetsEnableImpellerFromMetaData() { assertTrue(arguments.contains(enableImpellerArg)); } - @Test - public void itSetsEnableSkParagraphByDefault() { - // SkParagraph is enabled by default - FlutterJNI mockFlutterJNI = mock(FlutterJNI.class); - FlutterLoader flutterLoader = new FlutterLoader(mockFlutterJNI); - FlutterLoader.Settings settings = new FlutterLoader.Settings(); - flutterLoader.startInitialization(ctx, settings); - flutterLoader.ensureInitializationComplete(ctx, null); - shadowOf(getMainLooper()).idle(); - - ArgumentCaptor shellArgsCaptor = ArgumentCaptor.forClass(String[].class); - verify(mockFlutterJNI, times(1)) - .init(eq(ctx), shellArgsCaptor.capture(), anyString(), anyString(), anyString(), anyLong()); - List arguments = Arrays.asList(shellArgsCaptor.getValue()); - assertTrue(arguments.contains("--enable-skparagraph=true")); - } - - @Test - public void itSetsEnableSkParagraphFromMetaData() { - // SkParagraph can be disabled using metadata. - FlutterJNI mockFlutterJNI = mock(FlutterJNI.class); - FlutterLoader flutterLoader = new FlutterLoader(mockFlutterJNI); - Bundle metaData = new Bundle(); - metaData.putBoolean("io.flutter.embedding.android.EnableSkParagraph", false); - ctx.getApplicationInfo().metaData = metaData; - - FlutterLoader.Settings settings = new FlutterLoader.Settings(); - flutterLoader.startInitialization(ctx, settings); - flutterLoader.ensureInitializationComplete(ctx, null); - shadowOf(getMainLooper()).idle(); - - ArgumentCaptor shellArgsCaptor = ArgumentCaptor.forClass(String[].class); - verify(mockFlutterJNI, times(1)) - .init(eq(ctx), shellArgsCaptor.capture(), anyString(), anyString(), anyString(), anyLong()); - List arguments = Arrays.asList(shellArgsCaptor.getValue()); - assertTrue(arguments.contains("--enable-skparagraph=false")); - } - @Test @TargetApi(23) @Config(sdk = 23) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm b/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm index 9ad9c1d89b3c7..f7d62e9c4cd8b 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm @@ -156,10 +156,6 @@ settings.may_insecurely_connect_to_all_domains = true; settings.domain_network_policy = ""; - // SkParagraph text layout library - NSNumber* enableSkParagraph = [mainBundle objectForInfoDictionaryKey:@"FLTEnableSkParagraph"]; - settings.enable_skparagraph = (enableSkParagraph != nil) ? enableSkParagraph.boolValue : true; - // Whether to enable Impeller. NSNumber* nsEnableWideGamut = [mainBundle objectForInfoDictionaryKey:@"FLTEnableWideGamut"]; // TODO(gaaclarke): Make this value `on` by default (pending memory audit). diff --git a/shell/platform/fuchsia/flutter/platform_view.cc b/shell/platform/fuchsia/flutter/platform_view.cc index 85d671c1e773f..42e4ca01858ca 100644 --- a/shell/platform/fuchsia/flutter/platform_view.cc +++ b/shell/platform/fuchsia/flutter/platform_view.cc @@ -657,7 +657,7 @@ bool PlatformView::HandleFuchsiaShaderWarmupChannelPlatformMessage( } auto completion_callback = [response = - message->response()](uint num_successes) { + message->response()](uint32_t num_successes) { std::ostringstream result_stream; result_stream << "[" << num_successes << "]"; diff --git a/third_party/txt/BUILD.gn b/third_party/txt/BUILD.gn index 3060859fe4773..ca3d6234f2c5f 100644 --- a/third_party/txt/BUILD.gn +++ b/third_party/txt/BUILD.gn @@ -37,12 +37,6 @@ config("allow_posix_names") { } } -config("define_skshaper") { - if (flutter_enable_skshaper) { - defines = [ "FLUTTER_ENABLE_SKSHAPER" ] - } -} - source_set("txt") { defines = [] if (flutter_use_fontconfig) { @@ -50,44 +44,10 @@ source_set("txt") { } sources = [ - "src/log/log.cc", - "src/log/log.h", - "src/minikin/CmapCoverage.cpp", - "src/minikin/CmapCoverage.h", - "src/minikin/Emoji.cpp", - "src/minikin/Emoji.h", - "src/minikin/FontCollection.cpp", - "src/minikin/FontCollection.h", - "src/minikin/FontFamily.cpp", - "src/minikin/FontFamily.h", - "src/minikin/FontLanguage.cpp", - "src/minikin/FontLanguage.h", - "src/minikin/FontLanguageListCache.cpp", - "src/minikin/FontLanguageListCache.h", - "src/minikin/FontUtils.cpp", - "src/minikin/FontUtils.h", - "src/minikin/GraphemeBreak.cpp", - "src/minikin/GraphemeBreak.h", - "src/minikin/HbFontCache.cpp", - "src/minikin/HbFontCache.h", - "src/minikin/Hyphenator.cpp", - "src/minikin/Hyphenator.h", - "src/minikin/Layout.cpp", - "src/minikin/Layout.h", - "src/minikin/LayoutUtils.cpp", - "src/minikin/LayoutUtils.h", - "src/minikin/LineBreaker.cpp", - "src/minikin/LineBreaker.h", - "src/minikin/Measurement.cpp", - "src/minikin/Measurement.h", - "src/minikin/MinikinFont.cpp", - "src/minikin/MinikinFont.h", - "src/minikin/MinikinInternal.cpp", - "src/minikin/MinikinInternal.h", - "src/minikin/SparseBitSet.cpp", - "src/minikin/SparseBitSet.h", - "src/minikin/WordBreaker.cpp", - "src/minikin/WordBreaker.h", + "src/skia/paragraph_builder_skia.cc", + "src/skia/paragraph_builder_skia.h", + "src/skia/paragraph_skia.cc", + "src/skia/paragraph_skia.h", "src/txt/asset_font_manager.cc", "src/txt/asset_font_manager.h", "src/txt/font_asset_provider.cc", @@ -96,28 +56,18 @@ source_set("txt") { "src/txt/font_collection.h", "src/txt/font_features.cc", "src/txt/font_features.h", - "src/txt/font_skia.cc", - "src/txt/font_skia.h", "src/txt/font_style.h", "src/txt/font_weight.h", "src/txt/line_metrics.h", - "src/txt/paint_record.cc", - "src/txt/paint_record.h", "src/txt/paragraph.h", "src/txt/paragraph_builder.cc", "src/txt/paragraph_builder.h", - "src/txt/paragraph_builder_txt.cc", - "src/txt/paragraph_builder_txt.h", "src/txt/paragraph_style.cc", "src/txt/paragraph_style.h", - "src/txt/paragraph_txt.cc", - "src/txt/paragraph_txt.h", "src/txt/placeholder_run.cc", "src/txt/placeholder_run.h", "src/txt/platform.h", "src/txt/run_metrics.h", - "src/txt/styled_runs.cc", - "src/txt/styled_runs.h", "src/txt/test_font_manager.cc", "src/txt/test_font_manager.h", "src/txt/text_baseline.h", @@ -129,19 +79,10 @@ source_set("txt") { "src/txt/text_style.h", "src/txt/typeface_font_asset_provider.cc", "src/txt/typeface_font_asset_provider.h", - "src/utils/JenkinsHash.cpp", - "src/utils/JenkinsHash.h", - "src/utils/LinuxUtils.h", - "src/utils/LruCache.h", - "src/utils/MacUtils.h", - "src/utils/TypeHelpers.h", - "src/utils/WindowsUtils.h", ] public_configs = [ ":txt_config" ] - configs += [ ":define_skshaper" ] - public_deps = [ "//flutter/display_list", "//flutter/fml", @@ -150,23 +91,15 @@ source_set("txt") { "//third_party/skia", ] - deps = [ "//third_party/skia" ] + deps = [ + "//third_party/skia", + "//third_party/skia/modules/skparagraph", + ] if (flutter_use_fontconfig) { deps += [ "//third_party/fontconfig" ] } - if (flutter_enable_skshaper) { - sources += [ - "src/skia/paragraph_builder_skia.cc", - "src/skia/paragraph_builder_skia.h", - "src/skia/paragraph_skia.cc", - "src/skia/paragraph_skia.h", - ] - - deps += [ "//third_party/skia/modules/skparagraph" ] - } - if (is_mac || is_ios) { sources += [ "src/txt/platform_mac.mm" ] deps += [ "//flutter/fml" ] @@ -185,179 +118,47 @@ source_set("txt") { } if (enable_unittests) { - txt_common_executable_deps = [ - "//flutter/fml", # For ICU initialization. - "//third_party/dart/runtime:libdart_jit", # For logging. - ] - test_fixtures("txt_fixtures") { - fixtures = [ - "third_party/fonts/Bold.ttf", - "third_party/fonts/Bold.ttx", - "third_party/fonts/BoldItalic.ttf", - "third_party/fonts/BoldItalic.ttx", - "third_party/fonts/ColorEmojiFont.ttf", - "third_party/fonts/ColorEmojiFont.ttx", - "third_party/fonts/ColorTextMixedEmojiFont.ttf", - "third_party/fonts/ColorTextMixedEmojiFont.ttx", - "third_party/fonts/DroidSerif.ttf", - "third_party/fonts/Emoji.ttf", - "third_party/fonts/Emoji.ttx", - "third_party/fonts/HomemadeApple.ttf", - "third_party/fonts/Italic.ttf", - "third_party/fonts/Italic.ttx", - "third_party/fonts/Ja.ttf", - "third_party/fonts/Ja.ttx", - "third_party/fonts/Katibeh-Regular.ttf", - "third_party/fonts/Ko.ttf", - "third_party/fonts/Ko.ttx", - "third_party/fonts/MultiAxis.ttf", - "third_party/fonts/MultiAxis.ttx", - "third_party/fonts/NoCmapFormat14.ttf", - "third_party/fonts/NoCmapFormat14.ttx", - "third_party/fonts/NoGlyphFont.ttf", - "third_party/fonts/NoGlyphFont.ttx", - "third_party/fonts/NotoColorEmoji.ttf", - "third_party/fonts/NotoNaskhArabic-Regular.ttf", - "third_party/fonts/NotoSansCJK-Regular.ttc", - "third_party/fonts/NotoSansKhmer-Regular.ttf", - "third_party/fonts/Regular.ttf", - "third_party/fonts/Regular.ttx", - "third_party/fonts/Roboto-Black.ttf", - "third_party/fonts/Roboto-BlackItalic.ttf", - "third_party/fonts/Roboto-Bold.ttf", - "third_party/fonts/Roboto-BoldItalic.ttf", - "third_party/fonts/Roboto-Italic.ttf", - "third_party/fonts/Roboto-Light.ttf", - "third_party/fonts/Roboto-LightItalic.ttf", - "third_party/fonts/Roboto-Medium.ttf", - "third_party/fonts/Roboto-MediumItalic.ttf", - "third_party/fonts/Roboto-Regular.ttf", - "third_party/fonts/Roboto-Thin.ttf", - "third_party/fonts/Roboto-ThinItalic.ttf", - "third_party/fonts/SourceHanSerifCN-Bold.otf", - "third_party/fonts/SourceHanSerifCN-Regular.otf", - "third_party/fonts/TextEmojiFont.ttf", - "third_party/fonts/TextEmojiFont.ttx", - "third_party/fonts/UnicodeBMPOnly.ttf", - "third_party/fonts/UnicodeBMPOnly.ttx", - "third_party/fonts/UnicodeBMPOnly2.ttf", - "third_party/fonts/UnicodeBMPOnly2.ttx", - "third_party/fonts/UnicodeUCS4.ttf", - "third_party/fonts/UnicodeUCS4.ttx", - "third_party/fonts/VariationSelectorTest-Regular.ttf", - "third_party/fonts/VariationSelectorTest-Regular.ttx", - "third_party/fonts/ZhHans.ttf", - "third_party/fonts/ZhHans.ttx", - "third_party/fonts/ZhHant.ttf", - "third_party/fonts/ZhHant.ttx", - "third_party/fonts/ahem.ttf", - "third_party/fonts/emoji.xml", - "third_party/fonts/itemize.xml", - ] + fixtures = [ "third_party/fonts/Roboto-Regular.ttf" ] } - source_set("txt_test_utils") { + executable("txt_benchmarks") { + testonly = true + sources = [ + "benchmarks/skparagraph_benchmarks.cc", + "benchmarks/txt_run_all_benchmarks.cc", "tests/txt_test_utils.cc", "tests/txt_test_utils.h", ] - configs += [ ":define_skshaper" ] - deps = [ ":txt", + ":txt_fixtures", "//flutter/fml", - "//third_party/skia", - ] - } - - executable("txt_benchmarks") { - testonly = true - - sources = [ - "benchmarks/paint_record_benchmarks.cc", - "benchmarks/paragraph_benchmarks.cc", - "benchmarks/paragraph_builder_benchmarks.cc", - "benchmarks/txt_run_all_benchmarks.cc", + "//flutter/testing:testing_lib", + "//third_party/benchmark", + "//third_party/skia/modules/skparagraph", ] - - configs += [ ":define_skshaper" ] - - deps = [ - ":txt", - ":txt_fixtures", - ":txt_test_utils", - "//flutter/testing:testing_lib", - "//third_party/benchmark", - ] + txt_common_executable_deps - - if (flutter_enable_skshaper) { - sources += [ "benchmarks/skparagraph_benchmarks.cc" ] - - deps += [ "//third_party/skia/modules/skparagraph" ] - } } executable("txt_unittests") { testonly = true - sources = [ - "tests/CmapCoverageTest.cpp", - "tests/EmojiTest.cpp", - "tests/FileUtils.cpp", - "tests/FileUtils.h", - "tests/FontTestUtils.h", - "tests/GraphemeBreakTests.cpp", - "tests/ICUTestBase.h", - "tests/LayoutUtilsTest.cpp", - "tests/MeasurementTests.cpp", - "tests/SparseBitSetTest.cpp", - "tests/UnicodeUtils.cpp", - "tests/UnicodeUtils.h", - "tests/UnicodeUtilsTest.cpp", - "tests/font_collection_unittests.cc", - "tests/paragraph_unittests.cc", - "tests/render_test.cc", - "tests/render_test.h", - "tests/txt_run_all_unittests.cc", - - # These tests require static fixtures. - # "tests/FontCollectionItemizeTest.cpp", - # "tests/FontCollectionTest.cpp", - # "tests/FontFamilyTest.cpp", - # "tests/FontLanguageListCacheTest.cpp", - # "tests/FontTestUtils.cpp", - # "tests/HbFontCacheTest.cpp", - # "tests/HyphenatorTest.cpp", - # "tests/LayoutTest.cpp", - ] - - if (!is_win) { - sources += [ - "tests/MinikinFontForTest.cpp", - "tests/MinikinFontForTest.h", - ] - } + sources = [ "tests/txt_run_all_unittests.cc" ] - configs += [ - ":allow_posix_names", - ":define_skshaper", - ] + configs += [ ":allow_posix_names" ] deps = [ - ":txt", - ":txt_test_utils", - "//flutter/testing:testing_lib", - ":txt_fixtures", - ] + txt_common_executable_deps + ":txt_fixtures", + "//flutter/fml", + "//flutter/testing:testing_lib", + ] + # This is needed for //third_party/googletest for linking zircon symbols. if (is_fuchsia) { - sources += [ "tests/platform_fuchsia_unittests.cc" ] - deps += [ - "$fuchsia_sdk_root/fidl:fuchsia.fonts", - "$fuchsia_sdk_root/pkg:async-testing", - ] + libs = + [ "${fuchsia_sdk_path}/arch/${target_cpu}/sysroot/lib/libzircon.so" ] } } } diff --git a/third_party/txt/LICENSE b/third_party/txt/LICENSE deleted file mode 100644 index d645695673349..0000000000000 --- a/third_party/txt/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/third_party/txt/PATENTS b/third_party/txt/PATENTS deleted file mode 100644 index 2746e78d1beff..0000000000000 --- a/third_party/txt/PATENTS +++ /dev/null @@ -1,22 +0,0 @@ -Additional IP Rights Grant (Patents) - -"This implementation" means the copyrightable works distributed by -Google as part of the Fuchsia project. - -Google hereby grants to you a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this -section) patent license to make, have made, use, offer to sell, sell, -import, transfer, and otherwise run, modify and propagate the contents -of this implementation of Fuchsia, where such license applies only to -those patent claims, both currently owned by Google and acquired in -the future, licensable by Google that are necessarily infringed by -this implementation. This grant does not include claims that would be -infringed only as a consequence of further modification of this -implementation. If you or your agent or exclusive licensee institute -or order or agree to the institution of patent litigation or any other -patent enforcement activity against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that this -implementation of Fuchsia constitutes direct or contributory patent -infringement, or inducement of patent infringement, then any patent -rights granted to you under this License for this implementation of -Fuchsia shall terminate as of the date such litigation is filed. diff --git a/third_party/txt/benchmarks/paint_record_benchmarks.cc b/third_party/txt/benchmarks/paint_record_benchmarks.cc deleted file mode 100644 index 52366031c9060..0000000000000 --- a/third_party/txt/benchmarks/paint_record_benchmarks.cc +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 "flutter/fml/command_line.h" -#include "flutter/fml/logging.h" -#include "flutter/third_party/txt/tests/txt_test_utils.h" -#include "third_party/benchmark/include/benchmark/benchmark.h" -#include "txt/paint_record.h" -#include "txt/text_style.h" - -namespace txt { - -static void BM_PaintRecordInit(benchmark::State& state) { - TextStyle style; - style.font_families = std::vector(1, "Roboto"); - - SkFont font; - font.setEdging(SkFont::Edging::kAntiAlias); - font.setSize(14); - font.setEmbolden(false); - - SkTextBlobBuilder builder; - builder.allocRunPos(font, 100); - auto text_blob = builder.make(); - - while (state.KeepRunning()) { - PaintRecord PaintRecord(style, text_blob, SkFontMetrics(), 0, 0, 0, false); - } -} -BENCHMARK(BM_PaintRecordInit); - -} // namespace txt diff --git a/third_party/txt/benchmarks/paragraph_benchmarks.cc b/third_party/txt/benchmarks/paragraph_benchmarks.cc deleted file mode 100644 index babd637093e04..0000000000000 --- a/third_party/txt/benchmarks/paragraph_benchmarks.cc +++ /dev/null @@ -1,446 +0,0 @@ -/* - * 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 - -#include "flutter/fml/command_line.h" -#include "flutter/fml/logging.h" -#include "flutter/third_party/txt/tests/txt_test_utils.h" -#include "minikin/LayoutUtils.h" -#include "third_party/benchmark/include/benchmark/benchmark.h" -#include "third_party/icu/source/common/unicode/unistr.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkColor.h" -#include "txt/font_collection.h" -#include "txt/font_skia.h" -#include "txt/font_style.h" -#include "txt/font_weight.h" -#include "txt/paragraph.h" -#include "txt/paragraph_builder_txt.h" - -namespace txt { - -class ParagraphFixture : public benchmark::Fixture { - public: - void SetUp(const benchmark::State& state) { - font_collection_ = GetTestFontCollection(); - - bitmap_ = std::make_unique(); - bitmap_->allocN32Pixels(1000, 1000); - canvas_ = std::make_unique(*bitmap_); - canvas_->clear(SK_ColorWHITE); - } - - void TearDown(const benchmark::State& state) { font_collection_.reset(); } - - protected: - std::shared_ptr font_collection_; - std::unique_ptr canvas_; - std::unique_ptr bitmap_; -}; - -BENCHMARK_F(ParagraphFixture, ShortLayout)(benchmark::State& state) { - const char* text = "Hello World"; - 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::TextStyle text_style; - text_style.font_families = std::vector(1, "Roboto"); - text_style.color = SK_ColorBLACK; - txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_); - - builder.PushStyle(text_style); - builder.AddText(u16_text); - builder.Pop(); - auto paragraph = BuildParagraph(builder); - while (state.KeepRunning()) { - paragraph->SetDirty(); - paragraph->Layout(300); - } -} - -BENCHMARK_F(ParagraphFixture, LongLayout)(benchmark::State& state) { - 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; - - txt::TextStyle text_style; - text_style.font_families = std::vector(1, "Roboto"); - text_style.color = SK_ColorBLACK; - - txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_); - - builder.PushStyle(text_style); - builder.AddText(u16_text); - builder.Pop(); - auto paragraph = BuildParagraph(builder); - while (state.KeepRunning()) { - paragraph->SetDirty(); - paragraph->Layout(300); - } -} - -BENCHMARK_F(ParagraphFixture, JustifyLayout)(benchmark::State& state) { - 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.text_align = TextAlign::justify; - - txt::TextStyle text_style; - text_style.font_families = std::vector(1, "Roboto"); - text_style.color = SK_ColorBLACK; - - txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_); - - builder.PushStyle(text_style); - builder.AddText(u16_text); - builder.Pop(); - auto paragraph = BuildParagraph(builder); - while (state.KeepRunning()) { - paragraph->SetDirty(); - paragraph->Layout(300); - } -} - -BENCHMARK_F(ParagraphFixture, ManyStylesLayout)(benchmark::State& state) { - 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::TextStyle text_style; - text_style.font_families = std::vector(1, "Roboto"); - text_style.color = SK_ColorBLACK; - txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_); - for (int i = 0; i < 1000; ++i) { - builder.PushStyle(text_style); - builder.AddText(u16_text); - } - auto paragraph = BuildParagraph(builder); - while (state.KeepRunning()) { - paragraph->SetDirty(); - paragraph->Layout(300); - } -} - -BENCHMARK_DEFINE_F(ParagraphFixture, TextBigO)(benchmark::State& state) { - std::vector text; - for (uint16_t i = 0; i < state.range(0); ++i) { - text.push_back(i % 5 == 0 ? ' ' : i); - } - std::u16string u16_text(text.data(), text.data() + text.size()); - - txt::ParagraphStyle paragraph_style; - paragraph_style.font_family = "Roboto"; - - txt::TextStyle text_style; - text_style.font_families = std::vector(1, "Roboto"); - text_style.color = SK_ColorBLACK; - - txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_); - - builder.PushStyle(text_style); - builder.AddText(u16_text); - builder.Pop(); - auto paragraph = BuildParagraph(builder); - while (state.KeepRunning()) { - paragraph->SetDirty(); - paragraph->Layout(300); - } - state.SetComplexityN(state.range(0)); -} -BENCHMARK_REGISTER_F(ParagraphFixture, TextBigO) - ->RangeMultiplier(4) - ->Range(1 << 6, 1 << 14) - ->Complexity(benchmark::oN); - -BENCHMARK_DEFINE_F(ParagraphFixture, StylesBigO)(benchmark::State& state) { - const char* text = "vry shrt "; - 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::TextStyle text_style; - text_style.font_families = std::vector(1, "Roboto"); - text_style.color = SK_ColorBLACK; - - txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_); - - for (int i = 0; i < state.range(0); ++i) { - builder.PushStyle(text_style); - builder.AddText(u16_text); - } - auto paragraph = BuildParagraph(builder); - while (state.KeepRunning()) { - paragraph->SetDirty(); - paragraph->Layout(300); - } - state.SetComplexityN(state.range(0)); -} -BENCHMARK_REGISTER_F(ParagraphFixture, StylesBigO) - ->RangeMultiplier(4) - ->Range(1 << 3, 1 << 12) - ->Complexity(benchmark::oN); - -BENCHMARK_F(ParagraphFixture, PaintSimple)(benchmark::State& state) { - const char* text = "Hello world! This is a simple sentence to test drawing."; - 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::TextStyle text_style; - text_style.font_families = std::vector(1, "Roboto"); - text_style.color = SK_ColorBLACK; - txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_); - builder.PushStyle(text_style); - builder.AddText(u16_text); - auto paragraph = BuildParagraph(builder); - paragraph->Layout(300); - - int offset = 0; - while (state.KeepRunning()) { - paragraph->Paint(canvas_.get(), offset % 700, 10); - offset++; - } -} - -BENCHMARK_F(ParagraphFixture, PaintLarge)(benchmark::State& state) { - const char* text = - "Hello world! This is a simple sentence to test drawing. Hello world! " - "This is a simple sentence to test drawing. Hello world! This is a " - "simple sentence to test drawing.Hello world! This is a simple sentence " - "to test drawing. Hello world! " - "This is a simple sentence to test drawing. Hello world! This is a " - "simple sentence to test drawing.Hello world! This is a simple sentence " - "to test drawing. Hello world! " - "This is a simple sentence to test drawing. Hello world! This is a " - "simple sentence to test drawing.Hello world! This is a simple sentence " - "to test drawing. Hello world! " - "This is a simple sentence to test drawing. Hello world! This is a " - "simple sentence to test drawing.Hello world! This is a simple sentence " - "to test drawing. Hello world! " - "This is a simple sentence to test drawing. Hello world! This is a " - "simple sentence to test drawing.Hello world! This is a simple sentence " - "to test drawing. Hello world! " - "This is a simple sentence to test drawing. Hello world! This is a " - "simple sentence to test drawing."; - 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::TextStyle text_style; - text_style.font_families = std::vector(1, "Roboto"); - text_style.color = SK_ColorBLACK; - txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_); - builder.PushStyle(text_style); - builder.AddText(u16_text); - auto paragraph = BuildParagraph(builder); - paragraph->Layout(300); - - int offset = 0; - while (state.KeepRunning()) { - paragraph->Paint(canvas_.get(), offset % 700, 10); - offset++; - } -} - -BENCHMARK_F(ParagraphFixture, PaintDecoration)(benchmark::State& state) { - const char* text = - "Hello world! This is a simple sentence to test drawing. Hello world! " - "This is a simple sentence to test drawing."; - 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::TextStyle text_style; - text_style.font_families = std::vector(1, "Roboto"); - text_style.decoration = TextDecoration::kUnderline | - TextDecoration::kOverline | - TextDecoration::kLineThrough; - text_style.decoration_style = TextDecorationStyle(kSolid); - text_style.color = SK_ColorBLACK; - - txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_); - - builder.PushStyle(text_style); - builder.AddText(u16_text); - - text_style.decoration_style = TextDecorationStyle(kDotted); - builder.PushStyle(text_style); - builder.AddText(u16_text); - - text_style.decoration_style = TextDecorationStyle(kWavy); - builder.PushStyle(text_style); - builder.AddText(u16_text); - - auto paragraph = BuildParagraph(builder); - paragraph->Layout(300); - - int offset = 0; - while (state.KeepRunning()) { - paragraph->Paint(canvas_.get(), offset % 700, 10); - offset++; - } -} - -// ----------------------------------------------------------------------------- -// -// The following benchmarks break down the layout function and attempts to time -// each of the components to more finely attribute latency. -// -// ----------------------------------------------------------------------------- - -BENCHMARK_DEFINE_F(ParagraphFixture, MinikinDoLayout)(benchmark::State& state) { - std::vector text; - for (uint16_t i = 0; i < 16000 * 2; ++i) { - text.push_back(i % 5 == 0 ? ' ' : i); - } - minikin::FontStyle font; - txt::TextStyle text_style; - text_style.font_families = std::vector(1, "Roboto"); - minikin::MinikinPaint paint; - - font = minikin::FontStyle(4, false); - paint.size = text_style.font_size; - paint.letterSpacing = text_style.letter_spacing; - paint.wordSpacing = text_style.word_spacing; - - auto collection = font_collection_->GetMinikinFontCollectionForFamilies( - text_style.font_families, "en-US"); - - while (state.KeepRunning()) { - minikin::Layout layout; - layout.doLayout(text.data(), 0, state.range(0), state.range(0), 0, font, - paint, collection); - } - state.SetComplexityN(state.range(0)); -} -BENCHMARK_REGISTER_F(ParagraphFixture, MinikinDoLayout) - ->RangeMultiplier(4) - ->Range(1 << 7, 1 << 14) - ->Complexity(benchmark::oN); - -BENCHMARK_DEFINE_F(ParagraphFixture, AddStyleRun)(benchmark::State& state) { - std::vector text; - for (uint16_t i = 0; i < 16000 * 2; ++i) { - text.push_back(i % 5 == 0 ? ' ' : i); - } - minikin::FontStyle font; - txt::TextStyle text_style; - text_style.font_families = std::vector(1, "Roboto"); - minikin::MinikinPaint paint; - - font = minikin::FontStyle(4, false); - paint.size = text_style.font_size; - paint.letterSpacing = text_style.letter_spacing; - paint.wordSpacing = text_style.word_spacing; - - minikin::LineBreaker breaker; - breaker.setLocale(); - breaker.resize(text.size()); - memcpy(breaker.buffer(), text.data(), text.size() * sizeof(text[0])); - breaker.setText(); - - while (state.KeepRunning()) { - for (int i = 0; i < 20; ++i) { - breaker.addStyleRun(&paint, - font_collection_->GetMinikinFontCollectionForFamilies( - std::vector(1, "Roboto"), "en-US"), - font, state.range(0) / 20 * i, - state.range(0) / 20 * (i + 1), false); - } - } - state.SetComplexityN(state.range(0)); -} -BENCHMARK_REGISTER_F(ParagraphFixture, AddStyleRun) - ->RangeMultiplier(4) - ->Range(1 << 7, 1 << 14) - ->Complexity(benchmark::oN); - -BENCHMARK_DEFINE_F(ParagraphFixture, SkTextBlobAlloc)(benchmark::State& state) { - SkFont font; - font.setEdging(SkFont::Edging::kAntiAlias); - font.setSize(14); - font.setEmbolden(false); - - while (state.KeepRunning()) { - SkTextBlobBuilder builder; - builder.allocRunPos(font, state.range(0)); - } - state.SetComplexityN(state.range(0)); -} -BENCHMARK_REGISTER_F(ParagraphFixture, SkTextBlobAlloc) - ->RangeMultiplier(4) - ->Range(1 << 7, 1 << 14) - ->Complexity(benchmark::oN); - -} // namespace txt diff --git a/third_party/txt/benchmarks/paragraph_builder_benchmarks.cc b/third_party/txt/benchmarks/paragraph_builder_benchmarks.cc deleted file mode 100644 index b507db32e13b9..0000000000000 --- a/third_party/txt/benchmarks/paragraph_builder_benchmarks.cc +++ /dev/null @@ -1,200 +0,0 @@ -/* - * 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 "flutter/fml/logging.h" -#include "flutter/third_party/txt/tests/txt_test_utils.h" -#include "third_party/benchmark/include/benchmark/benchmark.h" -#include "third_party/icu/source/common/unicode/unistr.h" -#include "third_party/skia/include/core/SkColor.h" -#include "txt/font_collection.h" -#include "txt/font_style.h" -#include "txt/font_weight.h" -#include "txt/paragraph.h" -#include "txt/paragraph_builder_txt.h" - -namespace txt { - -static void BM_ParagraphBuilderConstruction(benchmark::State& state) { - txt::ParagraphStyle paragraph_style; - auto font_collection = GetTestFontCollection(); - while (state.KeepRunning()) { - txt::ParagraphBuilderTxt builder(paragraph_style, font_collection); - } -} -BENCHMARK(BM_ParagraphBuilderConstruction); - -static void BM_ParagraphBuilderPushStyle(benchmark::State& state) { - txt::ParagraphStyle paragraph_style; - - txt::TextStyle text_style; - text_style.color = SK_ColorBLACK; - auto font_collection = GetTestFontCollection(); - while (state.KeepRunning()) { - txt::ParagraphBuilderTxt builder(paragraph_style, font_collection); - builder.PushStyle(text_style); - } -} -BENCHMARK(BM_ParagraphBuilderPushStyle); - -static void BM_ParagraphBuilderPushPop(benchmark::State& state) { - txt::ParagraphStyle paragraph_style; - txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); - - txt::TextStyle text_style; - text_style.color = SK_ColorBLACK; - while (state.KeepRunning()) { - builder.PushStyle(text_style); - builder.Pop(); - } -} -BENCHMARK(BM_ParagraphBuilderPushPop); - -static void BM_ParagraphBuilderAddTextString(benchmark::State& state) { - std::u16string text = u"Hello World"; - - auto font_collection = GetTestFontCollection(); - - txt::ParagraphStyle paragraph_style; - - while (state.KeepRunning()) { - txt::ParagraphBuilderTxt builder(paragraph_style, font_collection); - builder.AddText(text); - } -} -BENCHMARK(BM_ParagraphBuilderAddTextString); - -static void BM_ParagraphBuilderAddTextChar(benchmark::State& state) { - std::u16string text = u"Hello World"; - - txt::ParagraphStyle paragraph_style; - auto font_collection = GetTestFontCollection(); - while (state.KeepRunning()) { - txt::ParagraphBuilderTxt builder(paragraph_style, font_collection); - builder.AddText(text); - } -} -BENCHMARK(BM_ParagraphBuilderAddTextChar); - -static void BM_ParagraphBuilderAddTextU16stringShort(benchmark::State& state) { - 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; - auto font_collection = GetTestFontCollection(); - while (state.KeepRunning()) { - txt::ParagraphBuilderTxt builder(paragraph_style, font_collection); - builder.AddText(u16_text); - } -} -BENCHMARK(BM_ParagraphBuilderAddTextU16stringShort); - -static void BM_ParagraphBuilderAddTextU16stringLong(benchmark::State& state) { - 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()); - - auto font_collection = GetTestFontCollection(); - - txt::ParagraphStyle paragraph_style; - - while (state.KeepRunning()) { - txt::ParagraphBuilderTxt builder(paragraph_style, font_collection); - builder.AddText(u16_text); - } -} -BENCHMARK(BM_ParagraphBuilderAddTextU16stringLong); - -static void BM_ParagraphBuilderShortParagraphConstruct( - benchmark::State& state) { - const char* text = "Hello World"; - 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::TextStyle text_style; - text_style.color = SK_ColorBLACK; - auto font_collection = GetTestFontCollection(); - while (state.KeepRunning()) { - txt::ParagraphBuilderTxt builder(paragraph_style, font_collection); - builder.PushStyle(text_style); - builder.AddText(u16_text); - builder.Pop(); - auto paragraph = builder.Build(); - } -} -BENCHMARK(BM_ParagraphBuilderShortParagraphConstruct); - -static void BM_ParagraphBuilderLongParagraphConstruct(benchmark::State& state) { - 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; - - txt::TextStyle text_style; - text_style.color = SK_ColorBLACK; - auto font_collection = GetTestFontCollection(); - while (state.KeepRunning()) { - txt::ParagraphBuilderTxt builder(paragraph_style, font_collection); - builder.PushStyle(text_style); - builder.AddText(u16_text); - builder.Pop(); - auto paragraph = builder.Build(); - } -} -BENCHMARK(BM_ParagraphBuilderLongParagraphConstruct); - -} // namespace txt diff --git a/third_party/txt/benchmarks/txt_run_all_benchmarks.cc b/third_party/txt/benchmarks/txt_run_all_benchmarks.cc index 9f4027e2a5f9a..ac9df5ed9e352 100644 --- a/third_party/txt/benchmarks/txt_run_all_benchmarks.cc +++ b/third_party/txt/benchmarks/txt_run_all_benchmarks.cc @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "flutter/fml/command_line.h" #include "flutter/fml/icu_util.h" #include "flutter/fml/logging.h" #include "flutter/testing/testing.h" @@ -24,7 +25,6 @@ int main(int argc, char** argv) { ::benchmark::Initialize(&argc, argv); fml::CommandLine cmd = fml::CommandLineFromPlatformOrArgcArgv(argc, argv); - txt::SetCommandLine(cmd); txt::SetFontDir(flutter::testing::GetFixturesPath()); if (txt::GetFontDir().length() <= 0) { FML_LOG(ERROR) << "Font directory not set via txt::SetFontDir."; diff --git a/third_party/txt/src/log/log.cc b/third_party/txt/src/log/log.cc deleted file mode 100644 index ab61fead31b37..0000000000000 --- a/third_party/txt/src/log/log.cc +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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 - -int __android_log_error_write(int tag, - const char* subTag, - int32_t uid, - const char* data, - uint32_t dataLen) { - return 0; -} diff --git a/third_party/txt/src/log/log.h b/third_party/txt/src/log/log.h deleted file mode 100644 index edc153a5625fd..0000000000000 --- a/third_party/txt/src/log/log.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -#include "flutter/fml/logging.h" - -#if defined(_WIN32) -// Conflicts with macro on Windows. -#undef ERROR -#endif - -#ifndef LOG_ALWAYS_FATAL_IF -#define LOG_ALWAYS_FATAL_IF(cond, ...) \ - ((cond) ? (FML_LOG(FATAL) << #cond) : (void)0) -#endif - -#ifndef LOG_ALWAYS_FATAL -#define LOG_ALWAYS_FATAL(...) FML_LOG(FATAL) -#endif - -#ifndef LOG_ASSERT -#define LOG_ASSERT(cond, ...) FML_CHECK(cond) -#define ALOG_ASSERT LOG_ASSERT -#endif - -#ifndef ALOGD -#define ALOGD(message, ...) FML_DLOG(INFO) << (message) -#endif - -#ifndef ALOGW -#define ALOGW(message, ...) FML_LOG(WARNING) << (message) -#endif - -#ifndef ALOGE -#define ALOGE(message, ...) FML_LOG(ERROR) << (message) -#endif - -#define android_errorWriteLog(tag, subTag) \ - __android_log_error_write(tag, subTag, -1, NULL, 0) -#define android_errorWriteWithInfoLog(tag, subTag, uid, data, dataLen) \ - __android_log_error_write(tag, subTag, uid, data, dataLen) -int __android_log_error_write(int tag, - const char* subTag, - int32_t uid, - const char* data, - uint32_t dataLen); diff --git a/third_party/txt/src/minikin/CmapCoverage.cpp b/third_party/txt/src/minikin/CmapCoverage.cpp deleted file mode 100644 index c61cd766e2738..0000000000000 --- a/third_party/txt/src/minikin/CmapCoverage.cpp +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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. - */ - -// Determine coverage of font given its raw "cmap" OpenType table - -#define LOG_TAG "Minikin" - -#include -using std::vector; - -#include - -#include -#include -#include "MinikinInternal.h" - -namespace minikin { - -// These could perhaps be optimized to use __builtin_bswap16 and friends. -static uint32_t readU16(const uint8_t* data, size_t offset) { - return ((uint32_t)data[offset]) << 8 | ((uint32_t)data[offset + 1]); -} - -static uint32_t readU32(const uint8_t* data, size_t offset) { - return ((uint32_t)data[offset]) << 24 | ((uint32_t)data[offset + 1]) << 16 | - ((uint32_t)data[offset + 2]) << 8 | ((uint32_t)data[offset + 3]); -} - -static void addRange(vector& coverage, uint32_t start, uint32_t end) { -#ifdef VERBOSE_DEBUG - ALOGD("adding range %d-%d\n", start, end); -#endif - if (coverage.empty() || coverage.back() < start) { - coverage.push_back(start); - coverage.push_back(end); - } else { - coverage.back() = end; - } -} - -// Get the coverage information out of a Format 4 subtable, storing it in the -// coverage vector -static bool getCoverageFormat4(vector& coverage, - const uint8_t* data, - size_t size) { - const size_t kSegCountOffset = 6; - const size_t kEndCountOffset = 14; - const size_t kHeaderSize = 16; - const size_t kSegmentSize = - 8; // total size of array elements for one segment - if (kEndCountOffset > size) { - return false; - } - size_t segCount = readU16(data, kSegCountOffset) >> 1; - if (kHeaderSize + segCount * kSegmentSize > size) { - return false; - } - for (size_t i = 0; i < segCount; i++) { - uint32_t end = readU16(data, kEndCountOffset + 2 * i); - uint32_t start = readU16(data, kHeaderSize + 2 * (segCount + i)); - if (end < start) { - // invalid segment range: size must be positive - android_errorWriteLog(0x534e4554, "26413177"); - return false; - } - uint32_t rangeOffset = readU16(data, kHeaderSize + 2 * (3 * segCount + i)); - if (rangeOffset == 0) { - uint32_t delta = readU16(data, kHeaderSize + 2 * (2 * segCount + i)); - if (((end + delta) & 0xffff) > end - start) { - addRange(coverage, start, end + 1); - } else { - for (uint32_t j = start; j < end + 1; j++) { - if (((j + delta) & 0xffff) != 0) { - addRange(coverage, j, j + 1); - } - } - } - } else { - for (uint32_t j = start; j < end + 1; j++) { - uint32_t actualRangeOffset = - kHeaderSize + 6 * segCount + rangeOffset + (i + j - start) * 2; - if (actualRangeOffset + 2 > size) { - // invalid rangeOffset is considered a "warning" by OpenType Sanitizer - continue; - } - uint32_t glyphId = readU16(data, actualRangeOffset); - if (glyphId != 0) { - addRange(coverage, j, j + 1); - } - } - } - } - return true; -} - -// Get the coverage information out of a Format 12 subtable, storing it in the -// coverage vector -static bool getCoverageFormat12(vector& coverage, - const uint8_t* data, - size_t size) { - const size_t kNGroupsOffset = 12; - const size_t kFirstGroupOffset = 16; - const size_t kGroupSize = 12; - const size_t kStartCharCodeOffset = 0; - const size_t kEndCharCodeOffset = 4; - const size_t kMaxNGroups = - 0xfffffff0 / kGroupSize; // protection against overflow - // For all values < kMaxNGroups, kFirstGroupOffset + nGroups * kGroupSize fits - // in 32 bits. - if (kFirstGroupOffset > size) { - return false; - } - uint32_t nGroups = readU32(data, kNGroupsOffset); - if (nGroups >= kMaxNGroups || - kFirstGroupOffset + nGroups * kGroupSize > size) { - android_errorWriteLog(0x534e4554, "25645298"); - return false; - } - for (uint32_t i = 0; i < nGroups; i++) { - uint32_t groupOffset = kFirstGroupOffset + i * kGroupSize; - uint32_t start = readU32(data, groupOffset + kStartCharCodeOffset); - uint32_t end = readU32(data, groupOffset + kEndCharCodeOffset); - if (end < start) { - // invalid group range: size must be positive - android_errorWriteLog(0x534e4554, "26413177"); - return false; - } - - // No need to read outside of Unicode code point range. - if (start > MAX_UNICODE_CODE_POINT) { - return true; - } - if (end > MAX_UNICODE_CODE_POINT) { - // file is inclusive, vector is exclusive - addRange(coverage, start, MAX_UNICODE_CODE_POINT + 1); - return true; - } - addRange(coverage, start, - end + 1); // file is inclusive, vector is exclusive - } - return true; -} - -// Lower value has higher priority. 0 for the highest priority table. -// kLowestPriority for unsupported tables. -// This order comes from HarfBuzz's hb-ot-font.cc and needs to be kept in sync -// with it. -constexpr uint8_t kLowestPriority = 255; -uint8_t getTablePriority(uint16_t platformId, uint16_t encodingId) { - if (platformId == 3 && encodingId == 10) { - return 0; - } - if (platformId == 0 && encodingId == 6) { - return 1; - } - if (platformId == 0 && encodingId == 4) { - return 2; - } - if (platformId == 3 && encodingId == 1) { - return 3; - } - if (platformId == 0 && encodingId == 3) { - return 4; - } - if (platformId == 0 && encodingId == 2) { - return 5; - } - if (platformId == 0 && encodingId == 1) { - return 6; - } - if (platformId == 0 && encodingId == 0) { - return 7; - } - // Tables other than above are not supported. - return kLowestPriority; -} - -SparseBitSet CmapCoverage::getCoverage(const uint8_t* cmap_data, - size_t cmap_size, - bool* has_cmap_format14_subtable) { - constexpr size_t kHeaderSize = 4; - constexpr size_t kNumTablesOffset = 2; - constexpr size_t kTableSize = 8; - constexpr size_t kPlatformIdOffset = 0; - constexpr size_t kEncodingIdOffset = 2; - constexpr size_t kOffsetOffset = 4; - constexpr size_t kFormatOffset = 0; - constexpr uint32_t kInvalidOffset = UINT32_MAX; - - if (kHeaderSize > cmap_size) { - return SparseBitSet(); - } - uint32_t numTables = readU16(cmap_data, kNumTablesOffset); - if (kHeaderSize + numTables * kTableSize > cmap_size) { - return SparseBitSet(); - } - - uint32_t bestTableOffset = kInvalidOffset; - uint16_t bestTableFormat = 0; - uint8_t bestTablePriority = kLowestPriority; - *has_cmap_format14_subtable = false; - for (uint32_t i = 0; i < numTables; ++i) { - const uint32_t tableHeadOffset = kHeaderSize + i * kTableSize; - const uint16_t platformId = - readU16(cmap_data, tableHeadOffset + kPlatformIdOffset); - const uint16_t encodingId = - readU16(cmap_data, tableHeadOffset + kEncodingIdOffset); - const uint32_t offset = readU32(cmap_data, tableHeadOffset + kOffsetOffset); - - if (offset > cmap_size - 2) { - continue; // Invalid table: not enough space to read. - } - const uint16_t format = readU16(cmap_data, offset + kFormatOffset); - - if (platformId == 0 /* Unicode */ && - encodingId == 5 /* Variation Sequences */) { - if (!(*has_cmap_format14_subtable) && format == 14) { - *has_cmap_format14_subtable = true; - } else { - // Ignore the (0, 5) table if we have already seen another valid one or - // it's in a format we don't understand. - } - } else { - uint32_t length; - uint32_t language; - - if (format == 4) { - constexpr size_t lengthOffset = 2; - constexpr size_t languageOffset = 4; - constexpr size_t minTableSize = languageOffset + 2; - if (offset > cmap_size - minTableSize) { - continue; // Invalid table: not enough space to read. - } - length = readU16(cmap_data, offset + lengthOffset); - language = readU16(cmap_data, offset + languageOffset); - } else if (format == 12) { - constexpr size_t lengthOffset = 4; - constexpr size_t languageOffset = 8; - constexpr size_t minTableSize = languageOffset + 4; - if (offset > cmap_size - minTableSize) { - continue; // Invalid table: not enough space to read. - } - length = readU32(cmap_data, offset + lengthOffset); - language = readU32(cmap_data, offset + languageOffset); - } else { - continue; - } - - if (length > cmap_size - offset) { - continue; // Invalid table: table length is larger than whole cmap data - // size. - } - if (language != 0) { - // Unsupported or invalid table: this is either a subtable for the - // Macintosh platform (which we don't support), or an invalid subtable - // since language field should be zero for non-Macintosh subtables. - continue; - } - const uint8_t priority = getTablePriority(platformId, encodingId); - if (priority < bestTablePriority) { - bestTableOffset = offset; - bestTablePriority = priority; - bestTableFormat = format; - } - } - if (*has_cmap_format14_subtable && - bestTablePriority == 0 /* highest priority */) { - // Already found the highest priority table and variation sequences table. - // No need to look at remaining tables. - break; - } - } - if (bestTableOffset == kInvalidOffset) { - return SparseBitSet(); - } - const uint8_t* tableData = cmap_data + bestTableOffset; - const size_t tableSize = cmap_size - bestTableOffset; - vector coverageVec; - bool success; - if (bestTableFormat == 4) { - success = getCoverageFormat4(coverageVec, tableData, tableSize); - } else { - success = getCoverageFormat12(coverageVec, tableData, tableSize); - } - if (success && (coverageVec.size() != 0)) { - return SparseBitSet(&coverageVec.front(), coverageVec.size() >> 1); - } else { - return SparseBitSet(); - } -} - -} // namespace minikin diff --git a/third_party/txt/src/minikin/CmapCoverage.h b/third_party/txt/src/minikin/CmapCoverage.h deleted file mode 100644 index 9ca72715a6719..0000000000000 --- a/third_party/txt/src/minikin/CmapCoverage.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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. - */ - -#ifndef MINIKIN_CMAP_COVERAGE_H -#define MINIKIN_CMAP_COVERAGE_H - -#include - -namespace minikin { - -class CmapCoverage { - public: - static SparseBitSet getCoverage(const uint8_t* cmap_data, - size_t cmap_size, - bool* has_cmap_format14_subtable); -}; - -} // namespace minikin - -#endif // MINIKIN_CMAP_COVERAGE_H diff --git a/third_party/txt/src/minikin/Emoji.cpp b/third_party/txt/src/minikin/Emoji.cpp deleted file mode 100644 index 3f974052bce48..0000000000000 --- a/third_party/txt/src/minikin/Emoji.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * 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 - -namespace minikin { - -bool isEmoji(uint32_t c) { - return u_hasBinaryProperty(c, UCHAR_EMOJI); -} - -bool isEmojiModifier(uint32_t c) { - return u_hasBinaryProperty(c, UCHAR_EMOJI_MODIFIER); -} - -bool isEmojiBase(uint32_t c) { - // These two characters were removed from Emoji_Modifier_Base in Emoji 4.0, - // but we need to keep them as emoji modifier bases since there are fonts and - // user-generated text out there that treats these as potential emoji bases. - if (c == 0x1F91D || c == 0x1F93C) { - return true; - } - return u_hasBinaryProperty(c, UCHAR_EMOJI_MODIFIER_BASE); -} - -UCharDirection emojiBidiOverride(const void* /* context */, UChar32 c) { - return u_charDirection(c); -} - -} // namespace minikin diff --git a/third_party/txt/src/minikin/Emoji.h b/third_party/txt/src/minikin/Emoji.h deleted file mode 100644 index 046a9d60283e6..0000000000000 --- a/third_party/txt/src/minikin/Emoji.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * 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 - -namespace minikin { - -// Returns true if c is emoji. -bool isEmoji(uint32_t c); - -// Returns true if c is emoji modifier base. -bool isEmojiBase(uint32_t c); - -// Returns true if c is emoji modifier. -bool isEmojiModifier(uint32_t c); - -// Bidi override for ICU that knows about new emoji. -UCharDirection emojiBidiOverride(const void* context, UChar32 c); - -} // namespace minikin diff --git a/third_party/txt/src/minikin/FontCollection.cpp b/third_party/txt/src/minikin/FontCollection.cpp deleted file mode 100644 index 91d1ac295cdc1..0000000000000 --- a/third_party/txt/src/minikin/FontCollection.cpp +++ /dev/null @@ -1,582 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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. - */ - -// #define VERBOSE_DEBUG - -#define LOG_TAG "Minikin" - -#include - -#include -#include "unicode/unistr.h" -#include "unicode/unorm2.h" -#include "unicode/utf16.h" - -#include -#include -#include "FontLanguage.h" -#include "FontLanguageListCache.h" -#include "MinikinInternal.h" - -using std::vector; - -namespace minikin { - -template -static inline T max(T a, T b) { - return a > b ? a : b; -} - -const uint32_t EMOJI_STYLE_VS = 0xFE0F; -const uint32_t TEXT_STYLE_VS = 0xFE0E; - -uint32_t FontCollection::sNextId = 0; - -// libtxt: return a locale string for a language list ID -std::string GetFontLocale(uint32_t langListId) { - const FontLanguages& langs = FontLanguageListCache::getById(langListId); - return langs.size() ? langs[0].getString() : ""; -} - -std::shared_ptr FontCollection::Create( - const std::vector>& typefaces) { - std::shared_ptr font_collection( - new minikin::FontCollection()); - if (!font_collection || !font_collection->init(typefaces)) { - return nullptr; - } - return font_collection; -} - -FontCollection::FontCollection() : mMaxChar(0) {} - -bool FontCollection::init( - const std::vector>& typefaces) { - std::scoped_lock _l(gMinikinLock); - mId = sNextId++; - vector lastChar; - size_t nTypefaces = typefaces.size(); -#ifdef VERBOSE_DEBUG - ALOGD("nTypefaces = %zd\n", nTypefaces); -#endif - const FontStyle defaultStyle; - for (size_t i = 0; i < nTypefaces; i++) { - const std::shared_ptr& family = typefaces[i]; - if (family->getClosestMatch(defaultStyle).font == nullptr) { - continue; - } - const SparseBitSet& coverage = family->getCoverage(); - mFamilies.push_back(family); // emplace_back would be better - if (family->hasVSTable()) { - mVSFamilyVec.push_back(family); - } - mMaxChar = max(mMaxChar, coverage.length()); - lastChar.push_back(coverage.nextSetBit(0)); - - const std::unordered_set& supportedAxes = family->supportedAxes(); - mSupportedAxes.insert(supportedAxes.begin(), supportedAxes.end()); - } - nTypefaces = mFamilies.size(); - if (nTypefaces == 0) { - ALOGE("Font collection must have at least one valid typeface."); - return false; - } - if (nTypefaces > 254) { - ALOGE("Font collection may only have up to 254 font families."); - return false; - } - size_t nPages = (mMaxChar + kPageMask) >> kLogCharsPerPage; - // TODO: Use variation selector map for mRanges construction. - // A font can have a glyph for a base code point and variation selector pair - // but no glyph for the base code point without variation selector. The family - // won't be listed in the range in this case. - for (size_t i = 0; i < nPages; i++) { - Range dummy; - mRanges.push_back(dummy); - Range* range = &mRanges.back(); -#ifdef VERBOSE_DEBUG - ALOGD("i=%zd: range start = %zd\n", i, offset); -#endif - range->start = mFamilyVec.size(); - for (size_t j = 0; j < nTypefaces; j++) { - if (lastChar[j] < (i + 1) << kLogCharsPerPage) { - const std::shared_ptr& family = mFamilies[j]; - mFamilyVec.push_back(static_cast(j)); - uint32_t nextChar = - family->getCoverage().nextSetBit((i + 1) << kLogCharsPerPage); -#ifdef VERBOSE_DEBUG - ALOGD("nextChar = %d (j = %zd)\n", nextChar, j); -#endif - lastChar[j] = nextChar; - } - } - range->end = mFamilyVec.size(); - } - - if (mFamilyVec.size() >= 0xFFFF) { - ALOGE("Exceeded the maximum indexable cmap coverage."); - return false; - } - return true; -} - -// Special scores for the font fallback. -const uint32_t kUnsupportedFontScore = 0; -const uint32_t kFirstFontScore = UINT32_MAX; - -// Calculates a font score. -// The score of the font family is based on three subscores. -// - Coverage Score: How well the font family covers the given character or -// variation sequence. -// - Language Score: How well the font family is appropriate for the language. -// - Variant Score: Whether the font family matches the variant. Note that this -// variant is not the -// one in BCP47. This is our own font variant (e.g., elegant, compact). -// -// Then, there is a priority for these three subscores as follow: -// Coverage Score > Language Score > Variant Score -// The returned score reflects this priority order. -// -// Note that there are two special scores. -// - kUnsupportedFontScore: When the font family doesn't support the variation -// sequence or even its -// base character. -// - kFirstFontScore: When the font is the first font family in the collection -// and it supports the -// given character or variation sequence. -uint32_t FontCollection::calcFamilyScore( - uint32_t ch, - uint32_t vs, - int variant, - uint32_t langListId, - const std::shared_ptr& fontFamily) const { - const uint32_t coverageScore = calcCoverageScore(ch, vs, fontFamily); - if (coverageScore == kFirstFontScore || - coverageScore == kUnsupportedFontScore) { - // No need to calculate other scores. - return coverageScore; - } - - const uint32_t languageScore = - calcLanguageMatchingScore(langListId, *fontFamily); - const uint32_t variantScore = calcVariantMatchingScore(variant, *fontFamily); - - // Subscores are encoded into 31 bits representation to meet the subscore - // priority. The highest 2 bits are for coverage score, then following 28 bits - // are for language score, then the last 1 bit is for variant score. - return coverageScore << 29 | languageScore << 1 | variantScore; -} - -// Calculates a font score based on variation sequence coverage. -// - Returns kUnsupportedFontScore if the font doesn't support the variation -// sequence or its base -// character. -// - Returns kFirstFontScore if the font family is the first font family in the -// collection and it -// supports the given character or variation sequence. -// - Returns 3 if the font family supports the variation sequence. -// - Returns 2 if the vs is a color variation selector (U+FE0F) and if the font -// is an emoji font. -// - Returns 2 if the vs is a text variation selector (U+FE0E) and if the font -// is not an emoji font. -// - Returns 1 if the variation selector is not specified or if the font family -// only supports the -// variation sequence's base character. -uint32_t FontCollection::calcCoverageScore( - uint32_t ch, - uint32_t vs, - const std::shared_ptr& fontFamily) const { - const bool hasVSGlyph = (vs != 0) && fontFamily->hasGlyph(ch, vs); - if (!hasVSGlyph && !fontFamily->getCoverage().get(ch)) { - // The font doesn't support either variation sequence or even the base - // character. - return kUnsupportedFontScore; - } - - if ((vs == 0 || hasVSGlyph) && mFamilies[0] == fontFamily) { - // If the first font family supports the given character or variation - // sequence, always use it. - return kFirstFontScore; - } - - if (vs == 0) { - return 1; - } - - if (hasVSGlyph) { - return 3; - } - - if (vs == EMOJI_STYLE_VS || vs == TEXT_STYLE_VS) { - const FontLanguages& langs = - FontLanguageListCache::getById(fontFamily->langId()); - bool hasEmojiFlag = false; - for (size_t i = 0; i < langs.size(); ++i) { - if (langs[i].getEmojiStyle() == FontLanguage::EMSTYLE_EMOJI) { - hasEmojiFlag = true; - break; - } - } - - if (vs == EMOJI_STYLE_VS) { - return hasEmojiFlag ? 2 : 1; - } else { // vs == TEXT_STYLE_VS - return hasEmojiFlag ? 1 : 2; - } - } - return 1; -} - -// Calculate font scores based on the script matching, subtag matching and -// primary language matching. -// -// 1. If only the font's language matches or there is no matches between -// requested font and -// supported font, then the font obtains a score of 0. -// 2. Without a match in language, considering subtag may change font's -// EmojiStyle over script, -// a match in subtag gets a score of 2 and a match in scripts gains a score -// of 1. -// 3. Regarding to two elements matchings, language-and-subtag matching has a -// score of 4, while -// language-and-script obtains a socre of 3 with the same reason above. -// -// If two languages in the requested list have the same language score, the font -// matching with higher priority language gets a higher score. For example, in -// the case the user requested language list is "ja-Jpan,en-Latn". The score of -// for the font of "ja-Jpan" gets a higher score than the font of "en-Latn". -// -// To achieve score calculation with priorities, the language score is -// determined as follows: -// LanguageScore = s(0) * 5^(m - 1) + s(1) * 5^(m - 2) + ... + s(m - 2) * 5 + -// s(m - 1) -// Here, m is the maximum number of languages to be compared, and s(i) is the -// i-th language's matching score. The possible values of s(i) are 0, 1, 2, 3 -// and 4. -uint32_t FontCollection::calcLanguageMatchingScore( - uint32_t userLangListId, - const FontFamily& fontFamily) { - const FontLanguages& langList = - FontLanguageListCache::getById(userLangListId); - const FontLanguages& fontLanguages = - FontLanguageListCache::getById(fontFamily.langId()); - - const size_t maxCompareNum = std::min(langList.size(), FONT_LANGUAGES_LIMIT); - uint32_t score = 0; - for (size_t i = 0; i < maxCompareNum; ++i) { - score = score * 5u + langList[i].calcScoreFor(fontLanguages); - } - return score; -} - -// Calculates a font score based on variant ("compact" or "elegant") matching. -// - Returns 1 if the font doesn't have variant or the variant matches with the -// text style. -// - No score if the font has a variant but it doesn't match with the text -// style. -uint32_t FontCollection::calcVariantMatchingScore( - int variant, - const FontFamily& fontFamily) { - return (fontFamily.variant() == 0 || fontFamily.variant() == variant) ? 1 : 0; -} - -// Implement heuristic for choosing best-match font. Here are the rules: -// 1. If first font in the collection has the character, it wins. -// 2. Calculate a score for the font family. See comments in calcFamilyScore for -// the detail. -// 3. Highest score wins, with ties resolved to the first font. -// This method never returns nullptr. -const std::shared_ptr& FontCollection::getFamilyForChar( - uint32_t ch, - uint32_t vs, - uint32_t langListId, - int variant) const { - if (ch >= mMaxChar) { - // libtxt: check if the fallback font provider can match this character - if (mFallbackFontProvider) { - const std::shared_ptr& fallback = - findFallbackFont(ch, vs, langListId); - if (fallback) { - return fallback; - } - } - return mFamilies[0]; - } - - Range range = mRanges[ch >> kLogCharsPerPage]; - - if (vs != 0) { - range = {0, static_cast(mFamilies.size())}; - } - -#ifdef VERBOSE_DEBUG - ALOGD("querying range %zd:%zd\n", range.start, range.end); -#endif - int bestFamilyIndex = -1; - uint32_t bestScore = kUnsupportedFontScore; - for (size_t i = range.start; i < range.end; i++) { - const std::shared_ptr& family = - vs == 0 ? mFamilies[mFamilyVec[i]] : mFamilies[i]; - const uint32_t score = calcFamilyScore(ch, vs, variant, langListId, family); - if (score == kFirstFontScore) { - // If the first font family supports the given character or variation - // sequence, always use it. - return family; - } - if (score > bestScore) { - bestScore = score; - bestFamilyIndex = i; - } - } - if (bestFamilyIndex == -1) { - // libtxt: check if the fallback font provider can match this character - if (mFallbackFontProvider) { - const std::shared_ptr& fallback = - findFallbackFont(ch, vs, langListId); - if (fallback) { - return fallback; - } - } - - UErrorCode errorCode = U_ZERO_ERROR; - const UNormalizer2* normalizer = unorm2_getNFDInstance(&errorCode); - if (U_SUCCESS(errorCode)) { - UChar decomposed[4]; - int len = - unorm2_getRawDecomposition(normalizer, ch, decomposed, 4, &errorCode); - if (U_SUCCESS(errorCode) && len > 0) { - int off = 0; - U16_NEXT_UNSAFE(decomposed, off, ch); - return getFamilyForChar(ch, vs, langListId, variant); - } - } - return mFamilies[0]; - } - return vs == 0 ? mFamilies[mFamilyVec[bestFamilyIndex]] - : mFamilies[bestFamilyIndex]; -} - -const std::shared_ptr& FontCollection::findFallbackFont( - uint32_t ch, - uint32_t vs, - uint32_t langListId) const { - std::string locale = GetFontLocale(langListId); - - const auto it = mCachedFallbackFamilies.find(locale); - if (it != mCachedFallbackFamilies.end()) { - for (const auto& fallbackFamily : it->second) { - if (calcCoverageScore(ch, vs, fallbackFamily)) { - return fallbackFamily; - } - } - } - - const std::shared_ptr& fallback = - mFallbackFontProvider->matchFallbackFont(ch, GetFontLocale(langListId)); - - if (fallback) { - mCachedFallbackFamilies[locale].push_back(fallback); - } - return fallback; -} - -const uint32_t NBSP = 0x00A0; -const uint32_t SOFT_HYPHEN = 0x00AD; -const uint32_t ZWJ = 0x200C; -const uint32_t ZWNJ = 0x200D; -const uint32_t HYPHEN = 0x2010; -const uint32_t NB_HYPHEN = 0x2011; -const uint32_t NNBSP = 0x202F; -const uint32_t FEMALE_SIGN = 0x2640; -const uint32_t MALE_SIGN = 0x2642; -const uint32_t STAFF_OF_AESCULAPIUS = 0x2695; - -// Characters where we want to continue using existing font run instead of -// recomputing the best match in the fallback list. -static const uint32_t stickyAllowlist[] = { - '!', ',', '-', '.', - ':', ';', '?', NBSP, - ZWJ, ZWNJ, HYPHEN, NB_HYPHEN, - NNBSP, FEMALE_SIGN, MALE_SIGN, STAFF_OF_AESCULAPIUS}; - -static bool isStickyAllowed(uint32_t c) { - for (size_t i = 0; i < sizeof(stickyAllowlist) / sizeof(stickyAllowlist[0]); - i++) { - if (stickyAllowlist[i] == c) - return true; - } - return false; -} - -static bool isVariationSelector(uint32_t c) { - return (0xFE00 <= c && c <= 0xFE0F) || (0xE0100 <= c && c <= 0xE01EF); -} - -bool FontCollection::hasVariationSelector(uint32_t baseCodepoint, - uint32_t variationSelector) const { - if (!isVariationSelector(variationSelector)) { - return false; - } - if (baseCodepoint >= mMaxChar) { - return false; - } - - std::scoped_lock _l(gMinikinLock); - - // Currently mRanges can not be used here since it isn't aware of the - // variation sequence. - for (size_t i = 0; i < mVSFamilyVec.size(); i++) { - if (mVSFamilyVec[i]->hasGlyph(baseCodepoint, variationSelector)) { - return true; - } - } - - // Even if there is no cmap format 14 subtable entry for the given sequence, - // should return true for case since we - // have special fallback rule for the sequence. Note that we don't need to - // restrict this to already standardized variation sequences, since Unicode is - // adding variation sequences more frequently now and may even move towards - // allowing text and emoji variation selectors on any character. - if (variationSelector == TEXT_STYLE_VS) { - for (size_t i = 0; i < mFamilies.size(); ++i) { - if (!mFamilies[i]->isColorEmojiFamily() && - mFamilies[i]->hasGlyph(baseCodepoint, 0)) { - return true; - } - } - } - - return false; -} - -void FontCollection::itemize(const uint16_t* string, - size_t string_size, - FontStyle style, - vector* result) const { - const uint32_t langListId = style.getLanguageListId(); - int variant = style.getVariant(); - const FontFamily* lastFamily = nullptr; - Run* run = NULL; - - if (string_size == 0) { - return; - } - - const uint32_t kEndOfString = 0xFFFFFFFF; - - uint32_t nextCh = 0; - uint32_t prevCh = 0; - size_t nextUtf16Pos = 0; - size_t readLength = 0; - U16_NEXT(string, readLength, string_size, nextCh); - - do { - const uint32_t ch = nextCh; - const size_t utf16Pos = nextUtf16Pos; - nextUtf16Pos = readLength; - if (readLength < string_size) { - U16_NEXT(string, readLength, string_size, nextCh); - } else { - nextCh = kEndOfString; - } - - bool shouldContinueRun = false; - if (lastFamily != nullptr) { - if (isStickyAllowed(ch)) { - // Continue using existing font as long as it has coverage and is - // allowed. - shouldContinueRun = lastFamily->getCoverage().get(ch); - } else if (ch == SOFT_HYPHEN || isVariationSelector(ch)) { - // Always continue if the character is the soft hyphen or a variation - // selector. - shouldContinueRun = true; - } - } - - if (!shouldContinueRun) { - const std::shared_ptr& family = getFamilyForChar( - ch, isVariationSelector(nextCh) ? nextCh : 0, langListId, variant); - if (utf16Pos == 0 || family.get() != lastFamily) { - size_t start = utf16Pos; - // Workaround for combining marks and emoji modifiers until we implement - // per-cluster font selection: if a combining mark or an emoji modifier - // is found in a different font that also supports the previous - // character, attach previous character to the new run. U+20E3 COMBINING - // ENCLOSING KEYCAP, used in emoji, is handled properly by this since - // it's a combining mark too. - if (utf16Pos != 0 && - ((U_GET_GC_MASK(ch) & U_GC_M_MASK) != 0 || - (isEmojiModifier(ch) && isEmojiBase(prevCh))) && - family != nullptr && family->getCoverage().get(prevCh)) { - const size_t prevChLength = U16_LENGTH(prevCh); - run->end -= prevChLength; - if (run->start == run->end) { - result->pop_back(); - } - start -= prevChLength; - } - result->push_back( - {family->getClosestMatch(style), static_cast(start), 0}); - run = &result->back(); - lastFamily = family.get(); - } - } - prevCh = ch; - run->end = nextUtf16Pos; // exclusive - } while (nextCh != kEndOfString); -} - -FakedFont FontCollection::baseFontFaked(FontStyle style) { - return mFamilies[0]->getClosestMatch(style); -} - -std::shared_ptr FontCollection::createCollectionWithVariation( - const std::vector& variations) { - if (variations.empty() || mSupportedAxes.empty()) { - return nullptr; - } - - bool hasSupportedAxis = false; - for (const FontVariation& variation : variations) { - if (mSupportedAxes.find(variation.axisTag) != mSupportedAxes.end()) { - hasSupportedAxis = true; - break; - } - } - if (!hasSupportedAxis) { - // None of variation axes are supported by this font collection. - return nullptr; - } - - std::vector> families; - for (const std::shared_ptr& family : mFamilies) { - std::shared_ptr newFamily = - family->createFamilyWithVariation(variations); - if (newFamily) { - families.push_back(newFamily); - } else { - families.push_back(family); - } - } - - return FontCollection::Create(std::move(families)); -} - -uint32_t FontCollection::getId() const { - return mId; -} - -} // namespace minikin diff --git a/third_party/txt/src/minikin/FontCollection.h b/third_party/txt/src/minikin/FontCollection.h deleted file mode 100644 index 85ca1f4b86619..0000000000000 --- a/third_party/txt/src/minikin/FontCollection.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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. - */ - -#ifndef MINIKIN_FONT_COLLECTION_H -#define MINIKIN_FONT_COLLECTION_H - -#include -#include -#include -#include - -#include -#include - -namespace minikin { - -class FontCollection { - private: - explicit FontCollection(); - - public: - static std::shared_ptr Create( - const std::vector>& typefaces); - - // libtxt extension: an interface for looking up fallback fonts for characters - // that do not match this collection's font families. - class FallbackFontProvider { - public: - virtual ~FallbackFontProvider() = default; - virtual const std::shared_ptr& matchFallbackFont( - uint32_t ch, - std::string locale) = 0; - }; - - struct Run { - FakedFont fakedFont; - int start; - int end; - }; - - void itemize(const uint16_t* string, - size_t string_length, - FontStyle style, - std::vector* result) const; - - // Returns true if there is a glyph for the code point and variation selector - // pair. Returns false if no fonts have a glyph for the code point and - // variation selector pair, or invalid variation selector is passed. - bool hasVariationSelector(uint32_t baseCodepoint, - uint32_t variationSelector) const; - - // Get base font with fakery information (fake bold could affect metrics) - FakedFont baseFontFaked(FontStyle style); - - // Creates new FontCollection based on this collection while applying font - // variations. Returns nullptr if none of variations apply to this collection. - std::shared_ptr createCollectionWithVariation( - const std::vector& variations); - - const std::unordered_set& getSupportedTags() const { - return mSupportedAxes; - } - - uint32_t getId() const; - - void set_fallback_font_provider(std::unique_ptr ffp) { - mFallbackFontProvider = std::move(ffp); - } - - private: - static const int kLogCharsPerPage = 8; - static const int kPageMask = (1 << kLogCharsPerPage) - 1; - - // mFamilyVec holds the indices of the mFamilies and mRanges holds the range - // of indices of mFamilyVec. The maximum number of pages is 0x10FF (U+10FFFF - // >> 8). The maximum number of the fonts is 0xFF. Thus, technically the - // maximum length of mFamilyVec is 0x10EE01 (0x10FF * 0xFF). However, in - // practice, 16-bit integers are enough since most fonts supports only limited - // range of code points. - struct Range { - uint16_t start; - uint16_t end; - }; - - // Initialize the FontCollection. - bool init(const std::vector>& typefaces); - - const std::shared_ptr& getFamilyForChar(uint32_t ch, - uint32_t vs, - uint32_t langListId, - int variant) const; - - const std::shared_ptr& - findFallbackFont(uint32_t ch, uint32_t vs, uint32_t langListId) const; - - uint32_t calcFamilyScore(uint32_t ch, - uint32_t vs, - int variant, - uint32_t langListId, - const std::shared_ptr& fontFamily) const; - - uint32_t calcCoverageScore( - uint32_t ch, - uint32_t vs, - const std::shared_ptr& fontFamily) const; - - static uint32_t calcLanguageMatchingScore(uint32_t userLangListId, - const FontFamily& fontFamily); - - static uint32_t calcVariantMatchingScore(int variant, - const FontFamily& fontFamily); - - // static for allocating unique id's - static uint32_t sNextId; - - // unique id for this font collection (suitable for cache key) - uint32_t mId; - - // Highest UTF-32 code point that can be mapped - uint32_t mMaxChar; - - // This vector has pointers to the all font family instances in this - // collection. This vector can't be empty. - std::vector> mFamilies; - - // Following two vectors are pre-calculated tables for resolving coverage - // faster. For example, to iterate over all fonts which support Unicode code - // point U+XXYYZZ, iterate font families index from - // mFamilyVec[mRanges[0xXXYY].start] to mFamilyVec[mRange[0xXXYY].end] instead - // of whole mFamilies. This vector contains indices into mFamilies. This - // vector can't be empty. - std::vector mRanges; - std::vector mFamilyVec; - - // This vector has pointers to the font family instances which have cmap 14 - // subtables. - std::vector> mVSFamilyVec; - - // Set of supported axes in this collection. - std::unordered_set mSupportedAxes; - - // libtxt extension: Fallback font provider. - std::unique_ptr mFallbackFontProvider; - - // libtxt extension: Fallback fonts discovered after this font collection - // was constructed. - mutable std::map>> - mCachedFallbackFamilies; -}; - -} // namespace minikin - -#endif // MINIKIN_FONT_COLLECTION_H diff --git a/third_party/txt/src/minikin/FontFamily.cpp b/third_party/txt/src/minikin/FontFamily.cpp deleted file mode 100644 index cf5a623c56132..0000000000000 --- a/third_party/txt/src/minikin/FontFamily.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "Minikin" - -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include -#include -#include "FontLanguage.h" -#include "FontLanguageListCache.h" -#include "FontUtils.h" -#include "HbFontCache.h" -#include "MinikinInternal.h" - -using std::vector; - -namespace minikin { - -FontStyle::FontStyle(int variant, int weight, bool italic) - : FontStyle(FontLanguageListCache::kEmptyListId, variant, weight, italic) {} - -FontStyle::FontStyle(uint32_t languageListId, - int variant, - int weight, - bool italic) - : bits(pack(variant, weight, italic)), mLanguageListId(languageListId) {} - -android::hash_t FontStyle::hash() const { - uint32_t hash = android::JenkinsHashMix(0, bits); - hash = android::JenkinsHashMix(hash, mLanguageListId); - return android::JenkinsHashWhiten(hash); -} - -// static -uint32_t FontStyle::registerLanguageList(const std::string& languages) { - std::scoped_lock _l(gMinikinLock); - return FontLanguageListCache::getId(languages); -} - -// static -uint32_t FontStyle::pack(int variant, int weight, bool italic) { - return (weight & kWeightMask) | (italic ? kItalicMask : 0) | - (variant << kVariantShift); -} - -Font::Font(const std::shared_ptr& typeface, FontStyle style) - : typeface(typeface), style(style) {} - -Font::Font(std::shared_ptr&& typeface, FontStyle style) - : typeface(typeface), style(style) {} - -std::unordered_set Font::getSupportedAxesLocked() const { - const uint32_t fvarTag = MinikinFont::MakeTag('f', 'v', 'a', 'r'); - HbBlob fvarTable(getFontTable(typeface.get(), fvarTag)); - if (fvarTable.size() == 0) { - return std::unordered_set(); - } - - std::unordered_set supportedAxes; - analyzeAxes(fvarTable.get(), fvarTable.size(), &supportedAxes); - return supportedAxes; -} - -Font::Font(Font&& o) { - typeface = std::move(o.typeface); - style = o.style; - o.typeface = nullptr; -} - -Font::Font(const Font& o) { - typeface = o.typeface; - style = o.style; -} - -// static -FontFamily::FontFamily(std::vector&& fonts) - : FontFamily(0 /* variant */, std::move(fonts)) {} - -FontFamily::FontFamily(int variant, std::vector&& fonts) - : FontFamily(FontLanguageListCache::kEmptyListId, - variant, - std::move(fonts)) {} - -FontFamily::FontFamily(uint32_t langId, int variant, std::vector&& fonts) - : mLangId(langId), - mVariant(variant), - mFonts(std::move(fonts)), - mHasVSTable(false) { - computeCoverage(); -} - -bool FontFamily::analyzeStyle(const std::shared_ptr& typeface, - int* weight, - bool* italic) { - std::scoped_lock _l(gMinikinLock); - const uint32_t os2Tag = MinikinFont::MakeTag('O', 'S', '/', '2'); - HbBlob os2Table(getFontTable(typeface.get(), os2Tag)); - if (os2Table.get() == nullptr) - return false; - return ::minikin::analyzeStyle(os2Table.get(), os2Table.size(), weight, - italic); -} - -// Compute a matching metric between two styles - 0 is an exact match -static int computeMatch(FontStyle style1, FontStyle style2) { - if (style1 == style2) - return 0; - int score = abs(style1.getWeight() - style2.getWeight()); - if (style1.getItalic() != style2.getItalic()) { - score += 2; - } - return score; -} - -static FontFakery computeFakery(FontStyle wanted, FontStyle actual) { - // If desired weight is semibold or darker, and 2 or more grades - // higher than actual (for example, medium 500 -> bold 700), then - // select fake bold. - int wantedWeight = wanted.getWeight(); - bool isFakeBold = - wantedWeight >= 6 && (wantedWeight - actual.getWeight()) >= 2; - bool isFakeItalic = wanted.getItalic() && !actual.getItalic(); - return FontFakery(isFakeBold, isFakeItalic); -} - -FakedFont FontFamily::getClosestMatch(FontStyle style) const { - const Font* bestFont = nullptr; - int bestMatch = 0; - for (size_t i = 0; i < mFonts.size(); i++) { - const Font& font = mFonts[i]; - int match = computeMatch(font.style, style); - if (i == 0 || match < bestMatch) { - bestFont = &font; - bestMatch = match; - } - } - if (bestFont != nullptr) { - return FakedFont{bestFont->typeface.get(), - computeFakery(style, bestFont->style)}; - } - return FakedFont{nullptr, FontFakery()}; -} - -bool FontFamily::isColorEmojiFamily() const { - const FontLanguages& languageList = FontLanguageListCache::getById(mLangId); - for (size_t i = 0; i < languageList.size(); ++i) { - if (languageList[i].getEmojiStyle() == FontLanguage::EMSTYLE_EMOJI) { - return true; - } - } - return false; -} - -void FontFamily::computeCoverage() { - std::scoped_lock _l(gMinikinLock); - const FontStyle defaultStyle; - const MinikinFont* typeface = getClosestMatch(defaultStyle).font; - const uint32_t cmapTag = MinikinFont::MakeTag('c', 'm', 'a', 'p'); - HbBlob cmapTable(getFontTable(typeface, cmapTag)); - if (cmapTable.get() == nullptr) { - // Missing or corrupt font cmap table; bail out. - // The cmap table maps charcodes to glyph indices in a font. - return; - } - mCoverage = CmapCoverage::getCoverage(cmapTable.get(), cmapTable.size(), - &mHasVSTable); - - for (size_t i = 0; i < mFonts.size(); ++i) { - std::unordered_set supportedAxes = - mFonts[i].getSupportedAxesLocked(); - mSupportedAxes.insert(supportedAxes.begin(), supportedAxes.end()); - } -} - -bool FontFamily::hasGlyph(uint32_t codepoint, - uint32_t variationSelector) const { - assertMinikinLocked(); - if (variationSelector != 0 && !mHasVSTable) { - // Early exit if the variation selector is specified but the font doesn't - // have a cmap format 14 subtable. - return false; - } - - const FontStyle defaultStyle; - hb_font_t* font = getHbFontLocked(getClosestMatch(defaultStyle).font); - uint32_t unusedGlyph; - bool result = - hb_font_get_glyph(font, codepoint, variationSelector, &unusedGlyph); - hb_font_destroy(font); - return result; -} - -std::shared_ptr FontFamily::createFamilyWithVariation( - const std::vector& variations) const { - if (variations.empty() || mSupportedAxes.empty()) { - return nullptr; - } - - bool hasSupportedAxis = false; - for (const FontVariation& variation : variations) { - if (mSupportedAxes.find(variation.axisTag) != mSupportedAxes.end()) { - hasSupportedAxis = true; - break; - } - } - if (!hasSupportedAxis) { - // None of variation axes are suppored by this family. - return nullptr; - } - - std::vector fonts; - for (const Font& font : mFonts) { - bool supportedVariations = false; - std::scoped_lock _l(gMinikinLock); - std::unordered_set supportedAxes = font.getSupportedAxesLocked(); - if (!supportedAxes.empty()) { - for (const FontVariation& variation : variations) { - if (supportedAxes.find(variation.axisTag) != supportedAxes.end()) { - supportedVariations = true; - break; - } - } - } - std::shared_ptr minikinFont; - if (supportedVariations) { - minikinFont = font.typeface->createFontWithVariation(variations); - } - if (minikinFont == nullptr) { - minikinFont = font.typeface; - } - fonts.push_back(Font(std::move(minikinFont), font.style)); - } - - return std::shared_ptr( - new FontFamily(mLangId, mVariant, std::move(fonts))); -} - -} // namespace minikin diff --git a/third_party/txt/src/minikin/FontFamily.h b/third_party/txt/src/minikin/FontFamily.h deleted file mode 100644 index b82e80ea222da..0000000000000 --- a/third_party/txt/src/minikin/FontFamily.h +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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. - */ - -#ifndef MINIKIN_FONT_FAMILY_H -#define MINIKIN_FONT_FAMILY_H - -#include -#include -#include -#include - -#include - -#include - -#include - -namespace minikin { - -class MinikinFont; - -// FontStyle represents all style information needed to select an actual font -// from a collection. The implementation is packed into two 32-bit words -// so it can be efficiently copied, embedded in other objects, etc. -class FontStyle { - public: - FontStyle() - : FontStyle(0 /* variant */, 4 /* weight */, false /* italic */) {} - FontStyle(int weight, bool italic) - : FontStyle(0 /* variant */, weight, italic) {} - FontStyle(uint32_t langListId) // NOLINT(google-explicit-constructor) - : FontStyle(langListId, - 0 /* variant */, - 4 /* weight */, - false /* italic */) {} - - FontStyle(int variant, int weight, bool italic); - FontStyle(uint32_t langListId, int variant, int weight, bool italic); - - int getWeight() const { return bits & kWeightMask; } - bool getItalic() const { return (bits & kItalicMask) != 0; } - int getVariant() const { return (bits >> kVariantShift) & kVariantMask; } - uint32_t getLanguageListId() const { return mLanguageListId; } - - bool operator==(const FontStyle other) const { - return bits == other.bits && mLanguageListId == other.mLanguageListId; - } - - android::hash_t hash() const; - - // Looks up a language list from an internal cache and returns its ID. - // If the passed language list is not in the cache, registers it and returns - // newly assigned ID. - static uint32_t registerLanguageList(const std::string& languages); - - private: - static const uint32_t kWeightMask = (1 << 4) - 1; - static const uint32_t kItalicMask = 1 << 4; - static const int kVariantShift = 5; - static const uint32_t kVariantMask = (1 << 2) - 1; - - static uint32_t pack(int variant, int weight, bool italic); - - uint32_t bits; - uint32_t mLanguageListId; -}; - -enum FontVariant { - VARIANT_DEFAULT = 0, - VARIANT_COMPACT = 1, - VARIANT_ELEGANT = 2, -}; - -inline android::hash_t hash_type(const FontStyle& style) { - return style.hash(); -} - -// attributes representing transforms (fake bold, fake italic) to match styles -class FontFakery { - public: - FontFakery() : mFakeBold(false), mFakeItalic(false) {} - FontFakery(bool fakeBold, bool fakeItalic) - : mFakeBold(fakeBold), mFakeItalic(fakeItalic) {} - // TODO: want to support graded fake bolding - bool isFakeBold() { return mFakeBold; } - bool isFakeItalic() { return mFakeItalic; } - - private: - bool mFakeBold; - bool mFakeItalic; -}; - -struct FakedFont { - // ownership is the enclosing FontCollection - MinikinFont* font; - FontFakery fakery; -}; - -typedef uint32_t AxisTag; - -struct Font { - Font(const std::shared_ptr& typeface, FontStyle style); - Font(std::shared_ptr&& typeface, FontStyle style); - Font(Font&& o); - Font(const Font& o); - - std::shared_ptr typeface; - FontStyle style; - - std::unordered_set getSupportedAxesLocked() const; -}; - -struct FontVariation { - FontVariation(AxisTag axisTag, float value) - : axisTag(axisTag), value(value) {} - AxisTag axisTag; - float value; -}; - -class FontFamily { - public: - explicit FontFamily(std::vector&& fonts); - FontFamily(int variant, std::vector&& fonts); - FontFamily(uint32_t langId, int variant, std::vector&& fonts); - - // TODO: Good to expose FontUtil.h. - static bool analyzeStyle(const std::shared_ptr& typeface, - int* weight, - bool* italic); - FakedFont getClosestMatch(FontStyle style) const; - - uint32_t langId() const { return mLangId; } - int variant() const { return mVariant; } - - // API's for enumerating the fonts in a family. These don't guarantee any - // particular order - size_t getNumFonts() const { return mFonts.size(); } - const std::shared_ptr& getFont(size_t index) const { - return mFonts[index].typeface; - } - FontStyle getStyle(size_t index) const { return mFonts[index].style; } - bool isColorEmojiFamily() const; - const std::unordered_set& supportedAxes() const { - return mSupportedAxes; - } - - // Get Unicode coverage. - const SparseBitSet& getCoverage() const { return mCoverage; } - - // Returns true if the font has a glyph for the code point and variation - // selector pair. Caller should acquire a lock before calling the method. - bool hasGlyph(uint32_t codepoint, uint32_t variationSelector) const; - - // Returns true if this font family has a variaion sequence table (cmap format - // 14 subtable). - bool hasVSTable() const { return mHasVSTable; } - - // Creates new FontFamily based on this family while applying font variations. - // Returns nullptr if none of variations apply to this family. - std::shared_ptr createFamilyWithVariation( - const std::vector& variations) const; - - private: - void computeCoverage(); - - uint32_t mLangId; - int mVariant; - std::vector mFonts; - std::unordered_set mSupportedAxes; - - SparseBitSet mCoverage; - bool mHasVSTable; - - // Forbid copying and assignment. - FontFamily(const FontFamily&) = delete; - void operator=(const FontFamily&) = delete; -}; - -} // namespace minikin - -#endif // MINIKIN_FONT_FAMILY_H diff --git a/third_party/txt/src/minikin/FontLanguage.cpp b/third_party/txt/src/minikin/FontLanguage.cpp deleted file mode 100644 index 0576a8340d5eb..0000000000000 --- a/third_party/txt/src/minikin/FontLanguage.cpp +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "Minikin" - -#include "FontLanguage.h" - -#include -#include -#include -#include - -namespace minikin { - -#define SCRIPT_TAG(c1, c2, c3, c4) \ - (((uint32_t)(c1)) << 24 | ((uint32_t)(c2)) << 16 | ((uint32_t)(c3)) << 8 | \ - ((uint32_t)(c4))) - -// Check if a language code supports emoji according to its subtag -static bool isEmojiSubtag(const char* buf, - size_t bufLen, - const char* subtag, - size_t subtagLen) { - if (bufLen < subtagLen) { - return false; - } - if (strncmp(buf, subtag, subtagLen) != 0) { - return false; // no match between two strings - } - return (bufLen == subtagLen || buf[subtagLen] == '\0' || - buf[subtagLen] == '-' || buf[subtagLen] == '_'); -} - -// Pack the three letter code into 15 bits and stored to 16 bit integer. The -// highest bit is 0. For the region code, the letters must be all digits in -// three letter case, so the number of possible values are 10. For the language -// code, the letters must be all small alphabets, so the number of possible -// values are 26. Thus, 5 bits are sufficient for each case and we can pack the -// three letter language code or region code to 15 bits. -// -// In case of two letter code, use fullbit(0x1f) for the first letter instead. -static uint16_t packLanguageOrRegion(const char* c, - size_t length, - uint8_t twoLetterBase, - uint8_t threeLetterBase) { - if (length == 2) { - return 0x7c00u | // 0x1fu << 10 - (uint16_t)(c[0] - twoLetterBase) << 5 | - (uint16_t)(c[1] - twoLetterBase); - } else { - return ((uint16_t)(c[0] - threeLetterBase) << 10) | - (uint16_t)(c[1] - threeLetterBase) << 5 | - (uint16_t)(c[2] - threeLetterBase); - } -} - -static size_t unpackLanguageOrRegion(uint16_t in, - char* out, - uint8_t twoLetterBase, - uint8_t threeLetterBase) { - uint8_t first = (in >> 10) & 0x1f; - uint8_t second = (in >> 5) & 0x1f; - uint8_t third = in & 0x1f; - - if (first == 0x1f) { - out[0] = second + twoLetterBase; - out[1] = third + twoLetterBase; - return 2; - } else { - out[0] = first + threeLetterBase; - out[1] = second + threeLetterBase; - out[2] = third + threeLetterBase; - return 3; - } -} - -// Find the next '-' or '_' index from startOffset position. If not found, -// returns bufferLength. -static size_t nextDelimiterIndex(const char* buffer, - size_t bufferLength, - size_t startOffset) { - for (size_t i = startOffset; i < bufferLength; ++i) { - if (buffer[i] == '-' || buffer[i] == '_') { - return i; - } - } - return bufferLength; -} - -static inline bool isLowercase(char c) { - return 'a' <= c && c <= 'z'; -} - -static inline bool isUppercase(char c) { - return 'A' <= c && c <= 'Z'; -} - -static inline bool isDigit(char c) { - return '0' <= c && c <= '9'; -} - -// Returns true if the buffer is valid for language code. -static inline bool isValidLanguageCode(const char* buffer, size_t length) { - if (length != 2 && length != 3) - return false; - if (!isLowercase(buffer[0])) - return false; - if (!isLowercase(buffer[1])) - return false; - if (length == 3 && !isLowercase(buffer[2])) - return false; - return true; -} - -// Returns true if buffer is valid for script code. The length of buffer must -// be 4. -static inline bool isValidScriptCode(const char* buffer) { - return isUppercase(buffer[0]) && isLowercase(buffer[1]) && - isLowercase(buffer[2]) && isLowercase(buffer[3]); -} - -// Returns true if the buffer is valid for region code. -static inline bool isValidRegionCode(const char* buffer, size_t length) { - return (length == 2 && isUppercase(buffer[0]) && isUppercase(buffer[1])) || - (length == 3 && isDigit(buffer[0]) && isDigit(buffer[1]) && - isDigit(buffer[2])); -} - -// Parse BCP 47 language identifier into internal structure -FontLanguage::FontLanguage(const char* buf, size_t length) : FontLanguage() { - size_t firstDelimiterPos = nextDelimiterIndex(buf, length, 0); - if (isValidLanguageCode(buf, firstDelimiterPos)) { - mLanguage = packLanguageOrRegion(buf, firstDelimiterPos, 'a', 'a'); - } else { - // We don't understand anything other than two-letter or three-letter - // language codes, so we skip parsing the rest of the string. - return; - } - - if (firstDelimiterPos == length) { - mHbLanguage = hb_language_from_string(getString().c_str(), -1); - return; // Language code only. - } - - size_t nextComponentStartPos = firstDelimiterPos + 1; - size_t nextDelimiterPos = - nextDelimiterIndex(buf, length, nextComponentStartPos); - size_t componentLength = nextDelimiterPos - nextComponentStartPos; - - if (componentLength == 4) { - // Possibly script code. - const char* p = buf + nextComponentStartPos; - if (isValidScriptCode(p)) { - mScript = SCRIPT_TAG(p[0], p[1], p[2], p[3]); - mSubScriptBits = scriptToSubScriptBits(mScript); - } - - if (nextDelimiterPos == length) { - mHbLanguage = hb_language_from_string(getString().c_str(), -1); - mEmojiStyle = resolveEmojiStyle(buf, length, mScript); - return; // No region code. - } - - nextComponentStartPos = nextDelimiterPos + 1; - nextDelimiterPos = nextDelimiterIndex(buf, length, nextComponentStartPos); - componentLength = nextDelimiterPos - nextComponentStartPos; - } - - if (componentLength == 2 || componentLength == 3) { - // Possibly region code. - const char* p = buf + nextComponentStartPos; - if (isValidRegionCode(p, componentLength)) { - mRegion = packLanguageOrRegion(p, componentLength, 'A', '0'); - } - } - - mHbLanguage = hb_language_from_string(getString().c_str(), -1); - mEmojiStyle = resolveEmojiStyle(buf, length, mScript); -} - -// static -FontLanguage::EmojiStyle FontLanguage::resolveEmojiStyle(const char* buf, - size_t length, - uint32_t script) { - // First, lookup emoji subtag. - // 10 is the length of "-u-em-text", which is the shortest emoji subtag, - // unnecessary comparison can be avoided if total length is smaller than 10. - const size_t kMinSubtagLength = 10; - if (length >= kMinSubtagLength) { - static const char kPrefix[] = "-u-em-"; - const char* pos = - std::search(buf, buf + length, kPrefix, kPrefix + strlen(kPrefix)); - if (pos != buf + length) { // found - pos += strlen(kPrefix); - const size_t remainingLength = length - (pos - buf); - if (isEmojiSubtag(pos, remainingLength, "emoji", 5)) { - return EMSTYLE_EMOJI; - } else if (isEmojiSubtag(pos, remainingLength, "text", 4)) { - return EMSTYLE_TEXT; - } else if (isEmojiSubtag(pos, remainingLength, "default", 7)) { - return EMSTYLE_DEFAULT; - } - } - } - - // If no emoji subtag was provided, resolve the emoji style from script code. - if (script == SCRIPT_TAG('Z', 's', 'y', 'e')) { - return EMSTYLE_EMOJI; - } else if (script == SCRIPT_TAG('Z', 's', 'y', 'm')) { - return EMSTYLE_TEXT; - } - - return EMSTYLE_EMPTY; -} - -// static -uint8_t FontLanguage::scriptToSubScriptBits(uint32_t script) { - uint8_t subScriptBits = 0u; - switch (script) { - case SCRIPT_TAG('B', 'o', 'p', 'o'): - subScriptBits = kBopomofoFlag; - break; - case SCRIPT_TAG('H', 'a', 'n', 'g'): - subScriptBits = kHangulFlag; - break; - case SCRIPT_TAG('H', 'a', 'n', 'b'): - // Bopomofo is almost exclusively used in Taiwan. - subScriptBits = kHanFlag | kBopomofoFlag; - break; - case SCRIPT_TAG('H', 'a', 'n', 'i'): - subScriptBits = kHanFlag; - break; - case SCRIPT_TAG('H', 'a', 'n', 's'): - subScriptBits = kHanFlag | kSimplifiedChineseFlag; - break; - case SCRIPT_TAG('H', 'a', 'n', 't'): - subScriptBits = kHanFlag | kTraditionalChineseFlag; - break; - case SCRIPT_TAG('H', 'i', 'r', 'a'): - subScriptBits = kHiraganaFlag; - break; - case SCRIPT_TAG('H', 'r', 'k', 't'): - subScriptBits = kKatakanaFlag | kHiraganaFlag; - break; - case SCRIPT_TAG('J', 'p', 'a', 'n'): - subScriptBits = kHanFlag | kKatakanaFlag | kHiraganaFlag; - break; - case SCRIPT_TAG('K', 'a', 'n', 'a'): - subScriptBits = kKatakanaFlag; - break; - case SCRIPT_TAG('K', 'o', 'r', 'e'): - subScriptBits = kHanFlag | kHangulFlag; - break; - } - return subScriptBits; -} - -std::string FontLanguage::getString() const { - if (isUnsupported()) { - return "und"; - } - char buf[16]; - size_t i = unpackLanguageOrRegion(mLanguage, buf, 'a', 'a'); - if (mScript != 0) { - buf[i++] = '-'; - buf[i++] = (mScript >> 24) & 0xFFu; - buf[i++] = (mScript >> 16) & 0xFFu; - buf[i++] = (mScript >> 8) & 0xFFu; - buf[i++] = mScript & 0xFFu; - } - if (mRegion != INVALID_CODE) { - buf[i++] = '-'; - i += unpackLanguageOrRegion(mRegion, buf + i, 'A', '0'); - } - return std::string(buf, i); -} - -bool FontLanguage::isEqualScript(const FontLanguage& other) const { - return other.mScript == mScript; -} - -// static -bool FontLanguage::supportsScript(uint8_t providedBits, uint8_t requestedBits) { - return requestedBits != 0 && (providedBits & requestedBits) == requestedBits; -} - -bool FontLanguage::supportsHbScript(hb_script_t script) const { - static_assert( - SCRIPT_TAG('J', 'p', 'a', 'n') == HB_TAG('J', 'p', 'a', 'n'), - "The Minikin script and HarfBuzz hb_script_t have different encodings."); - if (script == mScript) - return true; - return supportsScript(mSubScriptBits, scriptToSubScriptBits(script)); -} - -int FontLanguage::calcScoreFor(const FontLanguages& supported) const { - bool languageScriptMatch = false; - bool subtagMatch = false; - bool scriptMatch = false; - - for (size_t i = 0; i < supported.size(); ++i) { - if (mEmojiStyle != EMSTYLE_EMPTY && - mEmojiStyle == supported[i].mEmojiStyle) { - subtagMatch = true; - if (mLanguage == supported[i].mLanguage) { - return 4; - } - } - if (isEqualScript(supported[i]) || - supportsScript(supported[i].mSubScriptBits, mSubScriptBits)) { - scriptMatch = true; - if (mLanguage == supported[i].mLanguage) { - languageScriptMatch = true; - } - } - } - - if (supportsScript(supported.getUnionOfSubScriptBits(), mSubScriptBits)) { - scriptMatch = true; - if (mLanguage == supported[0].mLanguage && - supported.isAllTheSameLanguage()) { - return 3; - } - } - - if (languageScriptMatch) { - return 3; - } else if (subtagMatch) { - return 2; - } else if (scriptMatch) { - return 1; - } - return 0; -} - -FontLanguages::FontLanguages(std::vector&& languages) - : mLanguages(std::move(languages)) { - if (mLanguages.empty()) { - return; - } - - const FontLanguage& lang = mLanguages[0]; - - mIsAllTheSameLanguage = true; - mUnionOfSubScriptBits = lang.mSubScriptBits; - for (size_t i = 1; i < mLanguages.size(); ++i) { - mUnionOfSubScriptBits |= mLanguages[i].mSubScriptBits; - if (mIsAllTheSameLanguage && lang.mLanguage != mLanguages[i].mLanguage) { - mIsAllTheSameLanguage = false; - } - } -} - -#undef SCRIPT_TAG -} // namespace minikin diff --git a/third_party/txt/src/minikin/FontLanguage.h b/third_party/txt/src/minikin/FontLanguage.h deleted file mode 100644 index 1a46abb587342..0000000000000 --- a/third_party/txt/src/minikin/FontLanguage.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#ifndef MINIKIN_FONT_LANGUAGE_H -#define MINIKIN_FONT_LANGUAGE_H - -#include -#include - -#include - -namespace minikin { - -// Due to the limits in font fallback score calculation, we can't use anything -// more than 12 languages. -const size_t FONT_LANGUAGES_LIMIT = 12; - -// The language or region code is encoded to 15 bits. -const uint16_t INVALID_CODE = 0x7fff; - -class FontLanguages; - -// FontLanguage is a compact representation of a BCP 47 language tag. It -// does not capture all possible information, only what directly affects -// font rendering. -struct FontLanguage { - public: - enum EmojiStyle : uint8_t { - EMSTYLE_EMPTY = 0, - EMSTYLE_DEFAULT = 1, - EMSTYLE_EMOJI = 2, - EMSTYLE_TEXT = 3, - }; - // Default constructor creates the unsupported language. - FontLanguage() - : mScript(0ul), - mLanguage(INVALID_CODE), - mRegion(INVALID_CODE), - mHbLanguage(HB_LANGUAGE_INVALID), - mSubScriptBits(0ul), - mEmojiStyle(EMSTYLE_EMPTY) {} - - // Parse from string - FontLanguage(const char* buf, size_t length); - - bool operator==(const FontLanguage other) const { - return !isUnsupported() && isEqualScript(other) && - mLanguage == other.mLanguage && mRegion == other.mRegion && - mEmojiStyle == other.mEmojiStyle; - } - - bool operator!=(const FontLanguage other) const { return !(*this == other); } - - bool isUnsupported() const { return mLanguage == INVALID_CODE; } - EmojiStyle getEmojiStyle() const { return mEmojiStyle; } - hb_language_t getHbLanguage() const { return mHbLanguage; } - - bool isEqualScript(const FontLanguage& other) const; - - // Returns true if this script supports the given script. For example, ja-Jpan - // supports Hira, ja-Hira doesn't support Jpan. - bool supportsHbScript(hb_script_t script) const; - - std::string getString() const; - - // Calculates a matching score. This score represents how well the input - // languages cover this language. The maximum score in the language list is - // returned. 0 = no match, 1 = script match, 2 = script and primary language - // match. - int calcScoreFor(const FontLanguages& supported) const; - - uint64_t getIdentifier() const { - return ((uint64_t)mLanguage << 49) | ((uint64_t)mScript << 17) | - ((uint64_t)mRegion << 2) | mEmojiStyle; - } - - private: - friend class FontLanguages; // for FontLanguages constructor - - // ISO 15924 compliant script code. The 4 chars script code are packed into a - // 32 bit integer. - uint32_t mScript; - - // ISO 639-1 or ISO 639-2 compliant language code. - // The two- or three-letter language code is packed into a 15 bit integer. - // mLanguage = 0 means the FontLanguage is unsupported. - uint16_t mLanguage; - - // ISO 3166-1 or UN M.49 compliant region code. The two-letter or three-digit - // region code is packed into a 15 bit integer. - uint16_t mRegion; - - // The language to be passed HarfBuzz shaper. - hb_language_t mHbLanguage; - - // For faster comparing, use 7 bits for specific scripts. - static const uint8_t kBopomofoFlag = 1u; - static const uint8_t kHanFlag = 1u << 1; - static const uint8_t kHangulFlag = 1u << 2; - static const uint8_t kHiraganaFlag = 1u << 3; - static const uint8_t kKatakanaFlag = 1u << 4; - static const uint8_t kSimplifiedChineseFlag = 1u << 5; - static const uint8_t kTraditionalChineseFlag = 1u << 6; - uint8_t mSubScriptBits; - - EmojiStyle mEmojiStyle; - - static uint8_t scriptToSubScriptBits(uint32_t script); - - static EmojiStyle resolveEmojiStyle(const char* buf, - size_t length, - uint32_t script); - - // Returns true if the provide subscript bits has the requested subscript - // bits. Note that this function returns false if the requested subscript bits - // are empty. - static bool supportsScript(uint8_t providedBits, uint8_t requestedBits); -}; - -// An immutable list of languages. -class FontLanguages { - public: - explicit FontLanguages(std::vector&& languages); - FontLanguages() : mUnionOfSubScriptBits(0), mIsAllTheSameLanguage(false) {} - FontLanguages(FontLanguages&&) = default; - - size_t size() const { return mLanguages.size(); } - bool empty() const { return mLanguages.empty(); } - const FontLanguage& operator[](size_t n) const { return mLanguages[n]; } - - private: - friend struct FontLanguage; // for calcScoreFor - - std::vector mLanguages; - uint8_t mUnionOfSubScriptBits; - bool mIsAllTheSameLanguage; - - uint8_t getUnionOfSubScriptBits() const { return mUnionOfSubScriptBits; } - bool isAllTheSameLanguage() const { return mIsAllTheSameLanguage; } - - // Do not copy and assign. - FontLanguages(const FontLanguages&) = delete; - void operator=(const FontLanguages&) = delete; -}; - -} // namespace minikin - -#endif // MINIKIN_FONT_LANGUAGE_H diff --git a/third_party/txt/src/minikin/FontLanguageListCache.cpp b/third_party/txt/src/minikin/FontLanguageListCache.cpp deleted file mode 100644 index eb4ac69ee1346..0000000000000 --- a/third_party/txt/src/minikin/FontLanguageListCache.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "Minikin" - -#include "FontLanguageListCache.h" - -#include -#include -#include - -#include - -#include "FontLanguage.h" -#include "MinikinInternal.h" - -namespace minikin { - -const uint32_t FontLanguageListCache::kEmptyListId; - -// Returns the text length of output. -static size_t toLanguageTag(char* output, - size_t outSize, - const std::string& locale) { - output[0] = '\0'; - if (locale.empty()) { - return 0; - } - - size_t outLength = 0; - UErrorCode uErr = U_ZERO_ERROR; - outLength = uloc_canonicalize(locale.c_str(), output, outSize, &uErr); - if (U_FAILURE(uErr)) { - // unable to build a proper language identifier - ALOGD("uloc_canonicalize(\"%s\") failed: %s", locale.c_str(), - u_errorName(uErr)); - output[0] = '\0'; - return 0; - } - - // Preserve "und" and "und-****" since uloc_addLikelySubtags changes "und" to - // "en-Latn-US". - if (strncmp(output, "und", 3) == 0 && - (outLength == 3 || (outLength == 8 && output[3] == '_'))) { - return outLength; - } - - char likelyChars[ULOC_FULLNAME_CAPACITY]; - uErr = U_ZERO_ERROR; - uloc_addLikelySubtags(output, likelyChars, ULOC_FULLNAME_CAPACITY, &uErr); - if (U_FAILURE(uErr)) { - // unable to build a proper language identifier - ALOGD("uloc_addLikelySubtags(\"%s\") failed: %s", output, - u_errorName(uErr)); - output[0] = '\0'; - return 0; - } - - uErr = U_ZERO_ERROR; - outLength = - uloc_toLanguageTag(likelyChars, output, outSize, /*false*/ 0, &uErr); - if (U_FAILURE(uErr)) { - // unable to build a proper language identifier - ALOGD("uloc_toLanguageTag(\"%s\") failed: %s", likelyChars, - u_errorName(uErr)); - output[0] = '\0'; - return 0; - } -#ifdef VERBOSE_DEBUG - ALOGD("ICU normalized '%s' to '%s'", locale.c_str(), output); -#endif - return outLength; -} - -static std::vector parseLanguageList(const std::string& input) { - std::vector result; - size_t currentIdx = 0; - size_t commaLoc = 0; - char langTag[ULOC_FULLNAME_CAPACITY]; - std::unordered_set seen; - std::string locale(input.size(), 0); - - while ((commaLoc = input.find_first_of(',', currentIdx)) != - std::string::npos) { - locale.assign(input, currentIdx, commaLoc - currentIdx); - currentIdx = commaLoc + 1; - size_t length = toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, locale); - FontLanguage lang(langTag, length); - uint64_t identifier = lang.getIdentifier(); - if (!lang.isUnsupported() && seen.count(identifier) == 0) { - result.push_back(lang); - if (result.size() == FONT_LANGUAGES_LIMIT) { - break; - } - seen.insert(identifier); - } - } - if (result.size() < FONT_LANGUAGES_LIMIT) { - locale.assign(input, currentIdx, input.size() - currentIdx); - size_t length = toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, locale); - FontLanguage lang(langTag, length); - uint64_t identifier = lang.getIdentifier(); - if (!lang.isUnsupported() && seen.count(identifier) == 0) { - result.push_back(lang); - } - } - return result; -} - -// static -uint32_t FontLanguageListCache::getId(const std::string& languages) { - FontLanguageListCache* inst = FontLanguageListCache::getInstance(); - std::unordered_map::const_iterator it = - inst->mLanguageListLookupTable.find(languages); - if (it != inst->mLanguageListLookupTable.end()) { - return it->second; - } - - // Given language list is not in cache. Insert it and return newly assigned - // ID. - const uint32_t nextId = inst->mLanguageLists.size(); - FontLanguages fontLanguages(parseLanguageList(languages)); - if (fontLanguages.empty()) { - return kEmptyListId; - } - inst->mLanguageLists.push_back(std::move(fontLanguages)); - inst->mLanguageListLookupTable.insert(std::make_pair(languages, nextId)); - return nextId; -} - -// static -const FontLanguages& FontLanguageListCache::getById(uint32_t id) { - FontLanguageListCache* inst = FontLanguageListCache::getInstance(); - LOG_ALWAYS_FATAL_IF(id >= inst->mLanguageLists.size(), - "Lookup by unknown language list ID."); - return inst->mLanguageLists[id]; -} - -// static -FontLanguageListCache* FontLanguageListCache::getInstance() { - assertMinikinLocked(); - static FontLanguageListCache* instance = nullptr; - if (instance == nullptr) { - instance = new FontLanguageListCache(); - - // Insert an empty language list for mapping default language list to - // kEmptyListId. The default language list has only one FontLanguage and it - // is the unsupported language. - instance->mLanguageLists.push_back(FontLanguages()); - instance->mLanguageListLookupTable.insert(std::make_pair("", kEmptyListId)); - } - return instance; -} - -} // namespace minikin diff --git a/third_party/txt/src/minikin/FontLanguageListCache.h b/third_party/txt/src/minikin/FontLanguageListCache.h deleted file mode 100644 index c84dd8847798f..0000000000000 --- a/third_party/txt/src/minikin/FontLanguageListCache.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#ifndef MINIKIN_FONT_LANGUAGE_LIST_CACHE_H -#define MINIKIN_FONT_LANGUAGE_LIST_CACHE_H - -#include - -#include -#include "FontLanguage.h" - -namespace minikin { - -class FontLanguageListCache { - public: - // A special ID for the empty language list. - // This value must be 0 since the empty language list is inserted into - // mLanguageLists by default. - const static uint32_t kEmptyListId = 0; - - // Returns language list ID for the given string representation of - // FontLanguages. Caller should acquire a lock before calling the method. - static uint32_t getId(const std::string& languages); - - // Caller should acquire a lock before calling the method. - static const FontLanguages& getById(uint32_t id); - - private: - FontLanguageListCache() {} // Singleton - ~FontLanguageListCache() {} - - // Caller should acquire a lock before calling the method. - static FontLanguageListCache* getInstance(); - - std::vector mLanguageLists; - - // A map from string representation of the font language list to the ID. - std::unordered_map mLanguageListLookupTable; -}; - -} // namespace minikin - -#endif // MINIKIN_FONT_LANGUAGE_LIST_CACHE_H diff --git a/third_party/txt/src/minikin/FontUtils.cpp b/third_party/txt/src/minikin/FontUtils.cpp deleted file mode 100644 index b6a0f120484dc..0000000000000 --- a/third_party/txt/src/minikin/FontUtils.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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 - -#include "FontUtils.h" - -namespace minikin { - -static uint16_t readU16(const uint8_t* data, size_t offset) { - return data[offset] << 8 | data[offset + 1]; -} - -static uint32_t readU32(const uint8_t* data, size_t offset) { - return ((uint32_t)data[offset]) << 24 | ((uint32_t)data[offset + 1]) << 16 | - ((uint32_t)data[offset + 2]) << 8 | ((uint32_t)data[offset + 3]); -} - -bool analyzeStyle(const uint8_t* os2_data, - size_t os2_size, - int* weight, - bool* italic) { - const size_t kUsWeightClassOffset = 4; - const size_t kFsSelectionOffset = 62; - const uint16_t kItalicFlag = (1 << 0); - if (os2_size < kFsSelectionOffset + 2) { - return false; - } - uint16_t weightClass = readU16(os2_data, kUsWeightClassOffset); - *weight = weightClass / 100; - uint16_t fsSelection = readU16(os2_data, kFsSelectionOffset); - *italic = (fsSelection & kItalicFlag) != 0; - return true; -} - -void analyzeAxes(const uint8_t* fvar_data, - size_t fvar_size, - std::unordered_set* axes) { - const size_t kMajorVersionOffset = 0; - const size_t kMinorVersionOffset = 2; - const size_t kOffsetToAxesArrayOffset = 4; - const size_t kAxisCountOffset = 8; - const size_t kAxisSizeOffset = 10; - - axes->clear(); - - if (fvar_size < kAxisSizeOffset + 2) { - return; - } - const uint16_t majorVersion = readU16(fvar_data, kMajorVersionOffset); - const uint16_t minorVersion = readU16(fvar_data, kMinorVersionOffset); - const uint32_t axisOffset = readU16(fvar_data, kOffsetToAxesArrayOffset); - const uint32_t axisCount = readU16(fvar_data, kAxisCountOffset); - const uint32_t axisSize = readU16(fvar_data, kAxisSizeOffset); - - if (majorVersion != 1 || minorVersion != 0 || axisOffset != 0x10 || - axisSize != 0x14) { - return; // Unsupported version. - } - if (fvar_size < axisOffset + axisOffset * axisCount) { - return; // Invalid table size. - } - for (uint32_t i = 0; i < axisCount; ++i) { - size_t axisRecordOffset = axisOffset + i * axisSize; - uint32_t tag = readU32(fvar_data, axisRecordOffset); - axes->insert(tag); - } -} -} // namespace minikin diff --git a/third_party/txt/src/minikin/FontUtils.h b/third_party/txt/src/minikin/FontUtils.h deleted file mode 100644 index b01e54bd26aa5..0000000000000 --- a/third_party/txt/src/minikin/FontUtils.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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. - */ - -#ifndef MINIKIN_FONT_UTILS_H -#define MINIKIN_FONT_UTILS_H - -#include - -namespace minikin { - -bool analyzeStyle(const uint8_t* os2_data, - size_t os2_size, - int* weight, - bool* italic); -void analyzeAxes(const uint8_t* fvar_data, - size_t fvar_size, - std::unordered_set* axes); - -} // namespace minikin - -#endif // MINIKIN_ANALYZE_STYLE_H diff --git a/third_party/txt/src/minikin/GraphemeBreak.cpp b/third_party/txt/src/minikin/GraphemeBreak.cpp deleted file mode 100644 index b711fae9aab7b..0000000000000 --- a/third_party/txt/src/minikin/GraphemeBreak.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * 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 -#include -#include - -#include -#include -#include "MinikinInternal.h" -#include "utils/WindowsUtils.h" - -namespace minikin { - -int32_t tailoredGraphemeClusterBreak(uint32_t c) { - // Characters defined as Control that we want to treat them as Extend. - // These are curated manually. - if (c == 0x00AD // SHY - || c == 0x061C // ALM - || c == 0x180E // MONGOLIAN VOWEL SEPARATOR - || c == 0x200B // ZWSP - || c == 0x200E // LRM - || c == 0x200F // RLM - || (0x202A <= c && c <= 0x202E) // LRE, RLE, PDF, LRO, RLO - || ((c | 0xF) == - 0x206F) // WJ, invisible math operators, LRI, RLI, FSI, PDI, - // and the deprecated invisible format controls - || c == 0xFEFF // BOM - || ((c | 0x7F) == - 0xE007F)) // recently undeprecated tag characters in Plane 14 - return U_GCB_EXTEND; - // THAI CHARACTER SARA AM is treated as a normal letter by most other - // implementations: they allow a grapheme break before it. - else if (c == 0x0E33) - return U_GCB_OTHER; - else - return u_getIntPropertyValue(c, UCHAR_GRAPHEME_CLUSTER_BREAK); -} - -// Returns true for all characters whose IndicSyllabicCategory is Pure_Killer. -// From http://www.unicode.org/Public/9.0.0/ucd/IndicSyllabicCategory.txt -bool isPureKiller(uint32_t c) { - return (c == 0x0E3A || c == 0x0E4E || c == 0x0F84 || c == 0x103A || - c == 0x1714 || c == 0x1734 || c == 0x17D1 || c == 0x1BAA || - c == 0x1BF2 || c == 0x1BF3 || c == 0xA806 || c == 0xA953 || - c == 0xABED || c == 0x11134 || c == 0x112EA || c == 0x1172B); -} - -bool GraphemeBreak::isGraphemeBreak(const float* advances, - const uint16_t* buf, - size_t start, - size_t count, - const size_t offset) { - // This implementation closely follows Unicode Standard Annex #29 on - // Unicode Text Segmentation (http://www.unicode.org/reports/tr29/), - // implementing a tailored version of extended grapheme clusters. - // The GB rules refer to section 3.1.1, Grapheme Cluster Boundary Rules. - - // Rule GB1, sot ÷; Rule GB2, ÷ eot - if (offset <= start || offset >= start + count) { - return true; - } - if (U16_IS_TRAIL(buf[offset])) { - // Don't break a surrogate pair, but a lonely trailing surrogate pair is a - // break - return !U16_IS_LEAD(buf[offset - 1]); - } - uint32_t c1 = 0; - uint32_t c2 = 0; - size_t offset_back = offset; - size_t offset_forward = offset; - U16_PREV(buf, start, offset_back, c1); - U16_NEXT(buf, offset_forward, start + count, c2); - int32_t p1 = tailoredGraphemeClusterBreak(c1); - int32_t p2 = tailoredGraphemeClusterBreak(c2); - // Rule GB3, CR x LF - if (p1 == U_GCB_CR && p2 == U_GCB_LF) { - return false; - } - // Rule GB4, (Control | CR | LF) ÷ - if (p1 == U_GCB_CONTROL || p1 == U_GCB_CR || p1 == U_GCB_LF) { - return true; - } - // Rule GB5, ÷ (Control | CR | LF) - if (p2 == U_GCB_CONTROL || p2 == U_GCB_CR || p2 == U_GCB_LF) { - return true; - } - // Rule GB6, L x ( L | V | LV | LVT ) - if (p1 == U_GCB_L && - (p2 == U_GCB_L || p2 == U_GCB_V || p2 == U_GCB_LV || p2 == U_GCB_LVT)) { - return false; - } - // Rule GB7, ( LV | V ) x ( V | T ) - if ((p1 == U_GCB_LV || p1 == U_GCB_V) && (p2 == U_GCB_V || p2 == U_GCB_T)) { - return false; - } - // Rule GB8, ( LVT | T ) x T - if ((p1 == U_GCB_LVT || p1 == U_GCB_T) && p2 == U_GCB_T) { - return false; - } - // Rule GB9, x (Extend | ZWJ); Rule GB9a, x SpacingMark; Rule GB9b, Prepend x - if (p2 == U_GCB_EXTEND || p2 == U_GCB_ZWJ || p2 == U_GCB_SPACING_MARK || - p1 == U_GCB_PREPEND) { - return false; - } - - // This is used to decide font-dependent grapheme clusters. If we don't have - // the advance information, we become conservative in grapheme breaking and - // assume that it has no advance. - const bool c2_has_advance = - (advances != nullptr && advances[offset - start] != 0.0); - - // All the following rules are font-dependent, in the way that if we know c2 - // has an advance, we definitely know that it cannot form a grapheme with the - // character(s) before it. So we make the decision in favor a grapheme break - // early. - if (c2_has_advance) { - return true; - } - - // Note: For Rule GB10 and GB11 below, we do not use the Unicode line breaking - // properties for determining emoji-ness and carry our own data, because our - // data could be more fresh than what ICU provides. - // - // Tailored version of Rule GB10, (E_Base | EBG) Extend* × E_Modifier. - // The rule itself says do not break between emoji base and emoji modifiers, - // skipping all Extend characters. Variation selectors are considered Extend, - // so they are handled fine. - // - // We tailor this by requiring that an actual ligature is formed. If the font - // doesn't form a ligature, we allow a break before the modifier. - if (isEmojiModifier(c2)) { - uint32_t c0 = c1; - size_t offset_backback = offset_back; - int32_t p0 = p1; - if (p0 == U_GCB_EXTEND && offset_backback > start) { - // skip over emoji variation selector - U16_PREV(buf, start, offset_backback, c0); - } - if (isEmojiBase(c0)) { - return false; - } - } - - // Tailored version of Rule GB11, ZWJ × (Glue_After_Zwj | EBG) - // We try to make emoji sequences with ZWJ a single grapheme cluster, but only - // if they actually merge to one cluster. So we are more relaxed than the UAX - // #29 rules in accepting any emoji character after the ZWJ, but are tighter - // in that we only treat it as one cluster if a ligature is actually formed - // and we also require the character before the ZWJ to also be an emoji. - if (p1 == U_GCB_ZWJ && isEmoji(c2) && offset_back > start) { - // look at character before ZWJ to see that both can participate in an - // emoji zwj sequence - uint32_t c0 = 0; - size_t offset_backback = offset_back; - U16_PREV(buf, start, offset_backback, c0); - if (c0 == 0xFE0F && offset_backback > start) { - // skip over emoji variation selector - U16_PREV(buf, start, offset_backback, c0); - } - if (isEmoji(c0)) { - return false; - } - } - - // Tailored version of Rule GB12 and Rule GB13 that look at even-odd cases. - // sot (RI RI)* RI x RI - // [^RI] (RI RI)* RI x RI - // - // If we have font information, we have already broken the cluster if and only - // if the second character had no advance, which means a ligature was formed. - // If we don't, we look back like UAX #29 recommends, but only up to 1000 code - // units. - if (p1 == U_GCB_REGIONAL_INDICATOR && p2 == U_GCB_REGIONAL_INDICATOR) { - if (advances != nullptr) { - // We have advances information. But if we are here, we already know c2 - // has no advance. So we should definitely disallow a break. - return false; - } else { - // Look at up to 1000 code units. - const size_t lookback_barrier = - std::max((ssize_t)start, (ssize_t)offset_back - 1000); - size_t offset_backback = offset_back; - while (offset_backback > lookback_barrier) { - uint32_t c0 = 0; - U16_PREV(buf, lookback_barrier, offset_backback, c0); - if (tailoredGraphemeClusterBreak(c0) != U_GCB_REGIONAL_INDICATOR) { - offset_backback += U16_LENGTH(c0); - break; - } - } - // The number 4 comes from the number of code units in a whole flag. - return (offset - offset_backback) % 4 == 0; - } - } - // Cluster Indic syllables together (tailoring of UAX #29). - // Immediately after each virama (that is not just a pure killer) followed by - // a letter, we disallow grapheme breaks (if we are here, we don't know about - // advances, or we already know that c2 has no advance). - if (u_getIntPropertyValue(c1, UCHAR_CANONICAL_COMBINING_CLASS) == 9 // virama - && !isPureKiller(c1) && - u_getIntPropertyValue(c2, UCHAR_GENERAL_CATEGORY) == U_OTHER_LETTER) { - return false; - } - // Rule GB999, Any ÷ Any - return true; -} - -size_t GraphemeBreak::getTextRunCursor(const float* advances, - const uint16_t* buf, - size_t start, - size_t count, - size_t offset, - MoveOpt opt) { - switch (opt) { - case AFTER: - if (offset < start + count) { - offset++; - } - // fall through - case AT_OR_AFTER: - while (!isGraphemeBreak(advances, buf, start, count, offset)) { - offset++; - } - break; - case BEFORE: - if (offset > start) { - offset--; - } - // fall through - case AT_OR_BEFORE: - while (!isGraphemeBreak(advances, buf, start, count, offset)) { - offset--; - } - break; - case AT: - if (!isGraphemeBreak(advances, buf, start, count, offset)) { - offset = (size_t)-1; - } - break; - } - return offset; -} - -} // namespace minikin diff --git a/third_party/txt/src/minikin/GraphemeBreak.h b/third_party/txt/src/minikin/GraphemeBreak.h deleted file mode 100644 index 62b9d59aa9344..0000000000000 --- a/third_party/txt/src/minikin/GraphemeBreak.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * 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. - */ - -#ifndef MINIKIN_GRAPHEME_BREAK_H -#define MINIKIN_GRAPHEME_BREAK_H - -#include -#include - -namespace minikin { - -class GraphemeBreak { - public: - // These values must be kept in sync with CURSOR_AFTER etc in Paint.java - enum MoveOpt { - AFTER = 0, - AT_OR_AFTER = 1, - BEFORE = 2, - AT_OR_BEFORE = 3, - AT = 4 - }; - - // Determine whether the given offset is a grapheme break. - // This implementation generally follows Unicode's UTR #29 extended - // grapheme break, with various tweaks. - static bool isGraphemeBreak(const float* advances, - const uint16_t* buf, - size_t start, - size_t count, - size_t offset); - - // Matches Android's Java API. Note, return (size_t)-1 for AT to - // signal non-break because unsigned return type. - static size_t getTextRunCursor(const float* advances, - const uint16_t* buf, - size_t start, - size_t count, - size_t offset, - MoveOpt opt); -}; - -} // namespace minikin - -#endif // MINIKIN_GRAPHEME_BREAK_H diff --git a/third_party/txt/src/minikin/HbFontCache.cpp b/third_party/txt/src/minikin/HbFontCache.cpp deleted file mode 100644 index d60fcc73730e0..0000000000000 --- a/third_party/txt/src/minikin/HbFontCache.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "Minikin" - -#include "HbFontCache.h" - -#include -#include - -#include -#include - -#include -#include "MinikinInternal.h" - -namespace minikin { - -class HbFontCache : private android::OnEntryRemoved { - public: - HbFontCache() : mCache(kMaxEntries) { - mCache.setOnEntryRemovedListener(this); - } - - // callback for OnEntryRemoved - void operator()(int32_t& /* key */, hb_font_t*& value) { - hb_font_destroy(value); - } - - hb_font_t* get(int32_t fontId) { return mCache.get(fontId); } - - void put(int32_t fontId, hb_font_t* font) { mCache.put(fontId, font); } - - void clear() { mCache.clear(); } - - void remove(int32_t fontId) { mCache.remove(fontId); } - - private: - static const size_t kMaxEntries = 100; - - android::LruCache mCache; -}; - -HbFontCache* getFontCacheLocked() { - assertMinikinLocked(); - static HbFontCache* cache = nullptr; - if (cache == nullptr) { - cache = new HbFontCache(); - } - return cache; -} - -void purgeHbFontCacheLocked() { - assertMinikinLocked(); - getFontCacheLocked()->clear(); -} - -void purgeHbFontLocked(const MinikinFont* minikinFont) { - assertMinikinLocked(); - const int32_t fontId = minikinFont->GetUniqueId(); - getFontCacheLocked()->remove(fontId); -} - -// Returns a new reference to a hb_font_t object, caller is -// responsible for calling hb_font_destroy() on it. -hb_font_t* getHbFontLocked(const MinikinFont* minikinFont) { - assertMinikinLocked(); - // TODO: get rid of nullFaceFont - static hb_font_t* nullFaceFont = nullptr; - if (minikinFont == nullptr) { - if (nullFaceFont == nullptr) { - nullFaceFont = hb_font_create(nullptr); - } - return hb_font_reference(nullFaceFont); - } - - HbFontCache* fontCache = getFontCacheLocked(); - const int32_t fontId = minikinFont->GetUniqueId(); - hb_font_t* font = fontCache->get(fontId); - if (font != nullptr) { - return hb_font_reference(font); - } - - hb_face_t* face = minikinFont->CreateHarfBuzzFace(); - - hb_font_t* parent_font = hb_font_create(face); - hb_ot_font_set_funcs(parent_font); - - unsigned int upem = hb_face_get_upem(face); - hb_font_set_scale(parent_font, upem, upem); - - font = hb_font_create_sub_font(parent_font); - std::vector variations; - for (const FontVariation& variation : minikinFont->GetAxes()) { - variations.push_back({variation.axisTag, variation.value}); - } - hb_font_set_variations(font, variations.data(), variations.size()); - hb_font_destroy(parent_font); - hb_face_destroy(face); - fontCache->put(fontId, font); - return hb_font_reference(font); -} - -} // namespace minikin diff --git a/third_party/txt/src/minikin/HbFontCache.h b/third_party/txt/src/minikin/HbFontCache.h deleted file mode 100644 index 59969e287e01a..0000000000000 --- a/third_party/txt/src/minikin/HbFontCache.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#ifndef MINIKIN_HBFONT_CACHE_H -#define MINIKIN_HBFONT_CACHE_H - -struct hb_font_t; - -namespace minikin { -class MinikinFont; - -void purgeHbFontCacheLocked(); -void purgeHbFontLocked(const MinikinFont* minikinFont); -hb_font_t* getHbFontLocked(const MinikinFont* minikinFont); - -} // namespace minikin -#endif // MINIKIN_HBFONT_CACHE_H diff --git a/third_party/txt/src/minikin/Hyphenator.cpp b/third_party/txt/src/minikin/Hyphenator.cpp deleted file mode 100644 index 321a0ec5c0d91..0000000000000 --- a/third_party/txt/src/minikin/Hyphenator.cpp +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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 -#include -#include -#include -#include - -// HACK: for reading pattern file -#include - -#define LOG_TAG "Minikin" - -#include "minikin/Hyphenator.h" -#include "utils/WindowsUtils.h" - -using std::vector; - -namespace minikin { - -static const uint16_t CHAR_HYPHEN_MINUS = 0x002D; -static const uint16_t CHAR_SOFT_HYPHEN = 0x00AD; -static const uint16_t CHAR_MIDDLE_DOT = 0x00B7; -static const uint16_t CHAR_HYPHEN = 0x2010; - -// The following are structs that correspond to tables inside the hyb file -// format - -struct AlphabetTable0 { - uint32_t version; - uint32_t min_codepoint; - uint32_t max_codepoint; - uint8_t data[1]; // actually flexible array, size is known at runtime -}; - -struct AlphabetTable1 { - uint32_t version; - uint32_t n_entries; - uint32_t data[1]; // actually flexible array, size is known at runtime - - static uint32_t codepoint(uint32_t entry) { return entry >> 11; } - static uint32_t value(uint32_t entry) { return entry & 0x7ff; } -}; - -struct Trie { - uint32_t version; - uint32_t char_mask; - uint32_t link_shift; - uint32_t link_mask; - uint32_t pattern_shift; - uint32_t n_entries; - uint32_t data[1]; // actually flexible array, size is known at runtime -}; - -struct Pattern { - uint32_t version; - uint32_t n_entries; - uint32_t pattern_offset; - uint32_t pattern_size; - uint32_t data[1]; // actually flexible array, size is known at runtime - - // accessors - static uint32_t len(uint32_t entry) { return entry >> 26; } - static uint32_t shift(uint32_t entry) { return (entry >> 20) & 0x3f; } - const uint8_t* buf(uint32_t entry) const { - return reinterpret_cast(this) + pattern_offset + - (entry & 0xfffff); - } -}; - -struct Header { - uint32_t magic; - uint32_t version; - uint32_t alphabet_offset; - uint32_t trie_offset; - uint32_t pattern_offset; - uint32_t file_size; - - // accessors - const uint8_t* bytes() const { - return reinterpret_cast(this); - } - uint32_t alphabetVersion() const { - return *reinterpret_cast(bytes() + alphabet_offset); - } - const AlphabetTable0* alphabetTable0() const { - return reinterpret_cast(bytes() + alphabet_offset); - } - const AlphabetTable1* alphabetTable1() const { - return reinterpret_cast(bytes() + alphabet_offset); - } - const Trie* trieTable() const { - return reinterpret_cast(bytes() + trie_offset); - } - const Pattern* patternTable() const { - return reinterpret_cast(bytes() + pattern_offset); - } -}; - -Hyphenator* Hyphenator::loadBinary(const uint8_t* patternData, - size_t minPrefix, - size_t minSuffix) { - Hyphenator* result = new Hyphenator; - result->patternData = patternData; - result->minPrefix = minPrefix; - result->minSuffix = minSuffix; - return result; -} - -void Hyphenator::hyphenate(vector* result, - const uint16_t* word, - size_t len, - const icu::Locale& locale) { - result->clear(); - result->resize(len); - const size_t paddedLen = len + 2; // start and stop code each count for 1 - if (patternData != nullptr && len >= minPrefix + minSuffix && - paddedLen <= MAX_HYPHENATED_SIZE) { - uint16_t alpha_codes[MAX_HYPHENATED_SIZE]; - const HyphenationType hyphenValue = alphabetLookup(alpha_codes, word, len); - if (hyphenValue != HyphenationType::DONT_BREAK) { - hyphenateFromCodes(result->data(), alpha_codes, paddedLen, hyphenValue); - return; - } - // TODO: try NFC normalization - // TODO: handle non-BMP Unicode (requires remapping of offsets) - } - // Note that we will always get here if the word contains a hyphen or a soft - // hyphen, because the alphabet is not expected to contain a hyphen or a soft - // hyphen character, so alphabetLookup would return DONT_BREAK. - hyphenateWithNoPatterns(result->data(), word, len, locale); -} - -// This function determines whether a character is like U+2010 HYPHEN in -// line breaking and usage: a character immediately after which line breaks -// are allowed, but words containing it should not be automatically -// hyphenated using patterns. This is a curated set, created by manually -// inspecting all the characters that have the Unicode line breaking -// property of BA or HY and seeing which ones are hyphens. -bool Hyphenator::isLineBreakingHyphen(uint32_t c) { - return (c == 0x002D || // HYPHEN-MINUS - c == 0x058A || // ARMENIAN HYPHEN - c == 0x05BE || // HEBREW PUNCTUATION MAQAF - c == 0x1400 || // CANADIAN SYLLABICS HYPHEN - c == 0x2010 || // HYPHEN - c == 0x2013 || // EN DASH - c == 0x2027 || // HYPHENATION POINT - c == 0x2E17 || // DOUBLE OBLIQUE HYPHEN - c == 0x2E40); // DOUBLE HYPHEN -} - -const static uint32_t HYPHEN_STR[] = {0x2010, 0}; -const static uint32_t ARMENIAN_HYPHEN_STR[] = {0x058A, 0}; -const static uint32_t MAQAF_STR[] = {0x05BE, 0}; -const static uint32_t UCAS_HYPHEN_STR[] = {0x1400, 0}; -const static uint32_t ZWJ_STR[] = {0x200D, 0}; -const static uint32_t ZWJ_AND_HYPHEN_STR[] = {0x200D, 0x2010, 0}; - -const uint32_t* HyphenEdit::getHyphenString(uint32_t hyph) { - switch (hyph) { - case INSERT_HYPHEN_AT_END: - case REPLACE_WITH_HYPHEN_AT_END: - case INSERT_HYPHEN_AT_START: - return HYPHEN_STR; - case INSERT_ARMENIAN_HYPHEN_AT_END: - return ARMENIAN_HYPHEN_STR; - case INSERT_MAQAF_AT_END: - return MAQAF_STR; - case INSERT_UCAS_HYPHEN_AT_END: - return UCAS_HYPHEN_STR; - case INSERT_ZWJ_AND_HYPHEN_AT_END: - return ZWJ_AND_HYPHEN_STR; - case INSERT_ZWJ_AT_START: - return ZWJ_STR; - default: - return nullptr; - } -} - -uint32_t HyphenEdit::editForThisLine(HyphenationType type) { - switch (type) { - case HyphenationType::DONT_BREAK: - return NO_EDIT; - case HyphenationType::BREAK_AND_INSERT_HYPHEN: - return INSERT_HYPHEN_AT_END; - case HyphenationType::BREAK_AND_INSERT_ARMENIAN_HYPHEN: - return INSERT_ARMENIAN_HYPHEN_AT_END; - case HyphenationType::BREAK_AND_INSERT_MAQAF: - return INSERT_MAQAF_AT_END; - case HyphenationType::BREAK_AND_INSERT_UCAS_HYPHEN: - return INSERT_UCAS_HYPHEN_AT_END; - case HyphenationType::BREAK_AND_REPLACE_WITH_HYPHEN: - return REPLACE_WITH_HYPHEN_AT_END; - case HyphenationType::BREAK_AND_INSERT_HYPHEN_AND_ZWJ: - return INSERT_ZWJ_AND_HYPHEN_AT_END; - default: - return BREAK_AT_END; - } -} - -uint32_t HyphenEdit::editForNextLine(HyphenationType type) { - switch (type) { - case HyphenationType::DONT_BREAK: - return NO_EDIT; - case HyphenationType::BREAK_AND_INSERT_HYPHEN_AT_NEXT_LINE: - return INSERT_HYPHEN_AT_START; - case HyphenationType::BREAK_AND_INSERT_HYPHEN_AND_ZWJ: - return INSERT_ZWJ_AT_START; - default: - return BREAK_AT_START; - } -} - -static UScriptCode getScript(uint32_t codePoint) { - UErrorCode errorCode = U_ZERO_ERROR; - const UScriptCode script = - uscript_getScript(static_cast(codePoint), &errorCode); - if (U_SUCCESS(errorCode)) { - return script; - } else { - return USCRIPT_INVALID_CODE; - } -} - -static HyphenationType hyphenationTypeBasedOnScript(uint32_t codePoint) { - // Note: It's not clear what the best hyphen for Hebrew is. While maqaf is the - // "correct" hyphen for Hebrew, modern practice may have shifted towards - // Western hyphens. We use normal hyphens for now to be safe. - // BREAK_AND_INSERT_MAQAF is already implemented, so if we want to switch to - // maqaf for Hebrew, we can simply add a condition here. - const UScriptCode script = getScript(codePoint); - if (script == USCRIPT_KANNADA || script == USCRIPT_MALAYALAM || - script == USCRIPT_TAMIL || script == USCRIPT_TELUGU) { - // Grantha is not included, since we don't support non-BMP hyphenation yet. - return HyphenationType::BREAK_AND_DONT_INSERT_HYPHEN; - } else if (script == USCRIPT_ARMENIAN) { - return HyphenationType::BREAK_AND_INSERT_ARMENIAN_HYPHEN; - } else if (script == USCRIPT_CANADIAN_ABORIGINAL) { - return HyphenationType::BREAK_AND_INSERT_UCAS_HYPHEN; - } else { - return HyphenationType::BREAK_AND_INSERT_HYPHEN; - } -} - -static inline int32_t getJoiningType(UChar32 codepoint) { - return u_getIntPropertyValue(codepoint, UCHAR_JOINING_TYPE); -} - -// Assumption for caller: location must be >= 2 and word[location] == -// CHAR_SOFT_HYPHEN. This function decides if the letters before and after the -// hyphen should appear as joining. -static inline HyphenationType getHyphTypeForArabic(const uint16_t* word, - size_t len, - size_t location) { - ssize_t i = location; - int32_t type = U_JT_NON_JOINING; - while (static_cast(i) < len && - (type = getJoiningType(word[i])) == U_JT_TRANSPARENT) { - i++; - } - if (type == U_JT_DUAL_JOINING || type == U_JT_RIGHT_JOINING || - type == U_JT_JOIN_CAUSING) { - // The next character is of the type that may join the last character. See - // if the last character is also of the right type. - i = location - 2; // Skip the soft hyphen - type = U_JT_NON_JOINING; - while (i >= 0 && (type = getJoiningType(word[i])) == U_JT_TRANSPARENT) { - i--; - } - if (type == U_JT_DUAL_JOINING || type == U_JT_LEFT_JOINING || - type == U_JT_JOIN_CAUSING) { - return HyphenationType::BREAK_AND_INSERT_HYPHEN_AND_ZWJ; - } - } - return HyphenationType::BREAK_AND_INSERT_HYPHEN; -} - -// Use various recommendations of UAX #14 Unicode Line Breaking Algorithm for -// hyphenating words that didn't match patterns, especially words that contain -// hyphens or soft hyphens (See sections 5.3, Use of Hyphen, and 5.4, Use of -// Soft Hyphen). -void Hyphenator::hyphenateWithNoPatterns(HyphenationType* result, - const uint16_t* word, - size_t len, - const icu::Locale& locale) { - result[0] = HyphenationType::DONT_BREAK; - for (size_t i = 1; i < len; i++) { - const uint16_t prevChar = word[i - 1]; - if (i > 1 && isLineBreakingHyphen(prevChar)) { - // Break after hyphens, but only if they don't start the word. - - if ((prevChar == CHAR_HYPHEN_MINUS || prevChar == CHAR_HYPHEN) && - strcmp(locale.getLanguage(), "pl") == 0 && - getScript(word[i]) == USCRIPT_LATIN) { - // In Polish, hyphens get repeated at the next line. To be safe, - // we will do this only if the next character is Latin. - result[i] = HyphenationType::BREAK_AND_INSERT_HYPHEN_AT_NEXT_LINE; - } else { - result[i] = HyphenationType::BREAK_AND_DONT_INSERT_HYPHEN; - } - } else if (i > 1 && prevChar == CHAR_SOFT_HYPHEN) { - // Break after soft hyphens, but only if they don't start the word (a soft - // hyphen starting the word doesn't give any useful break opportunities). - // The type of the break is based on the script of the character we break - // on. - if (getScript(word[i]) == USCRIPT_ARABIC) { - // For Arabic, we need to look and see if the characters around the soft - // hyphen actually join. If they don't, we'll just insert a normal - // hyphen. - result[i] = getHyphTypeForArabic(word, len, i); - } else { - result[i] = hyphenationTypeBasedOnScript(word[i]); - } - } else if (prevChar == CHAR_MIDDLE_DOT && minPrefix < i && - i <= len - minSuffix && - ((word[i - 2] == 'l' && word[i] == 'l') || - (word[i - 2] == 'L' && word[i] == 'L')) && - strcmp(locale.getLanguage(), "ca") == 0) { - // In Catalan, "l·l" should break as "l-" on the first line - // and "l" on the next line. - result[i] = HyphenationType::BREAK_AND_REPLACE_WITH_HYPHEN; - } else { - result[i] = HyphenationType::DONT_BREAK; - } - } -} - -HyphenationType Hyphenator::alphabetLookup(uint16_t* alpha_codes, - const uint16_t* word, - size_t len) { - const Header* header = getHeader(); - HyphenationType result = HyphenationType::BREAK_AND_INSERT_HYPHEN; - // TODO: check header magic - uint32_t alphabetVersion = header->alphabetVersion(); - if (alphabetVersion == 0) { - const AlphabetTable0* alphabet = header->alphabetTable0(); - uint32_t min_codepoint = alphabet->min_codepoint; - uint32_t max_codepoint = alphabet->max_codepoint; - alpha_codes[0] = 0; // word start - for (size_t i = 0; i < len; i++) { - uint16_t c = word[i]; - if (c < min_codepoint || c >= max_codepoint) { - return HyphenationType::DONT_BREAK; - } - uint8_t code = alphabet->data[c - min_codepoint]; - if (code == 0) { - return HyphenationType::DONT_BREAK; - } - if (result == HyphenationType::BREAK_AND_INSERT_HYPHEN) { - result = hyphenationTypeBasedOnScript(c); - } - alpha_codes[i + 1] = code; - } - alpha_codes[len + 1] = 0; // word termination - return result; - } else if (alphabetVersion == 1) { - const AlphabetTable1* alphabet = header->alphabetTable1(); - size_t n_entries = alphabet->n_entries; - const uint32_t* begin = alphabet->data; - const uint32_t* end = begin + n_entries; - alpha_codes[0] = 0; - for (size_t i = 0; i < len; i++) { - uint16_t c = word[i]; - auto p = std::lower_bound(begin, end, c << 11); - if (p == end) { - return HyphenationType::DONT_BREAK; - } - uint32_t entry = *p; - if (AlphabetTable1::codepoint(entry) != c) { - return HyphenationType::DONT_BREAK; - } - if (result == HyphenationType::BREAK_AND_INSERT_HYPHEN) { - result = hyphenationTypeBasedOnScript(c); - } - alpha_codes[i + 1] = AlphabetTable1::value(entry); - } - alpha_codes[len + 1] = 0; - return result; - } - return HyphenationType::DONT_BREAK; -} - -/** - * Internal implementation, after conversion to codes. All case folding and - *normalization has been done by now, and all characters have been found in the - *alphabet. Note: len here is the padded length including 0 codes at start and - *end. - **/ -void Hyphenator::hyphenateFromCodes(HyphenationType* result, - const uint16_t* codes, - size_t len, - HyphenationType hyphenValue) { - static_assert(sizeof(HyphenationType) == sizeof(uint8_t), - "HyphnationType must be uint8_t."); - // Reuse the result array as a buffer for calculating intermediate hyphenation - // numbers. - uint8_t* buffer = reinterpret_cast(result); - - const Header* header = getHeader(); - const Trie* trie = header->trieTable(); - const Pattern* pattern = header->patternTable(); - uint32_t char_mask = trie->char_mask; - uint32_t link_shift = trie->link_shift; - uint32_t link_mask = trie->link_mask; - uint32_t pattern_shift = trie->pattern_shift; - size_t maxOffset = len - minSuffix - 1; - for (size_t i = 0; i < len - 1; i++) { - uint32_t node = 0; // index into Trie table - for (size_t j = i; j < len; j++) { - uint16_t c = codes[j]; - uint32_t entry = trie->data[node + c]; - if ((entry & char_mask) == c) { - node = (entry & link_mask) >> link_shift; - } else { - break; - } - uint32_t pat_ix = trie->data[node] >> pattern_shift; - // pat_ix contains a 3-tuple of length, shift (number of trailing zeros), - // and an offset into the buf pool. This is the pattern for the substring - // (i..j) we just matched, which we combine (via point-wise max) into the - // buffer vector. - if (pat_ix != 0) { - uint32_t pat_entry = pattern->data[pat_ix]; - int pat_len = Pattern::len(pat_entry); - int pat_shift = Pattern::shift(pat_entry); - const uint8_t* pat_buf = pattern->buf(pat_entry); - int offset = j + 1 - (pat_len + pat_shift); - // offset is the index within buffer that lines up with the start of - // pat_buf - int start = std::max((int)minPrefix - offset, 0); - int end = std::min(pat_len, (int)maxOffset - offset); - for (int k = start; k < end; k++) { - buffer[offset + k] = std::max(buffer[offset + k], pat_buf[k]); - } - } - } - } - // Since the above calculation does not modify values outside - // [minPrefix, len - minSuffix], they are left as 0 = DONT_BREAK. - for (size_t i = minPrefix; i < maxOffset; i++) { - // Hyphenation opportunities happen when the hyphenation numbers are odd. - result[i] = (buffer[i] & 1u) ? hyphenValue : HyphenationType::DONT_BREAK; - } -} - -} // namespace minikin diff --git a/third_party/txt/src/minikin/Hyphenator.h b/third_party/txt/src/minikin/Hyphenator.h deleted file mode 100644 index 26b898ed24fa6..0000000000000 --- a/third_party/txt/src/minikin/Hyphenator.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -/** - * An implementation of Liang's hyphenation algorithm. - */ - -#ifndef U_USING_ICU_NAMESPACE -#define U_USING_ICU_NAMESPACE 0 -#endif // U_USING_ICU_NAMESPACE - -#include -#include -#include -#include "unicode/locid.h" - -#ifndef MINIKIN_HYPHENATOR_H -#define MINIKIN_HYPHENATOR_H - -namespace minikin { - -enum class HyphenationType : uint8_t { - // Note: There are implicit assumptions scattered in the code that DONT_BREAK - // is 0. - - // Do not break. - DONT_BREAK = 0, - // Break the line and insert a normal hyphen. - BREAK_AND_INSERT_HYPHEN = 1, - // Break the line and insert an Armenian hyphen (U+058A). - BREAK_AND_INSERT_ARMENIAN_HYPHEN = 2, - // Break the line and insert a maqaf (Hebrew hyphen, U+05BE). - BREAK_AND_INSERT_MAQAF = 3, - // Break the line and insert a Canadian Syllabics hyphen (U+1400). - BREAK_AND_INSERT_UCAS_HYPHEN = 4, - // Break the line, but don't insert a hyphen. Used for cases when there is - // already a hyphen - // present or the script does not use a hyphen (e.g. in Malayalam). - BREAK_AND_DONT_INSERT_HYPHEN = 5, - // Break and replace the last code unit with hyphen. Used for Catalan "l·l" - // which hyphenates - // as "l-/l". - BREAK_AND_REPLACE_WITH_HYPHEN = 6, - // Break the line, and repeat the hyphen (which is the last character) at the - // beginning of the - // next line. Used in Polish, where "czerwono-niebieska" should hyphenate as - // "czerwono-/-niebieska". - BREAK_AND_INSERT_HYPHEN_AT_NEXT_LINE = 7, - // Break the line, insert a ZWJ and hyphen at the first line, and a ZWJ at the - // second line. - // This is used in Arabic script, mostly for writing systems of Central Asia. - // It's our default - // behavior when a soft hyphen is used in Arabic script. - BREAK_AND_INSERT_HYPHEN_AND_ZWJ = 8 -}; - -// The hyphen edit represents an edit to the string when a word is -// hyphenated. The most common hyphen edit is adding a "-" at the end -// of a syllable, but nonstandard hyphenation allows for more choices. -// Note that a HyphenEdit can hold two types of edits at the same time, -// One at the beginning of the string/line and one at the end. -class HyphenEdit { - public: - static const uint32_t NO_EDIT = 0x00; - - static const uint32_t INSERT_HYPHEN_AT_END = 0x01; - static const uint32_t INSERT_ARMENIAN_HYPHEN_AT_END = 0x02; - static const uint32_t INSERT_MAQAF_AT_END = 0x03; - static const uint32_t INSERT_UCAS_HYPHEN_AT_END = 0x04; - static const uint32_t INSERT_ZWJ_AND_HYPHEN_AT_END = 0x05; - static const uint32_t REPLACE_WITH_HYPHEN_AT_END = 0x06; - static const uint32_t BREAK_AT_END = 0x07; - - static const uint32_t INSERT_HYPHEN_AT_START = 0x01 << 3; - static const uint32_t INSERT_ZWJ_AT_START = 0x02 << 3; - static const uint32_t BREAK_AT_START = 0x03 << 3; - - // Keep in sync with the definitions in the Java code at: - // frameworks/base/graphics/java/android/graphics/Paint.java - static const uint32_t MASK_END_OF_LINE = 0x07; - static const uint32_t MASK_START_OF_LINE = 0x03 << 3; - - inline static bool isReplacement(uint32_t hyph) { - return hyph == REPLACE_WITH_HYPHEN_AT_END; - } - - inline static bool isInsertion(uint32_t hyph) { - return (hyph == INSERT_HYPHEN_AT_END || - hyph == INSERT_ARMENIAN_HYPHEN_AT_END || - hyph == INSERT_MAQAF_AT_END || hyph == INSERT_UCAS_HYPHEN_AT_END || - hyph == INSERT_ZWJ_AND_HYPHEN_AT_END || - hyph == INSERT_HYPHEN_AT_START || hyph == INSERT_ZWJ_AT_START); - } - - const static uint32_t* getHyphenString(uint32_t hyph); - static uint32_t editForThisLine(HyphenationType type); - static uint32_t editForNextLine(HyphenationType type); - - HyphenEdit() : hyphen(NO_EDIT) {} - HyphenEdit(uint32_t hyphenInt) // NOLINT(google-explicit-constructor) - : hyphen(hyphenInt) {} - uint32_t getHyphen() const { return hyphen; } - bool operator==(const HyphenEdit& other) const { - return hyphen == other.hyphen; - } - - uint32_t getEnd() const { return hyphen & MASK_END_OF_LINE; } - uint32_t getStart() const { return hyphen & MASK_START_OF_LINE; } - - private: - uint32_t hyphen; -}; - -// hyb file header; implementation details are in the .cpp file -struct Header; - -class Hyphenator { - public: - // Compute the hyphenation of a word, storing the hyphenation in result - // vector. Each entry in the vector is a "hyphenation type" for a potential - // hyphenation that can be applied at the corresponding code unit offset in - // the word. - // - // Example: word is "hyphen", result is the following, corresponding to - // "hy-phen": [DONT_BREAK, DONT_BREAK, BREAK_AND_INSERT_HYPHEN, DONT_BREAK, - // DONT_BREAK, DONT_BREAK] - void hyphenate(std::vector* result, - const uint16_t* word, - size_t len, - const icu::Locale& locale); - - // Returns true if the codepoint is like U+2010 HYPHEN in line breaking and - // usage: a character immediately after which line breaks are allowed, but - // words containing it should not be automatically hyphenated. - static bool isLineBreakingHyphen(uint32_t cp); - - // pattern data is in binary format, as described in doc/hyb_file_format.md. - // Note: the caller is responsible for ensuring that the lifetime of the - // pattern data is at least as long as the Hyphenator object. - - // Note: nullptr is valid input, in which case the hyphenator only processes - // soft hyphens. - static Hyphenator* loadBinary(const uint8_t* patternData, - size_t minPrefix, - size_t minSuffix); - - private: - // apply various hyphenation rules including hard and soft hyphens, ignoring - // patterns - void hyphenateWithNoPatterns(HyphenationType* result, - const uint16_t* word, - size_t len, - const icu::Locale& locale); - - // Try looking up word in alphabet table, return DONT_BREAK if any code units - // fail to map. Otherwise, returns BREAK_AND_INSERT_HYPHEN, - // BREAK_AND_INSERT_ARMENIAN_HYPHEN, or BREAK_AND_DONT_INSERT_HYPHEN based on - // the script of the characters seen. Note that this method writes len+2 - // entries into alpha_codes (including start and stop) - HyphenationType alphabetLookup(uint16_t* alpha_codes, - const uint16_t* word, - size_t len); - - // calculate hyphenation from patterns, assuming alphabet lookup has already - // been done - void hyphenateFromCodes(HyphenationType* result, - const uint16_t* codes, - size_t len, - HyphenationType hyphenValue); - - // See also LONGEST_HYPHENATED_WORD in LineBreaker.cpp. Here the constant is - // used so that temporary buffers can be stack-allocated without waste, which - // is a slightly different use case. It measures UTF-16 code units. - static const size_t MAX_HYPHENATED_SIZE = 64; - - const uint8_t* patternData; - size_t minPrefix, minSuffix; - - // accessors for binary data - const Header* getHeader() const { - return reinterpret_cast(patternData); - } -}; - -} // namespace minikin - -#endif // MINIKIN_HYPHENATOR_H diff --git a/third_party/txt/src/minikin/Layout.cpp b/third_party/txt/src/minikin/Layout.cpp deleted file mode 100644 index 59c3d2a2e2543..0000000000000 --- a/third_party/txt/src/minikin/Layout.cpp +++ /dev/null @@ -1,1202 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "Minikin" - -#include -#include -#include -#include -#include -#include // for debugging -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include "FontLanguage.h" -#include "FontLanguageListCache.h" -#include "HbFontCache.h" -#include "LayoutUtils.h" -#include "MinikinInternal.h" - -namespace minikin { - -const int kDirection_Mask = 0x1; - -struct LayoutContext { - MinikinPaint paint; - FontStyle style; - std::vector hbFonts; // parallel to mFaces - - void clearHbFonts() { - for (size_t i = 0; i < hbFonts.size(); i++) { - hb_font_set_funcs(hbFonts[i], nullptr, nullptr, nullptr); - hb_font_destroy(hbFonts[i]); - } - hbFonts.clear(); - } -}; - -// Layout cache datatypes - -class LayoutCacheKey { - public: - LayoutCacheKey(const std::shared_ptr& collection, - const MinikinPaint& paint, - FontStyle style, - const uint16_t* chars, - size_t start, - size_t count, - size_t nchars, - bool dir) - : mChars(chars), - mNchars(nchars), - mStart(start), - mCount(count), - mId(collection->getId()), - mStyle(style), - mSize(paint.size), - mScaleX(paint.scaleX), - mSkewX(paint.skewX), - mLetterSpacing(paint.letterSpacing), - mPaintFlags(paint.paintFlags), - mHyphenEdit(paint.hyphenEdit), - mIsRtl(dir), - mHash(computeHash()) {} - bool operator==(const LayoutCacheKey& other) const; - - android::hash_t hash() const { return mHash; } - - void copyText() { - uint16_t* charsCopy = new uint16_t[mNchars]; - memcpy(charsCopy, mChars, mNchars * sizeof(uint16_t)); - mChars = charsCopy; - } - void freeText() { - delete[] mChars; - mChars = NULL; - } - - void doLayout(Layout* layout, - LayoutContext* ctx, - const std::shared_ptr& collection) const { - layout->mAdvances.resize(mCount, 0); - ctx->clearHbFonts(); - layout->doLayoutRun(mChars, mStart, mCount, mNchars, mIsRtl, ctx, - collection); - } - - private: - const uint16_t* mChars; - size_t mNchars; - size_t mStart; - size_t mCount; - uint32_t mId; // for the font collection - FontStyle mStyle; - float mSize; - float mScaleX; - float mSkewX; - float mLetterSpacing; - int32_t mPaintFlags; - HyphenEdit mHyphenEdit; - bool mIsRtl; - // Note: any fields added to MinikinPaint must also be reflected here. - // TODO: language matching (possibly integrate into style) - android::hash_t mHash; - - android::hash_t computeHash() const; -}; - -class LayoutCache : private android::OnEntryRemoved { - public: - LayoutCache() : mCache(kMaxEntries) { - mCache.setOnEntryRemovedListener(this); - } - - void clear() { mCache.clear(); } - - Layout* get(LayoutCacheKey& key, - LayoutContext* ctx, - const std::shared_ptr& collection) { - Layout* layout = mCache.get(key); - if (layout == NULL) { - key.copyText(); - layout = new Layout(); - key.doLayout(layout, ctx, collection); - mCache.put(key, layout); - } - return layout; - } - - private: - // callback for OnEntryRemoved - void operator()(LayoutCacheKey& key, Layout*& value) { - key.freeText(); - delete value; - } - - android::LruCache mCache; - - // static const size_t kMaxEntries = LruCache::kUnlimitedCapacity; - - // TODO: eviction based on memory footprint; for now, we just use a constant - // number of strings - static const size_t kMaxEntries = 5000; -}; - -class LayoutEngine { - public: - LayoutEngine() { - unicodeFunctions = hb_unicode_funcs_create(hb_icu_get_unicode_funcs()); - hbBuffer = hb_buffer_create(); - hb_buffer_set_unicode_funcs(hbBuffer, unicodeFunctions); - } - - hb_buffer_t* hbBuffer; - hb_unicode_funcs_t* unicodeFunctions; - LayoutCache layoutCache; - - static LayoutEngine& getInstance() { - static LayoutEngine* instance = new LayoutEngine(); - return *instance; - } -}; - -bool LayoutCacheKey::operator==(const LayoutCacheKey& other) const { - return mId == other.mId && mStart == other.mStart && mCount == other.mCount && - mStyle == other.mStyle && mSize == other.mSize && - mScaleX == other.mScaleX && mSkewX == other.mSkewX && - mLetterSpacing == other.mLetterSpacing && - mPaintFlags == other.mPaintFlags && mHyphenEdit == other.mHyphenEdit && - mIsRtl == other.mIsRtl && mNchars == other.mNchars && - !memcmp(mChars, other.mChars, mNchars * sizeof(uint16_t)); -} - -android::hash_t LayoutCacheKey::computeHash() const { - uint32_t hash = android::JenkinsHashMix(0, mId); - hash = android::JenkinsHashMix(hash, mStart); - hash = android::JenkinsHashMix(hash, mCount); - hash = android::JenkinsHashMix(hash, hash_type(mStyle)); - hash = android::JenkinsHashMix(hash, hash_type(mSize)); - hash = android::JenkinsHashMix(hash, hash_type(mScaleX)); - hash = android::JenkinsHashMix(hash, hash_type(mSkewX)); - hash = android::JenkinsHashMix(hash, hash_type(mLetterSpacing)); - hash = android::JenkinsHashMix(hash, hash_type(mPaintFlags)); - hash = android::JenkinsHashMix(hash, hash_type(mHyphenEdit.getHyphen())); - hash = android::JenkinsHashMix(hash, hash_type(mIsRtl)); - hash = android::JenkinsHashMixShorts(hash, mChars, mNchars); - return android::JenkinsHashWhiten(hash); -} - -android::hash_t hash_type(const LayoutCacheKey& key) { - return key.hash(); -} - -void MinikinRect::join(const MinikinRect& r) { - if (isEmpty()) { - set(r); - } else if (!r.isEmpty()) { - mLeft = std::min(mLeft, r.mLeft); - mTop = std::min(mTop, r.mTop); - mRight = std::max(mRight, r.mRight); - mBottom = std::max(mBottom, r.mBottom); - } -} - -void Layout::reset() { - mGlyphs.clear(); - mFaces.clear(); - mBounds.setEmpty(); - mAdvances.clear(); - mAdvance = 0; -} - -static hb_position_t harfbuzzGetGlyphHorizontalAdvance(hb_font_t* /* hbFont */, - void* fontData, - hb_codepoint_t glyph, - void* /* userData */) { - MinikinPaint* paint = reinterpret_cast(fontData); - float advance = paint->font->GetHorizontalAdvance(glyph, *paint); - return 256 * advance + 0.5; -} - -static hb_bool_t harfbuzzGetGlyphHorizontalOrigin(hb_font_t* /* hbFont */, - void* /* fontData */, - hb_codepoint_t /* glyph */, - hb_position_t* /* x */, - hb_position_t* /* y */, - void* /* userData */) { - // Just return true, following the way that Harfbuzz-FreeType - // implementation does. - return true; -} - -hb_font_funcs_t* getHbFontFuncs(bool forColorBitmapFont) { - assertMinikinLocked(); - - static hb_font_funcs_t* hbFuncs = nullptr; - static hb_font_funcs_t* hbFuncsForColorBitmap = nullptr; - - hb_font_funcs_t** funcs = - forColorBitmapFont ? &hbFuncs : &hbFuncsForColorBitmap; - if (*funcs == nullptr) { - *funcs = hb_font_funcs_create(); - if (forColorBitmapFont) { - // Don't override the h_advance function since we use HarfBuzz's - // implementation for emoji for performance reasons. Note that it is - // technically possible for a TrueType font to have outline and embedded - // bitmap at the same time. We ignore modified advances of hinted outline - // glyphs in that case. - } else { - // Override the h_advance function since we can't use HarfBuzz's - // implemenation. It may return the wrong value if the font uses hinting - // aggressively. - hb_font_funcs_set_glyph_h_advance_func( - *funcs, harfbuzzGetGlyphHorizontalAdvance, 0, 0); - } - hb_font_funcs_set_glyph_h_origin_func( - *funcs, harfbuzzGetGlyphHorizontalOrigin, 0, 0); - hb_font_funcs_make_immutable(*funcs); - } - return *funcs; -} - -static bool isColorBitmapFont(hb_font_t* font) { - hb_face_t* face = hb_font_get_face(font); - return hb_ot_color_has_png(face); -} - -static float HBFixedToFloat(hb_position_t v) { - return scalbnf(v, -8); -} - -static hb_position_t HBFloatToFixed(float v) { - return scalbnf(v, +8); -} - -void Layout::dump() const { - for (size_t i = 0; i < mGlyphs.size(); i++) { - const LayoutGlyph& glyph = mGlyphs[i]; - std::cout << glyph.glyph_id << ": " << glyph.x << ", " << glyph.y - << std::endl; - } -} - -int Layout::findFace(const FakedFont& face, LayoutContext* ctx) { - unsigned int ix; - for (ix = 0; ix < mFaces.size(); ix++) { - if (mFaces[ix].font == face.font) { - return ix; - } - } - mFaces.push_back(face); - // Note: ctx == NULL means we're copying from the cache, no need to create - // corresponding hb_font object. - if (ctx != NULL) { - hb_font_t* font = getHbFontLocked(face.font); - hb_font_set_funcs(font, getHbFontFuncs(isColorBitmapFont(font)), - &ctx->paint, 0); - ctx->hbFonts.push_back(font); - } - return ix; -} - -static hb_script_t codePointToScript(hb_codepoint_t codepoint) { - static hb_unicode_funcs_t* u = 0; - if (!u) { - u = LayoutEngine::getInstance().unicodeFunctions; - } - return hb_unicode_script(u, codepoint); -} - -static hb_codepoint_t decodeUtf16(const uint16_t* chars, - size_t len, - ssize_t* iter) { - const uint16_t v = chars[(*iter)++]; - // test whether v in (0xd800..0xdfff), lead or trail surrogate - if ((v & 0xf800) == 0xd800) { - // test whether v in (0xd800..0xdbff), lead surrogate - if (size_t(*iter) < len && (v & 0xfc00) == 0xd800) { - const uint16_t v2 = chars[(*iter)++]; - // test whether v2 in (0xdc00..0xdfff), trail surrogate - if ((v2 & 0xfc00) == 0xdc00) { - // (0xd800 0xdc00) in utf-16 maps to 0x10000 in ucs-32 - const hb_codepoint_t delta = (0xd800 << 10) + 0xdc00 - 0x10000; - return (((hb_codepoint_t)v) << 10) + v2 - delta; - } - (*iter) -= 1; - return 0xFFFDu; - } else { - return 0xFFFDu; - } - } else { - return v; - } -} - -static hb_script_t getScriptRun(const uint16_t* chars, - size_t len, - ssize_t* iter) { - if (size_t(*iter) == len) { - return HB_SCRIPT_UNKNOWN; - } - uint32_t cp = decodeUtf16(chars, len, iter); - hb_script_t current_script = codePointToScript(cp); - for (;;) { - if (size_t(*iter) == len) - break; - const ssize_t prev_iter = *iter; - cp = decodeUtf16(chars, len, iter); - const hb_script_t script = codePointToScript(cp); - if (script != current_script) { - if (current_script == HB_SCRIPT_INHERITED || - current_script == HB_SCRIPT_COMMON) { - current_script = script; - } else if (script == HB_SCRIPT_INHERITED || script == HB_SCRIPT_COMMON) { - continue; - } else { - *iter = prev_iter; - break; - } - } - } - if (current_script == HB_SCRIPT_INHERITED) { - current_script = HB_SCRIPT_COMMON; - } - - return current_script; -} - -/** - * Disable certain scripts (mostly those with cursive connection) from having - * letterspacing applied. See https://github.com/behdad/harfbuzz/issues/64 for - * more details. - */ -static bool isScriptOkForLetterspacing(hb_script_t script) { - return !(script == HB_SCRIPT_ARABIC || script == HB_SCRIPT_NKO || - script == HB_SCRIPT_PSALTER_PAHLAVI || script == HB_SCRIPT_MANDAIC || - script == HB_SCRIPT_MONGOLIAN || script == HB_SCRIPT_PHAGS_PA || - script == HB_SCRIPT_DEVANAGARI || script == HB_SCRIPT_BENGALI || - script == HB_SCRIPT_GURMUKHI || script == HB_SCRIPT_MODI || - script == HB_SCRIPT_SHARADA || script == HB_SCRIPT_SYLOTI_NAGRI || - script == HB_SCRIPT_TIRHUTA || script == HB_SCRIPT_OGHAM); -} - -class BidiText { - public: - class Iter { - public: - struct RunInfo { - int32_t mRunStart; - int32_t mRunLength; - bool mIsRtl; - }; - - Iter(UBiDi* bidi, - size_t start, - size_t end, - size_t runIndex, - size_t runCount, - bool isRtl); - - bool operator!=(const Iter& other) const { - return mIsEnd != other.mIsEnd || mNextRunIndex != other.mNextRunIndex || - mBidi != other.mBidi; - } - - const RunInfo& operator*() const { return mRunInfo; } - - const Iter& operator++() { - updateRunInfo(); - return *this; - } - - private: - UBiDi* const mBidi; - bool mIsEnd; - size_t mNextRunIndex; - const size_t mRunCount; - const int32_t mStart; - const int32_t mEnd; - RunInfo mRunInfo; - - void updateRunInfo(); - }; - - BidiText(const uint16_t* buf, - size_t start, - size_t count, - size_t bufSize, - int bidiFlags); - - ~BidiText() { - if (mBidi) { - ubidi_close(mBidi); - } - } - - Iter begin() const { return Iter(mBidi, mStart, mEnd, 0, mRunCount, mIsRtl); } - - Iter end() const { - return Iter(mBidi, mStart, mEnd, mRunCount, mRunCount, mIsRtl); - } - - private: - const size_t mStart; - const size_t mEnd; - const size_t mBufSize; - UBiDi* mBidi; - size_t mRunCount; - bool mIsRtl; - - BidiText(const BidiText&) = delete; - void operator=(const BidiText&) = delete; -}; - -BidiText::Iter::Iter(UBiDi* bidi, - size_t start, - size_t end, - size_t runIndex, - size_t runCount, - bool isRtl) - : mBidi(bidi), - mIsEnd(runIndex == runCount), - mNextRunIndex(runIndex), - mRunCount(runCount), - mStart(start), - mEnd(end), - mRunInfo() { - if (mRunCount == 1) { - mRunInfo.mRunStart = start; - mRunInfo.mRunLength = end - start; - mRunInfo.mIsRtl = isRtl; - mNextRunIndex = mRunCount; - return; - } - updateRunInfo(); -} - -void BidiText::Iter::updateRunInfo() { - if (mNextRunIndex == mRunCount) { - // All runs have been iterated. - mIsEnd = true; - return; - } - int32_t startRun = -1; - int32_t lengthRun = -1; - const UBiDiDirection runDir = - ubidi_getVisualRun(mBidi, mNextRunIndex, &startRun, &lengthRun); - mNextRunIndex++; - if (startRun == -1 || lengthRun == -1) { - ALOGE("invalid visual run"); - // skip the invalid run. - updateRunInfo(); - return; - } - const int32_t runEnd = std::min(startRun + lengthRun, mEnd); - mRunInfo.mRunStart = std::max(startRun, mStart); - mRunInfo.mRunLength = runEnd - mRunInfo.mRunStart; - if (mRunInfo.mRunLength <= 0) { - // skip the empty run. - updateRunInfo(); - return; - } - mRunInfo.mIsRtl = (runDir == UBIDI_RTL); -} - -BidiText::BidiText(const uint16_t* buf, - size_t start, - size_t count, - size_t bufSize, - int bidiFlags) - : mStart(start), - mEnd(start + count), - mBufSize(bufSize), - mBidi(NULL), - mRunCount(1), - mIsRtl((bidiFlags & kDirection_Mask) != 0) { - if (bidiFlags == kBidi_Force_LTR || bidiFlags == kBidi_Force_RTL) { - // force single run. - return; - } - mBidi = ubidi_open(); - if (!mBidi) { - ALOGE("error creating bidi object"); - return; - } - UErrorCode status = U_ZERO_ERROR; - // Set callbacks to override bidi classes of new emoji - ubidi_setClassCallback(mBidi, emojiBidiOverride, nullptr, nullptr, nullptr, - &status); - if (!U_SUCCESS(status)) { - ALOGE("error setting bidi callback function, status = %d", status); - return; - } - - UBiDiLevel bidiReq = bidiFlags; - if (bidiFlags == kBidi_Default_LTR) { - bidiReq = UBIDI_DEFAULT_LTR; - } else if (bidiFlags == kBidi_Default_RTL) { - bidiReq = UBIDI_DEFAULT_RTL; - } - ubidi_setPara(mBidi, reinterpret_cast(buf), mBufSize, bidiReq, - NULL, &status); - if (!U_SUCCESS(status)) { - ALOGE("error calling ubidi_setPara, status = %d", status); - return; - } - const int paraDir = ubidi_getParaLevel(mBidi) & kDirection_Mask; - const ssize_t rc = ubidi_countRuns(mBidi, &status); - if (!U_SUCCESS(status) || rc < 0) { - ALOGW("error counting bidi runs, status = %d", status); - } - if (!U_SUCCESS(status) || rc <= 1) { - mIsRtl = (paraDir == kBidi_RTL); - return; - } - mRunCount = rc; -} - -void Layout::doLayout(const uint16_t* buf, - size_t start, - size_t count, - size_t bufSize, - bool isRtl, - const FontStyle& style, - const MinikinPaint& paint, - const std::shared_ptr& collection) { - std::scoped_lock _l(gMinikinLock); - - LayoutContext ctx; - ctx.style = style; - ctx.paint = paint; - - reset(); - mAdvances.resize(count, 0); - - doLayoutRunCached(buf, start, count, bufSize, isRtl, &ctx, start, collection, - this, NULL); - - ctx.clearHbFonts(); -} - -float Layout::measureText(const uint16_t* buf, - size_t start, - size_t count, - size_t bufSize, - bool isRtl, - const FontStyle& style, - const MinikinPaint& paint, - const std::shared_ptr& collection, - float* advances) { - std::scoped_lock _l(gMinikinLock); - - LayoutContext ctx; - ctx.style = style; - ctx.paint = paint; - - float advance = doLayoutRunCached(buf, start, count, bufSize, isRtl, &ctx, 0, - collection, NULL, advances); - - ctx.clearHbFonts(); - return advance; -} - -float Layout::doLayoutRunCached( - const uint16_t* buf, - size_t start, - size_t count, - size_t bufSize, - bool isRtl, - LayoutContext* ctx, - size_t dstStart, - const std::shared_ptr& collection, - Layout* layout, - float* advances) { - const uint32_t originalHyphen = ctx->paint.hyphenEdit.getHyphen(); - float advance = 0; - if (!isRtl) { - // left to right - size_t wordstart = start == bufSize - ? start - : getPrevWordBreakForCache(buf, start + 1, bufSize); - size_t wordend; - for (size_t iter = start; iter < start + count; iter = wordend) { - wordend = getNextWordBreakForCache(buf, iter, bufSize); - // Only apply hyphen to the first or last word in the string. - uint32_t hyphen = originalHyphen; - if (iter != start) { // Not the first word - hyphen &= ~HyphenEdit::MASK_START_OF_LINE; - } - if (wordend < start + count) { // Not the last word - hyphen &= ~HyphenEdit::MASK_END_OF_LINE; - } - ctx->paint.hyphenEdit = hyphen; - size_t wordcount = std::min(start + count, wordend) - iter; - advance += doLayoutWord(buf + wordstart, iter - wordstart, wordcount, - wordend - wordstart, isRtl, ctx, iter - dstStart, - collection, layout, - advances ? advances + (iter - start) : advances); - wordstart = wordend; - } - } else { - // right to left - size_t wordstart; - size_t end = start + count; - size_t wordend = - end == 0 ? 0 : getNextWordBreakForCache(buf, end - 1, bufSize); - for (size_t iter = end; iter > start; iter = wordstart) { - wordstart = getPrevWordBreakForCache(buf, iter, bufSize); - // Only apply hyphen to the first (rightmost) or last (leftmost) word in - // the string. - uint32_t hyphen = originalHyphen; - if (wordstart > start) { // Not the first word - hyphen &= ~HyphenEdit::MASK_START_OF_LINE; - } - if (iter != end) { // Not the last word - hyphen &= ~HyphenEdit::MASK_END_OF_LINE; - } - ctx->paint.hyphenEdit = hyphen; - size_t bufStart = std::max(start, wordstart); - advance += doLayoutWord( - buf + wordstart, bufStart - wordstart, iter - bufStart, - wordend - wordstart, isRtl, ctx, bufStart - dstStart, collection, - layout, advances ? advances + (bufStart - start) : advances); - wordend = wordstart; - } - } - return advance; -} - -float Layout::doLayoutWord(const uint16_t* buf, - size_t start, - size_t count, - size_t bufSize, - bool isRtl, - LayoutContext* ctx, - size_t bufStart, - const std::shared_ptr& collection, - Layout* layout, - float* advances) { - LayoutCache& cache = LayoutEngine::getInstance().layoutCache; - LayoutCacheKey key(collection, ctx->paint, ctx->style, buf, start, count, - bufSize, isRtl); - - float wordSpacing = - count == 1 && isWordSpace(buf[start]) ? ctx->paint.wordSpacing : 0; - - float advance; - if (ctx->paint.skipCache()) { - Layout layoutForWord; - key.doLayout(&layoutForWord, ctx, collection); - if (layout) { - layout->appendLayout(&layoutForWord, bufStart, wordSpacing); - } - if (advances) { - layoutForWord.getAdvances(advances); - } - advance = layoutForWord.getAdvance(); - } else { - Layout* layoutForWord = cache.get(key, ctx, collection); - if (layout) { - layout->appendLayout(layoutForWord, bufStart, wordSpacing); - } - if (advances) { - layoutForWord->getAdvances(advances); - } - advance = layoutForWord->getAdvance(); - } - - if (wordSpacing != 0) { - advance += wordSpacing; - if (advances) { - advances[0] += wordSpacing; - } - } - return advance; -} - -static void addFeatures(const std::string& str, - std::vector* features) { - if (!str.size()) - return; - - const char* start = str.c_str(); - const char* end = start + str.size(); - - while (start < end) { - static hb_feature_t feature; - const char* p = strchr(start, ','); - if (!p) - p = end; - /* We do not allow setting features on ranges. As such, reject any - * setting that has non-universal range. */ - if (hb_feature_from_string(start, p - start, &feature) && - feature.start == 0 && feature.end == (unsigned int)-1) - features->push_back(feature); - start = p + 1; - } -} - -static const hb_codepoint_t CHAR_HYPHEN = 0x2010; /* HYPHEN */ - -static inline hb_codepoint_t determineHyphenChar(hb_codepoint_t preferredHyphen, - hb_font_t* font) { - hb_codepoint_t glyph; - if (preferredHyphen == 0x058A /* ARMENIAN_HYPHEN */ - || preferredHyphen == 0x05BE /* HEBREW PUNCTUATION MAQAF */ - || preferredHyphen == 0x1400 /* CANADIAN SYLLABIC HYPHEN */) { - if (hb_font_get_nominal_glyph(font, preferredHyphen, &glyph)) { - return preferredHyphen; - } else { - // The original hyphen requested was not supported. Let's try and see if - // the Unicode hyphen is supported. - preferredHyphen = CHAR_HYPHEN; - } - } - if (preferredHyphen == CHAR_HYPHEN) { /* HYPHEN */ - // Fallback to ASCII HYPHEN-MINUS if the font didn't have a glyph for the - // preferred hyphen. Note that we intentionally don't do anything special if - // the font doesn't have a HYPHEN-MINUS either, so a tofu could be shown, - // hinting towards something missing. - if (!hb_font_get_nominal_glyph(font, preferredHyphen, &glyph)) { - return 0x002D; // HYPHEN-MINUS - } - } - return preferredHyphen; -} - -static inline void addHyphenToHbBuffer(hb_buffer_t* buffer, - hb_font_t* font, - uint32_t hyphen, - uint32_t cluster) { - const uint32_t* hyphenStr = HyphenEdit::getHyphenString(hyphen); - while (*hyphenStr != 0) { - hb_codepoint_t hyphenChar = determineHyphenChar(*hyphenStr, font); - hb_buffer_add(buffer, hyphenChar, cluster); - hyphenStr++; - } -} - -// Returns the cluster value assigned to the first codepoint added to the -// buffer, which can be used to translate cluster values returned by HarfBuzz to -// input indices. -static inline uint32_t addToHbBuffer(hb_buffer_t* buffer, - const uint16_t* buf, - size_t start, - size_t count, - size_t bufSize, - ssize_t scriptRunStart, - ssize_t scriptRunEnd, - HyphenEdit hyphenEdit, - hb_font_t* hbFont) { - // Only hyphenate the very first script run for starting hyphens. - const uint32_t startHyphen = - (scriptRunStart == 0) ? hyphenEdit.getStart() : HyphenEdit::NO_EDIT; - // Only hyphenate the very last script run for ending hyphens. - const uint32_t endHyphen = (static_cast(scriptRunEnd) == count) - ? hyphenEdit.getEnd() - : HyphenEdit::NO_EDIT; - - // In the following code, we drop the pre-context and/or post-context if there - // is a hyphen edit at that end. This is not absolutely necessary, since - // HarfBuzz uses contexts only for joining scripts at the moment, e.g. to - // determine if the first or last letter of a text range to shape should take - // a joining form based on an adjacent letter or joiner (that comes from the - // context). - // - // TODO: Revisit this for: - // 1. Desperate breaks for joining scripts like Arabic (where it may be better - // to keep - // the context); - // 2. Special features like start-of-word font features (not implemented in - // HarfBuzz - // yet). - - // We don't have any start-of-line replacement edit yet, so we don't need to - // check for those. - if (HyphenEdit::isInsertion(startHyphen)) { - // A cluster value of zero guarantees that the inserted hyphen will be in - // the same cluster with the next codepoint, since there is no pre-context. - addHyphenToHbBuffer(buffer, hbFont, startHyphen, 0 /* cluster value */); - } - - const uint16_t* hbText; - int hbTextLength; - unsigned int hbItemOffset; - unsigned int hbItemLength = scriptRunEnd - scriptRunStart; // This is >= 1. - - const bool hasEndInsertion = HyphenEdit::isInsertion(endHyphen); - const bool hasEndReplacement = HyphenEdit::isReplacement(endHyphen); - if (hasEndReplacement) { - // Skip the last code unit while copying the buffer for HarfBuzz if it's a - // replacement. We don't need to worry about non-BMP characters yet since - // replacements are only done for code units at the moment. - hbItemLength -= 1; - } - - if (startHyphen == HyphenEdit::NO_EDIT) { - // No edit at the beginning. Use the whole pre-context. - hbText = buf; - hbItemOffset = start + scriptRunStart; - } else { - // There's an edit at the beginning. Drop the pre-context and start the - // buffer at where we want to start shaping. - hbText = buf + start + scriptRunStart; - hbItemOffset = 0; - } - - if (endHyphen == HyphenEdit::NO_EDIT) { - // No edit at the end, use the whole post-context. - hbTextLength = (buf + bufSize) - hbText; - } else { - // There is an edit at the end. Drop the post-context. - hbTextLength = hbItemOffset + hbItemLength; - } - - hb_buffer_add_utf16(buffer, hbText, hbTextLength, hbItemOffset, hbItemLength); - - unsigned int numCodepoints; - hb_glyph_info_t* cpInfo = hb_buffer_get_glyph_infos(buffer, &numCodepoints); - - // Add the hyphen at the end, if there's any. - if (hasEndInsertion || hasEndReplacement) { - // When a hyphen is inserted, by assigning the added hyphen and the last - // codepoint added to the HarfBuzz buffer to the same cluster, we can make - // sure that they always remain in the same cluster, even if the last - // codepoint gets merged into another cluster (for example when it's a - // combining mark). - // - // When a replacement happens instead, we want it to get the cluster value - // of the character it's replacing, which is one "codepoint length" larger - // than the last cluster. But since the character replaced is always just - // one code unit, we can just add 1. - uint32_t hyphenCluster; - if (numCodepoints == 0) { - // Nothing was added to the HarfBuzz buffer. This can only happen if - // we have a replacement that is replacing a one-code unit script run. - hyphenCluster = 0; - } else { - hyphenCluster = - cpInfo[numCodepoints - 1].cluster + (uint32_t)hasEndReplacement; - } - addHyphenToHbBuffer(buffer, hbFont, endHyphen, hyphenCluster); - // Since we have just added to the buffer, cpInfo no longer necessarily - // points to the right place. Refresh it. - cpInfo = - hb_buffer_get_glyph_infos(buffer, nullptr /* we don't need the size */); - } - return cpInfo[0].cluster; -} - -void Layout::doLayoutRun(const uint16_t* buf, - size_t start, - size_t count, - size_t bufSize, - bool isRtl, - LayoutContext* ctx, - const std::shared_ptr& collection) { - hb_buffer_t* buffer = LayoutEngine::getInstance().hbBuffer; - std::vector items; - collection->itemize(buf + start, count, ctx->style, &items); - - std::vector features; - // Disable default-on non-required ligature features if letter-spacing - // See http://dev.w3.org/csswg/css-text-3/#letter-spacing-property - // "When the effective spacing between two characters is not zero (due to - // either justification or a non-zero value of letter-spacing), user agents - // should not apply optional ligatures." - if (fabs(ctx->paint.letterSpacing) > 0.03) { - static const hb_feature_t no_liga = {HB_TAG('l', 'i', 'g', 'a'), 0, 0, ~0u}; - static const hb_feature_t no_clig = {HB_TAG('c', 'l', 'i', 'g'), 0, 0, ~0u}; - features.push_back(no_liga); - features.push_back(no_clig); - } - addFeatures(ctx->paint.fontFeatureSettings, &features); - - double size = ctx->paint.size; - double scaleX = ctx->paint.scaleX; - - float x = mAdvance; - float y = 0; - for (int run_ix = isRtl ? items.size() - 1 : 0; - isRtl ? run_ix >= 0 : run_ix < static_cast(items.size()); - isRtl ? --run_ix : ++run_ix) { - FontCollection::Run& run = items[run_ix]; - if (run.fakedFont.font == NULL) { - ALOGE("no font for run starting u+%04x length %d", buf[run.start], - run.end - run.start); - continue; - } - int font_ix = findFace(run.fakedFont, ctx); - ctx->paint.font = mFaces[font_ix].font; - ctx->paint.fakery = mFaces[font_ix].fakery; - hb_font_t* hbFont = ctx->hbFonts[font_ix]; -#ifdef VERBOSE_DEBUG - ALOGD("Run %zu, font %d [%d:%d]", run_ix, font_ix, run.start, run.end); -#endif - - hb_font_set_ppem(hbFont, size * scaleX, size); - hb_font_set_scale(hbFont, HBFloatToFixed(size * scaleX), - HBFloatToFixed(size)); - - const bool is_color_bitmap_font = isColorBitmapFont(hbFont); - - // TODO: if there are multiple scripts within a font in an RTL run, - // we need to reorder those runs. This is unlikely with our current - // font stack, but should be done for correctness. - - // Note: scriptRunStart and scriptRunEnd, as well as run.start and run.end, - // run between 0 and count. - ssize_t scriptRunEnd; - for (ssize_t scriptRunStart = run.start; scriptRunStart < run.end; - scriptRunStart = scriptRunEnd) { - scriptRunEnd = scriptRunStart; - hb_script_t script = - getScriptRun(buf + start, run.end, &scriptRunEnd /* iterator */); - // After the last line, scriptRunEnd is guaranteed to have increased, - // since the only time getScriptRun does not increase its iterator is when - // it has already reached the end of the buffer. But that can't happen, - // since if we have already reached the end of the buffer, we should have - // had (scriptRunEnd == run.end), which means (scriptRunStart == run.end) - // which is impossible due to the exit condition of the for loop. So we - // can be sure that scriptRunEnd > scriptRunStart. - - double letterSpace = 0.0; - double letterSpaceHalfLeft = 0.0; - double letterSpaceHalfRight = 0.0; - - if (ctx->paint.letterSpacing != 0.0 && - isScriptOkForLetterspacing(script)) { - letterSpace = ctx->paint.letterSpacing * size * scaleX; - if ((ctx->paint.paintFlags & LinearTextFlag) == 0) { - letterSpace = round(letterSpace); - letterSpaceHalfLeft = floor(letterSpace * 0.5); - } else { - letterSpaceHalfLeft = letterSpace * 0.5; - } - letterSpaceHalfRight = letterSpace - letterSpaceHalfLeft; - } - - hb_buffer_clear_contents(buffer); - hb_buffer_set_script(buffer, script); - hb_buffer_set_direction(buffer, - isRtl ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); - const FontLanguages& langList = - FontLanguageListCache::getById(ctx->style.getLanguageListId()); - if (langList.size() != 0) { - const FontLanguage* hbLanguage = &langList[0]; - for (size_t i = 0; i < langList.size(); ++i) { - if (langList[i].supportsHbScript(script)) { - hbLanguage = &langList[i]; - break; - } - } - hb_buffer_set_language(buffer, hbLanguage->getHbLanguage()); - } - - const uint32_t clusterStart = - addToHbBuffer(buffer, buf, start, count, bufSize, scriptRunStart, - scriptRunEnd, ctx->paint.hyphenEdit, hbFont); - - hb_shape(hbFont, buffer, features.empty() ? NULL : &features[0], - features.size()); - unsigned int numGlyphs; - hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, &numGlyphs); - hb_glyph_position_t* positions = - hb_buffer_get_glyph_positions(buffer, NULL); - - // At this point in the code, the cluster values in the info buffer - // correspond to the input characters with some shift. The cluster value - // clusterStart corresponds to the first character passed to HarfBuzz, - // which is at buf[start + scriptRunStart] whose advance needs to be saved - // into mAdvances[scriptRunStart]. So cluster values need to be reduced by - // (clusterStart - scriptRunStart) to get converted to indices of - // mAdvances. - const ssize_t clusterOffset = clusterStart - scriptRunStart; - - if (numGlyphs) { - mAdvances[info[0].cluster - clusterOffset] += letterSpaceHalfLeft; - x += letterSpaceHalfLeft; - } - for (unsigned int i = 0; i < numGlyphs; i++) { -#ifdef VERBOSE_DEBUG - ALOGD("%d %d %d %d", positions[i].x_advance, positions[i].y_advance, - positions[i].x_offset, positions[i].y_offset); - ALOGD("DoLayout %u: %f; %d, %d", info[i].codepoint, - HBFixedToFloat(positions[i].x_advance), positions[i].x_offset, - positions[i].y_offset); -#endif - if (i > 0 && info[i - 1].cluster != info[i].cluster) { - mAdvances[info[i - 1].cluster - clusterOffset] += - letterSpaceHalfRight; - mAdvances[info[i].cluster - clusterOffset] += letterSpaceHalfLeft; - x += letterSpace; - } - - hb_codepoint_t glyph_ix = info[i].codepoint; - float xoff = HBFixedToFloat(positions[i].x_offset); - float yoff = -HBFixedToFloat(positions[i].y_offset); - xoff += yoff * ctx->paint.skewX; - LayoutGlyph glyph = { - font_ix, glyph_ix, x + xoff, y + yoff, - static_cast(info[i].cluster - clusterOffset)}; - mGlyphs.push_back(glyph); - float xAdvance = HBFixedToFloat(positions[i].x_advance); - if ((ctx->paint.paintFlags & LinearTextFlag) == 0) { - xAdvance = roundf(xAdvance); - } - MinikinRect glyphBounds; - hb_glyph_extents_t extents = {}; - if (is_color_bitmap_font && - hb_font_get_glyph_extents(hbFont, glyph_ix, &extents)) { - // Note that it is technically possible for a TrueType font to have - // outline and embedded bitmap at the same time. We ignore modified - // bbox of hinted outline glyphs in that case. - glyphBounds.mLeft = roundf(HBFixedToFloat(extents.x_bearing)); - glyphBounds.mTop = roundf(HBFixedToFloat(-extents.y_bearing)); - glyphBounds.mRight = - roundf(HBFixedToFloat(extents.x_bearing + extents.width)); - glyphBounds.mBottom = - roundf(HBFixedToFloat(-extents.y_bearing - extents.height)); - } else { - ctx->paint.font->GetBounds(&glyphBounds, glyph_ix, ctx->paint); - } - glyphBounds.offset(x + xoff, y + yoff); - mBounds.join(glyphBounds); - if (static_cast(info[i].cluster - clusterOffset) < count) { - mAdvances[info[i].cluster - clusterOffset] += xAdvance; - } else { - ALOGE("cluster %zu (start %zu) out of bounds of count %zu", - info[i].cluster - clusterOffset, start, count); - } - x += xAdvance; - } - if (numGlyphs) { - mAdvances[info[numGlyphs - 1].cluster - clusterOffset] += - letterSpaceHalfRight; - x += letterSpaceHalfRight; - } - } - } - mAdvance = x; -} - -void Layout::appendLayout(Layout* src, size_t start, float extraAdvance) { - int fontMapStack[16]; - int* fontMap; - if (src->mFaces.size() < sizeof(fontMapStack) / sizeof(fontMapStack[0])) { - fontMap = fontMapStack; - } else { - fontMap = new int[src->mFaces.size()]; - } - for (size_t i = 0; i < src->mFaces.size(); i++) { - int font_ix = findFace(src->mFaces[i], NULL); - fontMap[i] = font_ix; - } - // LibTxt: Changed x0 from int to float to prevent rounding that causes text - // jitter. - float x0 = mAdvance; - for (size_t i = 0; i < src->mGlyphs.size(); i++) { - LayoutGlyph& srcGlyph = src->mGlyphs[i]; - int font_ix = fontMap[srcGlyph.font_ix]; - unsigned int glyph_id = srcGlyph.glyph_id; - float x = x0 + srcGlyph.x; - float y = srcGlyph.y; - LayoutGlyph glyph = {font_ix, glyph_id, x, y, - static_cast(srcGlyph.cluster + start)}; - mGlyphs.push_back(glyph); - } - for (size_t i = 0; i < src->mAdvances.size(); i++) { - mAdvances[i + start] = src->mAdvances[i]; - if (i == 0) - mAdvances[i + start] += extraAdvance; - } - MinikinRect srcBounds(src->mBounds); - srcBounds.offset(x0, 0); - mBounds.join(srcBounds); - mAdvance += src->mAdvance + extraAdvance; - - if (fontMap != fontMapStack) { - delete[] fontMap; - } -} - -size_t Layout::nGlyphs() const { - return mGlyphs.size(); -} - -const MinikinFont* Layout::getFont(int i) const { - const LayoutGlyph& glyph = mGlyphs[i]; - return mFaces[glyph.font_ix].font; -} - -FontFakery Layout::getFakery(int i) const { - const LayoutGlyph& glyph = mGlyphs[i]; - return mFaces[glyph.font_ix].fakery; -} - -unsigned int Layout::getGlyphId(int i) const { - const LayoutGlyph& glyph = mGlyphs[i]; - return glyph.glyph_id; -} - -// libtxt extension -unsigned int Layout::getGlyphCluster(int i) const { - const LayoutGlyph& glyph = mGlyphs[i]; - return glyph.cluster; -} - -float Layout::getX(int i) const { - const LayoutGlyph& glyph = mGlyphs[i]; - return glyph.x; -} - -float Layout::getY(int i) const { - const LayoutGlyph& glyph = mGlyphs[i]; - return glyph.y; -} - -float Layout::getAdvance() const { - return mAdvance; -} - -void Layout::getAdvances(float* advances) { - memcpy(advances, &mAdvances[0], mAdvances.size() * sizeof(float)); -} - -void Layout::getBounds(MinikinRect* bounds) const { - bounds->set(mBounds); -} - -void Layout::purgeCaches() { - std::scoped_lock _l(gMinikinLock); - LayoutCache& layoutCache = LayoutEngine::getInstance().layoutCache; - layoutCache.clear(); - purgeHbFontCacheLocked(); -} - -} // namespace minikin diff --git a/third_party/txt/src/minikin/Layout.h b/third_party/txt/src/minikin/Layout.h deleted file mode 100644 index 78cf7644ba39b..0000000000000 --- a/third_party/txt/src/minikin/Layout.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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. - */ - -#ifndef MINIKIN_LAYOUT_H -#define MINIKIN_LAYOUT_H - -#include - -#include -#include - -#include - -namespace minikin { - -struct LayoutGlyph { - // index into mFaces and mHbFonts vectors. We could imagine - // moving this into a run length representation, because it's - // more efficient for long strings, and we'll probably need - // something like that for paint attributes (color, underline, - // fake b/i, etc), as having those per-glyph is bloated. - int font_ix; - - unsigned int glyph_id; - float x; - float y; - - // libtxt extension: record the cluster (character index) that corresponds - // to this glyph - uint32_t cluster; -}; - -// Internal state used during layout operation -struct LayoutContext; - -enum { - kBidi_LTR = 0, - kBidi_RTL = 1, - kBidi_Default_LTR = 2, - kBidi_Default_RTL = 3, - kBidi_Force_LTR = 4, - kBidi_Force_RTL = 5, - - kBidi_Mask = 0x7 -}; - -// Lifecycle and threading assumptions for Layout: -// The object is assumed to be owned by a single thread; multiple threads -// may not mutate it at the same time. -class Layout { - public: - Layout() : mGlyphs(), mAdvances(), mFaces(), mAdvance(0), mBounds() { - mBounds.setEmpty(); - } - - Layout(Layout&& layout) = default; - - // Forbid copying and assignment. - Layout(const Layout&) = delete; - void operator=(const Layout&) = delete; - - void dump() const; - - void doLayout(const uint16_t* buf, - size_t start, - size_t count, - size_t bufSize, - bool isRtl, - const FontStyle& style, - const MinikinPaint& paint, - const std::shared_ptr& collection); - - static float measureText(const uint16_t* buf, - size_t start, - size_t count, - size_t bufSize, - bool isRtl, - const FontStyle& style, - const MinikinPaint& paint, - const std::shared_ptr& collection, - float* advances); - - // public accessors - size_t nGlyphs() const; - const MinikinFont* getFont(int i) const; - FontFakery getFakery(int i) const; - unsigned int getGlyphId(int i) const; - uint32_t getGlyphCluster(int i) const; // libtxt extension - float getX(int i) const; - float getY(int i) const; - - float getAdvance() const; - - // Get advances, copying into caller-provided buffer. The size of this - // buffer must match the length of the string (count arg to doLayout). - void getAdvances(float* advances); - - // The i parameter is an offset within the buf relative to start, it is < - // count, where start and count are the parameters to doLayout - float getCharAdvance(size_t i) const { return mAdvances[i]; } - - void getBounds(MinikinRect* rect) const; - - // Purge all caches, useful in low memory conditions - static void purgeCaches(); - - private: - friend class LayoutCacheKey; - - // Find a face in the mFaces vector, or create a new entry - int findFace(const FakedFont& face, LayoutContext* ctx); - - // Clears layout, ready to be used again - void reset(); - - // Lay out a single bidi run - // When layout is not null, layout info will be stored in the object. - // When advances is not null, measurement results will be stored in the array. - static float doLayoutRunCached( - const uint16_t* buf, - size_t runStart, - size_t runLength, - size_t bufSize, - bool isRtl, - LayoutContext* ctx, - size_t dstStart, - const std::shared_ptr& collection, - Layout* layout, - float* advances); - - // Lay out a single word - static float doLayoutWord(const uint16_t* buf, - size_t start, - size_t count, - size_t bufSize, - bool isRtl, - LayoutContext* ctx, - size_t bufStart, - const std::shared_ptr& collection, - Layout* layout, - float* advances); - - // Lay out a single bidi run - void doLayoutRun(const uint16_t* buf, - size_t start, - size_t count, - size_t bufSize, - bool isRtl, - LayoutContext* ctx, - const std::shared_ptr& collection); - - // Append another layout (for example, cached value) into this one - void appendLayout(Layout* src, size_t start, float extraAdvance); - - std::vector mGlyphs; - std::vector mAdvances; - - std::vector mFaces; - float mAdvance; - MinikinRect mBounds; -}; - -} // namespace minikin - -#endif // MINIKIN_LAYOUT_H diff --git a/third_party/txt/src/minikin/LayoutUtils.cpp b/third_party/txt/src/minikin/LayoutUtils.cpp deleted file mode 100644 index e461892d26bbd..0000000000000 --- a/third_party/txt/src/minikin/LayoutUtils.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "Minikin" - -#include "LayoutUtils.h" - -namespace minikin { - -const uint16_t CHAR_NBSP = 0x00A0; - -/* - * Determine whether the code unit is a word space for the purposes of - * justification. - */ -bool isWordSpace(uint16_t code_unit) { - return code_unit == ' ' || code_unit == CHAR_NBSP; -} - -/** - * For the purpose of layout, a word break is a boundary with no - * kerning or complex script processing. This is necessarily a - * heuristic, but should be accurate most of the time. - */ -static bool isWordBreakAfter(uint16_t c) { - if (isWordSpace(c) || (c >= 0x2000 && c <= 0x200a) || c == 0x3000) { - // spaces - return true; - } - // Note: kana is not included, as sophisticated fonts may kern kana - return false; -} - -static bool isWordBreakBefore(uint16_t c) { - // CJK ideographs (and yijing hexagram symbols) - return isWordBreakAfter(c) || (c >= 0x3400 && c <= 0x9fff); -} - -/** - * Return offset of previous word break. It is either < offset or == 0. - */ -size_t getPrevWordBreakForCache(const uint16_t* chars, - size_t offset, - size_t len) { - if (offset == 0) - return 0; - if (offset > len) - offset = len; - if (isWordBreakBefore(chars[offset - 1])) { - return offset - 1; - } - for (size_t i = offset - 1; i > 0; i--) { - if (isWordBreakBefore(chars[i]) || isWordBreakAfter(chars[i - 1])) { - return i; - } - } - return 0; -} - -/** - * Return offset of next word break. It is either > offset or == len. - */ -size_t getNextWordBreakForCache(const uint16_t* chars, - size_t offset, - size_t len) { - if (offset >= len) - return len; - if (isWordBreakAfter(chars[offset])) { - return offset + 1; - } - for (size_t i = offset + 1; i < len; i++) { - // No need to check isWordBreakAfter(chars[i - 1]) since it is checked - // in previous iteration. Note that isWordBreakBefore returns true - // whenever isWordBreakAfter returns true. - if (isWordBreakBefore(chars[i])) { - return i; - } - } - return len; -} - -} // namespace minikin diff --git a/third_party/txt/src/minikin/LayoutUtils.h b/third_party/txt/src/minikin/LayoutUtils.h deleted file mode 100644 index 2dcc6c510f472..0000000000000 --- a/third_party/txt/src/minikin/LayoutUtils.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#ifndef MINIKIN_LAYOUT_UTILS_H -#define MINIKIN_LAYOUT_UTILS_H - -#include -#include - -namespace minikin { - -/* - * Determine whether the code unit is a word space for the purposes of - * justification. - */ -bool isWordSpace(uint16_t code_unit); - -/** - * Return offset of previous word break. It is either < offset or == 0. - * - * For the purpose of layout, a word break is a boundary with no - * kerning or complex script processing. This is necessarily a - * heuristic, but should be accurate most of the time. - */ -size_t getPrevWordBreakForCache(const uint16_t* chars, - size_t offset, - size_t len); - -/** - * Return offset of next word break. It is either > offset or == len. - * - * For the purpose of layout, a word break is a boundary with no - * kerning or complex script processing. This is necessarily a - * heuristic, but should be accurate most of the time. - */ -size_t getNextWordBreakForCache(const uint16_t* chars, - size_t offset, - size_t len); - -} // namespace minikin -#endif // MINIKIN_LAYOUT_UTILS_H diff --git a/third_party/txt/src/minikin/LineBreaker.cpp b/third_party/txt/src/minikin/LineBreaker.cpp deleted file mode 100644 index 6a67f87e30a16..0000000000000 --- a/third_party/txt/src/minikin/LineBreaker.cpp +++ /dev/null @@ -1,557 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#define VERBOSE_DEBUG 0 - -#define LOG_TAG "Minikin" - -#include -#include - -#include - -#include -#include -#include -#include "LayoutUtils.h" - -using std::vector; - -namespace minikin { - -// Large scores in a hierarchy; we prefer desperate breaks to an overfull line. -// All these constants are larger than any reasonable actual width score. -const float SCORE_INFTY = std::numeric_limits::max(); -const float SCORE_OVERFULL = 1e12f; -const float SCORE_DESPERATE = 1e10f; - -// Multiplier for hyphen penalty on last line. -const float LAST_LINE_PENALTY_MULTIPLIER = 4.0f; -// Penalty assigned to each line break (to try to minimize number of lines) -// TODO: when we implement full justification (so spaces can shrink and -// stretch), this is probably not the most appropriate method. -const float LINE_PENALTY_MULTIPLIER = 2.0f; - -// Penalty assigned to shrinking the whitepsace. -const float SHRINK_PENALTY_MULTIPLIER = 4.0f; - -// Very long words trigger O(n^2) behavior in hyphenation, so we disable -// hyphenation for unreasonably long words. This is somewhat of a heuristic -// because extremely long words are possible in some languages. This does mean -// that very long real words can get broken by desperate breaks, with no -// hyphens. -const size_t LONGEST_HYPHENATED_WORD = 45; - -// When the text buffer is within this limit, capacity of vectors is retained at -// finish(), to avoid allocation. -const size_t MAX_TEXT_BUF_RETAIN = 32678; - -// Maximum amount that spaces can shrink, in justified text. -const float SHRINKABILITY = 1.0 / 3.0; - -// libtxt: Add a fudge factor to comparisons between currentLineWidth and -// postBreak width. The currentLineWidth passed by the Flutter framework -// is based on maxIntrinsicWidth/Layout::measureText calculations that may -// not precisely match the postBreak width. -const float LIBTXT_WIDTH_ADJUST = 0.00001; - -void LineBreaker::setLocale() { - mWordBreaker.setLocale(); - mLocale = icu::Locale(); - mHyphenator = nullptr; -} - -void LineBreaker::setText() { - mWordBreaker.setText(mTextBuf.data(), mTextBuf.size()); - - // handle initial break here because addStyleRun may never be called - mWordBreaker.next(); - mCandidates.clear(); - Candidate cand = {0, 0, 0.0, 0.0, 0.0, - 0.0, 0, 0, 0, HyphenationType::DONT_BREAK}; - mCandidates.push_back(cand); - - // reset greedy breaker state - mBreaks.clear(); - mWidths.clear(); - mFlags.clear(); - mLastBreak = 0; - mBestBreak = 0; - mBestScore = SCORE_INFTY; - mPreBreak = 0; - mLastHyphenation = HyphenEdit::NO_EDIT; - mFirstTabIndex = INT_MAX; - mSpaceCount = 0; -} - -void LineBreaker::setLineWidths(float firstWidth, - int firstWidthLineCount, - float restWidth) { - mLineWidths.setWidths(firstWidth, firstWidthLineCount, restWidth); -} - -void LineBreaker::setIndents(const std::vector& indents) { - mLineWidths.setIndents(indents); -} - -// This function determines whether a character is a space that disappears at -// end of line. It is the Unicode set: -// [[:General_Category=Space_Separator:]-[:Line_Break=Glue:]], plus '\n'. Note: -// all such characters are in the BMP, so it's ok to use code units for this. -bool isLineEndSpace(uint16_t c) { - return c == '\n' || c == ' ' || c == 0x1680 || - (0x2000 <= c && c <= 0x200A && c != 0x2007) || c == 0x205F || - c == 0x3000; -} - -// Ordinarily, this method measures the text in the range given. However, when -// paint is nullptr, it assumes the widths have already been calculated and -// stored in the width buffer. This method finds the candidate word breaks -// (using the ICU break iterator) and sends them to addCandidate. -float LineBreaker::addStyleRun(MinikinPaint* paint, - const std::shared_ptr& typeface, - FontStyle style, - size_t start, - size_t end, - bool isRtl) { - float width = 0.0f; - - float hyphenPenalty = 0.0; - if (paint != nullptr) { - width = Layout::measureText(mTextBuf.data(), start, end - start, - mTextBuf.size(), isRtl, style, *paint, typeface, - mCharWidths.data() + start); - - // a heuristic that seems to perform well - hyphenPenalty = - 0.5 * paint->size * paint->scaleX * mLineWidths.getLineWidth(0); - if (mHyphenationFrequency == kHyphenationFrequency_Normal) { - hyphenPenalty *= - 4.0; // TODO: Replace with a better value after some testing - } - - if (mJustified) { - // Make hyphenation more aggressive for fully justified text (so that - // "normal" in justified mode is the same as "full" in ragged-right). - hyphenPenalty *= 0.25; - } else { - // Line penalty is zero for justified text. - mLinePenalty = - std::max(mLinePenalty, hyphenPenalty * LINE_PENALTY_MULTIPLIER); - } - } - - size_t current = (size_t)mWordBreaker.current(); - size_t afterWord = start; - size_t lastBreak = start; - ParaWidth lastBreakWidth = mWidth; - ParaWidth postBreak = mWidth; - size_t postSpaceCount = mSpaceCount; - for (size_t i = start; i < end; i++) { - uint16_t c = mTextBuf[i]; - // libtxt: Tab handling was removed here. - if (isWordSpace(c)) - mSpaceCount += 1; - mWidth += mCharWidths[i]; - if (!isLineEndSpace(c)) { - postBreak = mWidth; - postSpaceCount = mSpaceCount; - afterWord = i + 1; - } - if (i + 1 == current) { - size_t wordStart = mWordBreaker.wordStart(); - size_t wordEnd = mWordBreaker.wordEnd(); - if (paint != nullptr && mHyphenator != nullptr && - mHyphenationFrequency != kHyphenationFrequency_None && - wordStart >= start && wordEnd > wordStart && - wordEnd - wordStart <= LONGEST_HYPHENATED_WORD) { - mHyphenator->hyphenate(&mHyphBuf, &mTextBuf[wordStart], - wordEnd - wordStart, mLocale); -#if VERBOSE_DEBUG - std::string hyphenatedString; - for (size_t j = wordStart; j < wordEnd; j++) { - if (mHyphBuf[j - wordStart] == - HyphenationType::BREAK_AND_INSERT_HYPHEN) { - hyphenatedString.push_back('-'); - } - // Note: only works with ASCII, should do UTF-8 conversion here - hyphenatedString.push_back(buffer()[j]); - } - ALOGD("hyphenated string: %s", hyphenatedString.c_str()); -#endif - - // measure hyphenated substrings - for (size_t j = wordStart; j < wordEnd; j++) { - HyphenationType hyph = mHyphBuf[j - wordStart]; - if (hyph != HyphenationType::DONT_BREAK) { - paint->hyphenEdit = HyphenEdit::editForThisLine(hyph); - const float firstPartWidth = Layout::measureText( - mTextBuf.data(), lastBreak, j - lastBreak, mTextBuf.size(), - isRtl, style, *paint, typeface, nullptr); - ParaWidth hyphPostBreak = lastBreakWidth + firstPartWidth; - - paint->hyphenEdit = HyphenEdit::editForNextLine(hyph); - const float secondPartWidth = Layout::measureText( - mTextBuf.data(), j, afterWord - j, mTextBuf.size(), isRtl, - style, *paint, typeface, nullptr); - ParaWidth hyphPreBreak = postBreak - secondPartWidth; - - addWordBreak(j, hyphPreBreak, hyphPostBreak, postSpaceCount, - postSpaceCount, hyphenPenalty, hyph); - - paint->hyphenEdit = HyphenEdit::NO_EDIT; - } - } - } - - // Skip break for zero-width characters inside replacement span - if (paint != nullptr || current == end || mCharWidths[current] > 0) { - float penalty = hyphenPenalty * mWordBreaker.breakBadness(); - addWordBreak(current, mWidth, postBreak, mSpaceCount, postSpaceCount, - penalty, HyphenationType::DONT_BREAK); - } - lastBreak = current; - lastBreakWidth = mWidth; - current = (size_t)mWordBreaker.next(); - } - } - - return width; -} - -// add a word break (possibly for a hyphenated fragment), and add desperate -// breaks if needed (ie when word exceeds current line width) -void LineBreaker::addWordBreak(size_t offset, - ParaWidth preBreak, - ParaWidth postBreak, - size_t preSpaceCount, - size_t postSpaceCount, - float penalty, - HyphenationType hyph) { - Candidate cand; - ParaWidth width = mCandidates.back().preBreak; - // libtxt: add a fudge factor to this comparison. The currentLineWidth passed - // by the framework is based on maxIntrinsicWidth/Layout::measureText - // calculations that may not precisely match the postBreak width. - if (postBreak - width > currentLineWidth() + LIBTXT_WIDTH_ADJUST) { - // Add desperate breaks. - // Note: these breaks are based on the shaping of the (non-broken) original - // text; they are imprecise especially in the presence of kerning, - // ligatures, and Arabic shaping. - size_t i = mCandidates.back().offset; - width += mCharWidths[i++]; - for (; i < offset; i++) { - float w = mCharWidths[i]; - if (w > 0) { - cand.offset = i; - cand.preBreak = width; - cand.postBreak = width; - // postSpaceCount doesn't include trailing spaces - cand.preSpaceCount = postSpaceCount; - cand.postSpaceCount = postSpaceCount; - cand.penalty = SCORE_DESPERATE; - cand.hyphenType = HyphenationType::BREAK_AND_DONT_INSERT_HYPHEN; -#if VERBOSE_DEBUG - ALOGD("desperate cand: %zd %g:%g", mCandidates.size(), cand.postBreak, - cand.preBreak); -#endif - addCandidate(cand); - width += w; - } - } - } - - cand.offset = offset; - cand.preBreak = preBreak; - cand.postBreak = postBreak; - cand.penalty = penalty; - cand.preSpaceCount = preSpaceCount; - cand.postSpaceCount = postSpaceCount; - cand.hyphenType = hyph; -#if VERBOSE_DEBUG - ALOGD("cand: %zd %g:%g", mCandidates.size(), cand.postBreak, cand.preBreak); -#endif - addCandidate(cand); -} - -// Helper method for addCandidate() -void LineBreaker::pushGreedyBreak() { - const Candidate& bestCandidate = mCandidates[mBestBreak]; - pushBreak( - bestCandidate.offset, bestCandidate.postBreak - mPreBreak, - mLastHyphenation | HyphenEdit::editForThisLine(bestCandidate.hyphenType)); - mBestScore = SCORE_INFTY; -#if VERBOSE_DEBUG - ALOGD("break: %d %g", mBreaks.back(), mWidths.back()); -#endif - mLastBreak = mBestBreak; - mPreBreak = bestCandidate.preBreak; - mLastHyphenation = HyphenEdit::editForNextLine(bestCandidate.hyphenType); -} - -// TODO performance: could avoid populating mCandidates if greedy only -void LineBreaker::addCandidate(Candidate cand) { - const size_t candIndex = mCandidates.size(); - mCandidates.push_back(cand); - - // mLastBreak is the index of the last line break we decided to do in - // mCandidates, and mPreBreak is its preBreak value. mBestBreak is the index - // of the best line breaking candidate we have found since then, and - // mBestScore is its penalty. - if (cand.postBreak - mPreBreak > currentLineWidth() + LIBTXT_WIDTH_ADJUST) { - // This break would create an overfull line, pick the best break and break - // there (greedy) - if (mBestBreak == mLastBreak) { - // No good break has been found since last break. Break here. - mBestBreak = candIndex; - } - pushGreedyBreak(); - } - - while (mLastBreak != candIndex && - cand.postBreak - mPreBreak > - currentLineWidth() + LIBTXT_WIDTH_ADJUST) { - // We should rarely come here. But if we are here, we have broken the line, - // but the remaining part still doesn't fit. We now need to break at the - // second best place after the last break, but we have not kept that - // information, so we need to go back and find it. - // - // In some really rare cases, postBreak - preBreak of a candidate itself may - // be over the current line width. We protect ourselves against an infinite - // loop in that case by checking that we have not broken the line at this - // candidate already. - for (size_t i = mLastBreak + 1; i < candIndex; i++) { - const float penalty = mCandidates[i].penalty; - if (penalty <= mBestScore) { - mBestBreak = i; - mBestScore = penalty; - } - } - if (mBestBreak == mLastBreak) { - // We didn't find anything good. Break here. - mBestBreak = candIndex; - } - pushGreedyBreak(); - } - - if (cand.penalty <= mBestScore) { - mBestBreak = candIndex; - mBestScore = cand.penalty; - } -} - -void LineBreaker::pushBreak(int offset, float width, uint8_t hyphenEdit) { - mBreaks.push_back(offset); - mWidths.push_back(width); - int flags = (mFirstTabIndex < mBreaks.back()) << kTab_Shift; - flags |= hyphenEdit; - mFlags.push_back(flags); - mFirstTabIndex = INT_MAX; -} - -// libtxt: Add ability to set custom char widths. This allows manual definition -// of the widths of arbitrary glyphs. To linebreak properly, call addStyleRun -// with nullptr as the paint property, which will lead it to assume the width -// has already been calculated. Used for properly breaking inline widgets. -void LineBreaker::setCustomCharWidth(size_t offset, float width) { - mCharWidths[offset] = (width); -} - -void LineBreaker::addReplacement(size_t start, size_t end, float width) { - mCharWidths[start] = width; - std::fill(&mCharWidths[start + 1], &mCharWidths[end], 0.0f); - addStyleRun(nullptr, nullptr, FontStyle(), start, end, false); -} - -// Get the width of a space. May return 0 if there are no spaces. -// Note: if there are multiple different widths for spaces (for example, because -// of mixing of fonts), it's only guaranteed to pick one. -float LineBreaker::getSpaceWidth() const { - for (size_t i = 0; i < mTextBuf.size(); i++) { - if (isWordSpace(mTextBuf[i])) { - return mCharWidths[i]; - } - } - return 0.0f; -} - -float LineBreaker::currentLineWidth() const { - return mLineWidths.getLineWidth(mBreaks.size()); -} - -void LineBreaker::computeBreaksGreedy() { - // All breaks but the last have been added in addCandidate already. - size_t nCand = mCandidates.size(); - if (nCand > 0 && (nCand == 1 || mLastBreak != nCand - 1)) { - pushBreak(mCandidates[nCand - 1].offset, - mCandidates[nCand - 1].postBreak - mPreBreak, mLastHyphenation); - // don't need to update mBestScore, because we're done -#if VERBOSE_DEBUG - ALOGD("final break: %d %g", mBreaks.back(), mWidths.back()); -#endif - } -} - -// Follow "prev" links in mCandidates array, and copy to result arrays. -void LineBreaker::finishBreaksOptimal() { - // clear existing greedy break result - mBreaks.clear(); - mWidths.clear(); - mFlags.clear(); - size_t nCand = mCandidates.size(); - size_t prev; - for (size_t i = nCand - 1; i > 0; i = prev) { - prev = mCandidates[i].prev; - mBreaks.push_back(mCandidates[i].offset); - mWidths.push_back(mCandidates[i].postBreak - mCandidates[prev].preBreak); - int flags = HyphenEdit::editForThisLine(mCandidates[i].hyphenType); - if (prev > 0) { - flags |= HyphenEdit::editForNextLine(mCandidates[prev].hyphenType); - } - mFlags.push_back(flags); - } - std::reverse(mBreaks.begin(), mBreaks.end()); - std::reverse(mWidths.begin(), mWidths.end()); - std::reverse(mFlags.begin(), mFlags.end()); -} - -void LineBreaker::computeBreaksOptimal(bool isRectangle) { - size_t active = 0; - size_t nCand = mCandidates.size(); - float width = mLineWidths.getLineWidth(0); - float shortLineFactor = mJustified ? 0.75f : 0.5f; - float maxShrink = mJustified ? SHRINKABILITY * getSpaceWidth() : 0.0f; - - // "i" iterates through candidates for the end of the line. - for (size_t i = 1; i < nCand; i++) { - bool atEnd = i == nCand - 1; - float best = SCORE_INFTY; - size_t bestPrev = 0; - size_t lineNumberLast = 0; - - if (!isRectangle) { - size_t lineNumberLast = mCandidates[active].lineNumber; - width = mLineWidths.getLineWidth(lineNumberLast); - } - ParaWidth leftEdge = mCandidates[i].postBreak - width; - float bestHope = 0; - - // "j" iterates through candidates for the beginning of the line. - for (size_t j = active; j < i; j++) { - if (!isRectangle) { - size_t lineNumber = mCandidates[j].lineNumber; - if (lineNumber != lineNumberLast) { - float widthNew = mLineWidths.getLineWidth(lineNumber); - if (widthNew != width) { - leftEdge = mCandidates[i].postBreak - width; - bestHope = 0; - width = widthNew; - } - lineNumberLast = lineNumber; - } - } - float jScore = mCandidates[j].score; - if (jScore + bestHope >= best) - continue; - float delta = mCandidates[j].preBreak - leftEdge; - - // compute width score for line - - // Note: the "bestHope" optimization makes the assumption that, when delta - // is non-negative, widthScore will increase monotonically as successive - // candidate breaks are considered. - float widthScore = 0.0f; - float additionalPenalty = 0.0f; - if ((atEnd || !mJustified) && delta < 0) { - widthScore = SCORE_OVERFULL; - } else if (atEnd && mStrategy != kBreakStrategy_Balanced) { - // increase penalty for hyphen on last line - additionalPenalty = - LAST_LINE_PENALTY_MULTIPLIER * mCandidates[j].penalty; - // Penalize very short (< 1 - shortLineFactor of total width) lines. - float underfill = delta - shortLineFactor * width; - widthScore = underfill > 0 ? underfill * underfill : 0; - } else { - widthScore = delta * delta; - if (delta < 0) { - if (-delta < maxShrink * (mCandidates[i].postSpaceCount - - mCandidates[j].preSpaceCount)) { - widthScore *= SHRINK_PENALTY_MULTIPLIER; - } else { - widthScore = SCORE_OVERFULL; - } - } - } - - if (delta < 0) { - active = j + 1; - } else { - bestHope = widthScore; - } - - float score = jScore + widthScore + additionalPenalty; - if (score <= best) { - best = score; - bestPrev = j; - } - } - mCandidates[i].score = best + mCandidates[i].penalty + mLinePenalty; - mCandidates[i].prev = bestPrev; - mCandidates[i].lineNumber = mCandidates[bestPrev].lineNumber + 1; -#if VERBOSE_DEBUG - ALOGD("break %zd: score=%g, prev=%zd", i, mCandidates[i].score, - mCandidates[i].prev); -#endif - } - finishBreaksOptimal(); -} - -size_t LineBreaker::computeBreaks() { - if (mStrategy == kBreakStrategy_Greedy) { - computeBreaksGreedy(); - } else { - computeBreaksOptimal(mLineWidths.isConstant()); - } - return mBreaks.size(); -} - -void LineBreaker::finish() { - mWordBreaker.finish(); - mWidth = 0; - mLineWidths.clear(); - mCandidates.clear(); - mBreaks.clear(); - mWidths.clear(); - mFlags.clear(); - if (mTextBuf.size() > MAX_TEXT_BUF_RETAIN) { - mTextBuf.clear(); - mTextBuf.shrink_to_fit(); - mCharWidths.clear(); - mCharWidths.shrink_to_fit(); - mHyphBuf.clear(); - mHyphBuf.shrink_to_fit(); - mCandidates.shrink_to_fit(); - mBreaks.shrink_to_fit(); - mWidths.shrink_to_fit(); - mFlags.shrink_to_fit(); - } - mStrategy = kBreakStrategy_Greedy; - mHyphenationFrequency = kHyphenationFrequency_Normal; - mLinePenalty = 0.0f; - mJustified = false; -} - -} // namespace minikin diff --git a/third_party/txt/src/minikin/LineBreaker.h b/third_party/txt/src/minikin/LineBreaker.h deleted file mode 100644 index a00f3b97ccdef..0000000000000 --- a/third_party/txt/src/minikin/LineBreaker.h +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -/** - * A module for breaking paragraphs into lines, supporting high quality - * hyphenation and justification. - */ - -#ifndef MINIKIN_LINE_BREAKER_H -#define MINIKIN_LINE_BREAKER_H - -#ifndef U_USING_ICU_NAMESPACE -#define U_USING_ICU_NAMESPACE 0 -#endif // U_USING_ICU_NAMESPACE - -#include -#include -#include "minikin/FontCollection.h" -#include "minikin/Hyphenator.h" -#include "minikin/MinikinFont.h" -#include "minikin/WordBreaker.h" -#include "unicode/brkiter.h" -#include "unicode/locid.h" - -namespace minikin { - -enum BreakStrategy { - kBreakStrategy_Greedy = 0, - kBreakStrategy_HighQuality = 1, - kBreakStrategy_Balanced = 2 -}; - -enum HyphenationFrequency { - kHyphenationFrequency_None = 0, - kHyphenationFrequency_Normal = 1, - kHyphenationFrequency_Full = 2 -}; - -bool isLineEndSpace(uint16_t c); - -// TODO: want to generalize to be able to handle array of line widths -class LineWidths { - public: - void setWidths(float firstWidth, int firstWidthLineCount, float restWidth) { - mFirstWidth = firstWidth; - mFirstWidthLineCount = firstWidthLineCount; - mRestWidth = restWidth; - } - void setIndents(const std::vector& indents) { mIndents = indents; } - bool isConstant() const { - // technically mFirstWidthLineCount == 0 would count too, but doesn't - // actually happen - return mRestWidth == mFirstWidth && mIndents.empty(); - } - float getLineWidth(int line) const { - float width = (line < mFirstWidthLineCount) ? mFirstWidth : mRestWidth; - if (!mIndents.empty()) { - if ((size_t)line < mIndents.size()) { - width -= mIndents[line]; - } else { - width -= mIndents.back(); - } - } - return width; - } - void clear() { mIndents.clear(); } - - private: - float mFirstWidth; - int mFirstWidthLineCount; - float mRestWidth; - std::vector mIndents; -}; - -class LineBreaker { - public: - const static int kTab_Shift = - 29; // keep synchronized with TAB_MASK in StaticLayout.java - - // Note: Locale persists across multiple invocations (it is not cleaned up by - // finish()), explicitly to avoid the cost of creating ICU BreakIterator - // objects. It should always be set on the first invocation, but callers are - // encouraged not to call again unless locale has actually changed. That logic - // could be here but it's better for performance that it's upstream because of - // the cost of constructing and comparing the ICU Locale object. - // Note: caller is responsible for managing lifetime of hyphenator - // - // libtxt extension: always use the default locale so that a cached instance - // of the ICU break iterator can be reused. - void setLocale(); - - void resize(size_t size) { - mTextBuf.resize(size); - mCharWidths.resize(size); - } - - size_t size() const { return mTextBuf.size(); } - - uint16_t* buffer() { return mTextBuf.data(); } - - float* charWidths() { return mCharWidths.data(); } - - // set text to current contents of buffer - void setText(); - - void setLineWidths(float firstWidth, - int firstWidthLineCount, - float restWidth); - - void setIndents(const std::vector& indents); - - BreakStrategy getStrategy() const { return mStrategy; } - - void setStrategy(BreakStrategy strategy) { mStrategy = strategy; } - - void setJustified(bool justified) { mJustified = justified; } - - HyphenationFrequency getHyphenationFrequency() const { - return mHyphenationFrequency; - } - - void setHyphenationFrequency(HyphenationFrequency frequency) { - mHyphenationFrequency = frequency; - } - - // TODO: this class is actually fairly close to being general and not tied to - // using Minikin to do the shaping of the strings. The main thing that would - // need to be changed is having some kind of callback (or virtual class, or - // maybe even template), which could easily be instantiated with Minikin's - // Layout. Future work for when needed. - float addStyleRun(MinikinPaint* paint, - const std::shared_ptr& typeface, - FontStyle style, - size_t start, - size_t end, - bool isRtl); - - void addReplacement(size_t start, size_t end, float width); - - size_t computeBreaks(); - - // libtxt: Add ability to set custom char widths. This allows manual - // definition of the widths of arbitrary glyphs. To linebreak properly, call - // addStyleRun with nullptr as the paint property, which will lead it to - // assume the width has already been calculated. Used for properly breaking - // inline placeholders. - void setCustomCharWidth(size_t offset, float width); - - const int* getBreaks() const { return mBreaks.data(); } - - const float* getWidths() const { return mWidths.data(); } - - const int* getFlags() const { return mFlags.data(); } - - void finish(); - - private: - // ParaWidth is used to hold cumulative width from beginning of paragraph. - // Note that for very large paragraphs, accuracy could degrade using only - // 32-bit float. Note however that float is used extensively on the Java side - // for this. This is a typedef so that we can easily change it based on - // performance/accuracy tradeoff. - typedef double ParaWidth; - - // A single candidate break - struct Candidate { - size_t offset; // offset to text buffer, in code units - size_t prev; // index to previous break - ParaWidth preBreak; // width of text until this point, if we decide to not - // break here - ParaWidth postBreak; // width of text until this point, if we decide to - // break here - float penalty; // penalty of this break (for example, hyphen penalty) - float score; // best score found for this break - size_t lineNumber; // only updated for non-constant line widths - size_t preSpaceCount; // preceding space count before breaking - size_t postSpaceCount; // preceding space count after breaking - HyphenationType hyphenType; - }; - - float currentLineWidth() const; - - void addWordBreak(size_t offset, - ParaWidth preBreak, - ParaWidth postBreak, - size_t preSpaceCount, - size_t postSpaceCount, - float penalty, - HyphenationType hyph); - - void addCandidate(Candidate cand); - void pushGreedyBreak(); - - // push an actual break to the output. Takes care of setting flags for tab - void pushBreak(int offset, float width, uint8_t hyphenEdit); - - float getSpaceWidth() const; - - void computeBreaksGreedy(); - - void computeBreaksOptimal(bool isRectangular); - - void finishBreaksOptimal(); - - WordBreaker mWordBreaker; - icu::Locale mLocale; - std::vector mTextBuf; - std::vector mCharWidths; - - Hyphenator* mHyphenator; - std::vector mHyphBuf; - - // layout parameters - BreakStrategy mStrategy = kBreakStrategy_Greedy; - HyphenationFrequency mHyphenationFrequency = kHyphenationFrequency_Normal; - bool mJustified; - LineWidths mLineWidths; - - // result of line breaking - std::vector mBreaks; - std::vector mWidths; - std::vector mFlags; - - ParaWidth mWidth = 0; - std::vector mCandidates; - float mLinePenalty = 0.0f; - - // the following are state for greedy breaker (updated while adding style - // runs) - size_t mLastBreak; - size_t mBestBreak; - float mBestScore; - ParaWidth mPreBreak; // prebreak of last break - uint32_t mLastHyphenation; // hyphen edit of last break kept for next line - int mFirstTabIndex; - size_t mSpaceCount; -}; - -} // namespace minikin - -#endif // MINIKIN_LINE_BREAKER_H diff --git a/third_party/txt/src/minikin/Measurement.cpp b/third_party/txt/src/minikin/Measurement.cpp deleted file mode 100644 index 87d08465ddddb..0000000000000 --- a/third_party/txt/src/minikin/Measurement.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "Minikin" - -#include -#include - -#include - -#include -#include - -namespace minikin { - -// These could be considered helper methods of layout, but need only be loosely -// coupled, so are separate. - -static float getRunAdvance(const float* advances, - const uint16_t* buf, - size_t layoutStart, - size_t start, - size_t count, - size_t offset) { - float advance = 0.0f; - size_t lastCluster = start; - float clusterWidth = 0.0f; - for (size_t i = start; i < offset; i++) { - float charAdvance = advances[i - layoutStart]; - if (charAdvance != 0.0f) { - advance += charAdvance; - lastCluster = i; - clusterWidth = charAdvance; - } - } - if (offset < start + count && advances[offset - layoutStart] == 0.0f) { - // In the middle of a cluster, distribute width of cluster so that each - // grapheme cluster gets an equal share. - // TODO: get caret information out of font when that's available - size_t nextCluster; - for (nextCluster = offset + 1; nextCluster < start + count; nextCluster++) { - if (advances[nextCluster - layoutStart] != 0.0f) - break; - } - int numGraphemeClusters = 0; - int numGraphemeClustersAfter = 0; - for (size_t i = lastCluster; i < nextCluster; i++) { - bool isAfter = i >= offset; - if (GraphemeBreak::isGraphemeBreak(advances + (start - layoutStart), buf, - start, count, i)) { - numGraphemeClusters++; - if (isAfter) { - numGraphemeClustersAfter++; - } - } - } - if (numGraphemeClusters > 0) { - advance -= clusterWidth * numGraphemeClustersAfter / numGraphemeClusters; - } - } - return advance; -} - -float getRunAdvance(const float* advances, - const uint16_t* buf, - size_t start, - size_t count, - size_t offset) { - return getRunAdvance(advances, buf, start, start, count, offset); -} - -/** - * Essentially the inverse of getRunAdvance. Compute the value of offset for - * which the measured caret comes closest to the provided advance param, and - * which is on a grapheme cluster boundary. - * - * The actual implementation fast-forwards through clusters to get "close", then - * does a finer-grain search within the cluster and grapheme breaks. - */ -size_t getOffsetForAdvance(const float* advances, - const uint16_t* buf, - size_t start, - size_t count, - float advance) { - float x = 0.0f, xLastClusterStart = 0.0f, xSearchStart = 0.0f; - size_t lastClusterStart = start, searchStart = start; - for (size_t i = start; i < start + count; i++) { - if (GraphemeBreak::isGraphemeBreak(advances, buf, start, count, i)) { - searchStart = lastClusterStart; - xSearchStart = xLastClusterStart; - } - float width = advances[i - start]; - if (width != 0.0f) { - lastClusterStart = i; - xLastClusterStart = x; - x += width; - if (x > advance) { - break; - } - } - } - size_t best = searchStart; - float bestDist = FLT_MAX; - for (size_t i = searchStart; i <= start + count; i++) { - if (GraphemeBreak::isGraphemeBreak(advances, buf, start, count, i)) { - // "getRunAdvance(layout, buf, start, count, i) - advance" but more - // efficient - float delta = getRunAdvance(advances, buf, start, searchStart, - count - searchStart, i) - - + xSearchStart - advance; - if (std::abs(delta) < bestDist) { - bestDist = std::abs(delta); - best = i; - } - if (delta >= 0.0f) { - break; - } - } - } - return best; -} - -} // namespace minikin diff --git a/third_party/txt/src/minikin/Measurement.h b/third_party/txt/src/minikin/Measurement.h deleted file mode 100644 index fac2848e16061..0000000000000 --- a/third_party/txt/src/minikin/Measurement.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#ifndef MINIKIN_MEASUREMENT_H -#define MINIKIN_MEASUREMENT_H - -#include - -namespace minikin { - -float getRunAdvance(const float* advances, - const uint16_t* buf, - size_t start, - size_t count, - size_t offset); - -size_t getOffsetForAdvance(const float* advances, - const uint16_t* buf, - size_t start, - size_t count, - float advance); - -} // namespace minikin - -#endif // MINIKIN_MEASUREMENT_H diff --git a/third_party/txt/src/minikin/MinikinFont.cpp b/third_party/txt/src/minikin/MinikinFont.cpp deleted file mode 100644 index c44b0a1407298..0000000000000 --- a/third_party/txt/src/minikin/MinikinFont.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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 "HbFontCache.h" -#include "MinikinInternal.h" - -namespace minikin { - -MinikinFont::~MinikinFont() { - std::scoped_lock _l(gMinikinLock); - purgeHbFontLocked(this); -} - -} // namespace minikin diff --git a/third_party/txt/src/minikin/MinikinFont.h b/third_party/txt/src/minikin/MinikinFont.h deleted file mode 100644 index b7d69562af4f6..0000000000000 --- a/third_party/txt/src/minikin/MinikinFont.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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. - */ - -#ifndef MINIKIN_FONT_H -#define MINIKIN_FONT_H - -#include -#include - -#include -#include - -// An abstraction for platform fonts, allowing Minikin to be used with -// multiple actual implementations of fonts. - -namespace minikin { - -class MinikinFont; - -// Possibly move into own .h file? -// Note: if you add a field here, either add it to LayoutCacheKey or to -// skipCache() -struct MinikinPaint { - MinikinPaint() - : font(nullptr), - size(0), - scaleX(0), - skewX(0), - letterSpacing(0), - wordSpacing(0), - paintFlags(0), - fakery(), - hyphenEdit(), - fontFeatureSettings() {} - - bool skipCache() const { return !fontFeatureSettings.empty(); } - - MinikinFont* font; - float size; - float scaleX; - float skewX; - float letterSpacing; - float wordSpacing; - uint32_t paintFlags; - FontFakery fakery; - HyphenEdit hyphenEdit; - std::string fontFeatureSettings; -}; - -// Only a few flags affect layout, but those that do should have values -// consistent with Android's paint flags. -enum MinikinPaintFlags { - LinearTextFlag = 0x40, -}; - -struct MinikinRect { - float mLeft, mTop, mRight, mBottom; - bool isEmpty() const { return mLeft == mRight || mTop == mBottom; } - void set(const MinikinRect& r) { - mLeft = r.mLeft; - mTop = r.mTop; - mRight = r.mRight; - mBottom = r.mBottom; - } - void offset(float dx, float dy) { - mLeft += dx; - mTop += dy; - mRight += dx; - mBottom += dy; - } - void setEmpty() { mLeft = mTop = mRight = mBottom = 0; } - void join(const MinikinRect& r); -}; - -// Callback for freeing data -typedef void (*MinikinDestroyFunc)(void* data); - -class MinikinFont { - public: - explicit MinikinFont(int32_t uniqueId) : mUniqueId(uniqueId) {} - - virtual ~MinikinFont(); - - virtual float GetHorizontalAdvance(uint32_t glyph_id, - const MinikinPaint& paint) const = 0; - - virtual void GetBounds(MinikinRect* bounds, - uint32_t glyph_id, - const MinikinPaint& paint) const = 0; - - virtual hb_face_t* CreateHarfBuzzFace() const { return nullptr; } - - virtual const std::vector& GetAxes() const = 0; - - virtual std::shared_ptr createFontWithVariation( - const std::vector&) const { - return nullptr; - } - - static uint32_t MakeTag(char c1, char c2, char c3, char c4) { - return ((uint32_t)c1 << 24) | ((uint32_t)c2 << 16) | ((uint32_t)c3 << 8) | - (uint32_t)c4; - } - - int32_t GetUniqueId() const { return mUniqueId; } - - private: - const int32_t mUniqueId; -}; - -} // namespace minikin - -#endif // MINIKIN_FONT_H diff --git a/third_party/txt/src/minikin/MinikinInternal.cpp b/third_party/txt/src/minikin/MinikinInternal.cpp deleted file mode 100644 index 7fd68162d6cc7..0000000000000 --- a/third_party/txt/src/minikin/MinikinInternal.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * 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. - */ - -// Definitions internal to Minikin -#define LOG_TAG "Minikin" - -#include "MinikinInternal.h" -#include "HbFontCache.h" - -#include - -namespace minikin { - -#ifdef __clang__ -[[clang::no_destroy]] -#endif -std::recursive_mutex gMinikinLock; - -void assertMinikinLocked() { -#ifdef ENABLE_RACE_DETECTION - LOG_ALWAYS_FATAL_IF(gMinikinLock.tryLock() == 0); -#endif -} - -hb_blob_t* getFontTable(const MinikinFont* minikinFont, uint32_t tag) { - assertMinikinLocked(); - hb_font_t* font = getHbFontLocked(minikinFont); - hb_face_t* face = hb_font_get_face(font); - hb_blob_t* blob = hb_face_reference_table(face, tag); - hb_font_destroy(font); - return blob; -} - -} // namespace minikin diff --git a/third_party/txt/src/minikin/MinikinInternal.h b/third_party/txt/src/minikin/MinikinInternal.h deleted file mode 100644 index c07ad479a82f0..0000000000000 --- a/third_party/txt/src/minikin/MinikinInternal.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * 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. - */ - -// Definitions internal to Minikin - -#ifndef MINIKIN_INTERNAL_H -#define MINIKIN_INTERNAL_H - -#include - -#include - -#include - -namespace minikin { - -// All external Minikin interfaces are designed to be thread-safe. -// Presently, that's implemented by through a global lock, and having -// all external interfaces take that lock. - -extern std::recursive_mutex gMinikinLock; - -// Aborts if gMinikinLock is not acquired. Do nothing on the release build. -void assertMinikinLocked(); - -hb_blob_t* getFontTable(const MinikinFont* minikinFont, uint32_t tag); - -constexpr uint32_t MAX_UNICODE_CODE_POINT = 0x10FFFF; - -// An RAII wrapper for hb_blob_t -class HbBlob { - public: - // Takes ownership of hb_blob_t object, caller is no longer - // responsible for calling hb_blob_destroy(). - explicit HbBlob(hb_blob_t* blob) : mBlob(blob) {} - - ~HbBlob() { hb_blob_destroy(mBlob); } - - const uint8_t* get() const { - const char* data = hb_blob_get_data(mBlob, nullptr); - return reinterpret_cast(data); - } - - size_t size() const { return (size_t)hb_blob_get_length(mBlob); } - - private: - hb_blob_t* mBlob; -}; - -} // namespace minikin - -#endif // MINIKIN_INTERNAL_H diff --git a/third_party/txt/src/minikin/SparseBitSet.cpp b/third_party/txt/src/minikin/SparseBitSet.cpp deleted file mode 100644 index edb5160c3835d..0000000000000 --- a/third_party/txt/src/minikin/SparseBitSet.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "SparseBitSet" - -#include -#include - -#include - -#include -#include - -namespace minikin { - -const uint32_t SparseBitSet::kNotFound; - -uint32_t SparseBitSet::calcNumPages(const uint32_t* ranges, size_t nRanges) { - bool haveZeroPage = false; - uint32_t nonzeroPageEnd = 0; - uint32_t nPages = 0; - for (size_t i = 0; i < nRanges; i++) { - uint32_t start = ranges[i * 2]; - uint32_t end = ranges[i * 2 + 1]; - uint32_t startPage = start >> kLogValuesPerPage; - uint32_t endPage = (end - 1) >> kLogValuesPerPage; - if (startPage >= nonzeroPageEnd) { - if (startPage > nonzeroPageEnd) { - if (!haveZeroPage) { - haveZeroPage = true; - nPages++; - } - } - nPages++; - } - nPages += endPage - startPage; - nonzeroPageEnd = endPage + 1; - } - return nPages; -} - -void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) { - if (nRanges == 0) { - return; - } - const uint32_t maxVal = ranges[nRanges * 2 - 1]; - if (maxVal >= kMaximumCapacity) { - return; - } - mMaxVal = maxVal; - mIndices.reset(new uint16_t[(mMaxVal + kPageMask) >> kLogValuesPerPage]); - uint32_t nPages = calcNumPages(ranges, nRanges); - mBitmaps.reset(new element[nPages << (kLogValuesPerPage - kLogBitsPerEl)]()); - mZeroPageIndex = noZeroPage; - uint32_t nonzeroPageEnd = 0; - uint32_t currentPage = 0; - for (size_t i = 0; i < nRanges; i++) { - uint32_t start = ranges[i * 2]; - uint32_t end = ranges[i * 2 + 1]; - LOG_ALWAYS_FATAL_IF(end < start); // make sure range size is nonnegative - uint32_t startPage = start >> kLogValuesPerPage; - uint32_t endPage = (end - 1) >> kLogValuesPerPage; - if (startPage >= nonzeroPageEnd) { - if (startPage > nonzeroPageEnd) { - if (mZeroPageIndex == noZeroPage) { - mZeroPageIndex = (currentPage++) - << (kLogValuesPerPage - kLogBitsPerEl); - } - for (uint32_t j = nonzeroPageEnd; j < startPage; j++) { - mIndices[j] = mZeroPageIndex; - } - } - mIndices[startPage] = (currentPage++) - << (kLogValuesPerPage - kLogBitsPerEl); - } - - size_t index = ((currentPage - 1) << (kLogValuesPerPage - kLogBitsPerEl)) + - ((start & kPageMask) >> kLogBitsPerEl); - size_t nElements = (end - (start & ~kElMask) + kElMask) >> kLogBitsPerEl; - if (nElements == 1) { - mBitmaps[index] |= (kElAllOnes >> (start & kElMask)) & - (kElAllOnes << ((~end + 1) & kElMask)); - } else { - mBitmaps[index] |= kElAllOnes >> (start & kElMask); - for (size_t j = 1; j < nElements - 1; j++) { - mBitmaps[index + j] = kElAllOnes; - } - mBitmaps[index + nElements - 1] |= kElAllOnes << ((~end + 1) & kElMask); - } - for (size_t j = startPage + 1; j < endPage + 1; j++) { - mIndices[j] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl); - } - nonzeroPageEnd = endPage + 1; - } -} - -#if defined(_WIN32) -int SparseBitSet::CountLeadingZeros(element x) { - return sizeof(element) <= sizeof(int) ? clz_win(x) : clzl_win(x); -} -#else -int SparseBitSet::CountLeadingZeros(element x) { - // Note: GCC / clang builtin - return sizeof(element) <= sizeof(int) ? __builtin_clz(x) : __builtin_clzl(x); -} -#endif - -uint32_t SparseBitSet::nextSetBit(uint32_t fromIndex) const { - if (fromIndex >= mMaxVal) { - return kNotFound; - } - uint32_t fromPage = fromIndex >> kLogValuesPerPage; - const element* bitmap = &mBitmaps[mIndices[fromPage]]; - uint32_t offset = (fromIndex & kPageMask) >> kLogBitsPerEl; - element e = bitmap[offset] & (kElAllOnes >> (fromIndex & kElMask)); - if (e != 0) { - return (fromIndex & ~kElMask) + CountLeadingZeros(e); - } - for (uint32_t j = offset + 1; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); - j++) { - e = bitmap[j]; - if (e != 0) { - return (fromIndex & ~kPageMask) + (j << kLogBitsPerEl) + - CountLeadingZeros(e); - } - } - uint32_t maxPage = (mMaxVal + kPageMask) >> kLogValuesPerPage; - for (uint32_t page = fromPage + 1; page < maxPage; page++) { - uint16_t index = mIndices[page]; - if (index == mZeroPageIndex) { - continue; - } - bitmap = &mBitmaps[index]; - for (uint32_t j = 0; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++) { - e = bitmap[j]; - if (e != 0) { - return (page << kLogValuesPerPage) + (j << kLogBitsPerEl) + - CountLeadingZeros(e); - } - } - } - return kNotFound; -} - -} // namespace minikin diff --git a/third_party/txt/src/minikin/SparseBitSet.h b/third_party/txt/src/minikin/SparseBitSet.h deleted file mode 100644 index c0bf576920f4a..0000000000000 --- a/third_party/txt/src/minikin/SparseBitSet.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * 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. - */ - -#ifndef MINIKIN_SPARSE_BIT_SET_H -#define MINIKIN_SPARSE_BIT_SET_H - -#include -#include - -#include - -// --------------------------------------------------------------------------- - -namespace minikin { - -// This is an implementation of a set of integers. It is optimized for -// values that are somewhat sparse, in the ballpark of a maximum value -// of thousands to millions. It is particularly efficient when there are -// large gaps. The motivating example is Unicode coverage of a font, but -// the abstraction itself is fully general. -class SparseBitSet { - public: - // Create an empty bit set. - SparseBitSet() : mMaxVal(0) {} - - // Initialize the set to a new value, represented by ranges. For - // simplicity, these ranges are arranged as pairs of values, - // inclusive of start, exclusive of end, laid out in a uint32 array. - SparseBitSet(const uint32_t* ranges, size_t nRanges) : SparseBitSet() { - initFromRanges(ranges, nRanges); - } - - SparseBitSet(SparseBitSet&&) = default; - SparseBitSet& operator=(SparseBitSet&&) = default; - - // Determine whether the value is included in the set - bool get(uint32_t ch) const { - if (ch >= mMaxVal) - return false; - const uint32_t* bitmap = &mBitmaps[mIndices[ch >> kLogValuesPerPage]]; - uint32_t index = ch & kPageMask; - return (bitmap[index >> kLogBitsPerEl] & (kElFirst >> (index & kElMask))) != - 0; - } - - // One more than the maximum value in the set, or zero if empty - uint32_t length() const { return mMaxVal; } - - // The next set bit starting at fromIndex, inclusive, or kNotFound - // if none exists. - uint32_t nextSetBit(uint32_t fromIndex) const; - - static const uint32_t kNotFound = ~0u; - - private: - void initFromRanges(const uint32_t* ranges, size_t nRanges); - - static const uint32_t kMaximumCapacity = 0xFFFFFF; - static const int kLogValuesPerPage = 8; - static const int kPageMask = (1 << kLogValuesPerPage) - 1; - static const int kLogBytesPerEl = 2; - static const int kLogBitsPerEl = kLogBytesPerEl + 3; - static const int kElMask = (1 << kLogBitsPerEl) - 1; - // invariant: sizeof(element) == (1 << kLogBytesPerEl) - typedef uint32_t element; - static const element kElAllOnes = ~((element)0); - static const element kElFirst = ((element)1) << kElMask; - static const uint16_t noZeroPage = 0xFFFF; - - static uint32_t calcNumPages(const uint32_t* ranges, size_t nRanges); - static int CountLeadingZeros(element x); - - uint32_t mMaxVal; - - std::unique_ptr mIndices; - std::unique_ptr mBitmaps; - uint16_t mZeroPageIndex; - - // Forbid copy and assign. - SparseBitSet(const SparseBitSet&) = delete; - void operator=(const SparseBitSet&) = delete; -}; - -} // namespace minikin - -#endif // MINIKIN_SPARSE_BIT_SET_H diff --git a/third_party/txt/src/minikin/WordBreaker.cpp b/third_party/txt/src/minikin/WordBreaker.cpp deleted file mode 100644 index 107674d9b8643..0000000000000 --- a/third_party/txt/src/minikin/WordBreaker.cpp +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "Minikin" - -#include - -#include -#include -#include -#include "MinikinInternal.h" - -#include -#include - -namespace minikin { - -const uint32_t CHAR_SOFT_HYPHEN = 0x00AD; -const uint32_t CHAR_ZWJ = 0x200D; - -// libtxt extension: avoid the cost of initializing new ICU break iterators -// by constructing a global iterator using the default locale and then -// creating a clone for each WordBreaker instance. -static std::once_flag gLibtxtBreakIteratorInitFlag; -static icu::BreakIterator* gLibtxtDefaultBreakIterator = nullptr; - -void WordBreaker::setLocale() { - UErrorCode status = U_ZERO_ERROR; - std::call_once(gLibtxtBreakIteratorInitFlag, [&status] { - gLibtxtDefaultBreakIterator = - icu::BreakIterator::createLineInstance(icu::Locale(), status); - }); - mBreakIterator.reset(gLibtxtDefaultBreakIterator->clone()); - // TODO: handle failure status - if (mText != nullptr) { - mBreakIterator->setText(&mUText, status); - } - mIteratorWasReset = true; -} - -void WordBreaker::setText(const uint16_t* data, size_t size) { - mText = data; - mTextSize = size; - mIteratorWasReset = false; - mLast = 0; - mCurrent = 0; - mScanOffset = 0; - mInEmailOrUrl = false; - UErrorCode status = U_ZERO_ERROR; - utext_openUChars(&mUText, reinterpret_cast(data), size, - &status); - mBreakIterator->setText(&mUText, status); - mBreakIterator->first(); -} - -ssize_t WordBreaker::current() const { - return mCurrent; -} - -/** - * Determine whether a line break at position i within the buffer buf is valid. - *This represents customization beyond the ICU behavior, because plain ICU - *provides some line break opportunities that we don't want. - **/ -static bool isBreakValid(const uint16_t* buf, size_t bufEnd, size_t i) { - uint32_t codePoint; - size_t prev_offset = i; - U16_PREV(buf, 0, prev_offset, codePoint); - // Do not break on hard or soft hyphens. These are handled by automatic - // hyphenation. - if (Hyphenator::isLineBreakingHyphen(codePoint) || - codePoint == CHAR_SOFT_HYPHEN) { - // txt addition: Temporarily always break on hyphen. Changed from false to - // true. - return true; - } - // For Myanmar kinzi sequences, created by . This is to go around a bug in ICU line breaking: - // http://bugs.icu-project.org/trac/ticket/12561. To avoid too much looking - // around in the strings, we simply avoid breaking after any Myanmar virama, - // where no line break could be imagined, since the Myanmar virama is a pure - // stacker. - if (codePoint == 0x1039) { // MYANMAR SIGN VIRAMA - return false; - } - - uint32_t next_codepoint; - size_t next_offset = i; - U16_NEXT(buf, next_offset, bufEnd, next_codepoint); - - // Rule LB8 for Emoji ZWJ sequences. We need to do this ourselves since we may - // have fresher emoji data than ICU does. - if (codePoint == CHAR_ZWJ && isEmoji(next_codepoint)) { - return false; - } - - // Rule LB30b. We need to this ourselves since we may have fresher emoji data - // than ICU does. - if (isEmojiModifier(next_codepoint)) { - if (codePoint == 0xFE0F && prev_offset > 0) { - // skip over emoji variation selector - U16_PREV(buf, 0, prev_offset, codePoint); - } - if (isEmojiBase(codePoint)) { - return false; - } - } - return true; -} - -// Customized iteratorNext that takes care of both resets and our modifications -// to ICU's behavior. -int32_t WordBreaker::iteratorNext() { - int32_t result; - do { - if (mIteratorWasReset) { - result = mBreakIterator->following(mCurrent); - mIteratorWasReset = false; - } else { - result = mBreakIterator->next(); - } - } while (!(result == icu::BreakIterator::DONE || - (size_t)result == mTextSize || - isBreakValid(mText, mTextSize, result))); - return result; -} - -// Chicago Manual of Style recommends breaking after these characters in URLs -// and email addresses -static bool breakAfter(uint16_t c) { - return c == ':' || c == '=' || c == '&'; -} - -// Chicago Manual of Style recommends breaking before these characters in URLs -// and email addresses -static bool breakBefore(uint16_t c) { - return c == '~' || c == '.' || c == ',' || c == '-' || c == '_' || c == '?' || - c == '#' || c == '%' || c == '=' || c == '&'; -} - -enum ScanState { - START, - SAW_AT, - SAW_COLON, - SAW_COLON_SLASH, - SAW_COLON_SLASH_SLASH, -}; - -void WordBreaker::detectEmailOrUrl() { - // scan forward from current ICU position for email address or URL - if (mLast >= mScanOffset) { - ScanState state = START; - size_t i; - for (i = mLast; i < mTextSize; i++) { - uint16_t c = mText[i]; - // scan only ASCII characters, stop at space - if (!(' ' < c && c <= 0x007E)) { - break; - } - if (state == START && c == '@') { - state = SAW_AT; - } else if (state == START && c == ':') { - state = SAW_COLON; - } else if (state == SAW_COLON || state == SAW_COLON_SLASH) { - if (c == '/') { - state = static_cast((int)state + - 1); // next state adds a slash - } else { - state = START; - } - } - } - if (state == SAW_AT || state == SAW_COLON_SLASH_SLASH) { - if (!mBreakIterator->isBoundary(i)) { - // If there are combining marks or such at the end of the URL or the - // email address, consider them a part of the URL or the email, and skip - // to the next actual boundary. - i = mBreakIterator->following(i); - } - mInEmailOrUrl = true; - mIteratorWasReset = true; - } else { - mInEmailOrUrl = false; - } - mScanOffset = i; - } -} - -ssize_t WordBreaker::findNextBreakInEmailOrUrl() { - // special rules for email addresses and URL's as per Chicago Manual of Style - // (16th ed.) - uint16_t lastChar = mText[mLast]; - ssize_t i; - for (i = mLast + 1; i < mScanOffset; i++) { - if (breakAfter(lastChar)) { - break; - } - // break after double slash - if (lastChar == '/' && i >= mLast + 2 && mText[i - 2] == '/') { - break; - } - const uint16_t thisChar = mText[i]; - // never break after hyphen - if (lastChar != '-') { - if (breakBefore(thisChar)) { - break; - } - // break before single slash - if (thisChar == '/' && lastChar != '/' && - !(i + 1 < mScanOffset && mText[i + 1] == '/')) { - break; - } - } - lastChar = thisChar; - } - return i; -} - -ssize_t WordBreaker::next() { - mLast = mCurrent; - - detectEmailOrUrl(); - if (mInEmailOrUrl) { - mCurrent = findNextBreakInEmailOrUrl(); - } else { // Business as usual - mCurrent = (ssize_t)iteratorNext(); - } - return mCurrent; -} - -ssize_t WordBreaker::wordStart() const { - if (mInEmailOrUrl) { - return mLast; - } - ssize_t result = mLast; - while (result < mCurrent) { - UChar32 c; - ssize_t ix = result; - U16_NEXT(mText, ix, mCurrent, c); - const int32_t lb = u_getIntPropertyValue(c, UCHAR_LINE_BREAK); - // strip leading punctuation, defined as OP and QU line breaking classes, - // see UAX #14 - if (!(lb == U_LB_OPEN_PUNCTUATION || lb == U_LB_QUOTATION)) { - break; - } - result = ix; - } - return result; -} - -ssize_t WordBreaker::wordEnd() const { - if (mInEmailOrUrl) { - return mLast; - } - ssize_t result = mCurrent; - while (result > mLast) { - UChar32 c; - ssize_t ix = result; - U16_PREV(mText, mLast, ix, c); - const int32_t gc_mask = U_GET_GC_MASK(c); - // strip trailing space and punctuation - if ((gc_mask & (U_GC_ZS_MASK | U_GC_P_MASK)) == 0) { - break; - } - result = ix; - } - return result; -} - -int WordBreaker::breakBadness() const { - return (mInEmailOrUrl && mCurrent < mScanOffset) ? 1 : 0; -} - -void WordBreaker::finish() { - mText = nullptr; - // Note: calling utext_close multiply is safe - utext_close(&mUText); -} - -} // namespace minikin diff --git a/third_party/txt/src/minikin/WordBreaker.h b/third_party/txt/src/minikin/WordBreaker.h deleted file mode 100644 index f318a95660307..0000000000000 --- a/third_party/txt/src/minikin/WordBreaker.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -/** - * A wrapper around ICU's line break iterator, that gives customized line - * break opportunities, as well as identifying words for the purpose of - * hyphenation. - */ - -#ifndef MINIKIN_WORD_BREAKER_H -#define MINIKIN_WORD_BREAKER_H - -#include -#include "unicode/brkiter.h" -#include "utils/WindowsUtils.h" - -namespace minikin { - -class WordBreaker { - public: - ~WordBreaker() { finish(); } - - // libtxt extension: always use the default locale so that a cached instance - // of the ICU break iterator can be reused. - void setLocale(); - - void setText(const uint16_t* data, size_t size); - - // Advance iterator to next word break. Return offset, or -1 if EOT - ssize_t next(); - - // Current offset of iterator, equal to 0 at BOT or last return from next() - ssize_t current() const; - - // After calling next(), wordStart() and wordEnd() are offsets defining the - // previous word. If wordEnd <= wordStart, it's not a word for the purpose of - // hyphenation. - ssize_t wordStart() const; - - ssize_t wordEnd() const; - - int breakBadness() const; - - void finish(); - - private: - int32_t iteratorNext(); - void detectEmailOrUrl(); - ssize_t findNextBreakInEmailOrUrl(); - - std::unique_ptr mBreakIterator; - UText mUText = UTEXT_INITIALIZER; - const uint16_t* mText = nullptr; - size_t mTextSize; - ssize_t mLast; - ssize_t mCurrent; - bool mIteratorWasReset; - - // state for the email address / url detector - ssize_t mScanOffset; - bool mInEmailOrUrl; -}; - -} // namespace minikin - -#endif // MINIKIN_WORD_BREAKER_H diff --git a/third_party/txt/src/skia/paragraph_skia.cc b/third_party/txt/src/skia/paragraph_skia.cc index 359a0880de218..9c9d76b164074 100644 --- a/third_party/txt/src/skia/paragraph_skia.cc +++ b/third_party/txt/src/skia/paragraph_skia.cc @@ -223,10 +223,6 @@ void ParagraphSkia::Layout(double width) { paragraph_->layout(width); } -void ParagraphSkia::Paint(SkCanvas* canvas, double x, double y) { - paragraph_->paint(canvas, x, y); -} - bool ParagraphSkia::Paint(DisplayListBuilder* builder, double x, double y) { DisplayListParagraphPainter painter(builder, dl_paints_); paragraph_->paint(&painter, x, y); diff --git a/third_party/txt/src/skia/paragraph_skia.h b/third_party/txt/src/skia/paragraph_skia.h index 640ab479d41f7..8fa1314209049 100644 --- a/third_party/txt/src/skia/paragraph_skia.h +++ b/third_party/txt/src/skia/paragraph_skia.h @@ -53,7 +53,6 @@ class ParagraphSkia : public Paragraph { void Layout(double width) override; - void Paint(SkCanvas* canvas, double x, double y) override; bool Paint(flutter::DisplayListBuilder* builder, double x, double y) override; std::vector GetRectsForRange( diff --git a/third_party/txt/src/txt/font_collection.cc b/third_party/txt/src/txt/font_collection.cc index f5d5022c7fc33..9d1e8b51be4ce 100644 --- a/third_party/txt/src/txt/font_collection.cc +++ b/third_party/txt/src/txt/font_collection.cc @@ -26,71 +26,17 @@ #include #include "flutter/fml/logging.h" #include "flutter/fml/trace_event.h" -#include "font_skia.h" -#include "minikin/Layout.h" #include "txt/platform.h" #include "txt/text_style.h" namespace txt { -namespace { - -const std::shared_ptr g_null_family; - -} // anonymous namespace - -FontCollection::FamilyKey::FamilyKey(const std::vector& families, - const std::string& loc) { - locale = loc; - - std::stringstream stream; - for_each(families.begin(), families.end(), - [&stream](const std::string& str) { stream << str << ','; }); - font_families = stream.str(); -} - -bool FontCollection::FamilyKey::operator==( - const FontCollection::FamilyKey& other) const { - return font_families == other.font_families && locale == other.locale; -} - -size_t FontCollection::FamilyKey::Hasher::operator()( - const FontCollection::FamilyKey& key) const { - return std::hash()(key.font_families) ^ - std::hash()(key.locale); -} - -class TxtFallbackFontProvider - : public minikin::FontCollection::FallbackFontProvider { - public: - TxtFallbackFontProvider(std::shared_ptr font_collection) - : font_collection_(font_collection) {} - - virtual const std::shared_ptr& matchFallbackFont( - uint32_t ch, - std::string locale) { - std::shared_ptr fc = font_collection_.lock(); - if (fc) { - return fc->MatchFallbackFont(ch, locale); - } else { - return g_null_family; - } - } - - private: - std::weak_ptr font_collection_; -}; - FontCollection::FontCollection() : enable_font_fallback_(true) {} FontCollection::~FontCollection() { - minikin::Layout::purgeCaches(); - -#if FLUTTER_ENABLE_SKSHAPER if (skt_collection_) { skt_collection_->clearCaches(); } -#endif } size_t FontCollection::GetFontManagersCount() const { @@ -104,34 +50,22 @@ void FontCollection::SetupDefaultFontManager( void FontCollection::SetDefaultFontManager(sk_sp font_manager) { default_font_manager_ = font_manager; - -#if FLUTTER_ENABLE_SKSHAPER skt_collection_.reset(); -#endif } void FontCollection::SetAssetFontManager(sk_sp font_manager) { asset_font_manager_ = font_manager; - -#if FLUTTER_ENABLE_SKSHAPER skt_collection_.reset(); -#endif } void FontCollection::SetDynamicFontManager(sk_sp font_manager) { dynamic_font_manager_ = font_manager; - -#if FLUTTER_ENABLE_SKSHAPER skt_collection_.reset(); -#endif } void FontCollection::SetTestFontManager(sk_sp font_manager) { test_font_manager_ = font_manager; - -#if FLUTTER_ENABLE_SKSHAPER skt_collection_.reset(); -#endif } // Return the available font managers in the order they should be queried. @@ -150,249 +84,17 @@ std::vector> FontCollection::GetFontManagerOrder() const { void FontCollection::DisableFontFallback() { enable_font_fallback_ = false; - -#if FLUTTER_ENABLE_SKSHAPER if (skt_collection_) { skt_collection_->disableFontFallback(); } -#endif -} - -std::shared_ptr -FontCollection::GetMinikinFontCollectionForFamilies( - const std::vector& font_families, - const std::string& locale) { - // Look inside the font collections cache first. - FamilyKey family_key(font_families, locale); - auto cached = font_collections_cache_.find(family_key); - if (cached != font_collections_cache_.end()) { - return cached->second; - } - - std::vector> minikin_families; - - // Search for all user provided font families. - for (size_t fallback_index = 0; fallback_index < font_families.size(); - fallback_index++) { - std::shared_ptr minikin_family = - FindFontFamilyInManagers(font_families[fallback_index]); - if (minikin_family != nullptr) { - minikin_families.push_back(minikin_family); - } - } - // Search for default font family if no user font families were found. - if (minikin_families.empty()) { - const auto default_font_families = GetDefaultFontFamilies(); - for (const auto& family : default_font_families) { - std::shared_ptr minikin_family = - FindFontFamilyInManagers(family); - if (minikin_family != nullptr) { - minikin_families.push_back(minikin_family); - break; - } - } - } - // Default font family also not found. We fail to get a FontCollection. - if (minikin_families.empty()) { - font_collections_cache_[family_key] = nullptr; - return nullptr; - } - if (enable_font_fallback_) { - for (const std::string& fallback_family : - fallback_fonts_for_locale_[locale]) { - auto it = fallback_fonts_.find(fallback_family); - if (it != fallback_fonts_.end()) { - minikin_families.push_back(it->second); - } - } - } - // Create the minikin font collection. - auto font_collection = - minikin::FontCollection::Create(std::move(minikin_families)); - if (!font_collection) { - font_collections_cache_[family_key] = nullptr; - return nullptr; - } - if (enable_font_fallback_) { - font_collection->set_fallback_font_provider( - std::make_unique(shared_from_this())); - } - - // Cache the font collection for future queries. - font_collections_cache_[family_key] = font_collection; - - return font_collection; -} - -std::shared_ptr FontCollection::FindFontFamilyInManagers( - const std::string& family_name) { - TRACE_EVENT0("flutter", "FontCollection::FindFontFamilyInManagers"); - // Search for the font family in each font manager. - for (sk_sp& manager : GetFontManagerOrder()) { - std::shared_ptr minikin_family = - CreateMinikinFontFamily(manager, family_name); - if (!minikin_family) - continue; - return minikin_family; - } - return nullptr; -} - -void FontCollection::SortSkTypefaces( - std::vector>& sk_typefaces) { - std::sort( - sk_typefaces.begin(), sk_typefaces.end(), - [](const sk_sp& a, const sk_sp& b) { - SkFontStyle a_style = a->fontStyle(); - SkFontStyle b_style = b->fontStyle(); - - int a_delta = std::abs(a_style.width() - SkFontStyle::kNormal_Width); - int b_delta = std::abs(b_style.width() - SkFontStyle::kNormal_Width); - - if (a_delta != b_delta) { - // If a family name query is so generic it ends up bringing in fonts - // of multiple widths (e.g. condensed, expanded), opt to be - // conservative and select the most standard width. - // - // If a specific width is desired, it should be narrowed down via - // the family name. - // - // The font weights are also sorted lightest to heaviest but Flutter - // APIs have the weight specified to narrow it down later. The width - // ordering here is more consequential since TextStyle doesn't have - // letter width APIs. - return a_delta < b_delta; - } else if (a_style.width() != b_style.width()) { - // However, if the 2 fonts are equidistant from the "normal" width, - // just arbitrarily but consistently return the more condensed font. - return a_style.width() < b_style.width(); - } else if (a_style.weight() != b_style.weight()) { - return a_style.weight() < b_style.weight(); - } else { - return a_style.slant() < b_style.slant(); - } - // Use a cascade of conditions so results are consistent each time. - }); -} - -std::shared_ptr FontCollection::CreateMinikinFontFamily( - const sk_sp& manager, - const std::string& family_name) { - TRACE_EVENT1("flutter", "FontCollection::CreateMinikinFontFamily", - "family_name", family_name.c_str()); - sk_sp font_style_set( - manager->matchFamily(family_name.c_str())); - if (font_style_set == nullptr || font_style_set->count() == 0) { - return nullptr; - } - - std::vector> skia_typefaces; - for (int i = 0; i < font_style_set->count(); ++i) { - TRACE_EVENT0("flutter", "CreateSkiaTypeface"); - sk_sp skia_typeface( - sk_sp(font_style_set->createTypeface(i))); - if (skia_typeface != nullptr) { - skia_typefaces.emplace_back(std::move(skia_typeface)); - } - } - - if (skia_typefaces.empty()) { - return nullptr; - } - - SortSkTypefaces(skia_typefaces); - - std::vector minikin_fonts; - for (const sk_sp& skia_typeface : skia_typefaces) { - // Create the minikin font from the skia typeface. - // Divide by 100 because the weights are given as "100", "200", etc. - minikin_fonts.emplace_back( - std::make_shared(skia_typeface), - minikin::FontStyle{skia_typeface->fontStyle().weight() / 100, - skia_typeface->isItalic()}); - } - - return std::make_shared(std::move(minikin_fonts)); -} - -const std::shared_ptr& FontCollection::MatchFallbackFont( - uint32_t ch, - std::string locale) { - // Check if the ch's matched font has been cached. We cache the results of - // this method as repeated matchFamilyStyleCharacter calls can become - // extremely laggy when typing a large number of complex emojis. - auto lookup = fallback_match_cache_.find(ch); - if (lookup != fallback_match_cache_.end()) { - return *lookup->second; - } - const std::shared_ptr* match = - &DoMatchFallbackFont(ch, locale); - fallback_match_cache_.insert(std::make_pair(ch, match)); - return *match; -} - -const std::shared_ptr& FontCollection::DoMatchFallbackFont( - uint32_t ch, - std::string locale) { - for (const sk_sp& manager : GetFontManagerOrder()) { - std::vector bcp47; - if (!locale.empty()) - bcp47.push_back(locale.c_str()); - sk_sp typeface(manager->matchFamilyStyleCharacter( - 0, SkFontStyle(), bcp47.data(), bcp47.size(), ch)); - if (!typeface) - continue; - - SkString sk_family_name; - typeface->getFamilyName(&sk_family_name); - std::string family_name(sk_family_name.c_str()); - - if (std::find(fallback_fonts_for_locale_[locale].begin(), - fallback_fonts_for_locale_[locale].end(), - family_name) == fallback_fonts_for_locale_[locale].end()) - fallback_fonts_for_locale_[locale].push_back(family_name); - - return GetFallbackFontFamily(manager, family_name); - } - return g_null_family; -} - -const std::shared_ptr& -FontCollection::GetFallbackFontFamily(const sk_sp& manager, - const std::string& family_name) { - TRACE_EVENT0("flutter", "FontCollection::GetFallbackFontFamily"); - auto fallback_it = fallback_fonts_.find(family_name); - if (fallback_it != fallback_fonts_.end()) { - return fallback_it->second; - } - - std::shared_ptr minikin_family = - CreateMinikinFontFamily(manager, family_name); - if (!minikin_family) - return g_null_family; - - auto insert_it = - fallback_fonts_.insert(std::make_pair(family_name, minikin_family)); - - // Clear the cache to force creation of new font collections that will - // include this fallback font. - font_collections_cache_.clear(); - - return insert_it.first->second; } void FontCollection::ClearFontFamilyCache() { - font_collections_cache_.clear(); - -#if FLUTTER_ENABLE_SKSHAPER if (skt_collection_) { skt_collection_->clearCaches(); } -#endif } -#if FLUTTER_ENABLE_SKSHAPER - sk_sp FontCollection::CreateSktFontCollection() { if (!skt_collection_) { @@ -415,6 +117,4 @@ FontCollection::CreateSktFontCollection() { return skt_collection_; } -#endif // FLUTTER_ENABLE_SKSHAPER - } // namespace txt diff --git a/third_party/txt/src/txt/font_collection.h b/third_party/txt/src/txt/font_collection.h index 4e9f1a579d4c3..08631bef8a142 100644 --- a/third_party/txt/src/txt/font_collection.h +++ b/third_party/txt/src/txt/font_collection.h @@ -23,18 +23,13 @@ #include #include "flutter/fml/macros.h" -#include "minikin/FontCollection.h" -#include "minikin/FontFamily.h" #include "third_party/googletest/googletest/include/gtest/gtest_prod.h" // nogncheck #include "third_party/skia/include/core/SkFontMgr.h" #include "third_party/skia/include/core/SkRefCnt.h" +#include "third_party/skia/modules/skparagraph/include/FontCollection.h" // nogncheck #include "txt/asset_font_manager.h" #include "txt/text_style.h" -#if FLUTTER_ENABLE_SKSHAPER -#include "third_party/skia/modules/skparagraph/include/FontCollection.h" // nogncheck -#endif - namespace txt { class FontCollection : public std::enable_shared_from_this { @@ -51,16 +46,6 @@ class FontCollection : public std::enable_shared_from_this { void SetDynamicFontManager(sk_sp font_manager); void SetTestFontManager(sk_sp font_manager); - std::shared_ptr GetMinikinFontCollectionForFamilies( - const std::vector& font_families, - const std::string& locale); - - // Provides a FontFamily that contains glyphs for ch. This caches previously - // matched fonts. Also see FontCollection::DoMatchFallbackFont. - const std::shared_ptr& MatchFallbackFont( - uint32_t ch, - std::string locale); - // Do not provide alternative fonts that can match characters which are // missing from the requested font family. void DisableFontFallback(); @@ -68,75 +53,21 @@ class FontCollection : public std::enable_shared_from_this { // Remove all entries in the font family cache. void ClearFontFamilyCache(); -#if FLUTTER_ENABLE_SKSHAPER - // Construct a Skia text layout FontCollection based on this collection. sk_sp CreateSktFontCollection(); -#endif // FLUTTER_ENABLE_SKSHAPER - private: - struct FamilyKey { - FamilyKey(const std::vector& families, const std::string& loc); - - // Concatenated string with all font families. - std::string font_families; - std::string locale; - - bool operator==(const FamilyKey& other) const; - - struct Hasher { - size_t operator()(const FamilyKey& key) const; - }; - }; - sk_sp default_font_manager_; sk_sp asset_font_manager_; sk_sp dynamic_font_manager_; sk_sp test_font_manager_; - std::unordered_map, - FamilyKey::Hasher> - font_collections_cache_; - // Cache that stores the results of MatchFallbackFont to ensure lag-free emoji - // font fallback matching. - std::unordered_map*> - fallback_match_cache_; - std::unordered_map> - fallback_fonts_; - std::unordered_map> - fallback_fonts_for_locale_; bool enable_font_fallback_; -#if FLUTTER_ENABLE_SKSHAPER // An equivalent font collection usable by the Skia text shaper library. sk_sp skt_collection_; -#endif - - // Performs the actual work of MatchFallbackFont. The result is cached in - // fallback_match_cache_. - const std::shared_ptr& DoMatchFallbackFont( - uint32_t ch, - std::string locale); std::vector> GetFontManagerOrder() const; - std::shared_ptr FindFontFamilyInManagers( - const std::string& family_name); - - std::shared_ptr CreateMinikinFontFamily( - const sk_sp& manager, - const std::string& family_name); - - // Sorts in-place a group of SkTypeface from an SkTypefaceSet into a - // reasonable order for future queries. - FRIEND_TEST(FontCollectionTest, CheckSkTypefacesSorting); - static void SortSkTypefaces(std::vector>& sk_typefaces); - - const std::shared_ptr& GetFallbackFontFamily( - const sk_sp& manager, - const std::string& family_name); - FML_DISALLOW_COPY_AND_ASSIGN(FontCollection); }; diff --git a/third_party/txt/src/txt/font_skia.cc b/third_party/txt/src/txt/font_skia.cc deleted file mode 100644 index 9843ab05aa76b..0000000000000 --- a/third_party/txt/src/txt/font_skia.cc +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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 "font_skia.h" - -#include - -#include "third_party/skia/include/core/SkFont.h" - -namespace txt { -namespace { - -hb_blob_t* GetTable(hb_face_t* face, hb_tag_t tag, void* context) { - SkTypeface* typeface = reinterpret_cast(context); - - const size_t table_size = typeface->getTableSize(tag); - if (table_size == 0) - return nullptr; - void* buffer = malloc(table_size); - if (buffer == nullptr) - return nullptr; - - size_t actual_size = typeface->getTableData(tag, 0, table_size, buffer); - if (table_size != actual_size) { - free(buffer); - return nullptr; - } - return hb_blob_create(reinterpret_cast(buffer), table_size, - HB_MEMORY_MODE_WRITABLE, buffer, free); -} - -} // namespace - -FontSkia::FontSkia(sk_sp typeface) - : MinikinFont(typeface->uniqueID()), typeface_(std::move(typeface)) {} - -FontSkia::~FontSkia() = default; - -static void FontSkia_SetSkiaFont(sk_sp typeface, - SkFont* skFont, - const minikin::MinikinPaint& paint) { - skFont->setTypeface(std::move(typeface)); - skFont->setLinearMetrics((paint.paintFlags & minikin::LinearTextFlag) != 0); - // TODO: set more paint parameters from Minikin - skFont->setSize(paint.size); -} - -float FontSkia::GetHorizontalAdvance(uint32_t glyph_id, - const minikin::MinikinPaint& paint) const { - SkFont skFont; - uint16_t glyph16 = glyph_id; - SkScalar skWidth; - FontSkia_SetSkiaFont(typeface_, &skFont, paint); - skFont.getWidths(&glyph16, 1, &skWidth); - return skWidth; -} - -void FontSkia::GetBounds(minikin::MinikinRect* bounds, - uint32_t glyph_id, - const minikin::MinikinPaint& paint) const { - SkFont skFont; - uint16_t glyph16 = glyph_id; - SkRect skBounds; - FontSkia_SetSkiaFont(typeface_, &skFont, paint); - skFont.getWidths(&glyph16, 1, NULL, &skBounds); - bounds->mLeft = skBounds.fLeft; - bounds->mTop = skBounds.fTop; - bounds->mRight = skBounds.fRight; - bounds->mBottom = skBounds.fBottom; -} - -hb_face_t* FontSkia::CreateHarfBuzzFace() const { - return hb_face_create_for_tables(GetTable, typeface_.get(), 0); -} - -const std::vector& FontSkia::GetAxes() const { - return variations_; -} - -const sk_sp& FontSkia::GetSkTypeface() const { - return typeface_; -} - -} // namespace txt diff --git a/third_party/txt/src/txt/font_skia.h b/third_party/txt/src/txt/font_skia.h deleted file mode 100644 index 72e9bddc234bc..0000000000000 --- a/third_party/txt/src/txt/font_skia.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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/macros.h" -#include "third_party/skia/include/core/SkPaint.h" -#include "third_party/skia/include/core/SkTypeface.h" - -namespace txt { - -class FontSkia : public minikin::MinikinFont { - public: - explicit FontSkia(sk_sp typeface); - - ~FontSkia(); - - float GetHorizontalAdvance(uint32_t glyph_id, - const minikin::MinikinPaint& paint) const override; - - void GetBounds(minikin::MinikinRect* bounds, - uint32_t glyph_id, - const minikin::MinikinPaint& paint) const override; - - hb_face_t* CreateHarfBuzzFace() const override; - - const std::vector& GetAxes() const override; - - const sk_sp& GetSkTypeface() const; - - private: - sk_sp typeface_; - std::vector variations_; - - FML_DISALLOW_COPY_AND_ASSIGN(FontSkia); -}; - -} // namespace txt diff --git a/third_party/txt/src/txt/paint_record.cc b/third_party/txt/src/txt/paint_record.cc deleted file mode 100644 index 21ff440886e15..0000000000000 --- a/third_party/txt/src/txt/paint_record.cc +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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 "paint_record.h" - -#include "flutter/fml/logging.h" - -namespace txt { - -PaintRecord::~PaintRecord() = default; - -PaintRecord::PaintRecord(TextStyle style, - SkPoint offset, - sk_sp text, - SkFontMetrics metrics, - size_t line, - double x_start, - double x_end, - bool is_ghost) - : style_(style), - offset_(offset), - text_(std::move(text)), - metrics_(metrics), - line_(line), - x_start_(x_start), - x_end_(x_end), - is_ghost_(is_ghost) {} - -PaintRecord::PaintRecord(TextStyle style, - SkPoint offset, - sk_sp text, - SkFontMetrics metrics, - size_t line, - double x_start, - double x_end, - bool is_ghost, - PlaceholderRun* placeholder_run) - : style_(style), - offset_(offset), - text_(std::move(text)), - metrics_(metrics), - line_(line), - x_start_(x_start), - x_end_(x_end), - is_ghost_(is_ghost), - placeholder_run_(placeholder_run) {} - -PaintRecord::PaintRecord(TextStyle style, - sk_sp text, - SkFontMetrics metrics, - size_t line, - double x_start, - double x_end, - bool is_ghost) - : style_(style), - text_(std::move(text)), - metrics_(metrics), - line_(line), - x_start_(x_start), - x_end_(x_end), - is_ghost_(is_ghost) {} - -PaintRecord::PaintRecord(PaintRecord&& other) { - style_ = other.style_; - offset_ = other.offset_; - text_ = std::move(other.text_); - metrics_ = other.metrics_; - line_ = other.line_; - placeholder_run_ = other.placeholder_run_; - x_start_ = other.x_start_; - x_end_ = other.x_end_; - is_ghost_ = other.is_ghost_; -} - -PaintRecord& PaintRecord::operator=(PaintRecord&& other) { - style_ = other.style_; - offset_ = other.offset_; - text_ = std::move(other.text_); - metrics_ = other.metrics_; - line_ = other.line_; - x_start_ = other.x_start_; - x_end_ = other.x_end_; - is_ghost_ = other.is_ghost_; - placeholder_run_ = other.placeholder_run_; - return *this; -} - -void PaintRecord::SetOffset(SkPoint pt) { - offset_ = pt; -} - -} // namespace txt diff --git a/third_party/txt/src/txt/paint_record.h b/third_party/txt/src/txt/paint_record.h deleted file mode 100644 index 33917488ccc82..0000000000000 --- a/third_party/txt/src/txt/paint_record.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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. - */ - -#ifndef LIB_TXT_SRC_PAINT_RECORD_H_ -#define LIB_TXT_SRC_PAINT_RECORD_H_ - -#include "flutter/fml/logging.h" -#include "flutter/fml/macros.h" -#include "placeholder_run.h" -#include "text_style.h" -#include "third_party/skia/include/core/SkFontMetrics.h" -#include "third_party/skia/include/core/SkTextBlob.h" - -namespace txt { - -// PaintRecord holds the layout data after Paragraph::Layout() is called. This -// stores all necessary offsets, blobs, metrics, and more for Skia to draw the -// text. -class PaintRecord { - public: - PaintRecord() = delete; - - ~PaintRecord(); - - PaintRecord(TextStyle style, - SkPoint offset, - sk_sp text, - SkFontMetrics metrics, - size_t line, - double x_start, - double x_end, - bool is_ghost); - - PaintRecord(TextStyle style, - SkPoint offset, - sk_sp text, - SkFontMetrics metrics, - size_t line, - double x_start, - double x_end, - bool is_ghost, - PlaceholderRun* placeholder_run); - - PaintRecord(TextStyle style, - sk_sp text, - SkFontMetrics metrics, - size_t line, - double x_start, - double x_end, - bool is_ghost); - - PaintRecord(PaintRecord&& other); - - PaintRecord& operator=(PaintRecord&& other); - - SkPoint offset() const { return offset_; } - - void SetOffset(SkPoint pt); - - SkTextBlob* text() const { return text_.get(); } - - const SkFontMetrics& metrics() const { return metrics_; } - - const TextStyle& style() const { return style_; } - - size_t line() const { return line_; } - - double x_start() const { return x_start_; } - double x_end() const { return x_end_; } - double GetRunWidth() const { return x_end_ - x_start_; } - - PlaceholderRun* GetPlaceholderRun() const { return placeholder_run_; } - - bool isGhost() const { return is_ghost_; } - - bool isPlaceholder() const { return placeholder_run_ == nullptr; } - - private: - TextStyle style_; - // offset_ is the overall offset of the origin of the SkTextBlob. - SkPoint offset_; - // SkTextBlob stores the glyphs and coordinates to draw them. - sk_sp text_; - // FontMetrics stores the measurements of the font used. - SkFontMetrics metrics_; - size_t line_; - double x_start_ = 0.0f; - double x_end_ = 0.0f; - // 'Ghost' runs represent trailing whitespace. 'Ghost' runs should not have - // decorations painted on them and do not impact layout of visible glyphs. - bool is_ghost_ = false; - // Stores the corresponding PlaceholderRun that the record corresponds to. - // When this is nullptr, then the record is of normal text and does not - // represent an inline placeholder. - PlaceholderRun* placeholder_run_ = nullptr; - - FML_DISALLOW_COPY_AND_ASSIGN(PaintRecord); -}; - -} // namespace txt - -#endif // LIB_TXT_SRC_PAINT_RECORD_H_ diff --git a/third_party/txt/src/txt/paragraph.h b/third_party/txt/src/txt/paragraph.h index db713241d5936..2bc726c9a6e19 100644 --- a/third_party/txt/src/txt/paragraph.h +++ b/third_party/txt/src/txt/paragraph.h @@ -27,9 +27,8 @@ class SkCanvas; namespace txt { -// Interface for text layout engines. The original implementation was based on -// the Minikin text layout library used by Android. Another implementation is -// available based on Skia's SkShaper/SkParagraph text layout module. +// Interface for text layout engines. The current implementation is based on +// Skia's SkShaper/SkParagraph text layout module. class Paragraph { public: enum Affinity { UPSTREAM, DOWNSTREAM }; @@ -144,9 +143,8 @@ class Paragraph { // before Painting and getting any statistics from this class. virtual void Layout(double width) = 0; - // Paints the laid out text onto the supplied SkCanvas at (x, y) offset from - // the origin. Only valid after Layout() is called. - virtual void Paint(SkCanvas* canvas, double x, double y) = 0; + // Paints the laid out text onto the supplied DisplayListBuilder at + // (x, y) offset from the origin. Only valid after Layout() is called. virtual bool Paint(flutter::DisplayListBuilder* builder, double x, double y) = 0; diff --git a/third_party/txt/src/txt/paragraph_builder.cc b/third_party/txt/src/txt/paragraph_builder.cc index bb446fdf83621..ac1f7dc1b859f 100644 --- a/third_party/txt/src/txt/paragraph_builder.cc +++ b/third_party/txt/src/txt/paragraph_builder.cc @@ -16,30 +16,16 @@ #include "paragraph_builder.h" -#include "paragraph_builder_txt.h" +#include "flutter/third_party/txt/src/skia/paragraph_builder_skia.h" #include "paragraph_style.h" #include "third_party/icu/source/common/unicode/unistr.h" -#if FLUTTER_ENABLE_SKSHAPER -#include "flutter/third_party/txt/src/skia/paragraph_builder_skia.h" -#endif - namespace txt { -std::unique_ptr ParagraphBuilder::CreateTxtBuilder( - const ParagraphStyle& style, - std::shared_ptr font_collection) { - return std::make_unique(style, font_collection); -} - -#if FLUTTER_ENABLE_SKSHAPER - std::unique_ptr ParagraphBuilder::CreateSkiaBuilder( const ParagraphStyle& style, std::shared_ptr font_collection) { return std::make_unique(style, font_collection); } -#endif // FLUTTER_ENABLE_SKSHAPER - } // namespace txt diff --git a/third_party/txt/src/txt/paragraph_builder.h b/third_party/txt/src/txt/paragraph_builder.h index c3953b9b0ef22..67376940031e0 100644 --- a/third_party/txt/src/txt/paragraph_builder.h +++ b/third_party/txt/src/txt/paragraph_builder.h @@ -31,15 +31,9 @@ namespace txt { class ParagraphBuilder { public: - static std::unique_ptr CreateTxtBuilder( - const ParagraphStyle& style, - std::shared_ptr font_collection); - -#if FLUTTER_ENABLE_SKSHAPER static std::unique_ptr CreateSkiaBuilder( const ParagraphStyle& style, std::shared_ptr font_collection); -#endif virtual ~ParagraphBuilder() = default; diff --git a/third_party/txt/src/txt/paragraph_builder_txt.cc b/third_party/txt/src/txt/paragraph_builder_txt.cc deleted file mode 100644 index 54af9c275dc22..0000000000000 --- a/third_party/txt/src/txt/paragraph_builder_txt.cc +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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 "paragraph_builder_txt.h" - -#include "paragraph_txt.h" - -namespace txt { - -ParagraphBuilderTxt::ParagraphBuilderTxt( - const ParagraphStyle& style, - std::shared_ptr font_collection) - : font_collection_(std::move(font_collection)) { - SetParagraphStyle(style); -} - -ParagraphBuilderTxt::~ParagraphBuilderTxt() = default; - -void ParagraphBuilderTxt::SetParagraphStyle(const ParagraphStyle& style) { - paragraph_style_ = style; - paragraph_style_index_ = runs_.AddStyle(style.GetTextStyle()); - runs_.StartRun(paragraph_style_index_, text_.size()); -} - -void ParagraphBuilderTxt::PushStyle(const TextStyle& style) { - size_t style_index = runs_.AddStyle(style); - style_stack_.push_back(style_index); - runs_.StartRun(style_index, text_.size()); -} - -void ParagraphBuilderTxt::Pop() { - if (style_stack_.empty()) { - return; - } - style_stack_.pop_back(); - runs_.StartRun(PeekStyleIndex(), text_.size()); -} - -size_t ParagraphBuilderTxt::PeekStyleIndex() const { - return style_stack_.size() ? style_stack_.back() : paragraph_style_index_; -} - -const TextStyle& ParagraphBuilderTxt::PeekStyle() { - return runs_.GetStyle(PeekStyleIndex()); -} - -void ParagraphBuilderTxt::AddText(const std::u16string& text) { - text_.insert(text_.end(), text.begin(), text.end()); -} - -void ParagraphBuilderTxt::AddPlaceholder(PlaceholderRun& span) { - obj_replacement_char_indexes_.insert(text_.size()); - runs_.StartRun(PeekStyleIndex(), text_.size()); - AddText(std::u16string(1ull, objReplacementChar)); - runs_.StartRun(PeekStyleIndex(), text_.size()); - inline_placeholders_.push_back(span); -} - -std::unique_ptr ParagraphBuilderTxt::Build() { - runs_.EndRunIfNeeded(text_.size()); - - std::unique_ptr paragraph = std::make_unique(); - paragraph->SetText(std::move(text_), std::move(runs_)); - paragraph->SetInlinePlaceholders(std::move(inline_placeholders_), - std::move(obj_replacement_char_indexes_)); - paragraph->SetParagraphStyle(paragraph_style_); - paragraph->SetFontCollection(font_collection_); - SetParagraphStyle(paragraph_style_); - return paragraph; -} - -} // namespace txt diff --git a/third_party/txt/src/txt/paragraph_builder_txt.h b/third_party/txt/src/txt/paragraph_builder_txt.h deleted file mode 100644 index bf44eb4f91858..0000000000000 --- a/third_party/txt/src/txt/paragraph_builder_txt.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2019 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. - */ - -#ifndef LIB_TXT_SRC_PARAGRAPH_BUILDER_TXT_H_ -#define LIB_TXT_SRC_PARAGRAPH_BUILDER_TXT_H_ - -#include "paragraph_builder.h" - -#include "styled_runs.h" - -namespace txt { - -// Implementation of ParagraphBuilder that produces paragraphs backed by the -// Minikin text layout library. -class ParagraphBuilderTxt : public ParagraphBuilder { - public: - ParagraphBuilderTxt(const ParagraphStyle& style, - std::shared_ptr font_collection); - - virtual ~ParagraphBuilderTxt(); - - virtual void PushStyle(const TextStyle& style) override; - virtual void Pop() override; - virtual const TextStyle& PeekStyle() override; - virtual void AddText(const std::u16string& text) override; - virtual void AddPlaceholder(PlaceholderRun& span) override; - virtual std::unique_ptr Build() override; - - private: - std::vector text_; - // A vector of PlaceholderRuns, which detail the sizes, positioning and break - // behavior of the empty spaces to leave. Each placeholder span corresponds to - // a 0xFFFC (object replacement character) in text_, which indicates the - // position in the text where the placeholder will occur. There should be an - // equal number of 0xFFFC characters and elements in this vector. - std::vector inline_placeholders_; - // The indexes of the obj replacement characters added through - // ParagraphBuilder::addPlaceholder(). - std::unordered_set obj_replacement_char_indexes_; - std::vector style_stack_; - std::shared_ptr font_collection_; - StyledRuns runs_; - ParagraphStyle paragraph_style_; - size_t paragraph_style_index_; - - void SetParagraphStyle(const ParagraphStyle& style); - - size_t PeekStyleIndex() const; -}; - -} // namespace txt - -#endif // LIB_TXT_SRC_PARAGRAPH_BUILDER_TXT_H_ diff --git a/third_party/txt/src/txt/paragraph_style.h b/third_party/txt/src/txt/paragraph_style.h index 8fa135695a41e..7c3043b8ad899 100644 --- a/third_party/txt/src/txt/paragraph_style.h +++ b/third_party/txt/src/txt/paragraph_style.h @@ -22,7 +22,6 @@ #include "font_style.h" #include "font_weight.h" -#include "minikin/LineBreaker.h" #include "text_style.h" namespace txt { @@ -96,13 +95,6 @@ class ParagraphStyle { std::u16string ellipsis; std::string locale; - // Default strategy is kBreakStrategy_Greedy. Sometimes, - // kBreakStrategy_HighQuality will produce more desirable layouts (e.g., very - // long words are more likely to be reasonably placed). - // kBreakStrategy_Balanced will balance between the two. - minikin::BreakStrategy break_strategy = - minikin::BreakStrategy::kBreakStrategy_Greedy; - TextStyle GetTextStyle() const; bool unlimited_lines() const; diff --git a/third_party/txt/src/txt/paragraph_txt.cc b/third_party/txt/src/txt/paragraph_txt.cc deleted file mode 100644 index a3b458cbfc4c1..0000000000000 --- a/third_party/txt/src/txt/paragraph_txt.cc +++ /dev/null @@ -1,2026 +0,0 @@ -/* - * 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 "paragraph_txt.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "flutter/fml/logging.h" -#include "font_collection.h" -#include "font_skia.h" -#include "minikin/FontLanguageListCache.h" -#include "minikin/GraphemeBreak.h" -#include "minikin/HbFontCache.h" -#include "minikin/LayoutUtils.h" -#include "minikin/LineBreaker.h" -#include "minikin/MinikinFont.h" -#include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkFont.h" -#include "third_party/skia/include/core/SkFontMetrics.h" -#include "third_party/skia/include/core/SkMaskFilter.h" -#include "third_party/skia/include/core/SkPaint.h" -#include "third_party/skia/include/core/SkTextBlob.h" -#include "third_party/skia/include/core/SkTypeface.h" -#include "third_party/skia/include/effects/SkDashPathEffect.h" -#include "third_party/skia/include/effects/SkDiscretePathEffect.h" -#include "unicode/ubidi.h" -#include "unicode/utf16.h" - -namespace txt { -namespace { - -class GlyphTypeface { - public: - GlyphTypeface(sk_sp typeface, minikin::FontFakery fakery) - : typeface_(std::move(typeface)), - fake_bold_(fakery.isFakeBold()), - fake_italic_(fakery.isFakeItalic()) {} - - bool operator==(GlyphTypeface& other) { - return other.typeface_.get() == typeface_.get() && - other.fake_bold_ == fake_bold_ && other.fake_italic_ == fake_italic_; - } - - bool operator!=(GlyphTypeface& other) { return !(*this == other); } - - void apply(SkFont& font) { - font.setTypeface(typeface_); - font.setEmbolden(fake_bold_); - font.setSkewX(fake_italic_ ? -SK_Scalar1 / 4 : 0); - } - - private: - sk_sp typeface_; - bool fake_bold_; - bool fake_italic_; -}; - -GlyphTypeface GetGlyphTypeface(const minikin::Layout& layout, size_t index) { - const FontSkia* font = static_cast(layout.getFont(index)); - return GlyphTypeface(font->GetSkTypeface(), layout.getFakery(index)); -} - -// Return ranges of text that have the same typeface in the layout. -std::vector> GetLayoutTypefaceRuns( - const minikin::Layout& layout) { - std::vector> result; - if (layout.nGlyphs() == 0) - return result; - size_t run_start = 0; - GlyphTypeface run_typeface = GetGlyphTypeface(layout, run_start); - for (size_t i = 1; i < layout.nGlyphs(); ++i) { - GlyphTypeface typeface = GetGlyphTypeface(layout, i); - if (typeface != run_typeface) { - result.emplace_back(run_start, i); - run_start = i; - run_typeface = typeface; - } - } - result.emplace_back(run_start, layout.nGlyphs()); - return result; -} - -int GetWeight(const FontWeight weight) { - switch (weight) { - case FontWeight::w100: - return 1; - case FontWeight::w200: - return 2; - case FontWeight::w300: - return 3; - case FontWeight::w400: // Normal. - return 4; - case FontWeight::w500: - return 5; - case FontWeight::w600: - return 6; - case FontWeight::w700: // Bold. - return 7; - case FontWeight::w800: - return 8; - case FontWeight::w900: - return 9; - default: - return -1; - } -} - -int GetWeight(const TextStyle& style) { - return GetWeight(style.font_weight); -} - -bool GetItalic(const TextStyle& style) { - switch (style.font_style) { - case FontStyle::italic: - return true; - case FontStyle::normal: - default: - return false; - } -} - -minikin::FontStyle GetMinikinFontStyle(const TextStyle& style) { - uint32_t language_list_id = - style.locale.empty() - ? minikin::FontLanguageListCache::kEmptyListId - : minikin::FontStyle::registerLanguageList(style.locale); - return minikin::FontStyle(language_list_id, 0, GetWeight(style), - GetItalic(style)); -} - -void GetFontAndMinikinPaint(const TextStyle& style, - minikin::FontStyle* font, - minikin::MinikinPaint* paint) { - *font = GetMinikinFontStyle(style); - paint->size = style.font_size; - // Divide by font size so letter spacing is pixels, not proportional to font - // size. - paint->letterSpacing = style.letter_spacing / style.font_size; - paint->wordSpacing = style.word_spacing; - paint->scaleX = 1.0f; - // Prevent spacing rounding in Minikin. This causes jitter when switching - // between same text content with different runs composing it, however, it - // also produces more accurate layouts. - paint->paintFlags |= minikin::LinearTextFlag; - paint->fontFeatureSettings = style.font_features.GetFeatureSettings(); -} - -void FindWords(const std::vector& text, - size_t start, - size_t end, - std::vector>* words) { - bool in_word = false; - size_t word_start; - for (size_t i = start; i < end; ++i) { - bool is_space = minikin::isWordSpace(text[i]); - if (!in_word && !is_space) { - word_start = i; - in_word = true; - } else if (in_word && is_space) { - words->emplace_back(word_start, i); - in_word = false; - } - } - if (in_word) - words->emplace_back(word_start, end); -} - -} // namespace - -static const float kDoubleDecorationSpacing = 3.0f; - -ParagraphTxt::GlyphPosition::GlyphPosition(double x_start, - double x_advance, - size_t code_unit_index, - size_t code_unit_width) - : code_units(code_unit_index, code_unit_index + code_unit_width), - x_pos(x_start, x_start + x_advance) {} - -void ParagraphTxt::GlyphPosition::Shift(double delta) { - x_pos.Shift(delta); -} - -ParagraphTxt::GlyphLine::GlyphLine(std::vector&& p, size_t tcu) - : positions(std::move(p)), total_code_units(tcu) {} - -ParagraphTxt::CodeUnitRun::CodeUnitRun(std::vector&& p, - Range cu, - Range x, - size_t line, - const SkFontMetrics& metrics, - const TextStyle& st, - TextDirection dir, - const PlaceholderRun* placeholder) - : positions(std::move(p)), - code_units(cu), - x_pos(x), - line_number(line), - font_metrics(metrics), - style(&st), - direction(dir), - placeholder_run(placeholder) {} - -void ParagraphTxt::CodeUnitRun::Shift(double delta) { - x_pos.Shift(delta); - for (GlyphPosition& position : positions) - position.Shift(delta); -} - -ParagraphTxt::ParagraphTxt() { - breaker_.setLocale(); -} - -ParagraphTxt::~ParagraphTxt() = default; - -void ParagraphTxt::SetText(std::vector text, StyledRuns runs) { - SetDirty(true); - if (text.size() == 0) - return; - text_ = std::move(text); - runs_ = std::move(runs); -} - -void ParagraphTxt::SetInlinePlaceholders( - std::vector inline_placeholders, - std::unordered_set obj_replacement_char_indexes) { - needs_layout_ = true; - inline_placeholders_ = std::move(inline_placeholders); - obj_replacement_char_indexes_ = std::move(obj_replacement_char_indexes); -} - -bool ParagraphTxt::ComputeLineBreaks() { - line_metrics_.clear(); - line_widths_.clear(); - max_intrinsic_width_ = 0; - - std::vector newline_positions; - // Discover and add all hard breaks. - for (size_t i = 0; i < text_.size(); ++i) { - ULineBreak ulb = static_cast( - u_getIntPropertyValue(text_[i], UCHAR_LINE_BREAK)); - if (ulb == U_LB_LINE_FEED || ulb == U_LB_MANDATORY_BREAK) - newline_positions.push_back(i); - } - // Break at the end of the paragraph. - newline_positions.push_back(text_.size()); - - // Calculate and add any breaks due to a line being too long. - size_t run_index = 0; - size_t inline_placeholder_index = 0; - for (size_t newline_index = 0; newline_index < newline_positions.size(); - ++newline_index) { - size_t block_start = - (newline_index > 0) ? newline_positions[newline_index - 1] + 1 : 0; - size_t block_end = newline_positions[newline_index]; - size_t block_size = block_end - block_start; - - if (block_size == 0) { - line_metrics_.emplace_back(block_start, block_end, block_end, - block_end + 1, true); - line_widths_.push_back(0); - continue; - } - - // Setup breaker. We wait to set the line width in order to account for the - // widths of the inline placeholders, which are calculated in the loop over - // the runs. - breaker_.setLineWidths(0.0f, 0, width_); - breaker_.setJustified(paragraph_style_.text_align == TextAlign::justify); - breaker_.setStrategy(paragraph_style_.break_strategy); - breaker_.resize(block_size); - memcpy(breaker_.buffer(), text_.data() + block_start, - block_size * sizeof(text_[0])); - breaker_.setText(); - - // Add the runs that include this line to the LineBreaker. - double block_total_width = 0; - while (run_index < runs_.size()) { - StyledRuns::Run run = runs_.GetRun(run_index); - if (run.start >= block_end) - break; - if (run.end < block_start) { - run_index++; - continue; - } - - minikin::FontStyle font; - minikin::MinikinPaint paint; - GetFontAndMinikinPaint(run.style, &font, &paint); - std::shared_ptr collection = - GetMinikinFontCollectionForStyle(run.style); - if (collection == nullptr) { - FML_LOG(INFO) << "Could not find font collection for families \"" - << (run.style.font_families.empty() - ? "" - : run.style.font_families[0]) - << "\"."; - return false; - } - size_t run_start = std::max(run.start, block_start) - block_start; - size_t run_end = std::min(run.end, block_end) - block_start; - bool isRtl = (paragraph_style_.text_direction == TextDirection::rtl); - - // Check if the run is an object replacement character-only run. We should - // leave space for inline placeholder and break around it if appropriate. - if (run.end - run.start == 1 && - obj_replacement_char_indexes_.count(run.start) != 0 && - text_[run.start] == objReplacementChar && - inline_placeholder_index < inline_placeholders_.size()) { - // Is a inline placeholder run. - PlaceholderRun placeholder_run = - inline_placeholders_[inline_placeholder_index]; - block_total_width += placeholder_run.width; - - // Inject custom width into minikin breaker. (Uses LibTxt-minikin - // patch). - breaker_.setCustomCharWidth(run_start, placeholder_run.width); - - // Called with nullptr as paint in order to use the custom widths passed - // above. - breaker_.addStyleRun(nullptr, collection, font, run_start, run_end, - isRtl); - inline_placeholder_index++; - } else { - // Is a regular text run. - double run_width = breaker_.addStyleRun(&paint, collection, font, - run_start, run_end, isRtl); - block_total_width += run_width; - } - - if (run.end > block_end) - break; - run_index++; - } - max_intrinsic_width_ = std::max(max_intrinsic_width_, block_total_width); - - size_t breaks_count = breaker_.computeBreaks(); - const int* breaks = breaker_.getBreaks(); - for (size_t i = 0; i < breaks_count; ++i) { - size_t break_start = (i > 0) ? breaks[i - 1] : 0; - size_t line_start = break_start + block_start; - size_t line_end = breaks[i] + block_start; - bool hard_break = i == breaks_count - 1; - size_t line_end_including_newline = - (hard_break && line_end < text_.size()) ? line_end + 1 : line_end; - size_t line_end_excluding_whitespace = line_end; - while ( - line_end_excluding_whitespace > line_start && - minikin::isLineEndSpace(text_[line_end_excluding_whitespace - 1])) { - line_end_excluding_whitespace--; - } - line_metrics_.emplace_back(line_start, line_end, - line_end_excluding_whitespace, - line_end_including_newline, hard_break); - line_widths_.push_back(breaker_.getWidths()[i]); - } - - breaker_.finish(); - } - - return true; -} - -bool ParagraphTxt::ComputeBidiRuns(std::vector* result) { - if (text_.empty()) - return true; - - auto ubidi_closer = [](UBiDi* b) { ubidi_close(b); }; - std::unique_ptr bidi(ubidi_open(), - ubidi_closer); - if (!bidi) - return false; - - UBiDiLevel paraLevel = (paragraph_style_.text_direction == TextDirection::rtl) - ? UBIDI_RTL - : UBIDI_LTR; - UErrorCode status = U_ZERO_ERROR; - ubidi_setPara(bidi.get(), reinterpret_cast(text_.data()), - text_.size(), paraLevel, nullptr, &status); - if (!U_SUCCESS(status)) - return false; - - int32_t bidi_run_count = ubidi_countRuns(bidi.get(), &status); - if (!U_SUCCESS(status)) - return false; - - // Detect if final trailing run is a single ambiguous whitespace. - // We want to bundle the final ambiguous whitespace with the preceding - // run in order to maintain logical typing behavior when mixing RTL and LTR - // text. We do not want this to be a true ghost run since the contrasting - // directionality causes the trailing space to not render at the visual end of - // the paragraph. - // - // This only applies to the final whitespace at the end as other whitespace is - // no longer ambiguous when surrounded by additional text. - - // TODO(garyq): Handle this in the text editor caret code instead at layout - // level. - bool has_trailing_whitespace = false; - int32_t bidi_run_start, bidi_run_length; - if (bidi_run_count > 1) { - ubidi_getVisualRun(bidi.get(), bidi_run_count - 1, &bidi_run_start, - &bidi_run_length); - if (!U_SUCCESS(status)) - return false; - if (bidi_run_length == 1) { - UChar32 last_char; - U16_GET(text_.data(), 0, bidi_run_start + bidi_run_length - 1, - static_cast(text_.size()), last_char); - if (u_hasBinaryProperty(last_char, UCHAR_WHITE_SPACE)) { - // Check if the trailing whitespace occurs before the previous run or - // not. If so, this trailing whitespace was a leading whitespace. - int32_t second_last_bidi_run_start, second_last_bidi_run_length; - ubidi_getVisualRun(bidi.get(), bidi_run_count - 2, - &second_last_bidi_run_start, - &second_last_bidi_run_length); - if (bidi_run_start == - second_last_bidi_run_start + second_last_bidi_run_length) { - has_trailing_whitespace = true; - bidi_run_count--; - } - } - } - } - - // Build a map of styled runs indexed by start position. - std::map styled_run_map; - for (size_t i = 0; i < runs_.size(); ++i) { - StyledRuns::Run run = runs_.GetRun(i); - styled_run_map.emplace(std::make_pair(run.start, run)); - } - - for (int32_t bidi_run_index = 0; bidi_run_index < bidi_run_count; - ++bidi_run_index) { - UBiDiDirection direction = ubidi_getVisualRun( - bidi.get(), bidi_run_index, &bidi_run_start, &bidi_run_length); - if (!U_SUCCESS(status)) - return false; - - // Exclude the leading bidi control character if present. - UChar32 first_char; - U16_GET(text_.data(), 0, bidi_run_start, static_cast(text_.size()), - first_char); - if (u_hasBinaryProperty(first_char, UCHAR_BIDI_CONTROL)) { - bidi_run_start++; - bidi_run_length--; - } - if (bidi_run_length == 0) - continue; - - // Exclude the trailing bidi control character if present. - UChar32 last_char; - U16_GET(text_.data(), 0, bidi_run_start + bidi_run_length - 1, - static_cast(text_.size()), last_char); - if (u_hasBinaryProperty(last_char, UCHAR_BIDI_CONTROL)) { - bidi_run_length--; - } - if (bidi_run_length == 0) - continue; - - // Attach the final trailing whitespace as part of this run. - if (has_trailing_whitespace && bidi_run_index == bidi_run_count - 1) { - bidi_run_length++; - } - - size_t bidi_run_end = bidi_run_start + bidi_run_length; - TextDirection text_direction = - direction == UBIDI_RTL ? TextDirection::rtl : TextDirection::ltr; - - // Break this bidi run into chunks based on text style. - std::vector chunks; - size_t chunk_start = bidi_run_start; - while (chunk_start < bidi_run_end) { - auto styled_run_iter = styled_run_map.upper_bound(chunk_start); - styled_run_iter--; - const StyledRuns::Run& styled_run = styled_run_iter->second; - size_t chunk_end = std::min(bidi_run_end, styled_run.end); - chunks.emplace_back(chunk_start, chunk_end, text_direction, - styled_run.style); - chunk_start = chunk_end; - } - - if (text_direction == TextDirection::ltr) { - result->insert(result->end(), chunks.begin(), chunks.end()); - } else { - result->insert(result->end(), chunks.rbegin(), chunks.rend()); - } - } - - return true; -} - -bool ParagraphTxt::IsStrutValid() const { - // Font size must be positive. - return (paragraph_style_.strut_enabled && - paragraph_style_.strut_font_size >= 0); -} - -void ParagraphTxt::ComputeStrut(StrutMetrics* strut, SkFont& font) { - strut->ascent = 0; - strut->descent = 0; - strut->leading = 0; - strut->half_leading = 0; - strut->line_height = 0; - strut->force_strut = false; - - if (!IsStrutValid()) - return; - - // force_strut makes all lines have exactly the strut metrics, and ignores all - // actual metrics. We only force the strut if the strut is non-zero and valid. - strut->force_strut = paragraph_style_.force_strut_height; - minikin::FontStyle minikin_font_style( - 0, GetWeight(paragraph_style_.strut_font_weight), - paragraph_style_.strut_font_style == FontStyle::italic); - - std::shared_ptr collection = - font_collection_->GetMinikinFontCollectionForFamilies( - paragraph_style_.strut_font_families, ""); - if (!collection) { - return; - } - minikin::FakedFont faked_font = collection->baseFontFaked(minikin_font_style); - - if (faked_font.font != nullptr) { - SkString str; - static_cast(faked_font.font) - ->GetSkTypeface() - ->getFamilyName(&str); - font.setTypeface(static_cast(faked_font.font)->GetSkTypeface()); - font.setSize(paragraph_style_.strut_font_size); - SkFontMetrics strut_metrics; - font.getMetrics(&strut_metrics); - - const double metrics_height = - -strut_metrics.fAscent + strut_metrics.fDescent; - - if (paragraph_style_.strut_has_height_override) { - const double strut_height = - paragraph_style_.strut_height * paragraph_style_.strut_font_size; - const double metrics_leading = - // Zero extra leading if there is no user specified strut leading. - paragraph_style_.strut_leading < 0 - ? 0 - : (paragraph_style_.strut_leading * - paragraph_style_.strut_font_size); - - const double available_height = - paragraph_style_.strut_half_leading ? metrics_height : strut_height; - - strut->ascent = - (-strut_metrics.fAscent / metrics_height) * available_height; - strut->descent = - (strut_metrics.fDescent / metrics_height) * available_height; - - strut->leading = metrics_leading + strut_height - available_height; - } else { - strut->ascent = -strut_metrics.fAscent; - strut->descent = strut_metrics.fDescent; - strut->leading = - // Use font's leading if there is no user specified strut leading. - paragraph_style_.strut_leading < 0 - ? strut_metrics.fLeading - : (paragraph_style_.strut_leading * - paragraph_style_.strut_font_size); - } - strut->half_leading = strut->leading / 2; - strut->line_height = strut->ascent + strut->descent + strut->leading; - } -} - -void ParagraphTxt::ComputePlaceholder(PlaceholderRun* placeholder_run, - double& ascent, - double& descent) { - if (placeholder_run != nullptr) { - // Calculate how much to shift the ascent and descent to account - // for the baseline choice. - // - // TODO(garyq): implement for various baselines. Currently only - // supports for alphabetic and ideographic - double baseline_adjustment = 0; - switch (placeholder_run->baseline) { - case TextBaseline::kAlphabetic: { - baseline_adjustment = 0; - break; - } - case TextBaseline::kIdeographic: { - baseline_adjustment = -descent / 2; - break; - } - } - // Convert the ascent and descent from the font's to the placeholder - // rect's. - switch (placeholder_run->alignment) { - case PlaceholderAlignment::kBaseline: { - ascent = baseline_adjustment + placeholder_run->baseline_offset; - descent = -baseline_adjustment + placeholder_run->height - - placeholder_run->baseline_offset; - break; - } - case PlaceholderAlignment::kAboveBaseline: { - ascent = baseline_adjustment + placeholder_run->height; - descent = -baseline_adjustment; - break; - } - case PlaceholderAlignment::kBelowBaseline: { - descent = baseline_adjustment + placeholder_run->height; - ascent = -baseline_adjustment; - break; - } - case PlaceholderAlignment::kTop: { - descent = placeholder_run->height - ascent; - break; - } - case PlaceholderAlignment::kBottom: { - ascent = placeholder_run->height - descent; - break; - } - case PlaceholderAlignment::kMiddle: { - double mid = (ascent - descent) / 2; - ascent = mid + placeholder_run->height / 2; - descent = -mid + placeholder_run->height / 2; - break; - } - } - placeholder_run->baseline_offset = ascent; - } -} - -// Implementation outline: -// -// -For each line: -// -Compute Bidi runs, convert into line_runs (keeps in-line-range runs, adds -// special runs) -// -For each line_run (runs in the line): -// -Calculate ellipsis -// -Obtain font -// -layout.doLayout(...), genereates glyph blobs -// -For each glyph blob: -// -Convert glyph blobs into pixel metrics/advances -// -Store as paint records (for painting) and code unit runs (for metrics -// and boxes). -// -Apply letter spacing, alignment, justification, etc -// -Calculate line vertical layout (ascent, descent, etc) -// -Store per-line metrics -void ParagraphTxt::Layout(double width) { - double rounded_width = floor(width); - // Do not allow calling layout multiple times without changing anything. - if (!needs_layout_ && rounded_width == width_) { - return; - } - - width_ = rounded_width; - - needs_layout_ = false; - - records_.clear(); - glyph_lines_.clear(); - code_unit_runs_.clear(); - inline_placeholder_code_unit_runs_.clear(); - max_right_ = std::numeric_limits::lowest(); - min_left_ = std::numeric_limits::max(); - final_line_count_ = 0; - - if (!ComputeLineBreaks()) - return; - - std::vector bidi_runs; - if (!ComputeBidiRuns(&bidi_runs)) - return; - - SkFont font; - font.setEdging(SkFont::Edging::kAntiAlias); - font.setSubpixel(true); - font.setHinting(SkFontHinting::kSlight); - - minikin::Layout layout; - SkTextBlobBuilder builder; - double y_offset = 0; - double prev_max_descent = 0; - double max_word_width = 0; - - // Compute strut minimums according to paragraph_style_. - ComputeStrut(&strut_, font); - - // Paragraph bounds tracking. - size_t line_limit = - std::min(paragraph_style_.max_lines, line_metrics_.size()); - did_exceed_max_lines_ = (line_metrics_.size() > paragraph_style_.max_lines); - - size_t placeholder_run_index = 0; - for (size_t line_number = 0; line_number < line_limit; ++line_number) { - LineMetrics& line_metrics = line_metrics_[line_number]; - - // Break the line into words if justification should be applied. - std::vector> words; - double word_gap_width = 0; - size_t word_index = 0; - bool justify_line = - (paragraph_style_.text_align == TextAlign::justify && - line_number != line_limit - 1 && !line_metrics.hard_break); - FindWords(text_, line_metrics.start_index, line_metrics.end_index, &words); - if (justify_line) { - if (words.size() > 1) { - word_gap_width = - (width_ - line_widths_[line_number]) / (words.size() - 1); - } - } - - // Exclude trailing whitespace from justified lines so the last visible - // character in the line will be flush with the right margin. - size_t line_end_index = - (paragraph_style_.effective_align() == TextAlign::right || - paragraph_style_.effective_align() == TextAlign::center || - paragraph_style_.effective_align() == TextAlign::justify) - ? line_metrics.end_excluding_whitespace - : line_metrics.end_index; - - // Find the runs comprising this line. - std::vector line_runs; - for (const BidiRun& bidi_run : bidi_runs) { - // A "ghost" run is a run that does not impact the layout, breaking, - // alignment, width, etc but is still "visible" through getRectsForRange. - // For example, trailing whitespace on centered text can be scrolled - // through with the caret but will not wrap the line. - // - // Here, we add an additional run for the whitespace, but dont - // let it impact metrics. After layout of the whitespace run, we do not - // add its width into the x-offset adjustment, effectively nullifying its - // impact on the layout. - std::unique_ptr ghost_run = nullptr; - if (paragraph_style_.ellipsis.empty() && - line_metrics.end_excluding_whitespace < line_metrics.end_index && - bidi_run.start() <= line_metrics.end_index && - bidi_run.end() > line_end_index) { - ghost_run = std::make_unique( - std::max(bidi_run.start(), line_end_index), - std::min(bidi_run.end(), line_metrics.end_index), - bidi_run.direction(), bidi_run.style(), true); - } - // Include the ghost run before normal run if RTL - if (bidi_run.direction() == TextDirection::rtl && ghost_run != nullptr) { - line_runs.push_back(*ghost_run); - } - // Emplace a normal line run. - if (bidi_run.start() < line_end_index && - bidi_run.end() > line_metrics.start_index) { - // The run is a placeholder run. - if (bidi_run.size() == 1 && - text_[bidi_run.start()] == objReplacementChar && - obj_replacement_char_indexes_.count(bidi_run.start()) != 0 && - placeholder_run_index < inline_placeholders_.size()) { - line_runs.emplace_back( - std::max(bidi_run.start(), line_metrics.start_index), - std::min(bidi_run.end(), line_end_index), bidi_run.direction(), - bidi_run.style(), inline_placeholders_[placeholder_run_index]); - placeholder_run_index++; - } else { - line_runs.emplace_back( - std::max(bidi_run.start(), line_metrics.start_index), - std::min(bidi_run.end(), line_end_index), bidi_run.direction(), - bidi_run.style()); - } - } - // Include the ghost run after normal run if LTR - if (bidi_run.direction() == TextDirection::ltr && ghost_run != nullptr) { - line_runs.push_back(*ghost_run); - } - } - bool line_runs_all_rtl = - line_runs.size() && - std::accumulate( - line_runs.begin(), line_runs.end(), true, - [](const bool a, const BidiRun& b) { return a && b.is_rtl(); }); - if (line_runs_all_rtl) { - std::reverse(words.begin(), words.end()); - } - - std::vector line_glyph_positions; - std::vector line_code_unit_runs; - std::vector line_inline_placeholder_code_unit_runs; - - double run_x_offset = 0; - double justify_x_offset = 0; - std::vector paint_records; - - for (auto line_run_it = line_runs.begin(); line_run_it != line_runs.end(); - ++line_run_it) { - const BidiRun& run = *line_run_it; - minikin::FontStyle minikin_font; - minikin::MinikinPaint minikin_paint; - GetFontAndMinikinPaint(run.style(), &minikin_font, &minikin_paint); - font.setSize(run.style().font_size); - - std::shared_ptr minikin_font_collection = - GetMinikinFontCollectionForStyle(run.style()); - if (!minikin_font_collection) { - return; - } - - // Lay out this run. - uint16_t* text_ptr = text_.data(); - size_t text_start = run.start(); - size_t text_count = run.end() - run.start(); - size_t text_size = text_.size(); - - // Apply ellipsizing if the run was not completely laid out and this - // is the last line (or lines are unlimited). - const std::u16string& ellipsis = paragraph_style_.ellipsis; - std::vector ellipsized_text; - if (ellipsis.length() && !isinf(width_) && !line_metrics.hard_break && - line_run_it == line_runs.end() - 1 && - (line_number == line_limit - 1 || - paragraph_style_.unlimited_lines())) { - float ellipsis_width = layout.measureText( - reinterpret_cast(ellipsis.data()), 0, - ellipsis.length(), ellipsis.length(), run.is_rtl(), minikin_font, - minikin_paint, minikin_font_collection, nullptr); - - std::vector text_advances(text_count); - float text_width = - layout.measureText(text_ptr, text_start, text_count, text_.size(), - run.is_rtl(), minikin_font, minikin_paint, - minikin_font_collection, text_advances.data()); - - // Truncate characters from the text until the ellipsis fits. - size_t truncate_count = 0; - while (truncate_count < text_count && - run_x_offset + text_width + ellipsis_width > width_) { - text_width -= text_advances[text_count - truncate_count - 1]; - truncate_count++; - } - - ellipsized_text.reserve(text_count - truncate_count + - ellipsis.length()); - ellipsized_text.insert(ellipsized_text.begin(), - text_.begin() + run.start(), - text_.begin() + run.end() - truncate_count); - ellipsized_text.insert(ellipsized_text.end(), ellipsis.begin(), - ellipsis.end()); - text_ptr = ellipsized_text.data(); - text_start = 0; - text_count = ellipsized_text.size(); - text_size = text_count; - - // If there is no line limit, then skip all lines after the ellipsized - // line. - if (paragraph_style_.unlimited_lines()) { - line_limit = line_number + 1; - did_exceed_max_lines_ = true; - } - } - - layout.doLayout(text_ptr, text_start, text_count, text_size, run.is_rtl(), - minikin_font, minikin_paint, minikin_font_collection); - - if (layout.nGlyphs() == 0) - continue; - - // When laying out RTL ghost runs, shift the run_x_offset here by the - // advance so that the ghost run is positioned to the left of the first - // real run of text in the line. However, since we do not want it to - // impact the layout of real text, this advance is subsequently added - // back into the run_x_offset after the ghost run positions have been - // calcuated and before the next real run of text is laid out, ensuring - // later runs are laid out in the same position as if there were no ghost - // run. - if (run.is_ghost() && run.is_rtl()) - run_x_offset -= layout.getAdvance(); - - std::vector layout_advances(text_count); - layout.getAdvances(layout_advances.data()); - - // Break the layout into blobs that share the same SkPaint parameters. - std::vector> glyph_blobs = GetLayoutTypefaceRuns(layout); - - double word_start_position = std::numeric_limits::quiet_NaN(); - - // Build a Skia text blob from each group of glyphs. - for (const Range& glyph_blob : glyph_blobs) { - std::vector glyph_positions; - - GetGlyphTypeface(layout, glyph_blob.start).apply(font); - const SkTextBlobBuilder::RunBuffer& blob_buffer = - builder.allocRunPos(font, glyph_blob.end - glyph_blob.start); - - double justify_x_offset_delta = 0; - for (size_t glyph_index = glyph_blob.start; - glyph_index < glyph_blob.end;) { - size_t cluster_start_glyph_index = glyph_index; - uint32_t cluster = layout.getGlyphCluster(cluster_start_glyph_index); - double glyph_x_offset; - // Add all the glyphs in this cluster to the text blob. - do { - size_t blob_index = glyph_index - glyph_blob.start; - blob_buffer.glyphs[blob_index] = layout.getGlyphId(glyph_index); - - size_t pos_index = blob_index * 2; - blob_buffer.pos[pos_index] = layout.getX(glyph_index) + - justify_x_offset + - justify_x_offset_delta; - blob_buffer.pos[pos_index + 1] = layout.getY(glyph_index); - - if (glyph_index == cluster_start_glyph_index) - glyph_x_offset = blob_buffer.pos[pos_index]; - - glyph_index++; - } while (glyph_index < glyph_blob.end && - layout.getGlyphCluster(glyph_index) == cluster); - - Range glyph_code_units(cluster, 0); - std::vector grapheme_code_unit_counts; - if (run.is_rtl()) { - if (cluster_start_glyph_index > 0) { - glyph_code_units.end = - layout.getGlyphCluster(cluster_start_glyph_index - 1); - } else { - glyph_code_units.end = text_count; - } - grapheme_code_unit_counts.push_back(glyph_code_units.width()); - } else { - if (glyph_index < layout.nGlyphs()) { - glyph_code_units.end = layout.getGlyphCluster(glyph_index); - } else { - glyph_code_units.end = text_count; - } - - // The glyph may be a ligature. Determine how many graphemes are - // joined into this glyph and how many input code units map to - // each grapheme. - size_t code_unit_count = 1; - for (int32_t offset = glyph_code_units.start + 1; - offset < glyph_code_units.end; ++offset) { - if (minikin::GraphemeBreak::isGraphemeBreak( - layout_advances.data(), text_ptr, text_start, text_count, - text_start + offset)) { - grapheme_code_unit_counts.push_back(code_unit_count); - code_unit_count = 1; - } else { - code_unit_count++; - } - } - grapheme_code_unit_counts.push_back(code_unit_count); - } - float glyph_advance; - if (run.is_placeholder_run()) { - // The placeholder run's layout should yield one glyph representing - // the object replacement character. Replace its width with the - // placeholder's width. - FML_DCHECK(layout.nGlyphs() == 1); - glyph_advance = run.placeholder_run()->width; - } else { - glyph_advance = layout.getCharAdvance(glyph_code_units.start); - } - float grapheme_advance = - glyph_advance / grapheme_code_unit_counts.size(); - - glyph_positions.emplace_back(run_x_offset + glyph_x_offset, - grapheme_advance, - run.start() + glyph_code_units.start, - grapheme_code_unit_counts[0]); - - // Compute positions for the additional graphemes in the ligature. - for (size_t i = 1; i < grapheme_code_unit_counts.size(); ++i) { - glyph_positions.emplace_back( - glyph_positions.back().x_pos.end, grapheme_advance, - glyph_positions.back().code_units.start + - grapheme_code_unit_counts[i - 1], - grapheme_code_unit_counts[i]); - } - - bool at_word_start = false; - bool at_word_end = false; - if (word_index < words.size()) { - at_word_start = - words[word_index].start == run.start() + glyph_code_units.start; - at_word_end = - words[word_index].end == run.start() + glyph_code_units.end; - if (line_runs_all_rtl) { - std::swap(at_word_start, at_word_end); - } - } - - if (at_word_start) { - word_start_position = run_x_offset + glyph_x_offset; - } - - if (at_word_end) { - if (justify_line) { - justify_x_offset_delta += word_gap_width; - } - word_index++; - - if (!isnan(word_start_position)) { - double word_width = - glyph_positions.back().x_pos.end - word_start_position; - max_word_width = std::max(word_width, max_word_width); - word_start_position = std::numeric_limits::quiet_NaN(); - } - } - } // for each in glyph_blob - - if (glyph_positions.empty()) - continue; - - // Store the font metrics and TextStyle in the LineMetrics for this line - // to provide metrics upon user request. We index this RunMetrics - // instance at `run.end() - 1` to allow map::lower_bound to access the - // correct RunMetrics at any text index. - size_t run_key = run.end() - 1; - line_metrics.run_metrics.emplace(run_key, &run.style()); - SkFontMetrics* metrics = - &line_metrics.run_metrics.at(run_key).font_metrics; - font.getMetrics(metrics); - - Range record_x_pos( - glyph_positions.front().x_pos.start - run_x_offset, - glyph_positions.back().x_pos.end - run_x_offset); - paint_records.emplace_back(run.style(), SkPoint::Make(run_x_offset, 0), - builder.make(), *metrics, line_number, - record_x_pos.start, record_x_pos.end, - run.is_ghost(), run.placeholder_run()); - - justify_x_offset += justify_x_offset_delta; - - line_glyph_positions.insert(line_glyph_positions.end(), - glyph_positions.begin(), - glyph_positions.end()); - - // Add a record of glyph positions sorted by code unit index. - std::vector code_unit_positions(glyph_positions); - std::sort(code_unit_positions.begin(), code_unit_positions.end(), - [](const GlyphPosition& a, const GlyphPosition& b) { - return a.code_units.start < b.code_units.start; - }); - - double blob_x_pos_start = glyph_positions.front().x_pos.start; - double blob_x_pos_end = glyph_positions.back().x_pos.end; - line_code_unit_runs.emplace_back( - std::move(code_unit_positions), - Range(run.start(), run.end()), - Range(blob_x_pos_start, blob_x_pos_end), line_number, - *metrics, run.style(), run.direction(), run.placeholder_run()); - - if (run.is_placeholder_run()) { - line_inline_placeholder_code_unit_runs.push_back( - line_code_unit_runs.back()); - } - - if (!run.is_ghost()) { - min_left_ = std::min(min_left_, blob_x_pos_start); - max_right_ = std::max(max_right_, blob_x_pos_end); - } - } // for each in glyph_blobs - - if (run.is_placeholder_run()) { - run_x_offset += run.placeholder_run()->width; - } else { - // Do not increase x offset for LTR trailing ghost runs as it should not - // impact the layout of visible glyphs. RTL tailing ghost runs have the - // advance subtracted, so we do add the advance here to reset the - // run_x_offset. We do keep the record though so GetRectsForRange() can - // find metrics for trailing spaces. - if (!run.is_ghost() || run.is_rtl()) { - run_x_offset += layout.getAdvance(); - } - } - } // for each in line_runs - - // Adjust the glyph positions based on the alignment of the line. - double line_x_offset = GetLineXOffset(run_x_offset, justify_line); - if (line_x_offset) { - for (CodeUnitRun& code_unit_run : line_code_unit_runs) { - code_unit_run.Shift(line_x_offset); - } - for (CodeUnitRun& code_unit_run : - line_inline_placeholder_code_unit_runs) { - code_unit_run.Shift(line_x_offset); - } - for (GlyphPosition& position : line_glyph_positions) { - position.Shift(line_x_offset); - } - } - - size_t next_line_start = (line_number < line_metrics_.size() - 1) - ? line_metrics_[line_number + 1].start_index - : text_.size(); - glyph_lines_.emplace_back(std::move(line_glyph_positions), - next_line_start - line_metrics.start_index); - code_unit_runs_.insert(code_unit_runs_.end(), line_code_unit_runs.begin(), - line_code_unit_runs.end()); - inline_placeholder_code_unit_runs_.insert( - inline_placeholder_code_unit_runs_.end(), - line_inline_placeholder_code_unit_runs.begin(), - line_inline_placeholder_code_unit_runs.end()); - - // Calculate the amount to advance in the y direction. This is done by - // computing the maximum ascent and descent with respect to the strut. - double max_ascent = IsStrutValid() ? strut_.ascent + strut_.half_leading - : std::numeric_limits::lowest(); - double max_descent = IsStrutValid() ? strut_.descent + strut_.half_leading - : std::numeric_limits::lowest(); - double max_unscaled_ascent = 0; - for (const PaintRecord& paint_record : paint_records) { - UpdateLineMetrics(paint_record.metrics(), paint_record.style(), - max_ascent, max_descent, max_unscaled_ascent, - paint_record.GetPlaceholderRun(), line_number, - line_limit); - } - - // If no fonts were actually rendered, then compute a baseline based on the - // font of the paragraph style. - if (paint_records.empty()) { - SkFontMetrics metrics; - TextStyle style(paragraph_style_.GetTextStyle()); - font.setTypeface(GetDefaultSkiaTypeface(style)); - font.setSize(style.font_size); - font.getMetrics(&metrics); - UpdateLineMetrics(metrics, style, max_ascent, max_descent, - max_unscaled_ascent, nullptr, line_number, line_limit); - } - - // Calculate the baselines. This is only done on the first line. - if (line_number == 0) { - alphabetic_baseline_ = max_ascent; - // TODO(garyq): Ideographic baseline is currently bottom of EM - // box, which is not correct. This should be obtained from metrics. - // Skia currently does not support various baselines. - ideographic_baseline_ = (max_ascent + max_descent); - } - - line_metrics.height = - (line_number == 0 ? 0 : line_metrics_[line_number - 1].height) + - round(max_ascent + max_descent); - line_metrics.baseline = line_metrics.height - max_descent; - - y_offset += round(max_ascent + prev_max_descent); - prev_max_descent = max_descent; - - line_metrics.line_number = line_number; - line_metrics.ascent = max_ascent; - line_metrics.descent = max_descent; - line_metrics.unscaled_ascent = max_unscaled_ascent; - line_metrics.width = line_widths_[line_number]; - line_metrics.left = line_x_offset; - - final_line_count_++; - - for (PaintRecord& paint_record : paint_records) { - paint_record.SetOffset( - SkPoint::Make(paint_record.offset().x() + line_x_offset, y_offset)); - records_.emplace_back(std::move(paint_record)); - } - } // for each line_number - - if (paragraph_style_.max_lines == 1 || - (paragraph_style_.unlimited_lines() && paragraph_style_.ellipsized())) { - min_intrinsic_width_ = max_intrinsic_width_; - } else { - min_intrinsic_width_ = std::min(max_word_width, max_intrinsic_width_); - } - - std::sort(code_unit_runs_.begin(), code_unit_runs_.end(), - [](const CodeUnitRun& a, const CodeUnitRun& b) { - return a.code_units.start < b.code_units.start; - }); - - longest_line_ = max_right_ - min_left_; -} - -void ParagraphTxt::UpdateLineMetrics(const SkFontMetrics& metrics, - const TextStyle& style, - double& max_ascent, - double& max_descent, - double& max_unscaled_ascent, - PlaceholderRun* placeholder_run, - size_t line_number, - size_t line_limit) { - if (!strut_.force_strut) { - const double metrics_font_height = metrics.fDescent - metrics.fAscent; - // The overall height of the glyph blob. If neither the ascent or the - // descent is disabled, we have block_height = ascent + descent, where - // "ascent" is the extent from the top of the blob to its baseline, and - // "descent" is the extent from the text blob's baseline to its bottom. Not - // to be mistaken with the font's ascent and descent. - const double blob_height = style.has_height_override - ? style.height * style.font_size - : metrics_font_height + metrics.fLeading; - - // Scale the ascent and descent such that the sum of ascent and - // descent is `style.height * style.font_size`. - // - // The raw metrics do not add up to fontSize. The state of font - // metrics is a mess: - // - // Each font has 4 sets of vertical metrics: - // - // * hhea: hheaAscender, hheaDescender, hheaLineGap. - // Used by Apple. - // * OS/2 typo: typoAscender, typoDescender, typoLineGap. - // Used sometimes by Windows for layout. - // * OS/2 win: winAscent, winDescent. - // Also used by Windows, generally will be cut if extends past - // these metrics. - // * EM Square: ascent, descent - // Not actively used, but this defines the 'scale' of the - // units used. - // - // `Use Typo Metrics` is a boolean that, when enabled, prefers - // typo metrics over win metrics. Default is off. Enabled by most - // modern fonts. - // - // In addition to these different sets of metrics, there are also - // multiple strategies for using these metrics: - // - // * Adobe: Set hhea values to typo equivalents. - // * Microsoft: Set hhea values to win equivalents. - // * Web: Use hhea values for text, regardless of `Use Typo Metrics` - // The hheaLineGap is distributed half across the top and half - // across the bottom of the line. - // Exceptions: - // Windows: All browsers respect `Use Typo Metrics` - // Firefox respects `Use Typo Metrics`. - // - // This pertains to this code in that it is ambiguous which set of - // metrics we are actually using via SkFontMetrics. This in turn - // means that if we use the raw metrics, we will see differences - // between platforms as well as unpredictable line heights. - // - // A more thorough explanation is available at - // https://glyphsapp.com/tutorials/vertical-metrics - // - // Doing this ascent/descent normalization to the EM Square allows - // a sane, consistent, and reasonable "blob_height" to be specified, - // though it breaks with what is done by any of the platforms above. - const bool shouldNormalizeFont = - style.has_height_override && !style.half_leading; - const double font_height = - shouldNormalizeFont ? style.font_size : metrics_font_height; - - // Reserve the outermost vertical space we want to distribute evenly over - // and under the text ("half-leading"). - double leading; - if (style.half_leading) { - leading = blob_height - font_height; - } else { - leading = style.has_height_override ? 0.0 : metrics.fLeading; - } - const double half_leading = leading / 2; - - // Proportionally distribute the remaining vertical space above and below - // the glyph blob's baseline, per the font's ascent/discent ratio. - const double available_vspace = blob_height - leading; - const double modifiedAscent = - -metrics.fAscent / metrics_font_height * available_vspace + - half_leading; - const double modifiedDescent = - metrics.fDescent / metrics_font_height * available_vspace + - half_leading; - - const bool disableAscent = - line_number == 0 && paragraph_style_.text_height_behavior & - TextHeightBehavior::kDisableFirstAscent; - const bool disableDescent = line_number == line_limit - 1 && - paragraph_style_.text_height_behavior & - TextHeightBehavior::kDisableLastDescent; - - double ascent = disableAscent ? -metrics.fAscent : modifiedAscent; - double descent = disableDescent ? metrics.fDescent : modifiedDescent; - - ComputePlaceholder(placeholder_run, ascent, descent); - - max_ascent = std::max(ascent, max_ascent); - max_descent = std::max(descent, max_descent); - } - - max_unscaled_ascent = - std::max(placeholder_run == nullptr ? -metrics.fAscent - : placeholder_run->baseline_offset, - max_unscaled_ascent); -}; - -double ParagraphTxt::GetLineXOffset(double line_total_advance, - bool justify_line) { - if (isinf(width_)) - return 0; - - TextAlign align = paragraph_style_.effective_align(); - - if (align == TextAlign::right || - (align == TextAlign::justify && - paragraph_style_.text_direction == TextDirection::rtl && - !justify_line)) { - return width_ - line_total_advance; - } else if (align == TextAlign::center) { - return (width_ - line_total_advance) / 2; - } else { - return 0; - } -} - -const ParagraphStyle& ParagraphTxt::GetParagraphStyle() const { - return paragraph_style_; -} - -double ParagraphTxt::GetAlphabeticBaseline() { - FML_DCHECK(!needs_layout_) << "only valid after layout"; - // Currently -fAscent - return alphabetic_baseline_; -} - -double ParagraphTxt::GetIdeographicBaseline() { - FML_DCHECK(!needs_layout_) << "only valid after layout"; - // TODO(garyq): Currently -fAscent + fUnderlinePosition. Verify this. - return ideographic_baseline_; -} - -double ParagraphTxt::GetMaxIntrinsicWidth() { - FML_DCHECK(!needs_layout_) << "only valid after layout"; - return max_intrinsic_width_; -} - -double ParagraphTxt::GetMinIntrinsicWidth() { - FML_DCHECK(!needs_layout_) << "only valid after layout"; - return min_intrinsic_width_; -} - -size_t ParagraphTxt::TextSize() const { - FML_DCHECK(!needs_layout_) << "only valid after layout"; - return text_.size(); -} - -double ParagraphTxt::GetHeight() { - FML_DCHECK(!needs_layout_) << "only valid after layout"; - return final_line_count_ == 0 ? 0 - : line_metrics_[final_line_count_ - 1].height; -} - -double ParagraphTxt::GetMaxWidth() { - FML_DCHECK(!needs_layout_) << "only valid after layout"; - return width_; -} - -double ParagraphTxt::GetLongestLine() { - FML_DCHECK(!needs_layout_) << "only valid after layout"; - return longest_line_; -} - -void ParagraphTxt::SetParagraphStyle(const ParagraphStyle& style) { - needs_layout_ = true; - paragraph_style_ = style; -} - -void ParagraphTxt::SetFontCollection( - std::shared_ptr font_collection) { - font_collection_ = std::move(font_collection); -} - -std::shared_ptr -ParagraphTxt::GetMinikinFontCollectionForStyle(const TextStyle& style) { - std::string locale; - if (!style.locale.empty()) { - uint32_t language_list_id = - minikin::FontStyle::registerLanguageList(style.locale); - const minikin::FontLanguages& langs = - minikin::FontLanguageListCache::getById(language_list_id); - if (langs.size()) { - locale = langs[0].getString(); - } - } - - return font_collection_->GetMinikinFontCollectionForFamilies( - style.font_families, locale); -} - -sk_sp ParagraphTxt::GetDefaultSkiaTypeface(const TextStyle& style) { - std::shared_ptr collection = - GetMinikinFontCollectionForStyle(style); - if (!collection) { - return nullptr; - } - minikin::FakedFont faked_font = - collection->baseFontFaked(GetMinikinFontStyle(style)); - return static_cast(faked_font.font)->GetSkTypeface(); -} - -// The x,y coordinates will be the very top left corner of the rendered -// paragraph. -void ParagraphTxt::Paint(SkCanvas* canvas, double x, double y) { - SkPoint base_offset = SkPoint::Make(x, y); - SkPaint paint; - // Paint the background first before painting any text to prevent - // potential overlap. - for (const PaintRecord& record : records_) { - PaintBackground(canvas, record, base_offset); - } - for (const PaintRecord& record : records_) { - if (record.style().has_foreground) { - paint = record.style().foreground; - } else { - paint.reset(); - paint.setColor(record.style().color); - } - SkPoint offset = base_offset + record.offset(); - if (record.GetPlaceholderRun() == nullptr) { - PaintShadow(canvas, record, offset); - canvas->drawTextBlob(record.text(), offset.x(), offset.y(), paint); - } - PaintDecorations(canvas, record, base_offset); - } -} - -void ParagraphTxt::PaintDecorations(SkCanvas* canvas, - const PaintRecord& record, - SkPoint base_offset) { - if (record.style().decoration == TextDecoration::kNone) - return; - - if (record.isGhost()) - return; - - const SkFontMetrics& metrics = record.metrics(); - SkPaint paint; - paint.setStyle(SkPaint::kStroke_Style); - if (record.style().decoration_color == SK_ColorTRANSPARENT) { - paint.setColor(record.style().color); - } else { - paint.setColor(record.style().decoration_color); - } - paint.setAntiAlias(true); - - // This is set to 2 for the double line style - int decoration_count = 1; - - // Filled when drawing wavy decorations. - SkPath path; - - double width = record.GetRunWidth(); - - SkScalar underline_thickness; - if ((metrics.fFlags & - SkFontMetrics::FontMetricsFlags::kUnderlineThicknessIsValid_Flag) && - metrics.fUnderlineThickness > 0) { - underline_thickness = metrics.fUnderlineThickness; - } else { - // Backup value if the fUnderlineThickness metric is not available: - // Divide by 14pt as it is the default size. - underline_thickness = record.style().font_size / 14.0f; - } - paint.setStrokeWidth(underline_thickness * - record.style().decoration_thickness_multiplier); - - SkPoint record_offset = base_offset + record.offset(); - SkScalar x = record_offset.x() + record.x_start(); - SkScalar y = record_offset.y(); - - // Setup the decorations. - switch (record.style().decoration_style) { - case TextDecorationStyle::kSolid: { - break; - } - case TextDecorationStyle::kDouble: { - decoration_count = 2; - break; - } - // Note: the intervals are scaled by the thickness of the line, so it is - // possible to change spacing by changing the decoration_thickness - // property of TextStyle. - case TextDecorationStyle::kDotted: { - // Divide by 14pt as it is the default size. - const float scale = record.style().font_size / 14.0f; - const SkScalar intervals[] = {1.0f * scale, 1.5f * scale, 1.0f * scale, - 1.5f * scale}; - size_t count = sizeof(intervals) / sizeof(intervals[0]); - paint.setPathEffect(SkPathEffect::MakeCompose( - SkDashPathEffect::Make(intervals, count, 0.0f), - SkDiscretePathEffect::Make(0, 0))); - break; - } - // Note: the intervals are scaled by the thickness of the line, so it is - // possible to change spacing by changing the decoration_thickness - // property of TextStyle. - case TextDecorationStyle::kDashed: { - // Divide by 14pt as it is the default size. - const float scale = record.style().font_size / 14.0f; - const SkScalar intervals[] = {4.0f * scale, 2.0f * scale, 4.0f * scale, - 2.0f * scale}; - size_t count = sizeof(intervals) / sizeof(intervals[0]); - paint.setPathEffect(SkPathEffect::MakeCompose( - SkDashPathEffect::Make(intervals, count, 0.0f), - SkDiscretePathEffect::Make(0, 0))); - break; - } - case TextDecorationStyle::kWavy: { - ComputeWavyDecoration( - path, x, y, width, - underline_thickness * record.style().decoration_thickness_multiplier); - break; - } - } - - // Draw the decorations. - // Use a for loop for "kDouble" decoration style - for (int i = 0; i < decoration_count; i++) { - double y_offset = i * underline_thickness * kDoubleDecorationSpacing; - double y_offset_original = y_offset; - // Underline - if (record.style().decoration & TextDecoration::kUnderline) { - y_offset += - (metrics.fFlags & - SkFontMetrics::FontMetricsFlags::kUnderlinePositionIsValid_Flag) - ? metrics.fUnderlinePosition - : underline_thickness; - if (record.style().decoration_style != TextDecorationStyle::kWavy) { - canvas->drawLine(x, y + y_offset, x + width, y + y_offset, paint); - } else { - SkPath offsetPath = path; - offsetPath.offset(0, y_offset); - canvas->drawPath(offsetPath, paint); - } - y_offset = y_offset_original; - } - // Overline - if (record.style().decoration & TextDecoration::kOverline) { - // We subtract fAscent here because for double overlines, we want the - // second line to be above, not below the first. - y_offset -= metrics.fAscent; - if (record.style().decoration_style != TextDecorationStyle::kWavy) { - canvas->drawLine(x, y - y_offset, x + width, y - y_offset, paint); - } else { - SkPath offsetPath = path; - offsetPath.offset(0, -y_offset); - canvas->drawPath(offsetPath, paint); - } - y_offset = y_offset_original; - } - // Strikethrough - if (record.style().decoration & TextDecoration::kLineThrough) { - if (metrics.fFlags & - SkFontMetrics::FontMetricsFlags::kStrikeoutThicknessIsValid_Flag) - paint.setStrokeWidth(metrics.fStrikeoutThickness * - record.style().decoration_thickness_multiplier); - // Make sure the double line is "centered" vertically. - y_offset += (decoration_count - 1.0) * underline_thickness * - kDoubleDecorationSpacing / -2.0; - y_offset += - (metrics.fFlags & - SkFontMetrics::FontMetricsFlags::kStrikeoutPositionIsValid_Flag) - ? metrics.fStrikeoutPosition - // Backup value if the strikeoutposition metric is not - // available: - : metrics.fXHeight / -2.0; - if (record.style().decoration_style != TextDecorationStyle::kWavy) { - canvas->drawLine(x, y + y_offset, x + width, y + y_offset, paint); - } else { - SkPath offsetPath = path; - offsetPath.offset(0, y_offset); - canvas->drawPath(offsetPath, paint); - } - y_offset = y_offset_original; - } - } -} - -void ParagraphTxt::ComputeWavyDecoration(SkPath& path, - double x, - double y, - double width, - double thickness) { - int wave_count = 0; - double x_start = 0; - // One full wavelength is 4 * thickness. - double quarter = thickness; - path.moveTo(x, y); - double remaining = width; - while (x_start + (quarter * 2) < width) { - path.rQuadTo(quarter, wave_count % 2 == 0 ? -quarter : quarter, quarter * 2, - 0); - x_start += quarter * 2; - remaining = width - x_start; - ++wave_count; - } - // Manually add a final partial quad for the remaining width that do - // not fit nicely into a half-wavelength. - // The following math is based off of quadratic bezier equations: - // - // * Let P(x) be the equation for the curve. - // * Let P0 = start, P1 = control point, P2 = end - // * P(x) = -2x^2 - 2x - // * P0 = (0, 0) - // * P1 = 2P(0.5) - 0.5 * P0 - 0.5 * P2 - // * P2 = P(remaining / (wavelength / 2)) - // - // Simplified implementation coursesy of @jim-flar at - // https://github.com/flutter/engine/pull/9468#discussion_r297872739 - // Unsimplified original version at - // https://github.com/flutter/engine/pull/9468#discussion_r297879129 - - double x1 = remaining / 2; - double y1 = remaining / 2 * (wave_count % 2 == 0 ? -1 : 1); - double x2 = remaining; - double y2 = (remaining - remaining * remaining / (quarter * 2)) * - (wave_count % 2 == 0 ? -1 : 1); - path.rQuadTo(x1, y1, x2, y2); -} - -void ParagraphTxt::PaintBackground(SkCanvas* canvas, - const PaintRecord& record, - SkPoint base_offset) { - if (!record.style().has_background) - return; - - const SkFontMetrics& metrics = record.metrics(); - SkRect rect(SkRect::MakeLTRB(record.x_start(), metrics.fAscent, - record.x_end(), metrics.fDescent)); - rect.offset(base_offset + record.offset()); - canvas->drawRect(rect, record.style().background); -} - -void ParagraphTxt::PaintShadow(SkCanvas* canvas, - const PaintRecord& record, - SkPoint offset) { - if (record.style().text_shadows.size() == 0) - return; - for (TextShadow text_shadow : record.style().text_shadows) { - if (!text_shadow.hasShadow()) { - continue; - } - - SkPaint paint; - paint.setColor(text_shadow.color); - if (text_shadow.blur_sigma > 0.5) { - paint.setMaskFilter(SkMaskFilter::MakeBlur( - kNormal_SkBlurStyle, text_shadow.blur_sigma, false)); - } - canvas->drawTextBlob(record.text(), offset.x() + text_shadow.offset.x(), - offset.y() + text_shadow.offset.y(), paint); - } -} - -std::vector ParagraphTxt::GetRectsForRange( - size_t start, - size_t end, - RectHeightStyle rect_height_style, - RectWidthStyle rect_width_style) { - FML_DCHECK(!needs_layout_) << "only valid after layout"; - // Struct that holds calculated metrics for each line. - struct LineBoxMetrics { - std::vector boxes; - // Per-line metrics for max and min coordinates for left and right boxes. - // These metrics cannot be calculated in layout generically because of - // selections that do not cover the whole line. - SkScalar max_right = std::numeric_limits::lowest(); - SkScalar min_left = std::numeric_limits::max(); - }; - - std::map line_box_metrics; - // Text direction of the first line so we can extend the correct side for - // RectWidthStyle::kMax. - TextDirection first_line_dir = TextDirection::ltr; - std::map newline_x_positions; - - // Lines that are actually in the requested range. - size_t max_line = 0; - size_t min_line = INT_MAX; - size_t glyph_length = 0; - - // Generate initial boxes and calculate metrics. - for (const CodeUnitRun& run : code_unit_runs_) { - // Check to see if we are finished. - if (run.code_units.start >= end) - break; - - // Update new line x position with the ending of last bidi run on the line - newline_x_positions[run.line_number] = - run.direction == TextDirection::ltr ? run.x_pos.end : run.x_pos.start; - - if (run.code_units.end <= start) - continue; - - double baseline = line_metrics_[run.line_number].baseline; - SkScalar top = baseline + run.font_metrics.fAscent; - SkScalar bottom = baseline + run.font_metrics.fDescent; - - if (run.placeholder_run != - nullptr) { // Use inline placeholder size as height. - top = baseline - run.placeholder_run->baseline_offset; - bottom = baseline + run.placeholder_run->height - - run.placeholder_run->baseline_offset; - } - - max_line = std::max(run.line_number, max_line); - min_line = std::min(run.line_number, min_line); - - // Calculate left and right. - SkScalar left, right; - if (run.code_units.start >= start && run.code_units.end <= end) { - left = run.x_pos.start; - right = run.x_pos.end; - } else { - left = SK_ScalarMax; - right = SK_ScalarMin; - for (const GlyphPosition& gp : run.positions) { - if (gp.code_units.start >= start && gp.code_units.end <= end) { - left = std::min(left, static_cast(gp.x_pos.start)); - right = std::max(right, static_cast(gp.x_pos.end)); - } else if (gp.code_units.end == end) { - // Calculate left and right when we are at - // the last position of a combining character. - glyph_length = (gp.code_units.end - gp.code_units.start) - 1; - if (gp.code_units.start == - std::max(0, (start - glyph_length))) { - left = std::min(left, static_cast(gp.x_pos.start)); - right = std::max(right, static_cast(gp.x_pos.end)); - } - } - } - if (left == SK_ScalarMax || right == SK_ScalarMin) - continue; - } - // Keep track of the min and max horizontal coordinates over all lines. Not - // needed for kTight. - if (rect_width_style == RectWidthStyle::kMax) { - line_box_metrics[run.line_number].max_right = - std::max(line_box_metrics[run.line_number].max_right, right); - line_box_metrics[run.line_number].min_left = - std::min(line_box_metrics[run.line_number].min_left, left); - if (min_line == run.line_number) { - first_line_dir = run.direction; - } - } - line_box_metrics[run.line_number].boxes.emplace_back( - SkRect::MakeLTRB(left, top, right, bottom), run.direction); - } - - // Add empty rectangles representing any newline characters within the - // range. - for (size_t line_number = 0; line_number < line_metrics_.size(); - ++line_number) { - LineMetrics& line = line_metrics_[line_number]; - if (line.start_index >= end) - break; - if (line.end_including_newline <= start) - continue; - if (line_box_metrics.find(line_number) == line_box_metrics.end()) { - if (line.end_index != line.end_including_newline && - line.end_index >= start && line.end_including_newline <= end) { - SkScalar x; - auto it = newline_x_positions.find(line_number); - if (it != newline_x_positions.end()) { - x = it->second; - } else { - x = GetLineXOffset(0, false); - } - SkScalar top = - (line_number > 0) ? line_metrics_[line_number - 1].height : 0; - SkScalar bottom = line_metrics_[line_number].height; - line_box_metrics[line_number].boxes.emplace_back( - SkRect::MakeLTRB(x, top, x, bottom), TextDirection::ltr); - } - } - } - - // "Post-process" metrics and aggregate final rects to return. - std::vector boxes; - for (const auto& kv : line_box_metrics) { - // Handle rect_width_styles. We skip the last line because not everything is - // selected. - - LineMetrics& line = - line_metrics_[fmin(line_metrics_.size() - 1, fmax(0, kv.first))]; - if (rect_width_style == RectWidthStyle::kMax && kv.first != max_line) { - if (line_box_metrics[kv.first].min_left > min_left_ && - (kv.first != min_line || first_line_dir == TextDirection::rtl)) { - line_box_metrics[kv.first].boxes.emplace_back( - SkRect::MakeLTRB(min_left_, line.baseline - line.unscaled_ascent, - line_box_metrics[kv.first].min_left, - line.baseline + line.descent), - TextDirection::rtl); - } - if (line_box_metrics[kv.first].max_right < max_right_ && - (kv.first != min_line || first_line_dir == TextDirection::ltr)) { - line_box_metrics[kv.first].boxes.emplace_back( - SkRect::MakeLTRB(line_box_metrics[kv.first].max_right, - line.baseline - line.unscaled_ascent, max_right_, - line.baseline + line.descent), - TextDirection::ltr); - } - } - - // Handle rect_height_styles. The height metrics used are all positive to - // make the signage clear here. - if (rect_height_style == RectHeightStyle::kTight) { - // Ignore line max height and width and generate tight bounds. - boxes.insert(boxes.end(), kv.second.boxes.begin(), kv.second.boxes.end()); - } else if (rect_height_style == RectHeightStyle::kMax) { - for (const Paragraph::TextBox& box : kv.second.boxes) { - boxes.emplace_back( - SkRect::MakeLTRB(box.rect.fLeft, line.baseline - line.ascent, - box.rect.fRight, line.baseline + line.descent), - box.direction); - } - } else if (rect_height_style == - RectHeightStyle::kIncludeLineSpacingMiddle) { - SkScalar adjusted_bottom = line.baseline + line.descent; - if (kv.first < line_metrics_.size() - 1) { - adjusted_bottom += (line_metrics_[kv.first + 1].ascent - - line_metrics_[kv.first + 1].unscaled_ascent) / - 2; - } - SkScalar adjusted_top = line.baseline - line.unscaled_ascent; - if (kv.first != 0) { - adjusted_top -= (line.ascent - line.unscaled_ascent) / 2; - } - for (const Paragraph::TextBox& box : kv.second.boxes) { - boxes.emplace_back(SkRect::MakeLTRB(box.rect.fLeft, adjusted_top, - box.rect.fRight, adjusted_bottom), - box.direction); - } - } else if (rect_height_style == RectHeightStyle::kIncludeLineSpacingTop) { - for (const Paragraph::TextBox& box : kv.second.boxes) { - SkScalar adjusted_top = kv.first == 0 - ? line.baseline - line.unscaled_ascent - : line.baseline - line.ascent; - boxes.emplace_back( - SkRect::MakeLTRB(box.rect.fLeft, adjusted_top, box.rect.fRight, - line.baseline + line.descent), - box.direction); - } - } else if (rect_height_style == - RectHeightStyle::kIncludeLineSpacingBottom) { - for (const Paragraph::TextBox& box : kv.second.boxes) { - SkScalar adjusted_bottom = line.baseline + line.descent; - if (kv.first < line_metrics_.size() - 1) { - adjusted_bottom += -line.unscaled_ascent + line.ascent; - } - boxes.emplace_back( - SkRect::MakeLTRB(box.rect.fLeft, - line.baseline - line.unscaled_ascent, - box.rect.fRight, adjusted_bottom), - box.direction); - } - } else if (rect_height_style == RectHeightStyle::kStrut) { - if (IsStrutValid()) { - for (const Paragraph::TextBox& box : kv.second.boxes) { - boxes.emplace_back( - SkRect::MakeLTRB(box.rect.fLeft, line.baseline - strut_.ascent, - box.rect.fRight, line.baseline + strut_.descent), - box.direction); - } - } else { - // Fall back to tight bounds if the strut is invalid. - boxes.insert(boxes.end(), kv.second.boxes.begin(), - kv.second.boxes.end()); - } - } - } - return boxes; -} - -Paragraph::PositionWithAffinity ParagraphTxt::GetGlyphPositionAtCoordinate( - double dx, - double dy) { - FML_DCHECK(!needs_layout_) << "only valid after layout"; - if (final_line_count_ <= 0) - return PositionWithAffinity(0, DOWNSTREAM); - - size_t y_index; - for (y_index = 0; y_index < final_line_count_ - 1; ++y_index) { - if (dy < line_metrics_[y_index].height) - break; - } - - const std::vector& line_glyph_position = - glyph_lines_[y_index].positions; - if (line_glyph_position.empty()) { - int line_start_index = - std::accumulate(glyph_lines_.begin(), glyph_lines_.begin() + y_index, 0, - [](const int a, const GlyphLine& b) { - return a + static_cast(b.total_code_units); - }); - return PositionWithAffinity(line_start_index, DOWNSTREAM); - } - - size_t x_index; - const GlyphPosition* gp = nullptr; - for (x_index = 0; x_index < line_glyph_position.size(); ++x_index) { - double glyph_end = (x_index < line_glyph_position.size() - 1) - ? line_glyph_position[x_index + 1].x_pos.start - : line_glyph_position[x_index].x_pos.end; - if (dx < glyph_end) { - gp = &line_glyph_position[x_index]; - break; - } - } - - if (gp == nullptr) { - gp = &line_glyph_position.back(); - } - - // Find the direction of the run that contains this glyph. - TextDirection direction = TextDirection::ltr; - for (const CodeUnitRun& run : code_unit_runs_) { - if (gp->code_units.start >= run.code_units.start && - gp->code_units.end <= run.code_units.end) { - direction = run.direction; - break; - } - } - - double glyph_center = (gp->x_pos.start + gp->x_pos.end) / 2; - if ((direction == TextDirection::ltr && dx < glyph_center) || - (direction == TextDirection::rtl && dx >= glyph_center)) { - return PositionWithAffinity(gp->code_units.start, DOWNSTREAM); - } else { - return PositionWithAffinity(gp->code_units.end, UPSTREAM); - } -} - -// We don't cache this because since this returns all boxes, it is usually -// unnecessary to call this multiple times in succession. -std::vector ParagraphTxt::GetRectsForPlaceholders() { - FML_DCHECK(!needs_layout_) << "only valid after layout"; - // Struct that holds calculated metrics for each line. - struct LineBoxMetrics { - std::vector boxes; - // Per-line metrics for max and min coordinates for left and right boxes. - // These metrics cannot be calculated in layout generically because of - // selections that do not cover the whole line. - SkScalar max_right = std::numeric_limits::lowest(); - SkScalar min_left = std::numeric_limits::max(); - }; - - std::vector boxes; - - // Generate initial boxes and calculate metrics. - for (const CodeUnitRun& run : inline_placeholder_code_unit_runs_) { - // Check to see if we are finished. - double baseline = line_metrics_[run.line_number].baseline; - SkScalar top = baseline + run.font_metrics.fAscent; - SkScalar bottom = baseline + run.font_metrics.fDescent; - - if (run.placeholder_run != - nullptr) { // Use inline placeholder size as height. - top = baseline - run.placeholder_run->baseline_offset; - bottom = baseline + run.placeholder_run->height - - run.placeholder_run->baseline_offset; - } - - // Calculate left and right. - SkScalar left, right; - left = run.x_pos.start; - right = run.x_pos.end; - - boxes.emplace_back(SkRect::MakeLTRB(left, top, right, bottom), - run.direction); - } - return boxes; -} - -Paragraph::Range ParagraphTxt::GetWordBoundary(size_t offset) { - FML_DCHECK(!needs_layout_) << "only valid after layout"; - if (text_.size() == 0) - return Range(0, 0); - - if (!word_breaker_) { - UErrorCode status = U_ZERO_ERROR; - word_breaker_.reset( - icu::BreakIterator::createWordInstance(icu::Locale(), status)); - if (!U_SUCCESS(status)) - return Range(0, 0); - } - - icu::UnicodeString icu_text(false, text_.data(), text_.size()); - word_breaker_->setText(icu_text); - - int32_t prev_boundary = word_breaker_->preceding(offset + 1); - int32_t next_boundary = word_breaker_->next(); - if (prev_boundary == icu::BreakIterator::DONE) - prev_boundary = offset; - if (next_boundary == icu::BreakIterator::DONE) - next_boundary = offset; - return Range(prev_boundary, next_boundary); -} - -size_t ParagraphTxt::GetLineCount() { - FML_DCHECK(!needs_layout_) << "only valid after layout"; - return final_line_count_; -} - -bool ParagraphTxt::DidExceedMaxLines() { - FML_DCHECK(!needs_layout_) << "only valid after layout"; - return did_exceed_max_lines_; -} - -void ParagraphTxt::SetDirty(bool dirty) { - needs_layout_ = dirty; -} - -std::vector& ParagraphTxt::GetLineMetrics() { - FML_DCHECK(!needs_layout_) << "only valid after layout"; - return line_metrics_; -} - -} // namespace txt diff --git a/third_party/txt/src/txt/paragraph_txt.h b/third_party/txt/src/txt/paragraph_txt.h deleted file mode 100644 index 989fc058bed37..0000000000000 --- a/third_party/txt/src/txt/paragraph_txt.h +++ /dev/null @@ -1,414 +0,0 @@ -/* - * 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. - */ - -#ifndef LIB_TXT_SRC_PARAGRAPH_TXT_H_ -#define LIB_TXT_SRC_PARAGRAPH_TXT_H_ - -#include -#include -#include - -#include "flutter/fml/compiler_specific.h" -#include "flutter/fml/macros.h" -#include "font_collection.h" -#include "line_metrics.h" -#include "minikin/LineBreaker.h" -#include "paint_record.h" -#include "paragraph.h" -#include "paragraph_style.h" -#include "placeholder_run.h" -#include "run_metrics.h" -#include "styled_runs.h" -#include "third_party/googletest/googletest/include/gtest/gtest_prod.h" // nogncheck -#include "third_party/skia/include/core/SkFontMetrics.h" -#include "third_party/skia/include/core/SkRect.h" -#include "utils/LinuxUtils.h" -#include "utils/MacUtils.h" -#include "utils/WindowsUtils.h" - -namespace txt { - -using GlyphID = uint32_t; - -// Constant with the unicode codepoint for the "Object replacement character". -// Used as a stand-in character for Placeholder boxes. -const int objReplacementChar = 0xFFFC; -// Constant with the unicode codepoint for the "Replacement character". This is -// the character that commonly renders as a black diamond with a white question -// mark. Used to replace non-placeholder instances of 0xFFFC in the text buffer. -const int replacementChar = 0xFFFD; - -// Paragraph provides Layout, metrics, and painting capabilities for text. Once -// a Paragraph is constructed with ParagraphBuilder::Build(), an example basic -// workflow can be this: -// -// std::unique_ptr paragraph = paragraph_builder.Build(); -// paragraph->Layout(); -// paragraph->Paint(, , ); -class ParagraphTxt : public Paragraph { - public: - // Constructor. It is highly recommended to construct a paragraph with a - // ParagraphBuilder. - ParagraphTxt(); - - virtual ~ParagraphTxt(); - - // Minikin Layout doLayout() and LineBreaker addStyleRun() has an - // O(N^2) (according to benchmarks) time complexity where N is the total - // number of characters. However, this is not significant for reasonably sized - // paragraphs. It is currently recommended to break up very long paragraphs - // (10k+ characters) to ensure speedy layout. - virtual void Layout(double width) override; - - virtual void Paint(SkCanvas* canvas, double x, double y) override; - virtual bool Paint(flutter::DisplayListBuilder* builder, - double x, - double y) override { - return false; - } - - // Getter for paragraph_style_. - const ParagraphStyle& GetParagraphStyle() const; - - // Returns the number of characters/unicode characters. AKA text_.size() - size_t TextSize() const; - - double GetHeight() override; - - double GetMaxWidth() override; - - double GetLongestLine() override; - - double GetAlphabeticBaseline() override; - - double GetIdeographicBaseline() override; - - double GetMaxIntrinsicWidth() override; - - // Currently, calculated similarly to as GetLayoutWidth(), however this is not - // necessarily 100% correct in all cases. - double GetMinIntrinsicWidth() override; - - std::vector GetRectsForRange( - size_t start, - size_t end, - RectHeightStyle rect_height_style, - RectWidthStyle rect_width_style) override; - - PositionWithAffinity GetGlyphPositionAtCoordinate(double dx, - double dy) override; - - std::vector GetRectsForPlaceholders() override; - - Range GetWordBoundary(size_t offset) override; - - // Returns the number of lines the paragraph takes up. If the text exceeds the - // amount width and maxlines provides, Layout() truncates the extra text from - // the layout and this will return the max lines allowed. - size_t GetLineCount(); - - bool DidExceedMaxLines() override; - - // Gets the full vector of LineMetrics which includes detailed data on each - // line in the final layout. - std::vector& GetLineMetrics() override; - - // Sets the needs_layout_ to dirty. When Layout() is called, a new Layout will - // be performed when this is set to true. Can also be used to prevent a new - // Layout from being calculated by setting to false. - void SetDirty(bool dirty = true); - - private: - friend class ParagraphBuilderTxt; - FRIEND_TEST(ParagraphTest, SimpleParagraph); - FRIEND_TEST(ParagraphTest, SimpleParagraphSmall); - FRIEND_TEST(ParagraphTest, SimpleRedParagraph); - FRIEND_TEST(ParagraphTest, RainbowParagraph); - FRIEND_TEST(ParagraphTest, DefaultStyleParagraph); - FRIEND_TEST(ParagraphTest, BoldParagraph); - FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, LeftAlignParagraph); - FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, RightAlignParagraph); - FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, CenterAlignParagraph); - FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, JustifyAlignParagraph); - FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, JustifyRTL); - FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, InlinePlaceholderLongestLine); - FRIEND_TEST_LINUX_ONLY(ParagraphTest, JustifyRTLNewLine); - FRIEND_TEST(ParagraphTest, DecorationsParagraph); - FRIEND_TEST(ParagraphTest, ItalicsParagraph); - FRIEND_TEST(ParagraphTest, ChineseParagraph); - FRIEND_TEST(ParagraphTest, DISABLED_ArabicParagraph); - FRIEND_TEST(ParagraphTest, SpacingParagraph); - FRIEND_TEST(ParagraphTest, LongWordParagraph); - FRIEND_TEST_LINUX_ONLY(ParagraphTest, KernScaleParagraph); - FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, NewlineParagraph); - FRIEND_TEST_LINUX_ONLY(ParagraphTest, EmojiParagraph); - FRIEND_TEST_LINUX_ONLY(ParagraphTest, EmojiMultiLineRectsParagraph); - FRIEND_TEST(ParagraphTest, HyphenBreakParagraph); - FRIEND_TEST(ParagraphTest, RepeatLayoutParagraph); - FRIEND_TEST(ParagraphTest, Ellipsize); - FRIEND_TEST(ParagraphTest, UnderlineShiftParagraph); - FRIEND_TEST(ParagraphTest, WavyDecorationParagraph); - FRIEND_TEST(ParagraphTest, SimpleShadow); - FRIEND_TEST(ParagraphTest, ComplexShadow); - FRIEND_TEST(ParagraphTest, FontFallbackParagraph); - FRIEND_TEST(ParagraphTest, InlinePlaceholder0xFFFCParagraph); - FRIEND_TEST(ParagraphTest, FontFeaturesParagraph); - FRIEND_TEST(ParagraphTest, GetGlyphPositionAtCoordinateSegfault); - FRIEND_TEST(ParagraphTest, KhmerLineBreaker); - FRIEND_TEST(ParagraphTest, TextHeightBehaviorRectsParagraph); - - // Starting data to layout. - std::vector text_; - // A vector of PlaceholderRuns, which detail the sizes, positioning and break - // behavior of the empty spaces to leave. Each placeholder span corresponds to - // a 0xFFFC (object replacement character) in text_, which indicates the - // position in the text where the placeholder will occur. There should be an - // equal number of 0xFFFC characters and elements in this vector. - std::vector inline_placeholders_; - // The indexes of the boxes that correspond to an inline placeholder. - std::vector inline_placeholder_boxes_; - // The indexes of instances of 0xFFFC that correspond to placeholders. This is - // necessary since the user may pass in manually entered 0xFFFC values using - // AddText(). - std::unordered_set obj_replacement_char_indexes_; - StyledRuns runs_; - ParagraphStyle paragraph_style_; - std::shared_ptr font_collection_; - - minikin::LineBreaker breaker_; - mutable std::unique_ptr word_breaker_; - - std::vector line_metrics_; - size_t final_line_count_ = 0; - std::vector line_widths_; - - // Stores the result of Layout(). - std::vector records_; - - bool did_exceed_max_lines_; - - // Strut metrics of zero will have no effect on the layout. - struct StrutMetrics { - double ascent = 0; // Positive value to keep signs clear. - double descent = 0; - double leading = 0; - double half_leading = 0; - double line_height = 0; - bool force_strut = false; - }; - - StrutMetrics strut_; - - // Overall left and right extremes over all lines. - double max_right_; - double min_left_; - - class BidiRun { - public: - // Constructs a BidiRun with is_ghost defaulted to false. - BidiRun(size_t s, size_t e, TextDirection d, const TextStyle& st) - : start_(s), end_(e), direction_(d), style_(&st), is_ghost_(false) {} - - // Constructs a BidiRun with a custom is_ghost flag. - BidiRun(size_t s, - size_t e, - TextDirection d, - const TextStyle& st, - bool is_ghost) - : start_(s), end_(e), direction_(d), style_(&st), is_ghost_(is_ghost) {} - - // Constructs a placeholder bidi run. - BidiRun(size_t s, - size_t e, - TextDirection d, - const TextStyle& st, - PlaceholderRun& placeholder) - : start_(s), - end_(e), - direction_(d), - style_(&st), - is_ghost_(false), - placeholder_run_(&placeholder) {} - - size_t start() const { return start_; } - size_t end() const { return end_; } - size_t size() const { return end_ - start_; } - TextDirection direction() const { return direction_; } - const TextStyle& style() const { return *style_; } - PlaceholderRun* placeholder_run() const { return placeholder_run_; } - bool is_rtl() const { return direction_ == TextDirection::rtl; } - // Tracks if the run represents trailing whitespace. - bool is_ghost() const { return is_ghost_; } - bool is_placeholder_run() const { return placeholder_run_ != nullptr; } - - private: - size_t start_, end_; - TextDirection direction_; - const TextStyle* style_; - bool is_ghost_; - PlaceholderRun* placeholder_run_ = nullptr; - }; - - struct GlyphPosition { - Range code_units; - Range x_pos; - - GlyphPosition(double x_start, - double x_advance, - size_t code_unit_index, - size_t code_unit_width); - - void Shift(double delta); - }; - - struct GlyphLine { - // Glyph positions sorted by x coordinate. - const std::vector positions; - const size_t total_code_units; - - GlyphLine(std::vector&& p, size_t tcu); - }; - - struct CodeUnitRun { - // Glyph positions sorted by code unit index. - std::vector positions; - Range code_units; - Range x_pos; - size_t line_number; - SkFontMetrics font_metrics; - const TextStyle* style; - TextDirection direction; - const PlaceholderRun* placeholder_run; - - CodeUnitRun(std::vector&& p, - Range cu, - Range x, - size_t line, - const SkFontMetrics& metrics, - const TextStyle& st, - TextDirection dir, - const PlaceholderRun* placeholder); - - void Shift(double delta); - }; - - // Holds the laid out x positions of each glyph. - std::vector glyph_lines_; - - // Holds the positions of each range of code units in the text. - // Sorted in code unit index order. - std::vector code_unit_runs_; - // Holds the positions of the inline placeholders. - std::vector inline_placeholder_code_unit_runs_; - - // The max width of the paragraph as provided in the most recent Layout() - // call. - double width_ = -1.0f; - double longest_line_ = -1.0f; - double max_intrinsic_width_ = 0; - double min_intrinsic_width_ = 0; - double alphabetic_baseline_ = std::numeric_limits::max(); - double ideographic_baseline_ = std::numeric_limits::max(); - - bool needs_layout_ = true; - - struct WaveCoordinates { - double x_start; - double y_start; - double x_end; - double y_end; - - WaveCoordinates(double x_s, double y_s, double x_e, double y_e) - : x_start(x_s), y_start(y_s), x_end(x_e), y_end(y_e) {} - }; - - // Passes in the text and Styled Runs. text_ and runs_ will later be passed - // into breaker_ in InitBreaker(), which is called in Layout(). - void SetText(std::vector text, StyledRuns runs); - - void SetParagraphStyle(const ParagraphStyle& style); - - void SetFontCollection(std::shared_ptr font_collection); - - void SetInlinePlaceholders( - std::vector inline_placeholders, - std::unordered_set obj_replacement_char_indexes); - - // Break the text into lines. - bool ComputeLineBreaks(); - - // Break the text into runs based on LTR/RTL text direction. - bool ComputeBidiRuns(std::vector* result); - - // Calculates and populates strut based on paragraph_style_ strut info. - void ComputeStrut(StrutMetrics* strut, SkFont& font); - - // Adjusts the ascent and descent based on the existence and type of - // placeholder. This method sets the proper metrics to achieve the different - // PlaceholderAlignment options. - void ComputePlaceholder(PlaceholderRun* placeholder_run, - double& ascent, - double& descent); - - bool IsStrutValid() const; - - void UpdateLineMetrics(const SkFontMetrics& metrics, - const TextStyle& style, - double& max_ascent, - double& max_descent, - double& max_unscaled_ascent, - PlaceholderRun* placeholder_run, - size_t line_number, - size_t line_limit); - - // Calculate the starting X offset of a line based on the line's width and - // alignment. - double GetLineXOffset(double line_total_advance, bool justify_line); - - // Creates and draws the decorations onto the canvas. - void PaintDecorations(SkCanvas* canvas, - const PaintRecord& record, - SkPoint base_offset); - - // Computes the beziers for a wavy decoration. The results will be - // applied to path. - void ComputeWavyDecoration(SkPath& path, - double x, - double y, - double width, - double thickness); - - // Draws the background onto the canvas. - void PaintBackground(SkCanvas* canvas, - const PaintRecord& record, - SkPoint base_offset); - - // Draws the shadows onto the canvas. - void PaintShadow(SkCanvas* canvas, const PaintRecord& record, SkPoint offset); - - // Obtain a Minikin font collection matching this text style. - std::shared_ptr GetMinikinFontCollectionForStyle( - const TextStyle& style); - - // Get a default SkTypeface for a text style. - sk_sp GetDefaultSkiaTypeface(const TextStyle& style); - - FML_DISALLOW_COPY_AND_ASSIGN(ParagraphTxt); -}; - -} // namespace txt - -#endif // LIB_TXT_SRC_PARAGRAPH_TXT_H_ diff --git a/third_party/txt/src/txt/styled_runs.cc b/third_party/txt/src/txt/styled_runs.cc deleted file mode 100644 index aa39ef75d93e6..0000000000000 --- a/third_party/txt/src/txt/styled_runs.cc +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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 "styled_runs.h" - -#include "flutter/fml/logging.h" -#include "utils/WindowsUtils.h" - -namespace txt { - -StyledRuns::StyledRuns() = default; - -StyledRuns::~StyledRuns() = default; - -StyledRuns::StyledRuns(StyledRuns&& other) { - styles_.swap(other.styles_); - runs_.swap(other.runs_); -} - -const StyledRuns& StyledRuns::operator=(StyledRuns&& other) { - styles_.swap(other.styles_); - runs_.swap(other.runs_); - return *this; -} - -void StyledRuns::swap(StyledRuns& other) { - styles_.swap(other.styles_); - runs_.swap(other.runs_); -} - -size_t StyledRuns::AddStyle(const TextStyle& style) { - const size_t style_index = styles_.size(); - styles_.push_back(style); - return style_index; -} - -const TextStyle& StyledRuns::GetStyle(size_t style_index) const { - return styles_[style_index]; -} - -void StyledRuns::StartRun(size_t style_index, size_t start) { - EndRunIfNeeded(start); - runs_.push_back(IndexedRun{style_index, start, start}); -} - -void StyledRuns::EndRunIfNeeded(size_t end) { - if (runs_.empty()) - return; - IndexedRun& run = runs_.back(); - if (run.start == end) { - // The run is empty. We can skip it. - runs_.pop_back(); - } else { - run.end = end; - } -} - -StyledRuns::Run StyledRuns::GetRun(size_t index) const { - const IndexedRun& run = runs_[index]; - return Run{styles_[run.style_index], run.start, run.end}; -} - -} // namespace txt diff --git a/third_party/txt/src/txt/styled_runs.h b/third_party/txt/src/txt/styled_runs.h deleted file mode 100644 index 04000629b63a4..0000000000000 --- a/third_party/txt/src/txt/styled_runs.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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. - */ - -#ifndef LIB_TXT_SRC_STYLED_RUNS_H_ -#define LIB_TXT_SRC_STYLED_RUNS_H_ - -#include -#include - -#include "text_style.h" -#include "third_party/googletest/googletest/include/gtest/gtest_prod.h" // nogncheck -#include "utils/WindowsUtils.h" - -namespace txt { - -// This holds and handles the start/end positions of discrete chunks of text -// that use different styles (a 'run'). -class StyledRuns { - public: - struct Run { - const TextStyle& style; - size_t start; - size_t end; - }; - - StyledRuns(); - - ~StyledRuns(); - - StyledRuns(const StyledRuns& other) = delete; - - StyledRuns(StyledRuns&& other); - - const StyledRuns& operator=(StyledRuns&& other); - - void swap(StyledRuns& other); - - size_t AddStyle(const TextStyle& style); - - const TextStyle& GetStyle(size_t style_index) const; - - void StartRun(size_t style_index, size_t start); - - void EndRunIfNeeded(size_t end); - - size_t size() const { return runs_.size(); } - - Run GetRun(size_t index) const; - - private: - FRIEND_TEST(ParagraphTest, SimpleParagraph); - FRIEND_TEST(ParagraphTest, SimpleParagraphSmall); - FRIEND_TEST(ParagraphTest, SimpleRedParagraph); - FRIEND_TEST(ParagraphTest, RainbowParagraph); - FRIEND_TEST(ParagraphTest, DefaultStyleParagraph); - FRIEND_TEST(ParagraphTest, BoldParagraph); - FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, LeftAlignParagraph); - FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, RightAlignParagraph); - FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, CenterAlignParagraph); - FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, JustifyAlignParagraph); - FRIEND_TEST(ParagraphTest, DecorationsParagraph); - FRIEND_TEST(ParagraphTest, ItalicsParagraph); - FRIEND_TEST(ParagraphTest, ChineseParagraph); - FRIEND_TEST(ParagraphTest, DISABLED_ArabicParagraph); - FRIEND_TEST(ParagraphTest, LongWordParagraph); - FRIEND_TEST(ParagraphTest, KernParagraph); - FRIEND_TEST(ParagraphTest, HyphenBreakParagraph); - FRIEND_TEST(ParagraphTest, RepeatLayoutParagraph); - FRIEND_TEST(ParagraphTest, Ellipsize); - FRIEND_TEST(ParagraphTest, SimpleShadow); - FRIEND_TEST(ParagraphTest, ComplexShadow); - FRIEND_TEST(ParagraphTest, FontFallbackParagraph); - - struct IndexedRun { - size_t style_index = 0; - size_t start = 0; - size_t end = 0; - - explicit IndexedRun(size_t style_index, size_t start, size_t end) - : style_index(style_index), start(start), end(end) {} - }; - - std::vector styles_; - std::vector runs_; -}; - -} // namespace txt - -#endif // LIB_TXT_SRC_STYLED_RUNS_H_ diff --git a/third_party/txt/src/utils/JenkinsHash.cpp b/third_party/txt/src/utils/JenkinsHash.cpp deleted file mode 100644 index 4df6d2a2bb2fb..0000000000000 --- a/third_party/txt/src/utils/JenkinsHash.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * 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. - */ - -/* Implementation of Jenkins one-at-a-time hash function. These choices are - * optimized for code size and portability, rather than raw speed. But speed - * should still be quite good. - **/ - -#include -#include - -namespace android { - -#ifdef __clang__ -__attribute__((no_sanitize("integer"))) -#endif -hash_t -JenkinsHashWhiten(uint32_t hash) { - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - return hash; -} - -uint32_t JenkinsHashMixBytes(uint32_t hash, const uint8_t* bytes, size_t size) { - if (size > UINT32_MAX) { - abort(); - } - hash = JenkinsHashMix(hash, (uint32_t)size); - size_t i; - for (i = 0; i < (size & -4); i += 4) { - uint32_t data = bytes[i] | (bytes[i + 1] << 8) | (bytes[i + 2] << 16) | - (bytes[i + 3] << 24); - hash = JenkinsHashMix(hash, data); - } - if (size & 3) { - uint32_t data = bytes[i]; - data |= ((size & 3) > 1) ? (bytes[i + 1] << 8) : 0; - data |= ((size & 3) > 2) ? (bytes[i + 2] << 16) : 0; - hash = JenkinsHashMix(hash, data); - } - return hash; -} - -uint32_t JenkinsHashMixShorts(uint32_t hash, - const uint16_t* shorts, - size_t size) { - if (size > UINT32_MAX) { - abort(); - } - hash = JenkinsHashMix(hash, (uint32_t)size); - size_t i; - for (i = 0; i < (size & -2); i += 2) { - uint32_t data = shorts[i] | (shorts[i + 1] << 16); - hash = JenkinsHashMix(hash, data); - } - if (size & 1) { - uint32_t data = shorts[i]; - hash = JenkinsHashMix(hash, data); - } - return hash; -} - -} // namespace android diff --git a/third_party/txt/src/utils/JenkinsHash.h b/third_party/txt/src/utils/JenkinsHash.h deleted file mode 100644 index 25a778b4bc044..0000000000000 --- a/third_party/txt/src/utils/JenkinsHash.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * 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. - */ - -/* Implementation of Jenkins one-at-a-time hash function. These choices are - * optimized for code size and portability, rather than raw speed. But speed - * should still be quite good. - **/ - -#ifndef ANDROID_JENKINS_HASH_H -#define ANDROID_JENKINS_HASH_H - -#include - -namespace android { - -/* The Jenkins hash of a sequence of 32 bit words A, B, C is: - * Whiten(Mix(Mix(Mix(0, A), B), C)) */ - -#ifdef __clang__ -__attribute__((no_sanitize("integer"))) -#endif -inline uint32_t -JenkinsHashMix(uint32_t hash, uint32_t data) { - hash += data; - hash += (hash << 10); - hash ^= (hash >> 6); - return hash; -} - -hash_t JenkinsHashWhiten(uint32_t hash); - -/* Helpful utility functions for hashing data in 32 bit chunks */ -uint32_t JenkinsHashMixBytes(uint32_t hash, const uint8_t* bytes, size_t size); - -uint32_t JenkinsHashMixShorts(uint32_t hash, - const uint16_t* shorts, - size_t size); - -} // namespace android - -#endif // ANDROID_JENKINS_HASH_H diff --git a/third_party/txt/src/utils/LinuxUtils.h b/third_party/txt/src/utils/LinuxUtils.h deleted file mode 100644 index 212aa9f8bc5af..0000000000000 --- a/third_party/txt/src/utils/LinuxUtils.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - */ - -#ifndef LINUX_UTILS_H -#define LINUX_UTILS_H - -#if defined(__linux__) -#define DISABLE_TEST_LINUX(TEST_NAME) TEST_NAME -#define FRIEND_TEST_LINUX_DISABLED_EXPANDED(SUITE, TEST_NAME) \ - FRIEND_TEST(SUITE, TEST_NAME) -#define FRIEND_TEST_LINUX_DISABLED(SUITE, TEST_NAME) \ - FRIEND_TEST_LINUX_DISABLED_EXPANDED(SUITE, DISABLE_TEST_LINUX(TEST_NAME)) - -#define FRIEND_TEST_LINUX_ONLY(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME) -#define LINUX_ONLY(TEST_NAME) TEST_NAME - -#else -#define DISABLE_TEST_LINUX(TEST_NAME) DISABLED_##TEST_NAME -#define FRIEND_TEST_LINUX_DISABLED(SUITE, TEST_NAME) \ - FRIEND_TEST(SUITE, TEST_NAME) - -#define LINUX_ONLY(TEST_NAME) DISABLED_##TEST_NAME -#define FRIEND_TEST_LINUX_ONLY_EXPANDED(SUITE, TEST_NAME) \ - FRIEND_TEST(SUITE, TEST_NAME) -#define FRIEND_TEST_LINUX_ONLY(SUITE, TEST_NAME) \ - FRIEND_TEST_LINUX_ONLY_EXPANDED(SUITE, DISABLE_TEST_LINUX(TEST_NAME)) -#endif // defined(__linux__) - -#endif // LINUX_UTILS_H diff --git a/third_party/txt/src/utils/LruCache.h b/third_party/txt/src/utils/LruCache.h deleted file mode 100644 index cb2adb7ddc895..0000000000000 --- a/third_party/txt/src/utils/LruCache.h +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * 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. - */ - -#ifndef ANDROID_UTILS_LRU_CACHE_H -#define ANDROID_UTILS_LRU_CACHE_H - -#include -#include - -#include "utils/TypeHelpers.h" // hash_t - -namespace android { - -/** - * GenerationCache callback used when an item is removed - */ -template -class OnEntryRemoved { - public: - virtual ~OnEntryRemoved(){}; - virtual void operator()(EntryKey& key, EntryValue& value) = 0; -}; // class OnEntryRemoved - -template -class LruCache { - public: - explicit LruCache(uint32_t maxCapacity); - virtual ~LruCache(); - - enum Capacity { - kUnlimitedCapacity, - }; - - void setOnEntryRemovedListener(OnEntryRemoved* listener); - size_t size() const; - const TValue& get(const TKey& key); - bool put(const TKey& key, const TValue& value); - bool remove(const TKey& key); - bool removeOldest(); - void clear(); - const TValue& peekOldestValue(); - - private: - LruCache(const LruCache& that); // disallow copy constructor - - // Super class so that we can have entries having only a key reference, for - // searches. - class KeyedEntry { - public: - virtual const TKey& getKey() const = 0; - // Make sure the right destructor is executed so that keys and values are - // deleted. - virtual ~KeyedEntry() {} - }; - - class Entry final : public KeyedEntry { - public: - TKey key; - TValue value; - Entry* parent; - Entry* child; - - Entry(TKey _key, TValue _value) - : key(_key), value(_value), parent(NULL), child(NULL) {} - const TKey& getKey() const final { return key; } - }; - - class EntryForSearch : public KeyedEntry { - public: - const TKey& key; - EntryForSearch(const TKey& key_) : key(key_) {} - const TKey& getKey() const final { return key; } - }; - - struct HashForEntry { - size_t operator()(const KeyedEntry* entry) const { - return hash_type(entry->getKey()); - }; - }; - - struct EqualityForHashedEntries { - bool operator()(const KeyedEntry* lhs, const KeyedEntry* rhs) const { - return lhs->getKey() == rhs->getKey(); - }; - }; - - // All entries in the set will be Entry*. Using the weaker KeyedEntry as to - // allow entries that have only a key reference, for searching. - typedef std:: - unordered_set - LruCacheSet; - - void attachToCache(Entry& entry); - void detachFromCache(Entry& entry); - - typename LruCacheSet::iterator findByKey(const TKey& key) { - EntryForSearch entryForSearch(key); - typename LruCacheSet::iterator result = mSet->find(&entryForSearch); - return result; - } - - std::unique_ptr mSet; - OnEntryRemoved* mListener; - Entry* mOldest; - Entry* mYoungest; - uint32_t mMaxCapacity; - TValue mNullValue; - - public: - // To be used like: - // while (it.next()) { - // it.value(); it.key(); - // } - class Iterator { - public: - Iterator(const LruCache& cache) - : mCache(cache), - mIterator(mCache.mSet->begin()), - mBeginReturned(false) {} - - bool next() { - if (mIterator == mCache.mSet->end()) { - return false; - } - if (!mBeginReturned) { - // mIterator has been initialized to the beginning and - // hasn't been returned. Do not advance: - mBeginReturned = true; - } else { - std::advance(mIterator, 1); - } - bool ret = (mIterator != mCache.mSet->end()); - return ret; - } - - const TValue& value() const { - // All the elements in the set are of type Entry. See comment in the - // definition of LruCacheSet above. - return reinterpret_cast(*mIterator)->value; - } - - const TKey& key() const { return (*mIterator)->getKey(); } - - private: - const LruCache& mCache; - typename LruCacheSet::iterator mIterator; - bool mBeginReturned; - }; -}; - -// Implementation is here, because it's fully templated -template -LruCache::LruCache(uint32_t maxCapacity) - : mSet(new LruCacheSet()), - mListener(NULL), - mOldest(NULL), - mYoungest(NULL), - mMaxCapacity(maxCapacity), - mNullValue(0) { - mSet->max_load_factor(1.0); -}; - -template -LruCache::~LruCache() { - // Need to delete created entries. - clear(); -}; - -template -void LruCache::setOnEntryRemovedListener(OnEntryRemoved* listener) { - mListener = listener; -} - -template -size_t LruCache::size() const { - return mSet->size(); -} - -template -const TValue& LruCache::get(const TKey& key) { - typename LruCacheSet::const_iterator find_result = findByKey(key); - if (find_result == mSet->end()) { - return mNullValue; - } - // All the elements in the set are of type Entry. See comment in the - // definition of LruCacheSet above. - Entry* entry = reinterpret_cast(*find_result); - detachFromCache(*entry); - attachToCache(*entry); - return entry->value; -} - -template -bool LruCache::put(const TKey& key, const TValue& value) { - if (mMaxCapacity != kUnlimitedCapacity && size() >= mMaxCapacity) { - removeOldest(); - } - - if (findByKey(key) != mSet->end()) { - return false; - } - - Entry* newEntry = new Entry(key, value); - mSet->insert(newEntry); - attachToCache(*newEntry); - return true; -} - -template -bool LruCache::remove(const TKey& key) { - typename LruCacheSet::const_iterator find_result = findByKey(key); - if (find_result == mSet->end()) { - return false; - } - // All the elements in the set are of type Entry. See comment in the - // definition of LruCacheSet above. - Entry* entry = reinterpret_cast(*find_result); - mSet->erase(entry); - if (mListener) { - (*mListener)(entry->key, entry->value); - } - detachFromCache(*entry); - delete entry; - return true; -} - -template -bool LruCache::removeOldest() { - if (mOldest != NULL) { - return remove(mOldest->key); - // TODO: should probably abort if false - } - return false; -} - -template -const TValue& LruCache::peekOldestValue() { - if (mOldest) { - return mOldest->value; - } - return mNullValue; -} - -template -void LruCache::clear() { - if (mListener) { - for (Entry* p = mOldest; p != NULL; p = p->child) { - (*mListener)(p->key, p->value); - } - } - mYoungest = NULL; - mOldest = NULL; - for (auto entry : *mSet.get()) { - delete entry; - } - mSet->clear(); -} - -template -void LruCache::attachToCache(Entry& entry) { - if (mYoungest == NULL) { - mYoungest = mOldest = &entry; - } else { - entry.parent = mYoungest; - mYoungest->child = &entry; - mYoungest = &entry; - } -} - -template -void LruCache::detachFromCache(Entry& entry) { - if (entry.parent != NULL) { - entry.parent->child = entry.child; - } else { - mOldest = entry.child; - } - if (entry.child != NULL) { - entry.child->parent = entry.parent; - } else { - mYoungest = entry.parent; - } - - entry.parent = NULL; - entry.child = NULL; -} - -} // namespace android -#endif // ANDROID_UTILS_LRU_CACHE_H diff --git a/third_party/txt/src/utils/MacUtils.h b/third_party/txt/src/utils/MacUtils.h deleted file mode 100644 index a4be25142e9d2..0000000000000 --- a/third_party/txt/src/utils/MacUtils.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - */ - -#ifndef MAC_UTILS_H -#define MAC_UTILS_H - -#if defined(__APPLE__) -#define DISABLE_TEST_MAC(TEST_NAME) DISABLED_##TEST_NAME -#define FRIEND_TEST_MAC_DISABLED_EXPANDED(SUITE, TEST_NAME) \ - FRIEND_TEST(SUITE, TEST_NAME) -#define FRIEND_TEST_MAC_DISABLED(SUITE, TEST_NAME) \ - FRIEND_TEST_MAC_DISABLED_EXPANDED(SUITE, DISABLE_TEST_MAC(TEST_NAME)) - -#define FRIEND_TEST_MAC_ONLY(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME) -#define MAC_ONLY(TEST_NAME) TEST_NAME - -#else -#define DISABLE_TEST_MAC(TEST_NAME) TEST_NAME -#define FRIEND_TEST_MAC_DISABLED(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME) - -#define MAC_ONLY(TEST_NAME) DISABLED_##TEST_NAME -#define FRIEND_TEST_MAC_ONLY_EXPANDED(SUITE, TEST_NAME) \ - FRIEND_TEST(SUITE, TEST_NAME) -#define FRIEND_TEST_MAC_ONLY(SUITE, TEST_NAME) \ - FRIEND_TEST_MAC_ONLY_EXPANDED(SUITE, DISABLE_TEST_MAC(TEST_NAME)) -#endif // defined(__APPLE__) -#endif // MAC_UTILS_H diff --git a/third_party/txt/src/utils/TypeHelpers.h b/third_party/txt/src/utils/TypeHelpers.h deleted file mode 100644 index 311b1379eefec..0000000000000 --- a/third_party/txt/src/utils/TypeHelpers.h +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright (C) 2005 The Android Open Source Project - * - * 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. - */ - -#ifndef ANDROID_TYPE_HELPERS_H -#define ANDROID_TYPE_HELPERS_H - -#include - -#include -#include -#include -#include - -// --------------------------------------------------------------------------- - -namespace android { - -/* - * Types traits - */ - -template -struct trait_trivial_ctor { - enum { value = false }; -}; -template -struct trait_trivial_dtor { - enum { value = false }; -}; -template -struct trait_trivial_copy { - enum { value = false }; -}; -template -struct trait_trivial_move { - enum { value = false }; -}; -template -struct trait_pointer { - enum { value = false }; -}; -template -struct trait_pointer { - enum { value = true }; -}; - -template -struct traits { - enum { - // whether this type is a pointer - is_pointer = trait_pointer::value, - // whether this type's constructor is a no-op - has_trivial_ctor = is_pointer || trait_trivial_ctor::value, - // whether this type's destructor is a no-op - has_trivial_dtor = is_pointer || trait_trivial_dtor::value, - // whether this type can be copy-constructed with memcpy - has_trivial_copy = is_pointer || trait_trivial_copy::value, - // whether this type can be moved with memmove - has_trivial_move = is_pointer || trait_trivial_move::value - }; -}; - -template -struct aggregate_traits { - enum { - is_pointer = false, - has_trivial_ctor = - traits::has_trivial_ctor && traits::has_trivial_ctor, - has_trivial_dtor = - traits::has_trivial_dtor && traits::has_trivial_dtor, - has_trivial_copy = - traits::has_trivial_copy && traits::has_trivial_copy, - has_trivial_move = - traits::has_trivial_move && traits::has_trivial_move - }; -}; - -#define ANDROID_TRIVIAL_CTOR_TRAIT(T) \ - template <> \ - struct trait_trivial_ctor { \ - enum { value = true }; \ - }; - -#define ANDROID_TRIVIAL_DTOR_TRAIT(T) \ - template <> \ - struct trait_trivial_dtor { \ - enum { value = true }; \ - }; - -#define ANDROID_TRIVIAL_COPY_TRAIT(T) \ - template <> \ - struct trait_trivial_copy { \ - enum { value = true }; \ - }; - -#define ANDROID_TRIVIAL_MOVE_TRAIT(T) \ - template <> \ - struct trait_trivial_move { \ - enum { value = true }; \ - }; - -#define ANDROID_BASIC_TYPES_TRAITS(T) \ - ANDROID_TRIVIAL_CTOR_TRAIT(T) \ - ANDROID_TRIVIAL_DTOR_TRAIT(T) \ - ANDROID_TRIVIAL_COPY_TRAIT(T) \ - ANDROID_TRIVIAL_MOVE_TRAIT(T) - -// --------------------------------------------------------------------------- - -/* - * basic types traits - */ - -ANDROID_BASIC_TYPES_TRAITS(void) -ANDROID_BASIC_TYPES_TRAITS(bool) -ANDROID_BASIC_TYPES_TRAITS(char) -ANDROID_BASIC_TYPES_TRAITS(unsigned char) -ANDROID_BASIC_TYPES_TRAITS(short) -ANDROID_BASIC_TYPES_TRAITS(unsigned short) -ANDROID_BASIC_TYPES_TRAITS(int) -ANDROID_BASIC_TYPES_TRAITS(unsigned int) -ANDROID_BASIC_TYPES_TRAITS(long) -ANDROID_BASIC_TYPES_TRAITS(unsigned long) -ANDROID_BASIC_TYPES_TRAITS(long long) -ANDROID_BASIC_TYPES_TRAITS(unsigned long long) -ANDROID_BASIC_TYPES_TRAITS(float) -ANDROID_BASIC_TYPES_TRAITS(double) - -// --------------------------------------------------------------------------- - -/* - * compare and order types - */ - -template -inline int strictly_order_type(const TYPE& lhs, const TYPE& rhs) { - return (lhs < rhs) ? 1 : 0; -} - -template -inline int compare_type(const TYPE& lhs, const TYPE& rhs) { - return strictly_order_type(rhs, lhs) - strictly_order_type(lhs, rhs); -} - -/* - * create, destroy, copy and move types... - */ - -template -inline void construct_type(TYPE* p, size_t n) { - if (!traits::has_trivial_ctor) { - while (n > 0) { - n--; - new (p++) TYPE; - } - } -} - -template -inline void destroy_type(TYPE* p, size_t n) { - if (!traits::has_trivial_dtor) { - while (n > 0) { - n--; - p->~TYPE(); - p++; - } - } -} - -template -typename std::enable_if::has_trivial_copy>::type inline copy_type( - TYPE* d, - const TYPE* s, - size_t n) { - memcpy(d, s, n * sizeof(TYPE)); -} - -template -typename std::enable_if::has_trivial_copy>::type inline copy_type( - TYPE* d, - const TYPE* s, - size_t n) { - while (n > 0) { - n--; - new (d) TYPE(*s); - d++, s++; - } -} - -template -inline void splat_type(TYPE* where, const TYPE* what, size_t n) { - if (!traits::has_trivial_copy) { - while (n > 0) { - n--; - new (where) TYPE(*what); - where++; - } - } else { - while (n > 0) { - n--; - *where++ = *what; - } - } -} - -template -struct use_trivial_move - : public std::integral_constant::has_trivial_dtor && - traits::has_trivial_copy) || - traits::has_trivial_move> {}; - -template -typename std::enable_if::value>:: - type inline move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) { - memmove(d, s, n * sizeof(TYPE)); -} - -template -typename std::enable_if::value>:: - type inline move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) { - d += n; - s += n; - while (n > 0) { - n--; - --d, --s; - if (!traits::has_trivial_copy) { - new (d) TYPE(*s); - } else { - *d = *s; - } - if (!traits::has_trivial_dtor) { - s->~TYPE(); - } - } -} - -template -typename std::enable_if::value>:: - type inline move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) { - memmove(d, s, n * sizeof(TYPE)); -} - -template -typename std::enable_if::value>:: - type inline move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) { - while (n > 0) { - n--; - if (!traits::has_trivial_copy) { - new (d) TYPE(*s); - } else { - *d = *s; - } - if (!traits::has_trivial_dtor) { - s->~TYPE(); - } - d++, s++; - } -} - -// --------------------------------------------------------------------------- - -/* - * a key/value pair - */ - -template -struct key_value_pair_t { - typedef KEY key_t; - typedef VALUE value_t; - - KEY key; - VALUE value; - key_value_pair_t() {} - key_value_pair_t(const key_value_pair_t& o) : key(o.key), value(o.value) {} - key_value_pair_t& operator=(const key_value_pair_t& o) { - key = o.key; - value = o.value; - return *this; - } - key_value_pair_t(const KEY& k, const VALUE& v) : key(k), value(v) {} - explicit key_value_pair_t(const KEY& k) : key(k) {} - inline bool operator<(const key_value_pair_t& o) const { - return strictly_order_type(key, o.key); - } - inline const KEY& getKey() const { return key; } - inline const VALUE& getValue() const { return value; } -}; - -template -struct trait_trivial_ctor> { - enum { value = aggregate_traits::has_trivial_ctor }; -}; -template -struct trait_trivial_dtor> { - enum { value = aggregate_traits::has_trivial_dtor }; -}; -template -struct trait_trivial_copy> { - enum { value = aggregate_traits::has_trivial_copy }; -}; -template -struct trait_trivial_move> { - enum { value = aggregate_traits::has_trivial_move }; -}; - -// --------------------------------------------------------------------------- - -/* - * Hash codes. - */ -typedef uint32_t hash_t; - -template -hash_t hash_type(const TKey& key); - -/* Built-in hash code specializations */ -#define ANDROID_INT32_HASH(T) \ - template <> \ - inline hash_t hash_type(const T& value) { \ - return hash_t(value); \ - } -#define ANDROID_INT64_HASH(T) \ - template <> \ - inline hash_t hash_type(const T& value) { \ - return hash_t((value >> 32) ^ value); \ - } -#define ANDROID_REINTERPRET_HASH(T, R) \ - template <> \ - inline hash_t hash_type(const T& value) { \ - R newValue; \ - static_assert(sizeof(newValue) == sizeof(value), "size mismatch"); \ - memcpy(&newValue, &value, sizeof(newValue)); \ - return hash_type(newValue); \ - } - -ANDROID_INT32_HASH(bool) -ANDROID_INT32_HASH(int8_t) -ANDROID_INT32_HASH(uint8_t) -ANDROID_INT32_HASH(int16_t) -ANDROID_INT32_HASH(uint16_t) -ANDROID_INT32_HASH(int32_t) -ANDROID_INT32_HASH(uint32_t) -ANDROID_INT64_HASH(int64_t) -ANDROID_INT64_HASH(uint64_t) -ANDROID_REINTERPRET_HASH(float, uint32_t) -ANDROID_REINTERPRET_HASH(double, uint64_t) - -template -inline hash_t hash_type(T* const& value) { - return hash_type(uintptr_t(value)); -} - -}; // namespace android - -// --------------------------------------------------------------------------- - -#endif // ANDROID_TYPE_HELPERS_H diff --git a/third_party/txt/src/utils/WindowsUtils.h b/third_party/txt/src/utils/WindowsUtils.h deleted file mode 100644 index 9c1af86781f01..0000000000000 --- a/third_party/txt/src/utils/WindowsUtils.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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. - */ - -#ifndef WINDOWS_UTILS_H -#define WINDOWS_UTILS_H - -#if defined(_WIN32) -#define DISABLE_TEST_WINDOWS(TEST_NAME) DISABLED_##TEST_NAME -#define FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, TEST_NAME) \ - FRIEND_TEST(SUITE, TEST_NAME) -#define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) \ - FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, DISABLE_TEST_WINDOWS(TEST_NAME)) - -#define FRIEND_TEST_WINDOWS_ONLY(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME) -#define WINDOWS_ONLY(TEST_NAME) TEST_NAME - -#define NOMINMAX -#include -#include -#include - -#undef ERROR - -inline unsigned int clz_win(unsigned int num) { - unsigned long r = 0; - _BitScanReverse(&r, num); - return r; -} - -inline unsigned int clzl_win(unsigned long num) { - unsigned long r = 0; -#if defined(_WIN64) - _BitScanReverse64(&r, num); -#else - _BitScanReverse(&r, num); -#endif - return r; -} - -inline unsigned int ctz_win(unsigned int num) { - unsigned long r = 0; - _BitScanForward(&r, num); - return r; -} - -typedef SSIZE_T ssize_t; - -#else -#define DISABLE_TEST_WINDOWS(TEST_NAME) TEST_NAME -#define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) \ - FRIEND_TEST(SUITE, TEST_NAME) - -#define WINDOWS_ONLY(TEST_NAME) DISABLED_##TEST_NAME -#define FRIEND_TEST_WINDOWS_ONLY_EXPANDED(SUITE, TEST_NAME) \ - FRIEND_TEST(SUITE, TEST_NAME) -#define FRIEND_TEST_WINDOWS_ONLY(SUITE, TEST_NAME) \ - FRIEND_TEST_WINDOWS_ONLY_EXPANDED(SUITE, DISABLE_TEST_WINDOWS(TEST_NAME)) -#endif // defined(_WIN32) -#endif // WINDOWS_UTILS_H diff --git a/third_party/txt/tests/CmapCoverageTest.cpp b/third_party/txt/tests/CmapCoverageTest.cpp deleted file mode 100644 index b85a9e0777563..0000000000000 --- a/third_party/txt/tests/CmapCoverageTest.cpp +++ /dev/null @@ -1,659 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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 -#include -#include -#include -#include - -namespace minikin { - -size_t writeU16(uint16_t x, uint8_t* out, size_t offset) { - out[offset] = x >> 8; - out[offset + 1] = x; - return offset + 2; -} - -size_t writeI16(int16_t sx, uint8_t* out, size_t offset) { - return writeU16(static_cast(sx), out, offset); -} - -size_t writeU32(uint32_t x, uint8_t* out, size_t offset) { - out[offset] = x >> 24; - out[offset + 1] = x >> 16; - out[offset + 2] = x >> 8; - out[offset + 3] = x; - return offset + 4; -} - -// Returns valid cmap format 4 table contents. All glyph ID is same value as -// code point. (e.g. 'a' (U+0061) is mapped to Glyph ID = 0x0061). 'range' -// should be specified with inclusive-inclusive values. -static std::vector buildCmapFormat4Table( - const std::vector& ranges) { - uint16_t segmentCount = ranges.size() / 2 + 1 /* +1 for end marker */; - - const size_t numOfUint16 = - 8 /* format, length, languages, segCountX2, searchRange, entrySelector, - rangeShift, pad */ - + segmentCount * 4 /* endCount, startCount, idRange, idRangeOffset */; - const size_t finalLength = sizeof(uint16_t) * numOfUint16; - - std::vector out(finalLength); - size_t head = 0; - head = writeU16(4, out.data(), head); // format - head = writeU16(finalLength, out.data(), head); // length - head = writeU16(0, out.data(), head); // language - - const uint16_t searchRange = - 2 * (1 << static_cast(floor(log2(segmentCount)))); - - head = writeU16(segmentCount * 2, out.data(), head); // segCountX2 - head = writeU16(searchRange, out.data(), head); // searchRange -#if defined(_WIN32) - head = writeU16(ctz_win(searchRange) - 1, out.data(), head); -#else - head = writeU16(__builtin_ctz(searchRange) - 1, out.data(), - head); // entrySelector -#endif - head = - writeU16(segmentCount * 2 - searchRange, out.data(), head); // rangeShift - - size_t endCountHead = head; - size_t startCountHead = - head + segmentCount * sizeof(uint16_t) + 2 /* padding */; - size_t idDeltaHead = startCountHead + segmentCount * sizeof(uint16_t); - size_t idRangeOffsetHead = idDeltaHead + segmentCount * sizeof(uint16_t); - - for (size_t i = 0; i < ranges.size() / 2; ++i) { - const uint16_t begin = ranges[i * 2]; - const uint16_t end = ranges[i * 2 + 1]; - startCountHead = writeU16(begin, out.data(), startCountHead); - endCountHead = writeU16(end, out.data(), endCountHead); - // map glyph ID as the same value of the code point. - idDeltaHead = writeU16(0, out.data(), idDeltaHead); - idRangeOffsetHead = - writeU16(0 /* we don't use this */, out.data(), idRangeOffsetHead); - } - - // fill end marker - endCountHead = writeU16(0xFFFF, out.data(), endCountHead); - startCountHead = writeU16(0xFFFF, out.data(), startCountHead); - idDeltaHead = writeU16(1, out.data(), idDeltaHead); - idRangeOffsetHead = writeU16(0, out.data(), idRangeOffsetHead); - LOG_ALWAYS_FATAL_IF(endCountHead > finalLength); - LOG_ALWAYS_FATAL_IF(startCountHead > finalLength); - LOG_ALWAYS_FATAL_IF(idDeltaHead > finalLength); - LOG_ALWAYS_FATAL_IF(idRangeOffsetHead != finalLength); - return out; -} - -// Returns valid cmap format 4 table contents. All glyph ID is same value as -// code point. (e.g. 'a' (U+0061) is mapped to Glyph ID = 0x0061). 'range' -// should be specified with inclusive-inclusive values. -static std::vector buildCmapFormat12Table( - const std::vector& ranges) { - uint32_t numGroups = ranges.size() / 2; - - const size_t finalLength = - 2 /* format */ + 2 /* reserved */ + 4 /* length */ + 4 /* languages */ + - 4 /* numGroups */ + 12 /* size of a group */ * numGroups; - - std::vector out(finalLength); - size_t head = 0; - head = writeU16(12, out.data(), head); // format - head = writeU16(0, out.data(), head); // reserved - head = writeU32(finalLength, out.data(), head); // length - head = writeU32(0, out.data(), head); // language - head = writeU32(numGroups, out.data(), head); // numGroups - - for (uint32_t i = 0; i < numGroups; ++i) { - const uint32_t start = ranges[2 * i]; - const uint32_t end = ranges[2 * i + 1]; - head = writeU32(start, out.data(), head); - head = writeU32(end, out.data(), head); - // map glyph ID as the same value of the code point. - // TODO: Use glyph IDs lower than 65535. - // Cmap can store 32 bit glyph ID but due to the size of numGlyph, a font - // file can contain up to 65535 glyphs in a file. - head = writeU32(start, out.data(), head); - } - - LOG_ALWAYS_FATAL_IF(head != finalLength); - return out; -} - -class CmapBuilder { - public: - static constexpr size_t kEncodingTableHead = 4; - static constexpr size_t kEncodingTableSize = 8; - - CmapBuilder(int numTables) : mNumTables(numTables), mCurrentTableIndex(0) { - const size_t headerSize = - 2 /* version */ + 2 /* numTables */ + kEncodingTableSize * numTables; - out.resize(headerSize); - writeU16(0, out.data(), 0); - writeU16(numTables, out.data(), 2); - } - - void appendTable(uint16_t platformId, - uint16_t encodingId, - const std::vector& table) { - appendEncodingTable(platformId, encodingId, out.size()); - out.insert(out.end(), table.begin(), table.end()); - } - - // TODO: Introduce Format 14 table builder. - - std::vector build() { - LOG_ALWAYS_FATAL_IF(mCurrentTableIndex != mNumTables); - return out; - } - - // Helper functions. - static std::vector buildSingleFormat4Cmap( - uint16_t platformId, - uint16_t encodingId, - const std::vector& ranges) { - CmapBuilder builder(1); - builder.appendTable(platformId, encodingId, buildCmapFormat4Table(ranges)); - return builder.build(); - } - - static std::vector buildSingleFormat12Cmap( - uint16_t platformId, - uint16_t encodingId, - const std::vector& ranges) { - CmapBuilder builder(1); - builder.appendTable(platformId, encodingId, buildCmapFormat12Table(ranges)); - return builder.build(); - } - - private: - void appendEncodingTable(uint16_t platformId, - uint16_t encodingId, - uint32_t offset) { - LOG_ALWAYS_FATAL_IF(mCurrentTableIndex == mNumTables); - - const size_t currentEncodingTableHead = - kEncodingTableHead + mCurrentTableIndex * kEncodingTableSize; - size_t head = writeU16(platformId, out.data(), currentEncodingTableHead); - head = writeU16(encodingId, out.data(), head); - head = writeU32(offset, out.data(), head); - LOG_ALWAYS_FATAL_IF((head - currentEncodingTableHead) != - kEncodingTableSize); - mCurrentTableIndex++; - } - - int mNumTables; - int mCurrentTableIndex; - std::vector out; -}; - -TEST(CmapCoverageTest, SingleFormat4_brokenCmap) { - bool has_cmap_format_14_subtable = false; - { - SCOPED_TRACE("Reading beyond buffer size - Too small cmap size"); - std::vector cmap = CmapBuilder::buildSingleFormat4Cmap( - 0, 0, std::vector({'a', 'a'})); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), 3 /* too small */, &has_cmap_format_14_subtable); - EXPECT_EQ(0U, coverage.length()); - EXPECT_FALSE(has_cmap_format_14_subtable); - } - { - SCOPED_TRACE( - "Reading beyond buffer size - space needed for tables goes beyond cmap " - "size"); - std::vector cmap = CmapBuilder::buildSingleFormat4Cmap( - 0, 0, std::vector({'a', 'a'})); - - writeU16(1000, cmap.data(), 2 /* offset of num tables in cmap header */); - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_EQ(0U, coverage.length()); - EXPECT_FALSE(has_cmap_format_14_subtable); - } - { - SCOPED_TRACE( - "Reading beyond buffer size - Invalid offset in encoding table"); - std::vector cmap = CmapBuilder::buildSingleFormat4Cmap( - 0, 0, std::vector({'a', 'a'})); - - writeU16(1000, cmap.data(), - 8 /* offset of the offset in the first encoding record */); - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_EQ(0U, coverage.length()); - EXPECT_FALSE(has_cmap_format_14_subtable); - } -} - -TEST(CmapCoverageTest, SingleFormat4) { - bool has_cmap_format_14_subtable = false; - struct TestCast { - std::string testTitle; - uint16_t platformId; - uint16_t encodingId; - } TEST_CASES[] = { - {"Platform 0, Encoding 0", 0, 0}, {"Platform 0, Encoding 1", 0, 1}, - {"Platform 0, Encoding 2", 0, 2}, {"Platform 0, Encoding 3", 0, 3}, - {"Platform 3, Encoding 1", 3, 1}, - }; - - for (const auto& testCase : TEST_CASES) { - SCOPED_TRACE(testCase.testTitle.c_str()); - std::vector cmap = CmapBuilder::buildSingleFormat4Cmap( - testCase.platformId, testCase.encodingId, - std::vector({'a', 'a'})); - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_TRUE(coverage.get('a')); - EXPECT_FALSE(coverage.get('b')); - EXPECT_FALSE(has_cmap_format_14_subtable); - } -} - -TEST(CmapCoverageTest, SingleFormat12) { - bool has_cmap_format_14_subtable = false; - - struct TestCast { - std::string testTitle; - uint16_t platformId; - uint16_t encodingId; - } TEST_CASES[] = { - {"Platform 0, Encoding 4", 0, 4}, - {"Platform 0, Encoding 6", 0, 6}, - {"Platform 3, Encoding 10", 3, 10}, - }; - - for (const auto& testCase : TEST_CASES) { - SCOPED_TRACE(testCase.testTitle.c_str()); - std::vector cmap = CmapBuilder::buildSingleFormat12Cmap( - testCase.platformId, testCase.encodingId, - std::vector({'a', 'a'})); - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_TRUE(coverage.get('a')); - EXPECT_FALSE(coverage.get('b')); - EXPECT_FALSE(has_cmap_format_14_subtable); - } -} - -TEST(CmapCoverageTest, Format12_beyondTheUnicodeLimit) { - bool has_cmap_format_14_subtable = false; - { - SCOPED_TRACE( - "Starting range is out of Unicode code point. Should be ignored."); - std::vector cmap = CmapBuilder::buildSingleFormat12Cmap( - 0, 0, std::vector({'a', 'a', 0x110000, 0x110000})); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_TRUE(coverage.get('a')); - EXPECT_FALSE(coverage.get(0x110000)); - EXPECT_FALSE(has_cmap_format_14_subtable); - } - { - SCOPED_TRACE( - "Ending range is out of Unicode code point. Should be ignored."); - std::vector cmap = CmapBuilder::buildSingleFormat12Cmap( - 0, 0, std::vector({'a', 'a', 0x10FF00, 0x110000})); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_TRUE(coverage.get('a')); - EXPECT_TRUE(coverage.get(0x10FF00)); - EXPECT_TRUE(coverage.get(0x10FFFF)); - EXPECT_FALSE(coverage.get(0x110000)); - EXPECT_FALSE(has_cmap_format_14_subtable); - } -} - -TEST(CmapCoverageTest, notSupportedEncodings) { - bool has_cmap_format_14_subtable = false; - - struct TestCast { - std::string testTitle; - uint16_t platformId; - uint16_t encodingId; - } TEST_CASES[] = { - // Any encodings with platform 2 is not supported. - {"Platform 2, Encoding 0", 2, 0}, - {"Platform 2, Encoding 1", 2, 1}, - {"Platform 2, Encoding 2", 2, 2}, - {"Platform 2, Encoding 3", 2, 3}, - // UCS-2 or UCS-4 are supported on Platform == 3. Others are not - // supported. - {"Platform 3, Encoding 0", 3, 0}, // Symbol - {"Platform 3, Encoding 2", 3, 2}, // ShiftJIS - {"Platform 3, Encoding 3", 3, 3}, // RPC - {"Platform 3, Encoding 4", 3, 4}, // Big5 - {"Platform 3, Encoding 5", 3, 5}, // Wansung - {"Platform 3, Encoding 6", 3, 6}, // Johab - {"Platform 3, Encoding 7", 3, 7}, // Reserved - {"Platform 3, Encoding 8", 3, 8}, // Reserved - {"Platform 3, Encoding 9", 3, 9}, // Reserved - // Uknown platforms - {"Platform 4, Encoding 0", 4, 0}, - {"Platform 5, Encoding 1", 5, 1}, - {"Platform 6, Encoding 0", 6, 0}, - {"Platform 7, Encoding 1", 7, 1}, - }; - - for (const auto& testCase : TEST_CASES) { - SCOPED_TRACE(testCase.testTitle.c_str()); - CmapBuilder builder(1); - std::vector cmap = CmapBuilder::buildSingleFormat4Cmap( - testCase.platformId, testCase.encodingId, - std::vector({'a', 'a'})); - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_EQ(0U, coverage.length()); - EXPECT_FALSE(has_cmap_format_14_subtable); - } -} - -TEST(CmapCoverageTest, brokenFormat4Table) { - bool has_cmap_format_14_subtable = false; - { - SCOPED_TRACE("Too small table cmap size"); - std::vector table = - buildCmapFormat4Table(std::vector({'a', 'a'})); - table.resize(2); // Remove trailing data. - - CmapBuilder builder(1); - builder.appendTable(0, 0, table); - std::vector cmap = builder.build(); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_EQ(0U, coverage.length()); - EXPECT_FALSE(has_cmap_format_14_subtable); - } - { - SCOPED_TRACE("Too many segments"); - std::vector table = - buildCmapFormat4Table(std::vector({'a', 'a'})); - writeU16(5000, table.data(), - 6 /* segment count offset */); // 5000 segments. - CmapBuilder builder(1); - builder.appendTable(0, 0, table); - std::vector cmap = builder.build(); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_EQ(0U, coverage.length()); - EXPECT_FALSE(has_cmap_format_14_subtable); - } - { - SCOPED_TRACE("Inversed range"); - std::vector table = - buildCmapFormat4Table(std::vector({'b', 'b'})); - // Put smaller end code point to inverse the range. - writeU16('a', table.data(), 14 /* the first element of endCount offset */); - CmapBuilder builder(1); - builder.appendTable(0, 0, table); - std::vector cmap = builder.build(); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_EQ(0U, coverage.length()); - EXPECT_FALSE(has_cmap_format_14_subtable); - } -} - -TEST(CmapCoverageTest, brokenFormat12Table) { - bool has_cmap_format_14_subtable = false; - { - SCOPED_TRACE("Too small cmap size"); - std::vector table = - buildCmapFormat12Table(std::vector({'a', 'a'})); - table.resize(2); // Remove trailing data. - - CmapBuilder builder(1); - builder.appendTable(0, 0, table); - std::vector cmap = builder.build(); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_EQ(0U, coverage.length()); - EXPECT_FALSE(has_cmap_format_14_subtable); - } - { - SCOPED_TRACE("Too many groups"); - std::vector table = - buildCmapFormat12Table(std::vector({'a', 'a'})); - writeU32(5000, table.data(), 12 /* num group offset */); // 5000 groups. - - CmapBuilder builder(1); - builder.appendTable(0, 0, table); - std::vector cmap = builder.build(); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_EQ(0U, coverage.length()); - EXPECT_FALSE(has_cmap_format_14_subtable); - } - { - SCOPED_TRACE("Inversed range."); - std::vector table = - buildCmapFormat12Table(std::vector({'a', 'a'})); - // Put larger start code point to inverse the range. - writeU32('b', table.data(), - 16 /* start code point offset in the first group */); - - CmapBuilder builder(1); - builder.appendTable(0, 0, table); - std::vector cmap = builder.build(); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_EQ(0U, coverage.length()); - EXPECT_FALSE(has_cmap_format_14_subtable); - } - { - SCOPED_TRACE("Too large code point"); - std::vector cmap = CmapBuilder::buildSingleFormat12Cmap( - 0, 0, std::vector({0x110000, 0x110000})); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_EQ(0U, coverage.length()); - EXPECT_FALSE(has_cmap_format_14_subtable); - } -} - -TEST(CmapCoverageTest, TableSelection_Priority) { - bool has_cmap_format_14_subtable = false; - std::vector highestFormat12Table = - buildCmapFormat12Table(std::vector({'a', 'a'})); - std::vector highestFormat4Table = - buildCmapFormat4Table(std::vector({'a', 'a'})); - std::vector format4 = - buildCmapFormat4Table(std::vector({'b', 'b'})); - std::vector format12 = - buildCmapFormat12Table(std::vector({'b', 'b'})); - - { - SCOPED_TRACE("(platform, encoding) = (3, 10) is the highest priority."); - - struct LowerPriorityTable { - uint16_t platformId; - uint16_t encodingId; - const std::vector& table; - } LOWER_PRIORITY_TABLES[] = { - {0, 0, format4}, {0, 1, format4}, {0, 2, format4}, {0, 3, format4}, - {0, 4, format12}, {0, 6, format12}, {3, 1, format4}, - }; - - for (const auto& table : LOWER_PRIORITY_TABLES) { - CmapBuilder builder(2); - builder.appendTable(table.platformId, table.encodingId, table.table); - builder.appendTable(3, 10, highestFormat12Table); - std::vector cmap = builder.build(); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_TRUE(coverage.get('a')); // comes from highest table - EXPECT_FALSE(coverage.get('b')); // should not use other table. - EXPECT_FALSE(has_cmap_format_14_subtable); - } - } - { - SCOPED_TRACE("(platform, encoding) = (3, 1) case"); - - struct LowerPriorityTable { - uint16_t platformId; - uint16_t encodingId; - const std::vector& table; - } LOWER_PRIORITY_TABLES[] = { - {0, 0, format4}, - {0, 1, format4}, - {0, 2, format4}, - {0, 3, format4}, - }; - - for (const auto& table : LOWER_PRIORITY_TABLES) { - CmapBuilder builder(2); - builder.appendTable(table.platformId, table.encodingId, table.table); - builder.appendTable(3, 1, highestFormat4Table); - std::vector cmap = builder.build(); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_TRUE(coverage.get('a')); // comes from highest table - EXPECT_FALSE(coverage.get('b')); // should not use other table. - EXPECT_FALSE(has_cmap_format_14_subtable); - } - } -} - -TEST(CmapCoverageTest, TableSelection_SkipBrokenFormat4Table) { - SparseBitSet coverage; - bool has_cmap_format_14_subtable = false; - std::vector validTable = - buildCmapFormat4Table(std::vector({'a', 'a'})); - { - SCOPED_TRACE("Unsupported format"); - CmapBuilder builder(2); - std::vector table = - buildCmapFormat4Table(std::vector({'b', 'b'})); - writeU16(0, table.data(), 0 /* format offset */); - builder.appendTable(3, 1, table); - builder.appendTable(0, 0, validTable); - std::vector cmap = builder.build(); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_TRUE(coverage.get('a')); // comes from valid table - EXPECT_FALSE(coverage.get('b')); // should not use invalid table. - EXPECT_FALSE(has_cmap_format_14_subtable); - } - { - SCOPED_TRACE("Invalid language"); - CmapBuilder builder(2); - std::vector table = - buildCmapFormat4Table(std::vector({'b', 'b'})); - writeU16(1, table.data(), 4 /* language offset */); - builder.appendTable(3, 1, table); - builder.appendTable(0, 0, validTable); - std::vector cmap = builder.build(); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_TRUE(coverage.get('a')); // comes from valid table - EXPECT_FALSE(coverage.get('b')); // should not use invalid table. - EXPECT_FALSE(has_cmap_format_14_subtable); - } - { - SCOPED_TRACE("Invalid length"); - CmapBuilder builder(2); - std::vector table = - buildCmapFormat4Table(std::vector({'b', 'b'})); - writeU16(5000, table.data(), 2 /* length offset */); - builder.appendTable(3, 1, table); - builder.appendTable(0, 0, validTable); - std::vector cmap = builder.build(); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_TRUE(coverage.get('a')); // comes from valid table - EXPECT_FALSE(coverage.get('b')); // should not use invalid table. - EXPECT_FALSE(has_cmap_format_14_subtable); - } -} - -TEST(CmapCoverageTest, TableSelection_SkipBrokenFormat12Table) { - SparseBitSet coverage; - bool has_cmap_format_14_subtable = false; - std::vector validTable = - buildCmapFormat12Table(std::vector({'a', 'a'})); - { - SCOPED_TRACE("Unsupported format"); - CmapBuilder builder(2); - std::vector table = - buildCmapFormat12Table(std::vector({'b', 'b'})); - writeU16(0, table.data(), 0 /* format offset */); - builder.appendTable(3, 1, table); - builder.appendTable(0, 0, validTable); - std::vector cmap = builder.build(); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_TRUE(coverage.get('a')); // comes from valid table - EXPECT_FALSE(coverage.get('b')); // should not use invalid table. - EXPECT_FALSE(has_cmap_format_14_subtable); - } - { - SCOPED_TRACE("Invalid language"); - CmapBuilder builder(2); - std::vector table = - buildCmapFormat12Table(std::vector({'b', 'b'})); - writeU32(1, table.data(), 8 /* language offset */); - builder.appendTable(3, 1, table); - builder.appendTable(0, 0, validTable); - std::vector cmap = builder.build(); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_TRUE(coverage.get('a')); // comes from valid table - EXPECT_FALSE(coverage.get('b')); // should not use invalid table. - EXPECT_FALSE(has_cmap_format_14_subtable); - } - { - SCOPED_TRACE("Invalid length"); - CmapBuilder builder(2); - std::vector table = - buildCmapFormat12Table(std::vector({'b', 'b'})); - writeU32(5000, table.data(), 4 /* length offset */); - builder.appendTable(3, 1, table); - builder.appendTable(0, 0, validTable); - std::vector cmap = builder.build(); - - SparseBitSet coverage = CmapCoverage::getCoverage( - cmap.data(), cmap.size(), &has_cmap_format_14_subtable); - EXPECT_TRUE(coverage.get('a')); // comes from valid table - EXPECT_FALSE(coverage.get('b')); // should not use invalid table. - EXPECT_FALSE(has_cmap_format_14_subtable); - } -} - -} // namespace minikin diff --git a/third_party/txt/tests/EmojiTest.cpp b/third_party/txt/tests/EmojiTest.cpp deleted file mode 100644 index 91512ddee5e48..0000000000000 --- a/third_party/txt/tests/EmojiTest.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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 - -#include - -namespace minikin { - -TEST(EmojiTest, isEmojiTest) { - EXPECT_TRUE(isEmoji(0x0023)); // NUMBER SIGN - EXPECT_TRUE(isEmoji(0x0035)); // DIGIT FIVE - // EXPECT_TRUE(isEmoji(0x2640)); // FEMALE SIGN - // EXPECT_TRUE(isEmoji(0x2642)); // MALE SIGN - // EXPECT_TRUE(isEmoji(0x2695)); // STAFF OF AESCULAPIUS - EXPECT_TRUE(isEmoji(0x1F0CF)); // PLAYING CARD BLACK JOKER - EXPECT_TRUE(isEmoji(0x1F1E9)); // REGIONAL INDICATOR SYMBOL LETTER D - EXPECT_TRUE(isEmoji(0x1F6F7)); // SLED - EXPECT_TRUE(isEmoji(0x1F9E6)); // SOCKS - - EXPECT_FALSE(isEmoji(0x0000)); // - EXPECT_FALSE(isEmoji(0x0061)); // LATIN SMALL LETTER A - EXPECT_FALSE(isEmoji(0x1F93B)); // MODERN PENTATHLON - EXPECT_FALSE(isEmoji(0x1F946)); // RIFLE - EXPECT_FALSE(isEmoji(0x29E3D)); // A han character. -} - -TEST(EmojiTest, isEmojiModifierTest) { - EXPECT_TRUE(isEmojiModifier(0x1F3FB)); // EMOJI MODIFIER FITZPATRICK TYPE-1-2 - EXPECT_TRUE(isEmojiModifier(0x1F3FC)); // EMOJI MODIFIER FITZPATRICK TYPE-3 - EXPECT_TRUE(isEmojiModifier(0x1F3FD)); // EMOJI MODIFIER FITZPATRICK TYPE-4 - EXPECT_TRUE(isEmojiModifier(0x1F3FE)); // EMOJI MODIFIER FITZPATRICK TYPE-5 - EXPECT_TRUE(isEmojiModifier(0x1F3FF)); // EMOJI MODIFIER FITZPATRICK TYPE-6 - - EXPECT_FALSE(isEmojiModifier(0x0000)); // - EXPECT_FALSE(isEmojiModifier(0x1F3FA)); // AMPHORA - EXPECT_FALSE(isEmojiModifier(0x1F400)); // RAT - EXPECT_FALSE(isEmojiModifier(0x29E3D)); // A han character. -} - -TEST(EmojiTest, isEmojiBaseTest) { - EXPECT_TRUE(isEmojiBase(0x261D)); // WHITE UP POINTING INDEX - EXPECT_TRUE(isEmojiBase(0x270D)); // WRITING HAND - EXPECT_TRUE(isEmojiBase(0x1F385)); // FATHER CHRISTMAS - // EXPECT_TRUE(isEmojiBase(0x1F3C2)); // SNOWBOARDER - // EXPECT_TRUE(isEmojiBase(0x1F3C7)); // HORSE RACING - // EXPECT_TRUE(isEmojiBase(0x1F3CC)); // GOLFER - // EXPECT_TRUE(isEmojiBase(0x1F574)); // MAN IN BUSINESS SUIT LEVITATING - // EXPECT_TRUE(isEmojiBase(0x1F6CC)); // SLEEPING ACCOMMODATION - EXPECT_TRUE(isEmojiBase( - 0x1F91D)); // HANDSHAKE (removed from Emoji 4.0, but we need it) - EXPECT_TRUE(isEmojiBase(0x1F91F)); // I LOVE YOU HAND SIGN - EXPECT_TRUE(isEmojiBase(0x1F931)); // BREAST-FEEDING - EXPECT_TRUE(isEmojiBase(0x1F932)); // PALMS UP TOGETHER - EXPECT_TRUE(isEmojiBase( - 0x1F93C)); // WRESTLERS (removed from Emoji 4.0, but we need it) - EXPECT_TRUE(isEmojiBase(0x1F9D1)); // ADULT - EXPECT_TRUE(isEmojiBase(0x1F9DD)); // ELF - - EXPECT_FALSE(isEmojiBase(0x0000)); // - EXPECT_FALSE(isEmojiBase(0x261C)); // WHITE LEFT POINTING INDEX - EXPECT_FALSE(isEmojiBase(0x1F384)); // CHRISTMAS TREE - EXPECT_FALSE(isEmojiBase(0x1F9DE)); // GENIE - EXPECT_FALSE(isEmojiBase(0x29E3D)); // A han character. -} - -TEST(EmojiTest, emojiBidiOverrideTest) { - EXPECT_EQ(U_RIGHT_TO_LEFT, - emojiBidiOverride(nullptr, 0x05D0)); // HEBREW LETTER ALEF - EXPECT_EQ(U_LEFT_TO_RIGHT, - emojiBidiOverride( - nullptr, 0x1F170)); // NEGATIVE SQUARED LATIN CAPITAL LETTER A - EXPECT_EQ(U_OTHER_NEUTRAL, emojiBidiOverride(nullptr, 0x1F6F7)); // SLED - EXPECT_EQ(U_OTHER_NEUTRAL, emojiBidiOverride(nullptr, 0x1F9E6)); // SOCKS -} - -} // namespace minikin diff --git a/third_party/txt/tests/FileUtils.cpp b/third_party/txt/tests/FileUtils.cpp deleted file mode 100644 index 07f65342ab1d4..0000000000000 --- a/third_party/txt/tests/FileUtils.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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 -#include - -#include -#include - -std::vector readWholeFile(const std::string& filePath) { - FILE* fp = fopen(filePath.c_str(), "r"); - LOG_ALWAYS_FATAL_IF(fp == nullptr); - struct stat st; - LOG_ALWAYS_FATAL_IF(fstat(fileno(fp), &st) != 0); - - std::vector result(st.st_size); - LOG_ALWAYS_FATAL_IF(fread(result.data(), 1, st.st_size, fp) != - static_cast(st.st_size)); - fclose(fp); - return result; -} diff --git a/third_party/txt/tests/FileUtils.h b/third_party/txt/tests/FileUtils.h deleted file mode 100644 index e9c5ef1c34da5..0000000000000 --- a/third_party/txt/tests/FileUtils.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -std::vector readWholeFile(const std::string& filePath); diff --git a/third_party/txt/tests/FontCollectionItemizeTest.cpp b/third_party/txt/tests/FontCollectionItemizeTest.cpp deleted file mode 100644 index cbef889a057ed..0000000000000 --- a/third_party/txt/tests/FontCollectionItemizeTest.cpp +++ /dev/null @@ -1,1550 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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 - -#include "FontTestUtils.h" -#include "ICUTestBase.h" -#include "MinikinFontForTest.h" -#include "UnicodeUtils.h" -#include "minikin/FontFamily.h" -#include "minikin/FontLanguage.h" -#include "minikin/FontLanguageListCache.h" -#include "minikin/MinikinInternal.h" - -namespace minikin { - -const char kItemizeFontXml[] = kTestFontDir "itemize.xml"; -const char kEmojiFont[] = kTestFontDir "Emoji.ttf"; -const char kJAFont[] = kTestFontDir "Ja.ttf"; -const char kKOFont[] = kTestFontDir "Ko.ttf"; -const char kLatinBoldFont[] = kTestFontDir "Bold.ttf"; -const char kLatinBoldItalicFont[] = kTestFontDir "BoldItalic.ttf"; -const char kLatinFont[] = kTestFontDir "Regular.ttf"; -const char kLatinItalicFont[] = kTestFontDir "Italic.ttf"; -const char kZH_HansFont[] = kTestFontDir "ZhHans.ttf"; -const char kZH_HantFont[] = kTestFontDir "ZhHant.ttf"; - -const char kEmojiXmlFile[] = kTestFontDir "emoji.xml"; -const char kNoGlyphFont[] = kTestFontDir "NoGlyphFont.ttf"; -const char kColorEmojiFont[] = kTestFontDir "ColorEmojiFont.ttf"; -const char kTextEmojiFont[] = kTestFontDir "TextEmojiFont.ttf"; -const char kMixedEmojiFont[] = kTestFontDir "ColorTextMixedEmojiFont.ttf"; - -const char kHasCmapFormat14Font[] = kTestFontDir "NoCmapFormat14.ttf"; -const char kNoCmapFormat14Font[] = - kTestFontDir "VariationSelectorTest-Regular.ttf"; - -typedef ICUTestBase FontCollectionItemizeTest; - -// Utility function for calling itemize function. -void itemize(const std::shared_ptr& collection, - const char* str, - FontStyle style, - std::vector* result) { - const size_t BUF_SIZE = 256; - uint16_t buf[BUF_SIZE]; - size_t len; - - result->clear(); - ParseUnicode(buf, BUF_SIZE, str, &len, NULL); - std::scoped_lock _l(gMinikinLock); - collection->itemize(buf, len, style, result); -} - -// Utility function to obtain font path associated with run. -const std::string& getFontPath(const FontCollection::Run& run) { - EXPECT_NE(nullptr, run.fakedFont.font); - return ((MinikinFontForTest*)run.fakedFont.font)->fontPath(); -} - -// Utility function to obtain FontLanguages from string. -const FontLanguages& registerAndGetFontLanguages( - const std::string& lang_string) { - std::scoped_lock _l(gMinikinLock); - return FontLanguageListCache::getById( - FontLanguageListCache::getId(lang_string)); -} - -TEST_F(FontCollectionItemizeTest, itemize_latin) { - std::shared_ptr collection( - getFontCollection(kTestFontDir, kItemizeFontXml)); - std::vector runs; - - const FontStyle kRegularStyle = FontStyle(); - const FontStyle kItalicStyle = FontStyle(4, true); - const FontStyle kBoldStyle = FontStyle(7, false); - const FontStyle kBoldItalicStyle = FontStyle(7, true); - - itemize(collection, "'a' 'b' 'c' 'd' 'e'", kRegularStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(5, runs[0].end); - EXPECT_EQ(kLatinFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - itemize(collection, "'a' 'b' 'c' 'd' 'e'", kItalicStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(5, runs[0].end); - EXPECT_EQ(kLatinItalicFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - itemize(collection, "'a' 'b' 'c' 'd' 'e'", kBoldStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(5, runs[0].end); - EXPECT_EQ(kLatinBoldFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - itemize(collection, "'a' 'b' 'c' 'd' 'e'", kBoldItalicStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(5, runs[0].end); - EXPECT_EQ(kLatinBoldItalicFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - // Continue if the specific characters (e.g. hyphen, comma, etc.) is - // followed. - itemize(collection, "'a' ',' '-' 'd' '!'", kRegularStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(5, runs[0].end); - EXPECT_EQ(kLatinFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - itemize(collection, "'a' ',' '-' 'd' '!'", kRegularStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(5, runs[0].end); - EXPECT_EQ(kLatinFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - // U+0301(COMBINING ACUTE ACCENT) must be in the same run with preceding - // chars if the font supports it. - itemize(collection, "'a' U+0301", kRegularStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kLatinFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); -} - -TEST_F(FontCollectionItemizeTest, itemize_emoji) { - std::shared_ptr collection( - getFontCollection(kTestFontDir, kItemizeFontXml)); - std::vector runs; - - itemize(collection, "U+1F469 U+1F467", FontStyle(), &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(4, runs[0].end); - EXPECT_EQ(kEmojiFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - // U+20E3(COMBINING ENCLOSING KEYCAP) must be in the same run with preceding - // character if the font supports. - itemize(collection, "'0' U+20E3", FontStyle(), &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kEmojiFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - itemize(collection, "U+1F470 U+20E3", FontStyle(), &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(3, runs[0].end); - EXPECT_EQ(kEmojiFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - itemize(collection, "U+242EE U+1F470 U+20E3", FontStyle(), &runs); - ASSERT_EQ(2U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kJAFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - EXPECT_EQ(2, runs[1].start); - EXPECT_EQ(5, runs[1].end); - EXPECT_EQ(kEmojiFont, getFontPath(runs[1])); - EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeItalic()); - - // Currently there is no fonts which has a glyph for 'a' + U+20E3, so they - // are splitted into two. - itemize(collection, "'a' U+20E3", FontStyle(), &runs); - ASSERT_EQ(2U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(1, runs[0].end); - EXPECT_EQ(kLatinFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - EXPECT_EQ(1, runs[1].start); - EXPECT_EQ(2, runs[1].end); - EXPECT_EQ(kEmojiFont, getFontPath(runs[1])); - EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeItalic()); -} - -TEST_F(FontCollectionItemizeTest, itemize_non_latin) { - std::shared_ptr collection( - getFontCollection(kTestFontDir, kItemizeFontXml)); - std::vector runs; - - FontStyle kJAStyle = FontStyle(FontStyle::registerLanguageList("ja_JP")); - FontStyle kUSStyle = FontStyle(FontStyle::registerLanguageList("en_US")); - FontStyle kZH_HansStyle = - FontStyle(FontStyle::registerLanguageList("zh_Hans")); - - // All Japanese Hiragana characters. - itemize(collection, "U+3042 U+3044 U+3046 U+3048 U+304A", kUSStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(5, runs[0].end); - EXPECT_EQ(kJAFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - // All Korean Hangul characters. - itemize(collection, "U+B300 U+D55C U+BBFC U+AD6D", kUSStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(4, runs[0].end); - EXPECT_EQ(kKOFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - // All Han characters ja, zh-Hans font having. - // Japanese font should be selected if the specified language is Japanese. - itemize(collection, "U+81ED U+82B1 U+5FCD", kJAStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(3, runs[0].end); - EXPECT_EQ(kJAFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - // Simplified Chinese font should be selected if the specified language is - // Simplified Chinese. - itemize(collection, "U+81ED U+82B1 U+5FCD", kZH_HansStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(3, runs[0].end); - EXPECT_EQ(kZH_HansFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - // Fallbacks to other fonts if there is no glyph in the specified language's - // font. There is no character U+4F60 in Japanese. - itemize(collection, "U+81ED U+4F60 U+5FCD", kJAStyle, &runs); - ASSERT_EQ(3U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(1, runs[0].end); - EXPECT_EQ(kJAFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - EXPECT_EQ(1, runs[1].start); - EXPECT_EQ(2, runs[1].end); - EXPECT_EQ(kZH_HansFont, getFontPath(runs[1])); - EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeItalic()); - - EXPECT_EQ(2, runs[2].start); - EXPECT_EQ(3, runs[2].end); - EXPECT_EQ(kJAFont, getFontPath(runs[2])); - EXPECT_FALSE(runs[2].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[2].fakedFont.fakery.isFakeItalic()); - - // Tone mark. - itemize(collection, "U+4444 U+302D", FontStyle(), &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kZH_HansFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - // Both zh-Hant and ja fonts support U+242EE, but zh-Hans doesn't. - // Here, ja and zh-Hant font should have the same score but ja should be - // selected since it is listed before zh-Hant. - itemize(collection, "U+242EE", kZH_HansStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kJAFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); -} - -TEST_F(FontCollectionItemizeTest, itemize_mixed) { - std::shared_ptr collection( - getFontCollection(kTestFontDir, kItemizeFontXml)); - std::vector runs; - - FontStyle kUSStyle = FontStyle(FontStyle::registerLanguageList("en_US")); - - itemize(collection, "'a' U+4F60 'b' U+4F60 'c'", kUSStyle, &runs); - ASSERT_EQ(5U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(1, runs[0].end); - EXPECT_EQ(kLatinFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - EXPECT_EQ(1, runs[1].start); - EXPECT_EQ(2, runs[1].end); - EXPECT_EQ(kZH_HansFont, getFontPath(runs[1])); - EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeItalic()); - - EXPECT_EQ(2, runs[2].start); - EXPECT_EQ(3, runs[2].end); - EXPECT_EQ(kLatinFont, getFontPath(runs[2])); - EXPECT_FALSE(runs[2].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[2].fakedFont.fakery.isFakeItalic()); - - EXPECT_EQ(3, runs[3].start); - EXPECT_EQ(4, runs[3].end); - EXPECT_EQ(kZH_HansFont, getFontPath(runs[3])); - EXPECT_FALSE(runs[3].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[3].fakedFont.fakery.isFakeItalic()); - - EXPECT_EQ(4, runs[4].start); - EXPECT_EQ(5, runs[4].end); - EXPECT_EQ(kLatinFont, getFontPath(runs[4])); - EXPECT_FALSE(runs[4].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[4].fakedFont.fakery.isFakeItalic()); -} - -TEST_F(FontCollectionItemizeTest, itemize_variationSelector) { - std::shared_ptr collection( - getFontCollection(kTestFontDir, kItemizeFontXml)); - std::vector runs; - - // A glyph for U+4FAE is provided by both Japanese font and Simplified - // Chinese font. Also a glyph for U+242EE is provided by both Japanese and - // Traditional Chinese font. To avoid effects of device default locale, - // explicitly specify the locale. - FontStyle kZH_HansStyle = - FontStyle(FontStyle::registerLanguageList("zh_Hans")); - FontStyle kZH_HantStyle = - FontStyle(FontStyle::registerLanguageList("zh_Hant")); - - // U+4FAE is available in both zh_Hans and ja font, but U+4FAE,U+FE00 is - // only available in ja font. - itemize(collection, "U+4FAE", kZH_HansStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(1, runs[0].end); - EXPECT_EQ(kZH_HansFont, getFontPath(runs[0])); - - itemize(collection, "U+4FAE U+FE00", kZH_HansStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kJAFont, getFontPath(runs[0])); - - itemize(collection, "U+4FAE U+4FAE U+FE00", kZH_HansStyle, &runs); - ASSERT_EQ(2U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(1, runs[0].end); - EXPECT_EQ(kZH_HansFont, getFontPath(runs[0])); - EXPECT_EQ(1, runs[1].start); - EXPECT_EQ(3, runs[1].end); - EXPECT_EQ(kJAFont, getFontPath(runs[1])); - - itemize(collection, "U+4FAE U+4FAE U+FE00 U+4FAE", kZH_HansStyle, &runs); - ASSERT_EQ(3U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(1, runs[0].end); - EXPECT_EQ(kZH_HansFont, getFontPath(runs[0])); - EXPECT_EQ(1, runs[1].start); - EXPECT_EQ(3, runs[1].end); - EXPECT_EQ(kJAFont, getFontPath(runs[1])); - EXPECT_EQ(3, runs[2].start); - EXPECT_EQ(4, runs[2].end); - EXPECT_EQ(kZH_HansFont, getFontPath(runs[2])); - - // Validation selector after validation selector. - itemize(collection, "U+4FAE U+FE00 U+FE00", kZH_HansStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(3, runs[0].end); - EXPECT_EQ(kJAFont, getFontPath(runs[1])); - - // No font supports U+242EE U+FE0E. - itemize(collection, "U+4FAE U+FE0E", kZH_HansStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kZH_HansFont, getFontPath(runs[0])); - - // Surrogate pairs handling. - // U+242EE is available in ja font and zh_Hant font. - // U+242EE U+FE00 is available only in ja font. - itemize(collection, "U+242EE", kZH_HantStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kZH_HantFont, getFontPath(runs[0])); - - itemize(collection, "U+242EE U+FE00", kZH_HantStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(3, runs[0].end); - EXPECT_EQ(kJAFont, getFontPath(runs[0])); - - itemize(collection, "U+242EE U+242EE U+FE00", kZH_HantStyle, &runs); - ASSERT_EQ(2U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kZH_HantFont, getFontPath(runs[0])); - EXPECT_EQ(2, runs[1].start); - EXPECT_EQ(5, runs[1].end); - EXPECT_EQ(kJAFont, getFontPath(runs[1])); - - itemize(collection, "U+242EE U+242EE U+FE00 U+242EE", kZH_HantStyle, &runs); - ASSERT_EQ(3U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kZH_HantFont, getFontPath(runs[0])); - EXPECT_EQ(2, runs[1].start); - EXPECT_EQ(5, runs[1].end); - EXPECT_EQ(kJAFont, getFontPath(runs[1])); - EXPECT_EQ(5, runs[2].start); - EXPECT_EQ(7, runs[2].end); - EXPECT_EQ(kZH_HantFont, getFontPath(runs[2])); - - // Validation selector after validation selector. - itemize(collection, "U+242EE U+FE00 U+FE00", kZH_HansStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(4, runs[0].end); - EXPECT_EQ(kJAFont, getFontPath(runs[0])); - - // No font supports U+242EE U+FE0E - itemize(collection, "U+242EE U+FE0E", kZH_HantStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(3, runs[0].end); - EXPECT_EQ(kZH_HantFont, getFontPath(runs[0])); - - // Isolated variation selector supplement. - itemize(collection, "U+FE00", FontStyle(), &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(1, runs[0].end); - EXPECT_TRUE(runs[0].fakedFont.font == nullptr || - kLatinFont == getFontPath(runs[0])); - - itemize(collection, "U+FE00", kZH_HantStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(1, runs[0].end); - EXPECT_TRUE(runs[0].fakedFont.font == nullptr || - kLatinFont == getFontPath(runs[0])); - - // First font family (Regular.ttf) supports U+203C but doesn't support U+203C - // U+FE0F. Emoji.ttf font supports U+203C U+FE0F. Emoji.ttf should be - // selected. - itemize(collection, "U+203C U+FE0F", kZH_HantStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kEmojiFont, getFontPath(runs[0])); - - // First font family (Regular.ttf) supports U+203C U+FE0E. - itemize(collection, "U+203C U+FE0E", kZH_HantStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kLatinFont, getFontPath(runs[0])); -} - -TEST_F(FontCollectionItemizeTest, itemize_variationSelectorSupplement) { - std::shared_ptr collection( - getFontCollection(kTestFontDir, kItemizeFontXml)); - std::vector runs; - - // A glyph for U+845B is provided by both Japanese font and Simplified - // Chinese font. Also a glyph for U+242EE is provided by both Japanese and - // Traditional Chinese font. To avoid effects of device default locale, - // explicitly specify the locale. - FontStyle kZH_HansStyle = - FontStyle(FontStyle::registerLanguageList("zh_Hans")); - FontStyle kZH_HantStyle = - FontStyle(FontStyle::registerLanguageList("zh_Hant")); - - // U+845B is available in both zh_Hans and ja font, but U+845B,U+E0100 is - // only available in ja font. - itemize(collection, "U+845B", kZH_HansStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(1, runs[0].end); - EXPECT_EQ(kZH_HansFont, getFontPath(runs[0])); - - itemize(collection, "U+845B U+E0100", kZH_HansStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(3, runs[0].end); - EXPECT_EQ(kJAFont, getFontPath(runs[0])); - - itemize(collection, "U+845B U+845B U+E0100", kZH_HansStyle, &runs); - ASSERT_EQ(2U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(1, runs[0].end); - EXPECT_EQ(kZH_HansFont, getFontPath(runs[0])); - EXPECT_EQ(1, runs[1].start); - EXPECT_EQ(4, runs[1].end); - EXPECT_EQ(kJAFont, getFontPath(runs[1])); - - itemize(collection, "U+845B U+845B U+E0100 U+845B", kZH_HansStyle, &runs); - ASSERT_EQ(3U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(1, runs[0].end); - EXPECT_EQ(kZH_HansFont, getFontPath(runs[0])); - EXPECT_EQ(1, runs[1].start); - EXPECT_EQ(4, runs[1].end); - EXPECT_EQ(kJAFont, getFontPath(runs[1])); - EXPECT_EQ(4, runs[2].start); - EXPECT_EQ(5, runs[2].end); - EXPECT_EQ(kZH_HansFont, getFontPath(runs[2])); - - // Validation selector after validation selector. - itemize(collection, "U+845B U+E0100 U+E0100", kZH_HansStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(5, runs[0].end); - EXPECT_EQ(kJAFont, getFontPath(runs[0])); - - // No font supports U+845B U+E01E0. - itemize(collection, "U+845B U+E01E0", kZH_HansStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(3, runs[0].end); - EXPECT_EQ(kZH_HansFont, getFontPath(runs[0])); - - // Isolated variation selector supplement - // Surrogate pairs handling. - // U+242EE is available in ja font and zh_Hant font. - // U+242EE U+E0100 is available only in ja font. - itemize(collection, "U+242EE", kZH_HantStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kZH_HantFont, getFontPath(runs[0])); - - itemize(collection, "U+242EE U+E0101", kZH_HantStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(4, runs[0].end); - EXPECT_EQ(kJAFont, getFontPath(runs[0])); - - itemize(collection, "U+242EE U+242EE U+E0101", kZH_HantStyle, &runs); - ASSERT_EQ(2U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kZH_HantFont, getFontPath(runs[0])); - EXPECT_EQ(2, runs[1].start); - EXPECT_EQ(6, runs[1].end); - EXPECT_EQ(kJAFont, getFontPath(runs[1])); - - itemize(collection, "U+242EE U+242EE U+E0101 U+242EE", kZH_HantStyle, &runs); - ASSERT_EQ(3U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kZH_HantFont, getFontPath(runs[0])); - EXPECT_EQ(2, runs[1].start); - EXPECT_EQ(6, runs[1].end); - EXPECT_EQ(kJAFont, getFontPath(runs[1])); - EXPECT_EQ(6, runs[2].start); - EXPECT_EQ(8, runs[2].end); - EXPECT_EQ(kZH_HantFont, getFontPath(runs[2])); - - // Validation selector after validation selector. - itemize(collection, "U+242EE U+E0100 U+E0100", kZH_HantStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(6, runs[0].end); - EXPECT_EQ(kJAFont, getFontPath(runs[0])); - - // No font supports U+242EE U+E01E0. - itemize(collection, "U+242EE U+E01E0", kZH_HantStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(4, runs[0].end); - EXPECT_EQ(kZH_HantFont, getFontPath(runs[0])); - - // Isolated variation selector supplement. - itemize(collection, "U+E0100", FontStyle(), &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_TRUE(runs[0].fakedFont.font == nullptr || - kLatinFont == getFontPath(runs[0])); - - itemize(collection, "U+E0100", kZH_HantStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_TRUE(runs[0].fakedFont.font == nullptr || - kLatinFont == getFontPath(runs[0])); -} - -TEST_F(FontCollectionItemizeTest, itemize_no_crash) { - std::shared_ptr collection( - getFontCollection(kTestFontDir, kItemizeFontXml)); - std::vector runs; - - // Broken Surrogate pairs. Check only not crashing. - itemize(collection, "'a' U+D83D 'a'", FontStyle(), &runs); - itemize(collection, "'a' U+DC69 'a'", FontStyle(), &runs); - itemize(collection, "'a' U+D83D U+D83D 'a'", FontStyle(), &runs); - itemize(collection, "'a' U+DC69 U+DC69 'a'", FontStyle(), &runs); - - // Isolated variation selector. Check only not crashing. - itemize(collection, "U+FE00 U+FE00", FontStyle(), &runs); - itemize(collection, "U+E0100 U+E0100", FontStyle(), &runs); - itemize(collection, "U+FE00 U+E0100", FontStyle(), &runs); - itemize(collection, "U+E0100 U+FE00", FontStyle(), &runs); - - // Tone mark only. Check only not crashing. - itemize(collection, "U+302D", FontStyle(), &runs); - itemize(collection, "U+302D U+302D", FontStyle(), &runs); - - // Tone mark and variation selector mixed. Check only not crashing. - itemize(collection, "U+FE00 U+302D U+E0100", FontStyle(), &runs); -} - -TEST_F(FontCollectionItemizeTest, itemize_fakery) { - std::shared_ptr collection( - getFontCollection(kTestFontDir, kItemizeFontXml)); - std::vector runs; - - FontStyle kJABoldStyle = - FontStyle(FontStyle::registerLanguageList("ja_JP"), 0, 7, false); - FontStyle kJAItalicStyle = - FontStyle(FontStyle::registerLanguageList("ja_JP"), 0, 5, true); - FontStyle kJABoldItalicStyle = - FontStyle(FontStyle::registerLanguageList("ja_JP"), 0, 7, true); - - // Currently there is no italic or bold font for Japanese. FontFakery has - // the differences between desired and actual font style. - - // All Japanese Hiragana characters. - itemize(collection, "U+3042 U+3044 U+3046 U+3048 U+304A", kJABoldStyle, - &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(5, runs[0].end); - EXPECT_EQ(kJAFont, getFontPath(runs[0])); - EXPECT_TRUE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic()); - - // All Japanese Hiragana characters. - itemize(collection, "U+3042 U+3044 U+3046 U+3048 U+304A", kJAItalicStyle, - &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(5, runs[0].end); - EXPECT_EQ(kJAFont, getFontPath(runs[0])); - EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_TRUE(runs[0].fakedFont.fakery.isFakeItalic()); - - // All Japanese Hiragana characters. - itemize(collection, "U+3042 U+3044 U+3046 U+3048 U+304A", kJABoldItalicStyle, - &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(5, runs[0].end); - EXPECT_EQ(kJAFont, getFontPath(runs[0])); - EXPECT_TRUE(runs[0].fakedFont.fakery.isFakeBold()); - EXPECT_TRUE(runs[0].fakedFont.fakery.isFakeItalic()); -} - -TEST_F(FontCollectionItemizeTest, itemize_vs_sequence_but_no_base_char) { - // kVSTestFont supports U+717D U+FE02 but doesn't support U+717D. - // kVSTestFont should be selected for U+717D U+FE02 even if it does not - // support the base code point. - const std::string kVSTestFont = - kTestFontDir "VariationSelectorTest-Regular.ttf"; - - std::vector> families; - std::shared_ptr font(new MinikinFontForTest(kLatinFont)); - std::shared_ptr family1(new FontFamily( - VARIANT_DEFAULT, std::vector{Font(font, FontStyle())})); - families.push_back(family1); - - std::shared_ptr font2(new MinikinFontForTest(kVSTestFont)); - std::shared_ptr family2(new FontFamily( - VARIANT_DEFAULT, std::vector{Font(font2, FontStyle())})); - families.push_back(family2); - - std::shared_ptr collection(new FontCollection(families)); - - std::vector runs; - - itemize(collection, "U+717D U+FE02", FontStyle(), &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kVSTestFont, getFontPath(runs[0])); -} - -TEST_F(FontCollectionItemizeTest, itemize_LanguageScore) { - struct TestCase { - std::string userPreferredLanguages; - std::vector fontLanguages; - int selectedFontIndex; - } testCases[] = { - // Font can specify empty language. - {"und", {"", ""}, 0}, - {"und", {"", "en-Latn"}, 0}, - {"en-Latn", {"", ""}, 0}, - {"en-Latn", {"", "en-Latn"}, 1}, - - // Single user preferred language. - // Exact match case - {"en-Latn", {"en-Latn", "ja-Jpan"}, 0}, - {"ja-Jpan", {"en-Latn", "ja-Jpan"}, 1}, - {"en-Latn", {"en-Latn", "nl-Latn", "es-Latn"}, 0}, - {"nl-Latn", {"en-Latn", "nl-Latn", "es-Latn"}, 1}, - {"es-Latn", {"en-Latn", "nl-Latn", "es-Latn"}, 2}, - {"es-Latn", {"en-Latn", "en-Latn", "nl-Latn"}, 0}, - - // Exact script match case - {"en-Latn", {"nl-Latn", "e-Latn"}, 0}, - {"en-Arab", {"nl-Latn", "ar-Arab"}, 1}, - {"en-Latn", {"be-Latn", "ar-Arab", "d-Beng"}, 0}, - {"en-Arab", {"be-Latn", "ar-Arab", "d-Beng"}, 1}, - {"en-Beng", {"be-Latn", "ar-Arab", "d-Beng"}, 2}, - {"en-Beng", {"be-Latn", "ar-Beng", "d-Beng"}, 1}, - {"zh-Hant", {"zh-Hant", "zh-Hans"}, 0}, - {"zh-Hans", {"zh-Hant", "zh-Hans"}, 1}, - - // Subscript match case, e.g. Jpan supports Hira. - {"en-Hira", {"ja-Jpan"}, 0}, - {"zh-Hani", {"zh-Hans", "zh-Hant"}, 0}, - {"zh-Hani", {"zh-Hant", "zh-Hans"}, 0}, - {"en-Hira", {"zh-Hant", "ja-Jpan", "ja-Jpan"}, 1}, - - // Language match case - {"ja-Latn", {"zh-Latn", "ja-Latn"}, 1}, - {"zh-Latn", {"zh-Latn", "ja-Latn"}, 0}, - {"ja-Latn", {"zh-Latn", "ja-Latn"}, 1}, - {"ja-Latn", {"zh-Latn", "ja-Latn", "ja-Latn"}, 1}, - - // Mixed case - // Script/subscript match is strongest. - {"ja-Jpan", {"en-Latn", "ja-Latn", "en-Jpan"}, 2}, - {"ja-Hira", {"en-Latn", "ja-Latn", "en-Jpan"}, 2}, - {"ja-Hira", {"en-Latn", "ja-Latn", "en-Jpan", "en-Jpan"}, 2}, - - // Language match only happens if the script matches. - {"ja-Hira", {"en-Latn", "ja-Latn"}, 0}, - {"ja-Hira", {"en-Jpan", "ja-Jpan"}, 1}, - - // Multiple languages. - // Even if all fonts have the same score, use the 2nd language for better - // selection. - {"en-Latn,ja-Jpan", {"zh-Hant", "zh-Hans", "ja-Jpan"}, 2}, - {"en-Latn,nl-Latn", {"es-Latn", "be-Latn", "nl-Latn"}, 2}, - {"en-Latn,br-Latn,nl-Latn", {"es-Latn", "be-Latn", "nl-Latn"}, 2}, - {"en-Latn,br-Latn,nl-Latn", - {"es-Latn", "be-Latn", "nl-Latn", "nl-Latn"}, - 2}, - - // Script score. - {"en-Latn,ja-Jpan", {"en-Arab", "en-Jpan"}, 1}, - {"en-Latn,ja-Jpan", {"en-Arab", "en-Jpan", "en-Jpan"}, 1}, - - // Language match case - {"en-Latn,ja-Latn", {"bd-Latn", "ja-Latn"}, 1}, - {"en-Latn,ja-Latn", {"bd-Latn", "ja-Latn", "ja-Latn"}, 1}, - - // Language match only happens if the script matches. - {"en-Latn,ar-Arab", {"en-Beng", "ar-Arab"}, 1}, - - // Multiple languages in the font settings. - {"ko-Jamo", {"ja-Jpan", "ko-Kore", "ko-Kore,ko-Jamo"}, 2}, - {"en-Latn", {"ja-Jpan", "en-Latn,ja-Jpan"}, 1}, - {"en-Latn", {"ja-Jpan", "ja-Jpan,en-Latn"}, 1}, - {"en-Latn", {"ja-Jpan,zh-Hant", "en-Latn,ja-Jpan", "en-Latn"}, 1}, - {"en-Latn", {"zh-Hant,ja-Jpan", "ja-Jpan,en-Latn", "en-Latn"}, 1}, - - // Kore = Hang + Hani, etc. - {"ko-Kore", {"ko-Hang", "ko-Jamo,ko-Hani", "ko-Hang,ko-Hani"}, 2}, - {"ja-Hrkt", {"ja-Hira", "ja-Kana", "ja-Hira,ja-Kana"}, 2}, - {"ja-Jpan", - {"ja-Hira", "ja-Kana", "ja-Hani", "ja-Hira,ja-Kana,ja-Hani"}, - 3}, - {"zh-Hanb", {"zh-Hant", "zh-Bopo", "zh-Hant,zh-Bopo"}, 2}, - {"zh-Hanb", {"ja-Hanb", "zh-Hant,zh-Bopo"}, 1}, - - // Language match with unified subscript bits. - {"zh-Hanb", - {"zh-Hant", "zh-Bopo", "ja-Hant,ja-Bopo", "zh-Hant,zh-Bopo"}, - 3}, - {"zh-Hanb", - {"zh-Hant", "zh-Bopo", "ja-Hant,zh-Bopo", "zh-Hant,zh-Bopo"}, - 3}, - - // Two elements subtag matching: language and subtag or language or - // script. - {"ja-Kana-u-em-emoji", {"zh-Hant", "ja-Kana"}, 1}, - {"ja-Kana-u-em-emoji", {"zh-Hant", "ja-Kana", "ja-Zsye"}, 2}, - {"ja-Zsym-u-em-emoji", {"ja-Kana", "ja-Zsym", "ja-Zsye"}, 2}, - - // One element subtag matching: subtag only or script only. - {"en-Latn-u-em-emoji", {"ja-Latn", "ja-Zsye"}, 1}, - {"en-Zsym-u-em-emoji", {"ja-Zsym", "ja-Zsye"}, 1}, - {"en-Zsye-u-em-text", {"ja-Zsym", "ja-Zsye"}, 0}, - - // Multiple languages list with subtags. - {"en-Latn,ja-Jpan-u-em-text", {"en-Latn", "en-Zsye", "en-Zsym"}, 0}, - {"en-Latn,en-Zsye,ja-Jpan-u-em-text", {"zh", "en-Zsye", "en-Zsym"}, 1}, - }; - - for (auto testCase : testCases) { - std::string fontLanguagesStr = "{"; - for (size_t i = 0; i < testCase.fontLanguages.size(); ++i) { - if (i != 0) { - fontLanguagesStr += ", "; - } - fontLanguagesStr += "\"" + testCase.fontLanguages[i] + "\""; - } - fontLanguagesStr += "}"; - SCOPED_TRACE("Test of user preferred languages: \"" + - testCase.userPreferredLanguages + - "\" with font languages: " + fontLanguagesStr); - - std::vector> families; - - // Prepare first font which doesn't supports U+9AA8 - std::shared_ptr firstFamilyMinikinFont( - new MinikinFontForTest(kNoGlyphFont)); - std::shared_ptr firstFamily(new FontFamily( - FontStyle::registerLanguageList("und"), 0 /* variant */, - std::vector({Font(firstFamilyMinikinFont, FontStyle())}))); - families.push_back(firstFamily); - - // Prepare font families - // Each font family is associated with a specified language. All font - // families except for the first font support U+9AA8. - std::unordered_map fontLangIdxMap; - - for (size_t i = 0; i < testCase.fontLanguages.size(); ++i) { - std::shared_ptr minikin_font( - new MinikinFontForTest(kJAFont)); - std::shared_ptr family(new FontFamily( - FontStyle::registerLanguageList(testCase.fontLanguages[i]), - 0 /* variant */, - std::vector({Font(minikin_font, FontStyle())}))); - families.push_back(family); - fontLangIdxMap.insert(std::make_pair(minikin_font.get(), i)); - } - std::shared_ptr collection(new FontCollection(families)); - // Do itemize - const FontStyle style = FontStyle( - FontStyle::registerLanguageList(testCase.userPreferredLanguages)); - std::vector runs; - itemize(collection, "U+9AA8", style, &runs); - ASSERT_EQ(1U, runs.size()); - ASSERT_NE(nullptr, runs[0].fakedFont.font); - - // First family doesn't support U+9AA8 and others support it, so the first - // font should not be selected. - EXPECT_NE(firstFamilyMinikinFont.get(), runs[0].fakedFont.font); - - // Lookup used font family by MinikinFont*. - const int usedLangIndex = fontLangIdxMap[runs[0].fakedFont.font]; - EXPECT_EQ(testCase.selectedFontIndex, usedLangIndex); - } -} - -TEST_F(FontCollectionItemizeTest, itemize_LanguageAndCoverage) { - struct TestCase { - std::string testString; - std::string requestedLanguages; - std::string expectedFont; - } testCases[] = { - // Following test cases verify that following rules in font fallback - // chain. - // - If the first font in the collection supports the given character or - // variation sequence, - // it should be selected. - // - If the font doesn't support the given character, variation sequence - // or its base - // character, it should not be selected. - // - If two or more fonts match the requested languages, the font matches - // with the highest - // priority language should be selected. - // - If two or more fonts get the same score, the font listed earlier in - // the XML file - // (here, kItemizeFontXml) should be selected. - - // Regardless of language, the first font is always selected if it covers - // the code point. - {"'a'", "", kLatinFont}, - {"'a'", "en-Latn", kLatinFont}, - {"'a'", "ja-Jpan", kLatinFont}, - {"'a'", "ja-Jpan,en-Latn", kLatinFont}, - {"'a'", "zh-Hans,zh-Hant,en-Latn,ja-Jpan,fr-Latn", kLatinFont}, - - // U+81ED is supported by both the ja font and zh-Hans font. - {"U+81ED", "", kZH_HansFont}, // zh-Hans font is listed before ja font. - {"U+81ED", "en-Latn", - kZH_HansFont}, // zh-Hans font is listed before ja font. - {"U+81ED", "ja-Jpan", kJAFont}, - {"U+81ED", "zh-Hans", kZH_HansFont}, - - {"U+81ED", "ja-Jpan,en-Latn", kJAFont}, - {"U+81ED", "en-Latn,ja-Jpan", kJAFont}, - {"U+81ED", "en-Latn,zh-Hans", kZH_HansFont}, - {"U+81ED", "zh-Hans,en-Latn", kZH_HansFont}, - {"U+81ED", "ja-Jpan,zh-Hans", kJAFont}, - {"U+81ED", "zh-Hans,ja-Jpan", kZH_HansFont}, - - {"U+81ED", "en-Latn,zh-Hans,ja-Jpan", kZH_HansFont}, - {"U+81ED", "en-Latn,ja-Jpan,zh-Hans", kJAFont}, - {"U+81ED", "en-Latn,zh-Hans,ja-Jpan", kZH_HansFont}, - {"U+81ED", "ja-Jpan,en-Latn,zh-Hans", kJAFont}, - {"U+81ED", "ja-Jpan,zh-Hans,en-Latn", kJAFont}, - {"U+81ED", "zh-Hans,en-Latn,ja-Jpan", kZH_HansFont}, - {"U+81ED", "zh-Hans,ja-Jpan,en-Latn", kZH_HansFont}, - - // U+304A is only supported by ja font. - {"U+304A", "", kJAFont}, - {"U+304A", "ja-Jpan", kJAFont}, - {"U+304A", "zh-Hant", kJAFont}, - {"U+304A", "zh-Hans", kJAFont}, - - {"U+304A", "ja-Jpan,zh-Hant", kJAFont}, - {"U+304A", "zh-Hant,ja-Jpan", kJAFont}, - {"U+304A", "zh-Hans,zh-Hant", kJAFont}, - {"U+304A", "zh-Hant,zh-Hans", kJAFont}, - {"U+304A", "zh-Hans,ja-Jpan", kJAFont}, - {"U+304A", "ja-Jpan,zh-Hans", kJAFont}, - - {"U+304A", "zh-Hans,ja-Jpan,zh-Hant", kJAFont}, - {"U+304A", "zh-Hans,zh-Hant,ja-Jpan", kJAFont}, - {"U+304A", "ja-Jpan,zh-Hans,zh-Hant", kJAFont}, - {"U+304A", "ja-Jpan,zh-Hant,zh-Hans", kJAFont}, - {"U+304A", "zh-Hant,zh-Hans,ja-Jpan", kJAFont}, - {"U+304A", "zh-Hant,ja-Jpan,zh-Hans", kJAFont}, - - // U+242EE is supported by both ja font and zh-Hant fonts but not by - // zh-Hans font. - {"U+242EE", "", kJAFont}, // ja font is listed before zh-Hant font. - {"U+242EE", "ja-Jpan", kJAFont}, - {"U+242EE", "zh-Hans", kJAFont}, - {"U+242EE", "zh-Hant", kZH_HantFont}, - - {"U+242EE", "ja-Jpan,zh-Hant", kJAFont}, - {"U+242EE", "zh-Hant,ja-Jpan", kZH_HantFont}, - {"U+242EE", "zh-Hans,zh-Hant", kZH_HantFont}, - {"U+242EE", "zh-Hant,zh-Hans", kZH_HantFont}, - {"U+242EE", "zh-Hans,ja-Jpan", kJAFont}, - {"U+242EE", "ja-Jpan,zh-Hans", kJAFont}, - - {"U+242EE", "zh-Hans,ja-Jpan,zh-Hant", kJAFont}, - {"U+242EE", "zh-Hans,zh-Hant,ja-Jpan", kZH_HantFont}, - {"U+242EE", "ja-Jpan,zh-Hans,zh-Hant", kJAFont}, - {"U+242EE", "ja-Jpan,zh-Hant,zh-Hans", kJAFont}, - {"U+242EE", "zh-Hant,zh-Hans,ja-Jpan", kZH_HantFont}, - {"U+242EE", "zh-Hant,ja-Jpan,zh-Hans", kZH_HantFont}, - - // U+9AA8 is supported by all ja-Jpan, zh-Hans, zh-Hant fonts. - {"U+9AA8", "", - kZH_HansFont}, // zh-Hans font is listed before ja and zh-Hant fonts. - {"U+9AA8", "ja-Jpan", kJAFont}, - {"U+9AA8", "zh-Hans", kZH_HansFont}, - {"U+9AA8", "zh-Hant", kZH_HantFont}, - - {"U+9AA8", "ja-Jpan,zh-Hant", kJAFont}, - {"U+9AA8", "zh-Hant,ja-Jpan", kZH_HantFont}, - {"U+9AA8", "zh-Hans,zh-Hant", kZH_HansFont}, - {"U+9AA8", "zh-Hant,zh-Hans", kZH_HantFont}, - {"U+9AA8", "zh-Hans,ja-Jpan", kZH_HansFont}, - {"U+9AA8", "ja-Jpan,zh-Hans", kJAFont}, - - {"U+9AA8", "zh-Hans,ja-Jpan,zh-Hant", kZH_HansFont}, - {"U+9AA8", "zh-Hans,zh-Hant,ja-Jpan", kZH_HansFont}, - {"U+9AA8", "ja-Jpan,zh-Hans,zh-Hant", kJAFont}, - {"U+9AA8", "ja-Jpan,zh-Hant,zh-Hans", kJAFont}, - {"U+9AA8", "zh-Hant,zh-Hans,ja-Jpan", kZH_HantFont}, - {"U+9AA8", "zh-Hant,ja-Jpan,zh-Hans", kZH_HantFont}, - - // U+242EE U+FE00 is supported by ja font but not by zh-Hans or zh-Hant - // fonts. - {"U+242EE U+FE00", "", kJAFont}, - {"U+242EE U+FE00", "ja-Jpan", kJAFont}, - {"U+242EE U+FE00", "zh-Hant", kJAFont}, - {"U+242EE U+FE00", "zh-Hans", kJAFont}, - - {"U+242EE U+FE00", "ja-Jpan,zh-Hant", kJAFont}, - {"U+242EE U+FE00", "zh-Hant,ja-Jpan", kJAFont}, - {"U+242EE U+FE00", "zh-Hans,zh-Hant", kJAFont}, - {"U+242EE U+FE00", "zh-Hant,zh-Hans", kJAFont}, - {"U+242EE U+FE00", "zh-Hans,ja-Jpan", kJAFont}, - {"U+242EE U+FE00", "ja-Jpan,zh-Hans", kJAFont}, - - {"U+242EE U+FE00", "zh-Hans,ja-Jpan,zh-Hant", kJAFont}, - {"U+242EE U+FE00", "zh-Hans,zh-Hant,ja-Jpan", kJAFont}, - {"U+242EE U+FE00", "ja-Jpan,zh-Hans,zh-Hant", kJAFont}, - {"U+242EE U+FE00", "ja-Jpan,zh-Hant,zh-Hans", kJAFont}, - {"U+242EE U+FE00", "zh-Hant,zh-Hans,ja-Jpan", kJAFont}, - {"U+242EE U+FE00", "zh-Hant,ja-Jpan,zh-Hans", kJAFont}, - - // U+3402 U+E0100 is supported by both zh-Hans and zh-Hant but not by ja - // font. - {"U+3402 U+E0100", "", - kZH_HansFont}, // zh-Hans font is listed before zh-Hant font. - {"U+3402 U+E0100", "ja-Jpan", - kZH_HansFont}, // zh-Hans font is listed before zh-Hant font. - {"U+3402 U+E0100", "zh-Hant", kZH_HantFont}, - {"U+3402 U+E0100", "zh-Hans", kZH_HansFont}, - - {"U+3402 U+E0100", "ja-Jpan,zh-Hant", kZH_HantFont}, - {"U+3402 U+E0100", "zh-Hant,ja-Jpan", kZH_HantFont}, - {"U+3402 U+E0100", "zh-Hans,zh-Hant", kZH_HansFont}, - {"U+3402 U+E0100", "zh-Hant,zh-Hans", kZH_HantFont}, - {"U+3402 U+E0100", "zh-Hans,ja-Jpan", kZH_HansFont}, - {"U+3402 U+E0100", "ja-Jpan,zh-Hans", kZH_HansFont}, - - {"U+3402 U+E0100", "zh-Hans,ja-Jpan,zh-Hant", kZH_HansFont}, - {"U+3402 U+E0100", "zh-Hans,zh-Hant,ja-Jpan", kZH_HansFont}, - {"U+3402 U+E0100", "ja-Jpan,zh-Hans,zh-Hant", kZH_HansFont}, - {"U+3402 U+E0100", "ja-Jpan,zh-Hant,zh-Hans", kZH_HantFont}, - {"U+3402 U+E0100", "zh-Hant,zh-Hans,ja-Jpan", kZH_HantFont}, - {"U+3402 U+E0100", "zh-Hant,ja-Jpan,zh-Hans", kZH_HantFont}, - - // No font supports U+4444 U+FE00 but only zh-Hans supports its base - // character U+4444. - {"U+4444 U+FE00", "", kZH_HansFont}, - {"U+4444 U+FE00", "ja-Jpan", kZH_HansFont}, - {"U+4444 U+FE00", "zh-Hant", kZH_HansFont}, - {"U+4444 U+FE00", "zh-Hans", kZH_HansFont}, - - {"U+4444 U+FE00", "ja-Jpan,zh-Hant", kZH_HansFont}, - {"U+4444 U+FE00", "zh-Hant,ja-Jpan", kZH_HansFont}, - {"U+4444 U+FE00", "zh-Hans,zh-Hant", kZH_HansFont}, - {"U+4444 U+FE00", "zh-Hant,zh-Hans", kZH_HansFont}, - {"U+4444 U+FE00", "zh-Hans,ja-Jpan", kZH_HansFont}, - {"U+4444 U+FE00", "ja-Jpan,zh-Hans", kZH_HansFont}, - - {"U+4444 U+FE00", "zh-Hans,ja-Jpan,zh-Hant", kZH_HansFont}, - {"U+4444 U+FE00", "zh-Hans,zh-Hant,ja-Jpan", kZH_HansFont}, - {"U+4444 U+FE00", "ja-Jpan,zh-Hans,zh-Hant", kZH_HansFont}, - {"U+4444 U+FE00", "ja-Jpan,zh-Hant,zh-Hans", kZH_HansFont}, - {"U+4444 U+FE00", "zh-Hant,zh-Hans,ja-Jpan", kZH_HansFont}, - {"U+4444 U+FE00", "zh-Hant,ja-Jpan,zh-Hans", kZH_HansFont}, - - // No font supports U+81ED U+E0100 but ja and zh-Hans support its base - // character U+81ED. - // zh-Hans font is listed before ja font. - {"U+81ED U+E0100", "", kZH_HansFont}, - {"U+81ED U+E0100", "ja-Jpan", kJAFont}, - {"U+81ED U+E0100", "zh-Hant", kZH_HansFont}, - {"U+81ED U+E0100", "zh-Hans", kZH_HansFont}, - - {"U+81ED U+E0100", "ja-Jpan,zh-Hant", kJAFont}, - {"U+81ED U+E0100", "zh-Hant,ja-Jpan", kJAFont}, - {"U+81ED U+E0100", "zh-Hans,zh-Hant", kZH_HansFont}, - {"U+81ED U+E0100", "zh-Hant,zh-Hans", kZH_HansFont}, - {"U+81ED U+E0100", "zh-Hans,ja-Jpan", kZH_HansFont}, - {"U+81ED U+E0100", "ja-Jpan,zh-Hans", kJAFont}, - - {"U+81ED U+E0100", "zh-Hans,ja-Jpan,zh-Hant", kZH_HansFont}, - {"U+81ED U+E0100", "zh-Hans,zh-Hant,ja-Jpan", kZH_HansFont}, - {"U+81ED U+E0100", "ja-Jpan,zh-Hans,zh-Hant", kJAFont}, - {"U+81ED U+E0100", "ja-Jpan,zh-Hant,zh-Hans", kJAFont}, - {"U+81ED U+E0100", "zh-Hant,zh-Hans,ja-Jpan", kZH_HansFont}, - {"U+81ED U+E0100", "zh-Hant,ja-Jpan,zh-Hans", kJAFont}, - - // No font supports U+9AA8 U+E0100 but all zh-Hans zh-hant ja fonts - // support its base - // character U+9AA8. - // zh-Hans font is listed before ja and zh-Hant fonts. - {"U+9AA8 U+E0100", "", kZH_HansFont}, - {"U+9AA8 U+E0100", "ja-Jpan", kJAFont}, - {"U+9AA8 U+E0100", "zh-Hans", kZH_HansFont}, - {"U+9AA8 U+E0100", "zh-Hant", kZH_HantFont}, - - {"U+9AA8 U+E0100", "ja-Jpan,zh-Hant", kJAFont}, - {"U+9AA8 U+E0100", "zh-Hant,ja-Jpan", kZH_HantFont}, - {"U+9AA8 U+E0100", "zh-Hans,zh-Hant", kZH_HansFont}, - {"U+9AA8 U+E0100", "zh-Hant,zh-Hans", kZH_HantFont}, - {"U+9AA8 U+E0100", "zh-Hans,ja-Jpan", kZH_HansFont}, - {"U+9AA8 U+E0100", "ja-Jpan,zh-Hans", kJAFont}, - - {"U+9AA8 U+E0100", "zh-Hans,ja-Jpan,zh-Hant", kZH_HansFont}, - {"U+9AA8 U+E0100", "zh-Hans,zh-Hant,ja-Jpan", kZH_HansFont}, - {"U+9AA8 U+E0100", "ja-Jpan,zh-Hans,zh-Hant", kJAFont}, - {"U+9AA8 U+E0100", "ja-Jpan,zh-Hant,zh-Hans", kJAFont}, - {"U+9AA8 U+E0100", "zh-Hant,zh-Hans,ja-Jpan", kZH_HantFont}, - {"U+9AA8 U+E0100", "zh-Hant,ja-Jpan,zh-Hans", kZH_HantFont}, - - // All zh-Hans,zh-Hant,ja fonts support U+35A8 U+E0100 and its base - // character U+35A8. - // zh-Hans font is listed before ja and zh-Hant fonts. - {"U+35A8", "", kZH_HansFont}, - {"U+35A8", "ja-Jpan", kJAFont}, - {"U+35A8", "zh-Hans", kZH_HansFont}, - {"U+35A8", "zh-Hant", kZH_HantFont}, - - {"U+35A8", "ja-Jpan,zh-Hant", kJAFont}, - {"U+35A8", "zh-Hant,ja-Jpan", kZH_HantFont}, - {"U+35A8", "zh-Hans,zh-Hant", kZH_HansFont}, - {"U+35A8", "zh-Hant,zh-Hans", kZH_HantFont}, - {"U+35A8", "zh-Hans,ja-Jpan", kZH_HansFont}, - {"U+35A8", "ja-Jpan,zh-Hans", kJAFont}, - - {"U+35A8", "zh-Hans,ja-Jpan,zh-Hant", kZH_HansFont}, - {"U+35A8", "zh-Hans,zh-Hant,ja-Jpan", kZH_HansFont}, - {"U+35A8", "ja-Jpan,zh-Hans,zh-Hant", kJAFont}, - {"U+35A8", "ja-Jpan,zh-Hant,zh-Hans", kJAFont}, - {"U+35A8", "zh-Hant,zh-Hans,ja-Jpan", kZH_HantFont}, - {"U+35A8", "zh-Hant,ja-Jpan,zh-Hans", kZH_HantFont}, - - // All zh-Hans,zh-Hant,ja fonts support U+35B6 U+E0100, but zh-Hant and ja - // fonts support its - // base character U+35B6. - // ja font is listed before zh-Hant font. - {"U+35B6", "", kJAFont}, - {"U+35B6", "ja-Jpan", kJAFont}, - {"U+35B6", "zh-Hant", kZH_HantFont}, - {"U+35B6", "zh-Hans", kJAFont}, - - {"U+35B6", "ja-Jpan,zh-Hant", kJAFont}, - {"U+35B6", "zh-Hant,ja-Jpan", kZH_HantFont}, - {"U+35B6", "zh-Hans,zh-Hant", kZH_HantFont}, - {"U+35B6", "zh-Hant,zh-Hans", kZH_HantFont}, - {"U+35B6", "zh-Hans,ja-Jpan", kJAFont}, - {"U+35B6", "ja-Jpan,zh-Hans", kJAFont}, - - {"U+35B6", "zh-Hans,ja-Jpan,zh-Hant", kJAFont}, - {"U+35B6", "zh-Hans,zh-Hant,ja-Jpan", kZH_HantFont}, - {"U+35B6", "ja-Jpan,zh-Hans,zh-Hant", kJAFont}, - {"U+35B6", "ja-Jpan,zh-Hant,zh-Hans", kJAFont}, - {"U+35B6", "zh-Hant,zh-Hans,ja-Jpan", kZH_HantFont}, - {"U+35B6", "zh-Hant,ja-Jpan,zh-Hans", kZH_HantFont}, - - // All zh-Hans,zh-Hant,ja fonts support U+35C5 U+E0100, but only ja font - // supports its base - // character U+35C5. - {"U+35C5", "", kJAFont}, - {"U+35C5", "ja-Jpan", kJAFont}, - {"U+35C5", "zh-Hant", kJAFont}, - {"U+35C5", "zh-Hans", kJAFont}, - - {"U+35C5", "ja-Jpan,zh-Hant", kJAFont}, - {"U+35C5", "zh-Hant,ja-Jpan", kJAFont}, - {"U+35C5", "zh-Hans,zh-Hant", kJAFont}, - {"U+35C5", "zh-Hant,zh-Hans", kJAFont}, - {"U+35C5", "zh-Hans,ja-Jpan", kJAFont}, - {"U+35C5", "ja-Jpan,zh-Hans", kJAFont}, - - {"U+35C5", "zh-Hans,ja-Jpan,zh-Hant", kJAFont}, - {"U+35C5", "zh-Hans,zh-Hant,ja-Jpan", kJAFont}, - {"U+35C5", "ja-Jpan,zh-Hans,zh-Hant", kJAFont}, - {"U+35C5", "ja-Jpan,zh-Hant,zh-Hans", kJAFont}, - {"U+35C5", "zh-Hant,zh-Hans,ja-Jpan", kJAFont}, - {"U+35C5", "zh-Hant,ja-Jpan,zh-Hans", kJAFont}, - - // None of ja-Jpan, zh-Hant, zh-Hans font supports U+1F469. Emoji font - // supports it. - {"U+1F469", "", kEmojiFont}, - {"U+1F469", "ja-Jpan", kEmojiFont}, - {"U+1F469", "zh-Hant", kEmojiFont}, - {"U+1F469", "zh-Hans", kEmojiFont}, - - {"U+1F469", "ja-Jpan,zh-Hant", kEmojiFont}, - {"U+1F469", "zh-Hant,ja-Jpan", kEmojiFont}, - {"U+1F469", "zh-Hans,zh-Hant", kEmojiFont}, - {"U+1F469", "zh-Hant,zh-Hans", kEmojiFont}, - {"U+1F469", "zh-Hans,ja-Jpan", kEmojiFont}, - {"U+1F469", "ja-Jpan,zh-Hans", kEmojiFont}, - - {"U+1F469", "zh-Hans,ja-Jpan,zh-Hant", kEmojiFont}, - {"U+1F469", "zh-Hans,zh-Hant,ja-Jpan", kEmojiFont}, - {"U+1F469", "ja-Jpan,zh-Hans,zh-Hant", kEmojiFont}, - {"U+1F469", "ja-Jpan,zh-Hant,zh-Hans", kEmojiFont}, - {"U+1F469", "zh-Hant,zh-Hans,ja-Jpan", kEmojiFont}, - {"U+1F469", "zh-Hant,ja-Jpan,zh-Hans", kEmojiFont}, - }; - - std::shared_ptr collection( - getFontCollection(kTestFontDir, kItemizeFontXml)); - - for (auto testCase : testCases) { - SCOPED_TRACE("Test for \"" + testCase.testString + "\" with languages " + - testCase.requestedLanguages); - - std::vector runs; - const FontStyle style = - FontStyle(FontStyle::registerLanguageList(testCase.requestedLanguages)); - itemize(collection, testCase.testString.c_str(), style, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(testCase.expectedFont, getFontPath(runs[0])); - } -} - -TEST_F(FontCollectionItemizeTest, itemize_emojiSelection_withFE0E) { - std::shared_ptr collection( - getFontCollection(kTestFontDir, kEmojiXmlFile)); - std::vector runs; - - const FontStyle kDefaultFontStyle; - - // U+00A9 is a text default emoji which is only available in - // TextEmojiFont.ttf. TextEmojiFont.ttf should be selected. - itemize(collection, "U+00A9 U+FE0E", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kTextEmojiFont, getFontPath(runs[0])); - - // U+00A9 is a text default emoji which is only available in - // ColorEmojiFont.ttf. ColorEmojiFont.ttf should be selected. - itemize(collection, "U+00AE U+FE0E", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - // Text emoji is specified but it is not available. Use color emoji instead. - EXPECT_EQ(kColorEmojiFont, getFontPath(runs[0])); - - // U+203C is a text default emoji which is available in both TextEmojiFont.ttf - // and ColorEmojiFont.ttf. TextEmojiFont.ttf should be selected. - itemize(collection, "U+203C U+FE0E", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kTextEmojiFont, getFontPath(runs[0])); - - // U+2049 is a text default emoji which is not available either - // TextEmojiFont.ttf or ColorEmojiFont.ttf. No font should be selected. - itemize(collection, "U+2049 U+FE0E", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kNoGlyphFont, getFontPath(runs[0])); - - // U+231A is a emoji default emoji which is available only in TextEmojifFont. - // TextEmojiFont.ttf sohuld be selected. - itemize(collection, "U+231A U+FE0E", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kTextEmojiFont, getFontPath(runs[0])); - - // U+231B is a emoji default emoji which is available only in - // ColorEmojiFont.ttf. ColorEmojiFont.ttf should be selected. - itemize(collection, "U+231B U+FE0E", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - // Text emoji is specified but it is not available. Use color emoji instead. - EXPECT_EQ(kColorEmojiFont, getFontPath(runs[0])); - - // U+23E9 is a emoji default emoji which is available in both - // TextEmojiFont.ttf and ColorEmojiFont.ttf. TextEmojiFont.ttf should be - // selected even if U+23E9 is emoji default emoji since U+FE0E is appended. - itemize(collection, "U+23E9 U+FE0E", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kTextEmojiFont, getFontPath(runs[0])); - - // U+23EA is a emoji default emoji but which is not available in either - // TextEmojiFont.ttf or ColorEmojiFont.ttf. No font should be selected. - itemize(collection, "U+23EA U+FE0E", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kNoGlyphFont, getFontPath(runs[0])); - - // U+26FA U+FE0E is specified but ColorTextMixedEmojiFont has a variation - // sequence U+26F9 U+FE0F in its cmap, so ColorTextMixedEmojiFont should be - // selected instaed of ColorEmojiFont. - itemize(collection, "U+26FA U+FE0E", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kMixedEmojiFont, getFontPath(runs[0])); -} - -TEST_F(FontCollectionItemizeTest, itemize_emojiSelection_withFE0F) { - std::shared_ptr collection( - getFontCollection(kTestFontDir, kEmojiXmlFile)); - std::vector runs; - - const FontStyle kDefaultFontStyle; - - // U+00A9 is a text default emoji which is available only in - // TextEmojiFont.ttf. TextEmojiFont.ttf should be selected. - itemize(collection, "U+00A9 U+FE0F", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - // Color emoji is specified but it is not available. Use text representation - // instead. - EXPECT_EQ(kTextEmojiFont, getFontPath(runs[0])); - - // U+00AE is a text default emoji which is available only in - // ColorEmojiFont.ttf. ColorEmojiFont.ttf should be selected. - itemize(collection, "U+00AE U+FE0F", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kColorEmojiFont, getFontPath(runs[0])); - - // U+203C is a text default emoji which is available in both TextEmojiFont.ttf - // and ColorEmojiFont.ttf. ColorEmojiFont.ttf should be selected even if - // U+203C is a text default emoji since U+FF0F is appended. - itemize(collection, "U+203C U+FE0F", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kColorEmojiFont, getFontPath(runs[0])); - - // U+2049 is a text default emoji which is not available in either - // TextEmojiFont.ttf or ColorEmojiFont.ttf. No font should be selected. - itemize(collection, "U+2049 U+FE0F", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kNoGlyphFont, getFontPath(runs[0])); - - // U+231A is a emoji default emoji which is available only in - // TextEmojiFont.ttf. TextEmojiFont.ttf should be selected. - itemize(collection, "U+231A U+FE0F", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - // Color emoji is specified but it is not available. Use text representation - // instead. - EXPECT_EQ(kTextEmojiFont, getFontPath(runs[0])); - - // U+231B is a emoji default emoji which is available only in - // ColorEmojiFont.ttf. ColorEmojiFont.ttf should be selected. - itemize(collection, "U+231B U+FE0F", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kColorEmojiFont, getFontPath(runs[0])); - - // U+23E9 is a emoji default emoji which is available in both - // TextEmojiFont.ttf and ColorEmojiFont.ttf. ColorEmojiFont.ttf should be - // selected. - itemize(collection, "U+23E9 U+FE0F", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kColorEmojiFont, getFontPath(runs[0])); - - // U+23EA is a emoji default emoji which is not available in either - // TextEmojiFont.ttf or ColorEmojiFont.ttf. No font should be selected. - itemize(collection, "U+23EA U+FE0F", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kNoGlyphFont, getFontPath(runs[0])); - - // U+26F9 U+FE0F is specified but ColorTextMixedEmojiFont has a variation - // sequence U+26F9 U+FE0F in its cmap, so ColorTextMixedEmojiFont should be - // selected instaed of ColorEmojiFont. - itemize(collection, "U+26F9 U+FE0F", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kMixedEmojiFont, getFontPath(runs[0])); -} - -TEST_F(FontCollectionItemizeTest, itemize_emojiSelection_with_skinTone) { - std::shared_ptr collection( - getFontCollection(kTestFontDir, kEmojiXmlFile)); - std::vector runs; - - const FontStyle kDefaultFontStyle; - - // TextEmoji font is selected since it is listed before ColorEmoji font. - itemize(collection, "U+261D", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(1, runs[0].end); - EXPECT_EQ(kTextEmojiFont, getFontPath(runs[0])); - - // If skin tone is specified, it should be colored. - itemize(collection, "U+261D U+1F3FD", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(3, runs[0].end); - EXPECT_EQ(kColorEmojiFont, getFontPath(runs[0])); - - // Still color font is selected if an emoji variation selector is specified. - itemize(collection, "U+261D U+FE0F U+1F3FD", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(4, runs[0].end); - EXPECT_EQ(kColorEmojiFont, getFontPath(runs[0])); - - // Text font should be selected if a text variation selector is specified and - // skin tone is rendered by itself. - itemize(collection, "U+261D U+FE0E U+1F3FD", kDefaultFontStyle, &runs); - ASSERT_EQ(2U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kTextEmojiFont, getFontPath(runs[0])); - EXPECT_EQ(2, runs[1].start); - EXPECT_EQ(4, runs[1].end); - EXPECT_EQ(kColorEmojiFont, getFontPath(runs[1])); -} - -TEST_F(FontCollectionItemizeTest, itemize_PrivateUseArea) { - std::shared_ptr collection( - getFontCollection(kTestFontDir, kEmojiXmlFile)); - std::vector runs; - - const FontStyle kDefaultFontStyle; - - // Should not set nullptr to the result run. (Issue 26808815) - itemize(collection, "U+FEE10", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(2, runs[0].end); - EXPECT_EQ(kNoGlyphFont, getFontPath(runs[0])); - - itemize(collection, "U+FEE40 U+FE4C5", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(4, runs[0].end); - EXPECT_EQ(kNoGlyphFont, getFontPath(runs[0])); -} - -TEST_F(FontCollectionItemizeTest, itemize_genderBalancedEmoji) { - std::shared_ptr collection( - getFontCollection(kTestFontDir, kEmojiXmlFile)); - std::vector runs; - - const FontStyle kDefaultFontStyle; - - itemize(collection, "U+1F469 U+200D U+1F373", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(5, runs[0].end); - EXPECT_EQ(kColorEmojiFont, getFontPath(runs[0])); - - itemize(collection, "U+1F469 U+200D U+2695 U+FE0F", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(5, runs[0].end); - EXPECT_EQ(kColorEmojiFont, getFontPath(runs[0])); - - itemize(collection, "U+1F469 U+200D U+2695", kDefaultFontStyle, &runs); - ASSERT_EQ(1U, runs.size()); - EXPECT_EQ(0, runs[0].start); - EXPECT_EQ(4, runs[0].end); - EXPECT_EQ(kColorEmojiFont, getFontPath(runs[0])); -} - -// For b/29585939 -TEST_F(FontCollectionItemizeTest, itemizeShouldKeepOrderForVS) { - const FontStyle kDefaultFontStyle; - - std::shared_ptr dummyFont(new MinikinFontForTest(kNoGlyphFont)); - std::shared_ptr fontA(new MinikinFontForTest(kZH_HansFont)); - std::shared_ptr fontB(new MinikinFontForTest(kZH_HansFont)); - - std::shared_ptr dummyFamily( - new FontFamily(std::vector({Font(dummyFont, FontStyle())}))); - std::shared_ptr familyA( - new FontFamily(std::vector({Font(fontA, FontStyle())}))); - std::shared_ptr familyB( - new FontFamily(std::vector({Font(fontB, FontStyle())}))); - - std::vector> families = {dummyFamily, familyA, - familyB}; - std::vector> reversedFamilies = { - dummyFamily, familyB, familyA}; - - std::shared_ptr collection(new FontCollection(families)); - std::shared_ptr reversedCollection( - new FontCollection(reversedFamilies)); - - // Both fontA/fontB support U+35A8 but don't support U+35A8 U+E0100. The first - // font should be selected. - std::vector runs; - itemize(collection, "U+35A8 U+E0100", kDefaultFontStyle, &runs); - EXPECT_EQ(fontA.get(), runs[0].fakedFont.font); - - itemize(reversedCollection, "U+35A8 U+E0100", kDefaultFontStyle, &runs); - EXPECT_EQ(fontB.get(), runs[0].fakedFont.font); -} - -// For b/29585939 -TEST_F(FontCollectionItemizeTest, itemizeShouldKeepOrderForVS2) { - const FontStyle kDefaultFontStyle; - - std::shared_ptr dummyFont(new MinikinFontForTest(kNoGlyphFont)); - std::shared_ptr hasCmapFormat14Font( - new MinikinFontForTest(kHasCmapFormat14Font)); - std::shared_ptr noCmapFormat14Font( - new MinikinFontForTest(kNoCmapFormat14Font)); - - std::shared_ptr dummyFamily( - new FontFamily(std::vector({Font(dummyFont, FontStyle())}))); - std::shared_ptr hasCmapFormat14Family(new FontFamily( - std::vector({Font(hasCmapFormat14Font, FontStyle())}))); - std::shared_ptr noCmapFormat14Family(new FontFamily( - std::vector({Font(noCmapFormat14Font, FontStyle())}))); - - std::vector> families = { - dummyFamily, hasCmapFormat14Family, noCmapFormat14Family}; - std::vector> reversedFamilies = { - dummyFamily, noCmapFormat14Family, hasCmapFormat14Family}; - - std::shared_ptr collection(new FontCollection(families)); - std::shared_ptr reversedCollection( - new FontCollection(reversedFamilies)); - - // Both hasCmapFormat14Font/noCmapFormat14Font support U+5380 but don't - // support U+5380 U+E0100. The first font should be selected. - std::vector runs; - itemize(collection, "U+5380 U+E0100", kDefaultFontStyle, &runs); - EXPECT_EQ(hasCmapFormat14Font.get(), runs[0].fakedFont.font); - - itemize(reversedCollection, "U+5380 U+E0100", kDefaultFontStyle, &runs); - EXPECT_EQ(noCmapFormat14Font.get(), runs[0].fakedFont.font); -} - -} // namespace minikin diff --git a/third_party/txt/tests/FontCollectionTest.cpp b/third_party/txt/tests/FontCollectionTest.cpp deleted file mode 100644 index 64b7921277efb..0000000000000 --- a/third_party/txt/tests/FontCollectionTest.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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 -#include "FontTestUtils.h" -#include "MinikinFontForTest.h" -#include "minikin/MinikinInternal.h" - -namespace minikin { - -// The test font has following glyphs. -// U+82A6 -// U+82A6 U+FE00 (VS1) -// U+82A6 U+E0100 (VS17) -// U+82A6 U+E0101 (VS18) -// U+82A6 U+E0102 (VS19) -// U+845B -// U+845B U+FE01 (VS2) -// U+845B U+E0101 (VS18) -// U+845B U+E0102 (VS19) -// U+845B U+E0103 (VS20) -// U+537F -// U+717D U+FE02 (VS3) -// U+717D U+E0102 (VS19) -// U+717D U+E0103 (VS20) -const char kVsTestFont[] = kTestFontDir "/VariationSelectorTest-Regular.ttf"; - -void expectVSGlyphs(const FontCollection* fc, - uint32_t codepoint, - const std::set& vsSet) { - for (uint32_t vs = 0xFE00; vs <= 0xE01EF; ++vs) { - // Move to variation selectors supplements after variation selectors. - if (vs == 0xFF00) { - vs = 0xE0100; - } - if (vsSet.find(vs) == vsSet.end()) { - EXPECT_FALSE(fc->hasVariationSelector(codepoint, vs)) - << "Glyph for U+" << std::hex << codepoint << " U+" << vs; - } else { - EXPECT_TRUE(fc->hasVariationSelector(codepoint, vs)) - << "Glyph for U+" << std::hex << codepoint << " U+" << vs; - } - } -} - -TEST(FontCollectionTest, hasVariationSelectorTest) { - std::shared_ptr font(new MinikinFontForTest(kVsTestFont)); - std::shared_ptr family( - new FontFamily(std::vector({Font(font, FontStyle())}))); - std::vector> families({family}); - std::shared_ptr fc(new FontCollection(families)); - - EXPECT_FALSE(fc->hasVariationSelector(0x82A6, 0)); - expectVSGlyphs( - fc.get(), 0x82A6, - std::set({0xFE00, 0xFE0E, 0xE0100, 0xE0101, 0xE0102})); - - EXPECT_FALSE(fc->hasVariationSelector(0x845B, 0)); - expectVSGlyphs( - fc.get(), 0x845B, - std::set({0xFE01, 0xFE0E, 0xE0101, 0xE0102, 0xE0103})); - - EXPECT_FALSE(fc->hasVariationSelector(0x537F, 0)); - expectVSGlyphs(fc.get(), 0x537F, std::set({0xFE0E})); - - EXPECT_FALSE(fc->hasVariationSelector(0x717D, 0)); - expectVSGlyphs(fc.get(), 0x717D, - std::set({0xFE02, 0xE0102, 0xE0103})); -} - -const char kEmojiXmlFile[] = kTestFontDir "emoji.xml"; - -TEST(FontCollectionTest, hasVariationSelectorTest_emoji) { - std::shared_ptr collection( - getFontCollection(kTestFontDir, kEmojiXmlFile)); - - // Both text/color font have cmap format 14 subtable entry for VS15/VS16 - // respectively. - EXPECT_TRUE(collection->hasVariationSelector(0x2623, 0xFE0E)); - EXPECT_TRUE(collection->hasVariationSelector(0x2623, 0xFE0F)); - - // The text font has cmap format 14 subtable entry for VS15 but the color font - // doesn't have for VS16 - EXPECT_TRUE(collection->hasVariationSelector(0x2626, 0xFE0E)); - EXPECT_FALSE(collection->hasVariationSelector(0x2626, 0xFE0F)); - - // The color font has cmap format 14 subtable entry for VS16 but the text font - // doesn't have for VS15. - EXPECT_TRUE(collection->hasVariationSelector(0x262A, 0xFE0E)); - EXPECT_TRUE(collection->hasVariationSelector(0x262A, 0xFE0F)); - - // Neither text/color font have cmap format 14 subtable entry for VS15/VS16. - EXPECT_TRUE(collection->hasVariationSelector(0x262E, 0xFE0E)); - EXPECT_FALSE(collection->hasVariationSelector(0x262E, 0xFE0F)); - - // Text font doesn't support U+1F3FD. Only the color emoji fonts has. So VS15 - // is not supported. - EXPECT_FALSE(collection->hasVariationSelector(0x1F3FD, 0xFE0E)); - - // Text font doesn't have U+262F U+FE0E or even its base code point U+262F. - EXPECT_FALSE(collection->hasVariationSelector(0x262F, 0xFE0E)); - - // None of the fonts support U+2229. - EXPECT_FALSE(collection->hasVariationSelector(0x2229, 0xFE0E)); - EXPECT_FALSE(collection->hasVariationSelector(0x2229, 0xFE0F)); -} - -TEST(FontCollectionTest, newEmojiTest) { - std::shared_ptr collection( - getFontCollection(kTestFontDir, kEmojiXmlFile)); - - // U+2695, U+2640, U+2642 are not in emoji catrgory in Unicode 9 but they are - // now in emoji category. Should return true even if U+FE0E was appended. - // These three emojis are only avalilable in TextEmoji.ttf but U+2695 is - // excluded here since it is used in other tests. - EXPECT_TRUE(collection->hasVariationSelector(0x2640, 0xFE0E)); - EXPECT_FALSE(collection->hasVariationSelector(0x2640, 0xFE0F)); - EXPECT_TRUE(collection->hasVariationSelector(0x2642, 0xFE0E)); - EXPECT_FALSE(collection->hasVariationSelector(0x2642, 0xFE0F)); -} - -TEST(FontCollectionTest, createWithVariations) { - // This font has 'wdth' and 'wght' axes. - const char kMultiAxisFont[] = kTestFontDir "/MultiAxis.ttf"; - const char kNoAxisFont[] = kTestFontDir "/Regular.ttf"; - - std::shared_ptr multiAxisFont( - new MinikinFontForTest(kMultiAxisFont)); - std::shared_ptr multiAxisFamily( - new FontFamily(std::vector({Font(multiAxisFont, FontStyle())}))); - std::vector> multiAxisFamilies({multiAxisFamily}); - std::shared_ptr multiAxisFc( - new FontCollection(multiAxisFamilies)); - - std::shared_ptr noAxisFont(new MinikinFontForTest(kNoAxisFont)); - std::shared_ptr noAxisFamily( - new FontFamily(std::vector({Font(noAxisFont, FontStyle())}))); - std::vector> noAxisFamilies({noAxisFamily}); - std::shared_ptr noAxisFc(new FontCollection(noAxisFamilies)); - - { - // Do not ceate new instance if none of variations are specified. - EXPECT_EQ(nullptr, multiAxisFc->createCollectionWithVariation( - std::vector())); - EXPECT_EQ(nullptr, noAxisFc->createCollectionWithVariation( - std::vector())); - } - { - // New instance should be used for supported variation. - std::vector variations = { - {MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f}}; - std::shared_ptr newFc( - multiAxisFc->createCollectionWithVariation(variations)); - EXPECT_NE(nullptr, newFc.get()); - EXPECT_NE(multiAxisFc.get(), newFc.get()); - - EXPECT_EQ(nullptr, noAxisFc->createCollectionWithVariation(variations)); - } - { - // New instance should be used for supported variation (multiple variations - // case). - std::vector variations = { - {MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f}, - {MinikinFont::MakeTag('w', 'g', 'h', 't'), 1.0f}}; - std::shared_ptr newFc( - multiAxisFc->createCollectionWithVariation(variations)); - EXPECT_NE(nullptr, newFc.get()); - EXPECT_NE(multiAxisFc.get(), newFc.get()); - - EXPECT_EQ(nullptr, noAxisFc->createCollectionWithVariation(variations)); - } - { - // Do not ceate new instance if none of variations are supported. - std::vector variations = { - {MinikinFont::MakeTag('Z', 'Z', 'Z', 'Z'), 1.0f}}; - EXPECT_EQ(nullptr, multiAxisFc->createCollectionWithVariation(variations)); - EXPECT_EQ(nullptr, noAxisFc->createCollectionWithVariation(variations)); - } - { - // At least one axis is supported, should create new instance. - std::vector variations = { - {MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f}, - {MinikinFont::MakeTag('Z', 'Z', 'Z', 'Z'), 1.0f}}; - std::shared_ptr newFc( - multiAxisFc->createCollectionWithVariation(variations)); - EXPECT_NE(nullptr, newFc.get()); - EXPECT_NE(multiAxisFc.get(), newFc.get()); - - EXPECT_EQ(nullptr, noAxisFc->createCollectionWithVariation(variations)); - } -} - -} // namespace minikin diff --git a/third_party/txt/tests/FontFamilyTest.cpp b/third_party/txt/tests/FontFamilyTest.cpp deleted file mode 100644 index 2cf823eca0058..0000000000000 --- a/third_party/txt/tests/FontFamilyTest.cpp +++ /dev/null @@ -1,726 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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 -#include - -#include "ICUTestBase.h" -#include "MinikinFontForTest.h" -#include "minikin/FontLanguageListCache.h" -#include "minikin/MinikinInternal.h" - -namespace minikin { - -typedef ICUTestBase FontLanguagesTest; -typedef ICUTestBase FontLanguageTest; - -static const FontLanguages& createFontLanguages(const std::string& input) { - std::scoped_lock _l(gMinikinLock); - uint32_t langId = FontLanguageListCache::getId(input); - return FontLanguageListCache::getById(langId); -} - -static FontLanguage createFontLanguage(const std::string& input) { - std::scoped_lock _l(gMinikinLock); - uint32_t langId = FontLanguageListCache::getId(input); - return FontLanguageListCache::getById(langId)[0]; -} - -static FontLanguage createFontLanguageWithoutICUSanitization( - const std::string& input) { - return FontLanguage(input.c_str(), input.size()); -} - -std::shared_ptr makeFamily(const std::string& fontPath) { - std::shared_ptr font(new MinikinFontForTest(fontPath)); - return std::make_shared( - std::vector({Font(font, FontStyle())})); -} - -TEST_F(FontLanguageTest, basicTests) { - FontLanguage defaultLang; - FontLanguage emptyLang("", 0); - FontLanguage english = createFontLanguage("en"); - FontLanguage french = createFontLanguage("fr"); - FontLanguage und = createFontLanguage("und"); - FontLanguage undZsye = createFontLanguage("und-Zsye"); - - EXPECT_EQ(english, english); - EXPECT_EQ(french, french); - - EXPECT_TRUE(defaultLang != defaultLang); - EXPECT_TRUE(emptyLang != emptyLang); - EXPECT_TRUE(defaultLang != emptyLang); - EXPECT_TRUE(defaultLang != und); - EXPECT_TRUE(emptyLang != und); - EXPECT_TRUE(english != defaultLang); - EXPECT_TRUE(english != emptyLang); - EXPECT_TRUE(english != french); - EXPECT_TRUE(english != undZsye); - EXPECT_TRUE(und != undZsye); - EXPECT_TRUE(english != und); - - EXPECT_TRUE(defaultLang.isUnsupported()); - EXPECT_TRUE(emptyLang.isUnsupported()); - - EXPECT_FALSE(english.isUnsupported()); - EXPECT_FALSE(french.isUnsupported()); - EXPECT_FALSE(und.isUnsupported()); - EXPECT_FALSE(undZsye.isUnsupported()); -} - -TEST_F(FontLanguageTest, getStringTest) { - EXPECT_EQ("en-Latn-US", createFontLanguage("en").getString()); - EXPECT_EQ("en-Latn-US", createFontLanguage("en-Latn").getString()); - - // Capitalized language code or lowercased script should be normalized. - EXPECT_EQ("en-Latn-US", createFontLanguage("EN-LATN").getString()); - EXPECT_EQ("en-Latn-US", createFontLanguage("EN-latn").getString()); - EXPECT_EQ("en-Latn-US", createFontLanguage("en-latn").getString()); - - // Invalid script should be kept. - EXPECT_EQ("en-Xyzt-US", createFontLanguage("en-xyzt").getString()); - - EXPECT_EQ("en-Latn-US", createFontLanguage("en-Latn-US").getString()); - EXPECT_EQ("ja-Jpan-JP", createFontLanguage("ja").getString()); - EXPECT_EQ("zh-Hant-TW", createFontLanguage("zh-TW").getString()); - EXPECT_EQ("zh-Hant-HK", createFontLanguage("zh-HK").getString()); - EXPECT_EQ("zh-Hant-MO", createFontLanguage("zh-MO").getString()); - EXPECT_EQ("zh-Hans-CN", createFontLanguage("zh").getString()); - EXPECT_EQ("zh-Hans-CN", createFontLanguage("zh-CN").getString()); - EXPECT_EQ("zh-Hans-SG", createFontLanguage("zh-SG").getString()); - EXPECT_EQ("und", createFontLanguage("und").getString()); - EXPECT_EQ("und", createFontLanguage("UND").getString()); - EXPECT_EQ("und", createFontLanguage("Und").getString()); - EXPECT_EQ("und-Zsye", createFontLanguage("und-Zsye").getString()); - EXPECT_EQ("und-Zsye", createFontLanguage("Und-ZSYE").getString()); - EXPECT_EQ("und-Zsye", createFontLanguage("Und-zsye").getString()); - - EXPECT_EQ("de-Latn-DE", createFontLanguage("de-1901").getString()); - - EXPECT_EQ("es-Latn-419", createFontLanguage("es-Latn-419").getString()); - - // Emoji subtag is dropped from getString(). - EXPECT_EQ("es-Latn-419", createFontLanguage("es-419-u-em-emoji").getString()); - EXPECT_EQ("es-Latn-419", - createFontLanguage("es-Latn-419-u-em-emoji").getString()); - - // This is not a necessary desired behavior, just known behavior. - EXPECT_EQ("en-Latn-US", createFontLanguage("und-Abcdefgh").getString()); -} - -TEST_F(FontLanguageTest, testReconstruction) { - EXPECT_EQ("en", createFontLanguageWithoutICUSanitization("en").getString()); - EXPECT_EQ("fil", createFontLanguageWithoutICUSanitization("fil").getString()); - EXPECT_EQ("und", createFontLanguageWithoutICUSanitization("und").getString()); - - EXPECT_EQ("en-Latn", - createFontLanguageWithoutICUSanitization("en-Latn").getString()); - EXPECT_EQ("fil-Taga", - createFontLanguageWithoutICUSanitization("fil-Taga").getString()); - EXPECT_EQ("und-Zsye", - createFontLanguageWithoutICUSanitization("und-Zsye").getString()); - - EXPECT_EQ("en-US", - createFontLanguageWithoutICUSanitization("en-US").getString()); - EXPECT_EQ("fil-PH", - createFontLanguageWithoutICUSanitization("fil-PH").getString()); - EXPECT_EQ("es-419", - createFontLanguageWithoutICUSanitization("es-419").getString()); - - EXPECT_EQ("en-Latn-US", - createFontLanguageWithoutICUSanitization("en-Latn-US").getString()); - EXPECT_EQ( - "fil-Taga-PH", - createFontLanguageWithoutICUSanitization("fil-Taga-PH").getString()); - EXPECT_EQ( - "es-Latn-419", - createFontLanguageWithoutICUSanitization("es-Latn-419").getString()); - - // Possible minimum/maximum values. - EXPECT_EQ("aa", createFontLanguageWithoutICUSanitization("aa").getString()); - EXPECT_EQ("zz", createFontLanguageWithoutICUSanitization("zz").getString()); - EXPECT_EQ("aa-Aaaa", - createFontLanguageWithoutICUSanitization("aa-Aaaa").getString()); - EXPECT_EQ("zz-Zzzz", - createFontLanguageWithoutICUSanitization("zz-Zzzz").getString()); - EXPECT_EQ( - "aaa-Aaaa-AA", - createFontLanguageWithoutICUSanitization("aaa-Aaaa-AA").getString()); - EXPECT_EQ( - "zzz-Zzzz-ZZ", - createFontLanguageWithoutICUSanitization("zzz-Zzzz-ZZ").getString()); - EXPECT_EQ( - "aaa-Aaaa-000", - createFontLanguageWithoutICUSanitization("aaa-Aaaa-000").getString()); - EXPECT_EQ( - "zzz-Zzzz-999", - createFontLanguageWithoutICUSanitization("zzz-Zzzz-999").getString()); -} - -TEST_F(FontLanguageTest, ScriptEqualTest) { - EXPECT_TRUE(createFontLanguage("en").isEqualScript(createFontLanguage("en"))); - EXPECT_TRUE( - createFontLanguage("en-Latn").isEqualScript(createFontLanguage("en"))); - EXPECT_TRUE(createFontLanguage("jp-Latn").isEqualScript( - createFontLanguage("en-Latn"))); - EXPECT_TRUE(createFontLanguage("en-Jpan").isEqualScript( - createFontLanguage("en-Jpan"))); - - EXPECT_FALSE(createFontLanguage("en-Jpan").isEqualScript( - createFontLanguage("en-Hira"))); - EXPECT_FALSE(createFontLanguage("en-Jpan").isEqualScript( - createFontLanguage("en-Hani"))); -} - -TEST_F(FontLanguageTest, ScriptMatchTest) { - const bool SUPPORTED = true; - const bool NOT_SUPPORTED = false; - - struct TestCase { - const std::string baseScript; - const std::string requestedScript; - bool isSupported; - } testCases[] = { - // Same scripts - {"en-Latn", "Latn", SUPPORTED}, - {"ja-Jpan", "Jpan", SUPPORTED}, - {"ja-Hira", "Hira", SUPPORTED}, - {"ja-Kana", "Kana", SUPPORTED}, - {"ja-Hrkt", "Hrkt", SUPPORTED}, - {"zh-Hans", "Hans", SUPPORTED}, - {"zh-Hant", "Hant", SUPPORTED}, - {"zh-Hani", "Hani", SUPPORTED}, - {"ko-Kore", "Kore", SUPPORTED}, - {"ko-Hang", "Hang", SUPPORTED}, - {"zh-Hanb", "Hanb", SUPPORTED}, - - // Japanese supports Hiragana, Katakanara, etc. - {"ja-Jpan", "Hira", SUPPORTED}, - {"ja-Jpan", "Kana", SUPPORTED}, - {"ja-Jpan", "Hrkt", SUPPORTED}, - {"ja-Hrkt", "Hira", SUPPORTED}, - {"ja-Hrkt", "Kana", SUPPORTED}, - - // Chinese supports Han. - {"zh-Hans", "Hani", SUPPORTED}, - {"zh-Hant", "Hani", SUPPORTED}, - {"zh-Hanb", "Hani", SUPPORTED}, - - // Hanb supports Bopomofo. - {"zh-Hanb", "Bopo", SUPPORTED}, - - // Korean supports Hangul. - {"ko-Kore", "Hang", SUPPORTED}, - - // Different scripts - {"ja-Jpan", "Latn", NOT_SUPPORTED}, - {"en-Latn", "Jpan", NOT_SUPPORTED}, - {"ja-Jpan", "Hant", NOT_SUPPORTED}, - {"zh-Hant", "Jpan", NOT_SUPPORTED}, - {"ja-Jpan", "Hans", NOT_SUPPORTED}, - {"zh-Hans", "Jpan", NOT_SUPPORTED}, - {"ja-Jpan", "Kore", NOT_SUPPORTED}, - {"ko-Kore", "Jpan", NOT_SUPPORTED}, - {"zh-Hans", "Hant", NOT_SUPPORTED}, - {"zh-Hant", "Hans", NOT_SUPPORTED}, - {"zh-Hans", "Kore", NOT_SUPPORTED}, - {"ko-Kore", "Hans", NOT_SUPPORTED}, - {"zh-Hant", "Kore", NOT_SUPPORTED}, - {"ko-Kore", "Hant", NOT_SUPPORTED}, - - // Hiragana doesn't support Japanese, etc. - {"ja-Hira", "Jpan", NOT_SUPPORTED}, - {"ja-Kana", "Jpan", NOT_SUPPORTED}, - {"ja-Hrkt", "Jpan", NOT_SUPPORTED}, - {"ja-Hani", "Jpan", NOT_SUPPORTED}, - {"ja-Hira", "Hrkt", NOT_SUPPORTED}, - {"ja-Kana", "Hrkt", NOT_SUPPORTED}, - {"ja-Hani", "Hrkt", NOT_SUPPORTED}, - {"ja-Hani", "Hira", NOT_SUPPORTED}, - {"ja-Hani", "Kana", NOT_SUPPORTED}, - - // Kanji doesn't support Chinese, etc. - {"zh-Hani", "Hant", NOT_SUPPORTED}, - {"zh-Hani", "Hans", NOT_SUPPORTED}, - {"zh-Hani", "Hanb", NOT_SUPPORTED}, - - // Hangul doesn't support Korean, etc. - {"ko-Hang", "Kore", NOT_SUPPORTED}, - {"ko-Hani", "Kore", NOT_SUPPORTED}, - {"ko-Hani", "Hang", NOT_SUPPORTED}, - {"ko-Hang", "Hani", NOT_SUPPORTED}, - - // Han with botomofo doesn't support simplified Chinese, etc. - {"zh-Hanb", "Hant", NOT_SUPPORTED}, - {"zh-Hanb", "Hans", NOT_SUPPORTED}, - {"zh-Hanb", "Jpan", NOT_SUPPORTED}, - {"zh-Hanb", "Kore", NOT_SUPPORTED}, - }; - - for (auto testCase : testCases) { - hb_script_t script = hb_script_from_iso15924_tag( - HB_TAG(testCase.requestedScript[0], testCase.requestedScript[1], - testCase.requestedScript[2], testCase.requestedScript[3])); - if (testCase.isSupported) { - EXPECT_TRUE( - createFontLanguage(testCase.baseScript).supportsHbScript(script)) - << testCase.baseScript << " should support " - << testCase.requestedScript; - } else { - EXPECT_FALSE( - createFontLanguage(testCase.baseScript).supportsHbScript(script)) - << testCase.baseScript << " shouldn't support " - << testCase.requestedScript; - } - } -} - -TEST_F(FontLanguagesTest, basicTests) { - FontLanguages emptyLangs; - EXPECT_EQ(0u, emptyLangs.size()); - - FontLanguage english = createFontLanguage("en"); - const FontLanguages& singletonLangs = createFontLanguages("en"); - EXPECT_EQ(1u, singletonLangs.size()); - EXPECT_EQ(english, singletonLangs[0]); - - FontLanguage french = createFontLanguage("fr"); - const FontLanguages& twoLangs = createFontLanguages("en,fr"); - EXPECT_EQ(2u, twoLangs.size()); - EXPECT_EQ(english, twoLangs[0]); - EXPECT_EQ(french, twoLangs[1]); -} - -TEST_F(FontLanguagesTest, unsupportedLanguageTests) { - const FontLanguages& oneUnsupported = createFontLanguages("abcd-example"); - EXPECT_TRUE(oneUnsupported.empty()); - - const FontLanguages& twoUnsupporteds = - createFontLanguages("abcd-example,abcd-example"); - EXPECT_TRUE(twoUnsupporteds.empty()); - - FontLanguage english = createFontLanguage("en"); - const FontLanguages& firstUnsupported = - createFontLanguages("abcd-example,en"); - EXPECT_EQ(1u, firstUnsupported.size()); - EXPECT_EQ(english, firstUnsupported[0]); - - const FontLanguages& lastUnsupported = createFontLanguages("en,abcd-example"); - EXPECT_EQ(1u, lastUnsupported.size()); - EXPECT_EQ(english, lastUnsupported[0]); -} - -TEST_F(FontLanguagesTest, repeatedLanguageTests) { - FontLanguage english = createFontLanguage("en"); - FontLanguage french = createFontLanguage("fr"); - FontLanguage canadianFrench = createFontLanguage("fr-CA"); - FontLanguage englishInLatn = createFontLanguage("en-Latn"); - ASSERT_TRUE(english == englishInLatn); - - const FontLanguages& langs = createFontLanguages("en,en-Latn"); - EXPECT_EQ(1u, langs.size()); - EXPECT_EQ(english, langs[0]); - - const FontLanguages& fr = createFontLanguages("fr,fr-FR,fr-Latn-FR"); - EXPECT_EQ(1u, fr.size()); - EXPECT_EQ(french, fr[0]); - - // ICU appends FR to fr. The third language is dropped which is same as the - // first language. - const FontLanguages& fr2 = createFontLanguages("fr,fr-CA,fr-FR"); - EXPECT_EQ(2u, fr2.size()); - EXPECT_EQ(french, fr2[0]); - EXPECT_EQ(canadianFrench, fr2[1]); - - // The order should be kept. - const FontLanguages& langs2 = createFontLanguages("en,fr,en-Latn"); - EXPECT_EQ(2u, langs2.size()); - EXPECT_EQ(english, langs2[0]); - EXPECT_EQ(french, langs2[1]); -} - -TEST_F(FontLanguagesTest, identifierTest) { - EXPECT_EQ(createFontLanguage("en-Latn-US"), createFontLanguage("en-Latn-US")); - EXPECT_EQ(createFontLanguage("zh-Hans-CN"), createFontLanguage("zh-Hans-CN")); - EXPECT_EQ(createFontLanguage("en-Zsye-US"), createFontLanguage("en-Zsye-US")); - - EXPECT_NE(createFontLanguage("en-Latn-US"), createFontLanguage("en-Latn-GB")); - EXPECT_NE(createFontLanguage("en-Latn-US"), createFontLanguage("en-Zsye-US")); - EXPECT_NE(createFontLanguage("es-Latn-US"), createFontLanguage("en-Latn-US")); - EXPECT_NE(createFontLanguage("zh-Hant-HK"), createFontLanguage("zh-Hant-TW")); -} - -TEST_F(FontLanguagesTest, undEmojiTests) { - FontLanguage emoji = createFontLanguage("und-Zsye"); - EXPECT_EQ(FontLanguage::EMSTYLE_EMOJI, emoji.getEmojiStyle()); - - FontLanguage und = createFontLanguage("und"); - EXPECT_EQ(FontLanguage::EMSTYLE_EMPTY, und.getEmojiStyle()); - EXPECT_FALSE(emoji == und); - - FontLanguage undExample = createFontLanguage("und-example"); - EXPECT_EQ(FontLanguage::EMSTYLE_EMPTY, undExample.getEmojiStyle()); - EXPECT_FALSE(emoji == undExample); -} - -TEST_F(FontLanguagesTest, subtagEmojiTest) { - std::string subtagEmojiStrings[] = { - // Duplicate subtag case. - "und-Latn-u-em-emoji-u-em-text", - - // Strings that contain language. - "und-u-em-emoji", - "en-u-em-emoji", - - // Strings that contain the script. - "und-Jpan-u-em-emoji", - "en-Latn-u-em-emoji", - "und-Zsym-u-em-emoji", - "und-Zsye-u-em-emoji", - "en-Zsym-u-em-emoji", - "en-Zsye-u-em-emoji", - - // Strings that contain the county. - "und-US-u-em-emoji", - "en-US-u-em-emoji", - "es-419-u-em-emoji", - "und-Latn-US-u-em-emoji", - "en-Zsym-US-u-em-emoji", - "en-Zsye-US-u-em-emoji", - "es-Zsye-419-u-em-emoji", - }; - - for (auto subtagEmojiString : subtagEmojiStrings) { - SCOPED_TRACE("Test for \"" + subtagEmojiString + "\""); - FontLanguage subtagEmoji = createFontLanguage(subtagEmojiString); - EXPECT_EQ(FontLanguage::EMSTYLE_EMOJI, subtagEmoji.getEmojiStyle()); - } -} - -TEST_F(FontLanguagesTest, subtagTextTest) { - std::string subtagTextStrings[] = { - // Duplicate subtag case. - "und-Latn-u-em-text-u-em-emoji", - - // Strings that contain language. - "und-u-em-text", - "en-u-em-text", - - // Strings that contain the script. - "und-Latn-u-em-text", - "en-Jpan-u-em-text", - "und-Zsym-u-em-text", - "und-Zsye-u-em-text", - "en-Zsym-u-em-text", - "en-Zsye-u-em-text", - - // Strings that contain the county. - "und-US-u-em-text", - "en-US-u-em-text", - "es-419-u-em-text", - "und-Latn-US-u-em-text", - "en-Zsym-US-u-em-text", - "en-Zsye-US-u-em-text", - "es-Zsye-419-u-em-text", - }; - - for (auto subtagTextString : subtagTextStrings) { - SCOPED_TRACE("Test for \"" + subtagTextString + "\""); - FontLanguage subtagText = createFontLanguage(subtagTextString); - EXPECT_EQ(FontLanguage::EMSTYLE_TEXT, subtagText.getEmojiStyle()); - } -} - -// TODO: add more "und" language cases whose language and script are -// unexpectedly translated to en-Latn by ICU. -TEST_F(FontLanguagesTest, subtagDefaultTest) { - std::string subtagDefaultStrings[] = { - // Duplicate subtag case. - "en-Latn-u-em-default-u-em-emoji", - "en-Latn-u-em-default-u-em-text", - - // Strings that contain language. - "und-u-em-default", - "en-u-em-default", - - // Strings that contain the script. - "en-Latn-u-em-default", - "en-Zsym-u-em-default", - "en-Zsye-u-em-default", - - // Strings that contain the county. - "en-US-u-em-default", - "en-Latn-US-u-em-default", - "es-Latn-419-u-em-default", - "en-Zsym-US-u-em-default", - "en-Zsye-US-u-em-default", - "es-Zsye-419-u-em-default", - }; - - for (auto subtagDefaultString : subtagDefaultStrings) { - SCOPED_TRACE("Test for \"" + subtagDefaultString + "\""); - FontLanguage subtagDefault = createFontLanguage(subtagDefaultString); - EXPECT_EQ(FontLanguage::EMSTYLE_DEFAULT, subtagDefault.getEmojiStyle()); - } -} - -TEST_F(FontLanguagesTest, subtagEmptyTest) { - std::string subtagEmptyStrings[] = { - "und", - "jp", - "en-US", - "en-Latn", - "en-Latn-US", - "en-Latn-US-u-em", - "en-Latn-US-u-em-defaultemoji", - }; - - for (auto subtagEmptyString : subtagEmptyStrings) { - SCOPED_TRACE("Test for \"" + subtagEmptyString + "\""); - FontLanguage subtagEmpty = createFontLanguage(subtagEmptyString); - EXPECT_EQ(FontLanguage::EMSTYLE_EMPTY, subtagEmpty.getEmojiStyle()); - } -} - -TEST_F(FontLanguagesTest, registerLanguageListTest) { - EXPECT_EQ(0UL, FontStyle::registerLanguageList("")); - EXPECT_NE(0UL, FontStyle::registerLanguageList("en")); - EXPECT_NE(0UL, FontStyle::registerLanguageList("jp")); - EXPECT_NE(0UL, FontStyle::registerLanguageList("en,zh-Hans")); - - EXPECT_EQ(FontStyle::registerLanguageList("en"), - FontStyle::registerLanguageList("en")); - EXPECT_NE(FontStyle::registerLanguageList("en"), - FontStyle::registerLanguageList("jp")); - - EXPECT_EQ(FontStyle::registerLanguageList("en,zh-Hans"), - FontStyle::registerLanguageList("en,zh-Hans")); - EXPECT_NE(FontStyle::registerLanguageList("en,zh-Hans"), - FontStyle::registerLanguageList("zh-Hans,en")); - EXPECT_NE(FontStyle::registerLanguageList("en,zh-Hans"), - FontStyle::registerLanguageList("jp")); - EXPECT_NE(FontStyle::registerLanguageList("en,zh-Hans"), - FontStyle::registerLanguageList("en")); - EXPECT_NE(FontStyle::registerLanguageList("en,zh-Hans"), - FontStyle::registerLanguageList("en,zh-Hant")); -} - -// The test font has following glyphs. -// U+82A6 -// U+82A6 U+FE00 (VS1) -// U+82A6 U+E0100 (VS17) -// U+82A6 U+E0101 (VS18) -// U+82A6 U+E0102 (VS19) -// U+845B -// U+845B U+FE00 (VS2) -// U+845B U+E0101 (VS18) -// U+845B U+E0102 (VS19) -// U+845B U+E0103 (VS20) -// U+537F -// U+717D U+FE02 (VS3) -// U+717D U+E0102 (VS19) -// U+717D U+E0103 (VS20) -const char kVsTestFont[] = kTestFontDir "VariationSelectorTest-Regular.ttf"; - -class FontFamilyTest : public ICUTestBase { - public: - virtual void SetUp() override { - ICUTestBase::SetUp(); - if (access(kVsTestFont, R_OK) != 0) { - FAIL() << "Unable to read " << kVsTestFont << ". " - << "Please prepare the test data directory. " - << "For more details, please see how_to_run.txt."; - } - } -}; - -// Asserts that the font family has glyphs for and only for specified codepoint -// and variationSelector pairs. -void expectVSGlyphs(FontFamily* family, - uint32_t codepoint, - const std::set& vs) { - for (uint32_t i = 0xFE00; i <= 0xE01EF; ++i) { - // Move to variation selectors supplements after variation selectors. - if (i == 0xFF00) { - i = 0xE0100; - } - if (vs.find(i) == vs.end()) { - EXPECT_FALSE(family->hasGlyph(codepoint, i)) - << "Glyph for U+" << std::hex << codepoint << " U+" << i; - } else { - EXPECT_TRUE(family->hasGlyph(codepoint, i)) - << "Glyph for U+" << std::hex << codepoint << " U+" << i; - } - } -} - -TEST_F(FontFamilyTest, hasVariationSelectorTest) { - std::shared_ptr minikinFont(new MinikinFontForTest(kVsTestFont)); - std::shared_ptr family( - new FontFamily(std::vector{Font(minikinFont, FontStyle())})); - - std::scoped_lock _l(gMinikinLock); - - const uint32_t kVS1 = 0xFE00; - const uint32_t kVS2 = 0xFE01; - const uint32_t kVS3 = 0xFE02; - const uint32_t kVS17 = 0xE0100; - const uint32_t kVS18 = 0xE0101; - const uint32_t kVS19 = 0xE0102; - const uint32_t kVS20 = 0xE0103; - - const uint32_t kSupportedChar1 = 0x82A6; - EXPECT_TRUE(family->getCoverage().get(kSupportedChar1)); - expectVSGlyphs(family.get(), kSupportedChar1, - std::set({kVS1, kVS17, kVS18, kVS19})); - - const uint32_t kSupportedChar2 = 0x845B; - EXPECT_TRUE(family->getCoverage().get(kSupportedChar2)); - expectVSGlyphs(family.get(), kSupportedChar2, - std::set({kVS2, kVS18, kVS19, kVS20})); - - const uint32_t kNoVsSupportedChar = 0x537F; - EXPECT_TRUE(family->getCoverage().get(kNoVsSupportedChar)); - expectVSGlyphs(family.get(), kNoVsSupportedChar, std::set()); - - const uint32_t kVsOnlySupportedChar = 0x717D; - EXPECT_FALSE(family->getCoverage().get(kVsOnlySupportedChar)); - expectVSGlyphs(family.get(), kVsOnlySupportedChar, - std::set({kVS3, kVS19, kVS20})); - - const uint32_t kNotSupportedChar = 0x845C; - EXPECT_FALSE(family->getCoverage().get(kNotSupportedChar)); - expectVSGlyphs(family.get(), kNotSupportedChar, std::set()); -} - -TEST_F(FontFamilyTest, hasVSTableTest) { - struct TestCase { - const std::string fontPath; - bool hasVSTable; - } testCases[] = { - {kTestFontDir "Ja.ttf", true}, {kTestFontDir "ZhHant.ttf", true}, - {kTestFontDir "ZhHans.ttf", true}, {kTestFontDir "Italic.ttf", false}, - {kTestFontDir "Bold.ttf", false}, {kTestFontDir "BoldItalic.ttf", false}, - }; - - for (auto testCase : testCases) { - SCOPED_TRACE(testCase.hasVSTable - ? "Font " + testCase.fontPath + - " should have a variation sequence table." - : "Font " + testCase.fontPath + - " shouldn't have a variation sequence table."); - - std::shared_ptr minikinFont( - new MinikinFontForTest(testCase.fontPath)); - std::shared_ptr family( - new FontFamily(std::vector{Font(minikinFont, FontStyle())})); - std::scoped_lock _l(gMinikinLock); - EXPECT_EQ(testCase.hasVSTable, family->hasVSTable()); - } -} - -TEST_F(FontFamilyTest, createFamilyWithVariationTest) { - // This font has 'wdth' and 'wght' axes. - const char kMultiAxisFont[] = kTestFontDir "/MultiAxis.ttf"; - const char kNoAxisFont[] = kTestFontDir "/Regular.ttf"; - - std::shared_ptr multiAxisFamily = makeFamily(kMultiAxisFont); - std::shared_ptr noAxisFamily = makeFamily(kNoAxisFont); - - { - // Do not ceate new instance if none of variations are specified. - EXPECT_EQ(nullptr, multiAxisFamily->createFamilyWithVariation( - std::vector())); - EXPECT_EQ(nullptr, noAxisFamily->createFamilyWithVariation( - std::vector())); - } - { - // New instance should be used for supported variation. - std::vector variations = { - {MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f}}; - std::shared_ptr newFamily( - multiAxisFamily->createFamilyWithVariation(variations)); - EXPECT_NE(nullptr, newFamily.get()); - EXPECT_NE(multiAxisFamily.get(), newFamily.get()); - EXPECT_EQ(nullptr, noAxisFamily->createFamilyWithVariation(variations)); - } - { - // New instance should be used for supported variation. (multiple variations - // case) - std::vector variations = { - {MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f}, - {MinikinFont::MakeTag('w', 'g', 'h', 't'), 1.0f}}; - std::shared_ptr newFamily( - multiAxisFamily->createFamilyWithVariation(variations)); - EXPECT_NE(nullptr, newFamily.get()); - EXPECT_NE(multiAxisFamily.get(), newFamily.get()); - EXPECT_EQ(nullptr, noAxisFamily->createFamilyWithVariation(variations)); - } - { - // Do not ceate new instance if none of variations are supported. - std::vector variations = { - {MinikinFont::MakeTag('Z', 'Z', 'Z', 'Z'), 1.0f}}; - EXPECT_EQ(nullptr, multiAxisFamily->createFamilyWithVariation(variations)); - EXPECT_EQ(nullptr, noAxisFamily->createFamilyWithVariation(variations)); - } - { - // At least one axis is supported, should create new instance. - std::vector variations = { - {MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f}, - {MinikinFont::MakeTag('Z', 'Z', 'Z', 'Z'), 1.0f}}; - std::shared_ptr newFamily( - multiAxisFamily->createFamilyWithVariation(variations)); - EXPECT_NE(nullptr, newFamily.get()); - EXPECT_NE(multiAxisFamily.get(), newFamily.get()); - EXPECT_EQ(nullptr, noAxisFamily->createFamilyWithVariation(variations)); - } -} - -TEST_F(FontFamilyTest, coverageTableSelectionTest) { - // This font supports U+0061. The cmap subtable is format 4 and its platform - // ID is 0 and encoding ID is 1. - const char kUnicodeEncoding1Font[] = kTestFontDir "UnicodeBMPOnly.ttf"; - - // This font supports U+0061. The cmap subtable is format 4 and its platform - // ID is 0 and encoding ID is 3. - const char kUnicodeEncoding3Font[] = kTestFontDir "UnicodeBMPOnly2.ttf"; - - // This font has both cmap format 4 subtable which platform ID is 0 and - // encoding ID is 1 and cmap format 14 subtable which platform ID is 0 and - // encoding ID is 10. U+0061 is listed in both subtable but U+1F926 is only - // listed in latter. - const char kUnicodeEncoding4Font[] = kTestFontDir "UnicodeUCS4.ttf"; - - std::shared_ptr unicodeEnc1Font = - makeFamily(kUnicodeEncoding1Font); - std::shared_ptr unicodeEnc3Font = - makeFamily(kUnicodeEncoding3Font); - std::shared_ptr unicodeEnc4Font = - makeFamily(kUnicodeEncoding4Font); - - std::scoped_lock _l(gMinikinLock); - - EXPECT_TRUE(unicodeEnc1Font->hasGlyph(0x0061, 0)); - EXPECT_TRUE(unicodeEnc3Font->hasGlyph(0x0061, 0)); - EXPECT_TRUE(unicodeEnc4Font->hasGlyph(0x0061, 0)); - - EXPECT_TRUE(unicodeEnc4Font->hasGlyph(0x1F926, 0)); -} - -} // namespace minikin diff --git a/third_party/txt/tests/FontLanguageListCacheTest.cpp b/third_party/txt/tests/FontLanguageListCacheTest.cpp deleted file mode 100644 index dccb5020619e6..0000000000000 --- a/third_party/txt/tests/FontLanguageListCacheTest.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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 - -#include "ICUTestBase.h" -#include "minikin/FontLanguageListCache.h" -#include "minikin/MinikinInternal.h" - -namespace minikin { - -typedef ICUTestBase FontLanguageListCacheTest; - -TEST_F(FontLanguageListCacheTest, getId) { - EXPECT_NE(0UL, FontStyle::registerLanguageList("en")); - EXPECT_NE(0UL, FontStyle::registerLanguageList("jp")); - EXPECT_NE(0UL, FontStyle::registerLanguageList("en,zh-Hans")); - - std::scoped_lock _l(gMinikinLock); - EXPECT_EQ(0UL, FontLanguageListCache::getId("")); - - EXPECT_EQ(FontLanguageListCache::getId("en"), - FontLanguageListCache::getId("en")); - EXPECT_NE(FontLanguageListCache::getId("en"), - FontLanguageListCache::getId("jp")); - - EXPECT_EQ(FontLanguageListCache::getId("en,zh-Hans"), - FontLanguageListCache::getId("en,zh-Hans")); - EXPECT_NE(FontLanguageListCache::getId("en,zh-Hans"), - FontLanguageListCache::getId("zh-Hans,en")); - EXPECT_NE(FontLanguageListCache::getId("en,zh-Hans"), - FontLanguageListCache::getId("jp")); - EXPECT_NE(FontLanguageListCache::getId("en,zh-Hans"), - FontLanguageListCache::getId("en")); - EXPECT_NE(FontLanguageListCache::getId("en,zh-Hans"), - FontLanguageListCache::getId("en,zh-Hant")); -} - -TEST_F(FontLanguageListCacheTest, getById) { - std::scoped_lock _l(gMinikinLock); - uint32_t enLangId = FontLanguageListCache::getId("en"); - uint32_t jpLangId = FontLanguageListCache::getId("jp"); - FontLanguage english = FontLanguageListCache::getById(enLangId)[0]; - FontLanguage japanese = FontLanguageListCache::getById(jpLangId)[0]; - - const FontLanguages& defLangs = FontLanguageListCache::getById(0); - EXPECT_TRUE(defLangs.empty()); - - const FontLanguages& langs = - FontLanguageListCache::getById(FontLanguageListCache::getId("en")); - ASSERT_EQ(1UL, langs.size()); - EXPECT_EQ(english, langs[0]); - - const FontLanguages& langs2 = - FontLanguageListCache::getById(FontLanguageListCache::getId("en,jp")); - ASSERT_EQ(2UL, langs2.size()); - EXPECT_EQ(english, langs2[0]); - EXPECT_EQ(japanese, langs2[1]); -} - -} // namespace minikin diff --git a/third_party/txt/tests/FontTestUtils.cpp b/third_party/txt/tests/FontTestUtils.cpp deleted file mode 100644 index 00b78ebd147fc..0000000000000 --- a/third_party/txt/tests/FontTestUtils.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "Minikin" - -#include -#include - -#include - -#include -#include -#include "MinikinFontForTest.h" -#include "minikin/FontLanguage.h" - -namespace minikin { - -std::vector> getFontFamilies(const char* fontDir, - const char* fontXml) { - xmlDoc* doc = xmlReadFile(fontXml, NULL, 0); - xmlNode* familySet = xmlDocGetRootElement(doc); - - std::vector> families; - for (xmlNode* familyNode = familySet->children; familyNode; - familyNode = familyNode->next) { - if (xmlStrcmp(familyNode->name, (const xmlChar*)"family") != 0) { - continue; - } - - xmlChar* variantXmlch = xmlGetProp(familyNode, (const xmlChar*)"variant"); - int variant = VARIANT_DEFAULT; - if (variantXmlch) { - if (xmlStrcmp(variantXmlch, (const xmlChar*)"elegant") == 0) { - variant = VARIANT_ELEGANT; - } else if (xmlStrcmp(variantXmlch, (const xmlChar*)"compact") == 0) { - variant = VARIANT_COMPACT; - } - } - - std::vector fonts; - for (xmlNode* fontNode = familyNode->children; fontNode; - fontNode = fontNode->next) { - if (xmlStrcmp(fontNode->name, (const xmlChar*)"font") != 0) { - continue; - } - - int weight = - atoi((const char*)(xmlGetProp(fontNode, (const xmlChar*)"weight"))) / - 100; - bool italic = xmlStrcmp(xmlGetProp(fontNode, (const xmlChar*)"style"), - (const xmlChar*)"italic") == 0; - xmlChar* index = xmlGetProp(familyNode, (const xmlChar*)"index"); - - xmlChar* fontFileName = - xmlNodeListGetString(doc, fontNode->xmlChildrenNode, 1); - std::string fontPath = fontDir + std::string((const char*)fontFileName); - xmlFree(fontFileName); - - if (access(fontPath.c_str(), R_OK) != 0) { - ALOGW("%s is not found.", fontPath.c_str()); - continue; - } - - if (index == nullptr) { - std::shared_ptr minikinFont = - std::make_shared(fontPath); - fonts.push_back(Font(minikinFont, FontStyle(weight, italic))); - } else { - std::shared_ptr minikinFont = - std::make_shared(fontPath, - atoi((const char*)index)); - fonts.push_back(Font(minikinFont, FontStyle(weight, italic))); - } - } - - xmlChar* lang = xmlGetProp(familyNode, (const xmlChar*)"lang"); - std::shared_ptr family; - if (lang == nullptr) { - family = std::make_shared(variant, std::move(fonts)); - } else { - uint32_t langId = FontStyle::registerLanguageList( - std::string((const char*)lang, xmlStrlen(lang))); - family = std::make_shared(langId, variant, std::move(fonts)); - } - families.push_back(family); - } - xmlFreeDoc(doc); - return families; -} -std::shared_ptr getFontCollection(const char* fontDir, - const char* fontXml) { - return std::make_shared(getFontFamilies(fontDir, fontXml)); -} - -} // namespace minikin diff --git a/third_party/txt/tests/FontTestUtils.h b/third_party/txt/tests/FontTestUtils.h deleted file mode 100644 index e059301f03bdf..0000000000000 --- a/third_party/txt/tests/FontTestUtils.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#ifndef MINIKIN_FONT_TEST_UTILS_H -#define MINIKIN_FONT_TEST_UTILS_H - -#include - -#include - -namespace minikin { - -/** - * Returns list of FontFamily from installed fonts. - * - * This function reads an XML file and makes font families. - * - * Caller must unref the returned pointer. - */ -std::vector> getFontFamilies(const char* fontDir, - const char* fontXml); - -/** - * Returns FontCollection from installed fonts. - * - * This function reads an XML file and makes font families and collections of - * them. MinikinFontForTest is used for FontFamily creation. - * - * Caller must unref the returned pointer. - */ -std::shared_ptr getFontCollection(const char* fontDir, - const char* fontXml); - -} // namespace minikin -#endif // MINIKIN_FONT_TEST_UTILS_H diff --git a/third_party/txt/tests/GraphemeBreakTests.cpp b/third_party/txt/tests/GraphemeBreakTests.cpp deleted file mode 100644 index 072630ad3b35a..0000000000000 --- a/third_party/txt/tests/GraphemeBreakTests.cpp +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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 -#include "UnicodeUtils.h" - -namespace minikin { - -bool IsBreak(const char* src) { - const size_t BUF_SIZE = 256; - uint16_t buf[BUF_SIZE]; - size_t offset; - size_t size; - ParseUnicode(buf, BUF_SIZE, src, &size, &offset); - return GraphemeBreak::isGraphemeBreak(nullptr, buf, 0, size, offset); -} - -bool IsBreakWithAdvances(const float* advances, const char* src) { - const size_t BUF_SIZE = 256; - uint16_t buf[BUF_SIZE]; - size_t offset; - size_t size; - ParseUnicode(buf, BUF_SIZE, src, &size, &offset); - return GraphemeBreak::isGraphemeBreak(advances, buf, 0, size, offset); -} - -TEST(GraphemeBreak, utf16) { - EXPECT_FALSE(IsBreak("U+D83C | U+DC31")); // emoji, U+1F431 - - // tests for invalid UTF-16 - EXPECT_TRUE(IsBreak("U+D800 | U+D800")); // two leading surrogates - EXPECT_TRUE(IsBreak("U+DC00 | U+DC00")); // two trailing surrogates - EXPECT_TRUE(IsBreak("'a' | U+D800")); // lonely leading surrogate - EXPECT_TRUE(IsBreak("U+DC00 | 'a'")); // lonely trailing surrogate - EXPECT_TRUE( - IsBreak("U+D800 | 'a'")); // leading surrogate followed by non-surrogate - EXPECT_TRUE( - IsBreak("'a' | U+DC00")); // non-surrogate followed by trailing surrogate -} - -TEST(GraphemeBreak, rules) { - // Rule GB1, sot ÷; Rule GB2, ÷ eot - EXPECT_TRUE(IsBreak("| 'a'")); - EXPECT_TRUE(IsBreak("'a' |")); - - // Rule GB3, CR x LF - EXPECT_FALSE(IsBreak("U+000D | U+000A")); // CR x LF - - // Rule GB4, (Control | CR | LF) ÷ - EXPECT_TRUE(IsBreak("'a' | U+2028")); // Line separator - EXPECT_TRUE(IsBreak("'a' | U+000D")); // LF - EXPECT_TRUE(IsBreak("'a' | U+000A")); // CR - - // Rule GB5, ÷ (Control | CR | LF) - EXPECT_TRUE(IsBreak("U+2028 | 'a'")); // Line separator - EXPECT_TRUE(IsBreak("U+000D | 'a'")); // LF - EXPECT_TRUE(IsBreak("U+000A | 'a'")); // CR - - // Rule GB6, L x ( L | V | LV | LVT ) - EXPECT_FALSE(IsBreak("U+1100 | U+1100")); // L x L - EXPECT_FALSE(IsBreak("U+1100 | U+1161")); // L x V - EXPECT_FALSE(IsBreak("U+1100 | U+AC00")); // L x LV - EXPECT_FALSE(IsBreak("U+1100 | U+AC01")); // L x LVT - - // Rule GB7, ( LV | V ) x ( V | T ) - EXPECT_FALSE(IsBreak("U+AC00 | U+1161")); // LV x V - EXPECT_FALSE(IsBreak("U+1161 | U+1161")); // V x V - EXPECT_FALSE(IsBreak("U+AC00 | U+11A8")); // LV x T - EXPECT_FALSE(IsBreak("U+1161 | U+11A8")); // V x T - - // Rule GB8, ( LVT | T ) x T - EXPECT_FALSE(IsBreak("U+AC01 | U+11A8")); // LVT x T - EXPECT_FALSE(IsBreak("U+11A8 | U+11A8")); // T x T - - // Other hangul pairs not counted above _are_ breaks (GB10) - EXPECT_TRUE(IsBreak("U+AC00 | U+1100")); // LV x L - EXPECT_TRUE(IsBreak("U+AC01 | U+1100")); // LVT x L - EXPECT_TRUE(IsBreak("U+11A8 | U+1100")); // T x L - EXPECT_TRUE(IsBreak("U+11A8 | U+AC00")); // T x LV - EXPECT_TRUE(IsBreak("U+11A8 | U+AC01")); // T x LVT - - // Rule GB12 and Rule GB13, Regional_Indicator x Regional_Indicator - EXPECT_FALSE(IsBreak("U+1F1FA | U+1F1F8")); - EXPECT_TRUE(IsBreak( - "U+1F1FA U+1F1F8 | U+1F1FA U+1F1F8")); // Regional indicator pair (flag) - EXPECT_FALSE(IsBreak( - "U+1F1FA | U+1F1F8 U+1F1FA U+1F1F8")); // Regional indicator pair (flag) - EXPECT_FALSE(IsBreak( - "U+1F1FA U+1F1F8 U+1F1FA | U+1F1F8")); // Regional indicator pair (flag) - - EXPECT_TRUE( - IsBreak("U+1F1FA U+1F1F8 | U+1F1FA")); // Regional indicator pair (flag) - EXPECT_FALSE( - IsBreak("U+1F1FA | U+1F1F8 U+1F1FA")); // Regional indicator pair (flag) - // Same case as the two above, knowing that the first two characters ligate, - // which is what would typically happen. - const float firstPairLigated[] = {1.0, 0.0, 0.0, 0.0, - 1.0, 0.0}; // Two entries per codepoint - EXPECT_TRUE( - IsBreakWithAdvances(firstPairLigated, "U+1F1FA U+1F1F8 | U+1F1FA")); - EXPECT_FALSE( - IsBreakWithAdvances(firstPairLigated, "U+1F1FA | U+1F1F8 U+1F1FA")); - // Repeat the tests, But now the font doesn't have a ligature for the first - // two characters, while it does have a ligature for the last two. This could - // happen for fonts that do not support some (potentially encoded later than - // they were developed) flags. - const float secondPairLigated[] = {1.0, 0.0, 1.0, 0.0, 0.0, 0.0}; - EXPECT_FALSE( - IsBreakWithAdvances(secondPairLigated, "U+1F1FA U+1F1F8 | U+1F1FA")); - EXPECT_TRUE( - IsBreakWithAdvances(secondPairLigated, "U+1F1FA | U+1F1F8 U+1F1FA")); - - EXPECT_TRUE(IsBreak( - "'a' U+1F1FA U+1F1F8 | U+1F1FA")); // Regional indicator pair (flag) - EXPECT_FALSE(IsBreak( - "'a' U+1F1FA | U+1F1F8 U+1F1FA")); // Regional indicator pair (flag) - - EXPECT_TRUE(IsBreak("'a' U+1F1FA U+1F1F8 | U+1F1FA U+1F1F8")); // Regional - // indicator - // pair (flag) - EXPECT_FALSE(IsBreak("'a' U+1F1FA | U+1F1F8 U+1F1FA U+1F1F8")); // Regional - // indicator - // pair - // (flag) - EXPECT_FALSE(IsBreak("'a' U+1F1FA U+1F1F8 U+1F1FA | U+1F1F8")); // Regional - // indicator - // pair - // (flag) - - // Rule GB9, x (Extend | ZWJ) - EXPECT_FALSE(IsBreak("'a' | U+0301")); // combining accent - // TODO(jsimmons): re-enable this test when ICU has been updated in all - // Flutter platforms. - // EXPECT_FALSE(IsBreak("'a' | U+200D")); // ZWJ - // Rule GB9a, x SpacingMark - EXPECT_FALSE(IsBreak("U+0915 | U+093E")); // KA, AA (spacing mark) - // Rule GB9b, Prepend x - // see tailoring test for prepend, as current ICU doesn't have any characters - // in the class - - // Rule GB999, Any ÷ Any - EXPECT_TRUE(IsBreak("'a' | 'b'")); - EXPECT_TRUE(IsBreak("'f' | 'i'")); // probable ligature - EXPECT_TRUE(IsBreak("U+0644 | U+0627")); // probable ligature, lam + alef - EXPECT_TRUE(IsBreak("U+4E00 | U+4E00")); // CJK ideographs - EXPECT_TRUE( - IsBreak("'a' | U+1F1FA U+1F1F8")); // Regional indicator pair (flag) - EXPECT_TRUE( - IsBreak("U+1F1FA U+1F1F8 | 'a'")); // Regional indicator pair (flag) - - // Extended rule for emoji tag sequence. - EXPECT_TRUE(IsBreak("'a' | U+1F3F4 'a'")); - EXPECT_TRUE(IsBreak("'a' U+1F3F4 | 'a'")); - - // Immediate tag_term after tag_base. - EXPECT_TRUE(IsBreak("'a' | U+1F3F4 U+E007F 'a'")); - EXPECT_FALSE(IsBreak("U+1F3F4 | U+E007F")); - EXPECT_TRUE(IsBreak("'a' U+1F3F4 U+E007F | 'a'")); - - // Flag sequence - // U+1F3F4 U+E0067 U+E0062 U+E0073 U+E0063 U+E0074 U+E007F is emoji tag - // sequence for the flag of Scotland. U+1F3F4 is WAVING BLACK FLAG. This can - // be a tag_base character. U+E0067 is TAG LATIN SMALL LETTER G. This can be a - // part of tag_spec. U+E0062 is TAG LATIN SMALL LETTER B. This can be a part - // of tag_spec. U+E0073 is TAG LATIN SMALL LETTER S. This can be a part of - // tag_spec. U+E0063 is TAG LATIN SMALL LETTER C. This can be a part of - // tag_spec. U+E0074 is TAG LATIN SMALL LETTER T. This can be a part of - // tag_spec. U+E007F is CANCEL TAG. This is a tag_term character. - EXPECT_TRUE( - IsBreak("'a' | U+1F3F4 U+E0067 U+E0062 U+E0073 U+E0063 U+E0074 U+E007F")); - EXPECT_FALSE( - IsBreak("U+1F3F4 | U+E0067 U+E0062 U+E0073 U+E0063 U+E0074 U+E007F")); - EXPECT_FALSE( - IsBreak("U+1F3F4 U+E0067 | U+E0062 U+E0073 U+E0063 U+E0074 U+E007F")); - EXPECT_FALSE( - IsBreak("U+1F3F4 U+E0067 U+E0062 | U+E0073 U+E0063 U+E0074 U+E007F")); - EXPECT_FALSE( - IsBreak("U+1F3F4 U+E0067 U+E0062 U+E0073 | U+E0063 U+E0074 U+E007F")); - EXPECT_FALSE( - IsBreak("U+1F3F4 U+E0067 U+E0062 U+E0073 U+E0063 | U+E0074 U+E007F")); - EXPECT_FALSE( - IsBreak("U+1F3F4 U+E0067 U+E0062 U+E0073 U+E0063 U+E0074 | U+E007F")); - EXPECT_TRUE( - IsBreak("U+1F3F4 U+E0067 U+E0062 U+E0073 U+E0063 U+E0074 U+E007F | 'a'")); -} - -TEST(GraphemeBreak, DISABLED_tailoring) { - // control characters that we interpret as "extend" - EXPECT_FALSE(IsBreak("'a' | U+00AD")); // soft hyphen - EXPECT_FALSE(IsBreak("'a' | U+200B")); // zwsp - EXPECT_FALSE(IsBreak("'a' | U+200E")); // lrm - EXPECT_FALSE(IsBreak("'a' | U+202A")); // lre - EXPECT_FALSE(IsBreak("'a' | U+E0041")); // tag character - - // UTC-approved characters for the Prepend class - EXPECT_FALSE( - IsBreak("U+06DD | U+0661")); // arabic subtending mark + digit one - - EXPECT_TRUE(IsBreak("U+0E01 | U+0E33")); // Thai sara am - - // virama is not a grapheme break, but "pure killer" is - EXPECT_FALSE(IsBreak("U+0915 | U+094D U+0915")); // Devanagari ka+virama+ka - EXPECT_FALSE(IsBreak("U+0915 U+094D | U+0915")); // Devanagari ka+virama+ka - EXPECT_FALSE( - IsBreak("U+0E01 | U+0E3A U+0E01")); // thai phinthu = pure killer - EXPECT_TRUE(IsBreak("U+0E01 U+0E3A | U+0E01")); // thai phinthu = pure killer - - // Repetition of above tests, but with a given advances array that implies - // everything became just one cluster. - const float conjoined[] = {1.0, 0.0, 0.0}; - EXPECT_FALSE(IsBreakWithAdvances( - conjoined, - "U+0915 | U+094D U+0915")); // Devanagari ka+virama+ka - EXPECT_FALSE(IsBreakWithAdvances( - conjoined, - "U+0915 U+094D | U+0915")); // Devanagari ka+virama+ka - EXPECT_FALSE(IsBreakWithAdvances( - conjoined, - "U+0E01 | U+0E3A U+0E01")); // thai phinthu = pure killer - EXPECT_TRUE(IsBreakWithAdvances( - conjoined, - "U+0E01 U+0E3A | U+0E01")); // thai phinthu = pure killer - - // Repetition of above tests, but with a given advances array that the virama - // did not form a cluster with the following consonant. The difference is that - // there is now a grapheme break after the virama in ka+virama+ka. - const float separate[] = {1.0, 0.0, 1.0}; - EXPECT_FALSE(IsBreakWithAdvances( - separate, - "U+0915 | U+094D U+0915")); // Devanagari ka+virama+ka - EXPECT_TRUE(IsBreakWithAdvances( - separate, - "U+0915 U+094D | U+0915")); // Devanagari ka+virama+ka - EXPECT_FALSE(IsBreakWithAdvances( - separate, - "U+0E01 | U+0E3A U+0E01")); // thai phinthu = pure killer - EXPECT_TRUE(IsBreakWithAdvances( - separate, - "U+0E01 U+0E3A | U+0E01")); // thai phinthu = pure killer - - // suppress grapheme breaks in zwj emoji sequences - EXPECT_FALSE( - IsBreak("U+1F469 U+200D | U+2764 U+FE0F U+200D U+1F48B U+200D U+1F468")); - EXPECT_FALSE( - IsBreak("U+1F469 U+200D U+2764 U+FE0F U+200D | U+1F48B U+200D U+1F468")); - EXPECT_FALSE( - IsBreak("U+1F469 U+200D U+2764 U+FE0F U+200D U+1F48B U+200D | U+1F468")); - EXPECT_FALSE(IsBreak("U+1F468 U+200D | U+1F469 U+200D U+1F466")); - EXPECT_FALSE(IsBreak("U+1F468 U+200D U+1F469 U+200D | U+1F466")); - EXPECT_FALSE( - IsBreak("U+1F469 U+200D | U+1F469 U+200D U+1F467 U+200D U+1F466")); - EXPECT_FALSE( - IsBreak("U+1F469 U+200D U+1F469 U+200D | U+1F467 U+200D U+1F466")); - EXPECT_FALSE( - IsBreak("U+1F469 U+200D U+1F469 U+200D U+1F467 U+200D | U+1F466")); - EXPECT_FALSE(IsBreak("U+1F441 U+200D | U+1F5E8")); - - // Do not break before and after zwj with all kind of emoji characters. - EXPECT_FALSE(IsBreak("U+1F431 | U+200D U+1F464")); - EXPECT_FALSE(IsBreak("U+1F431 U+200D | U+1F464")); - - // ARABIC LETTER BEH + ZWJ + heart, not a zwj emoji sequence, so we preserve - // the break - EXPECT_TRUE(IsBreak("U+0628 U+200D | U+2764")); -} - -TEST(GraphemeBreak, DISABLED_emojiModifiers) { - EXPECT_FALSE( - IsBreak("U+261D | U+1F3FB")); // white up pointing index + modifier - EXPECT_FALSE(IsBreak("U+270C | U+1F3FB")); // victory hand + modifier - EXPECT_FALSE(IsBreak("U+1F466 | U+1F3FB")); // boy + modifier - EXPECT_FALSE(IsBreak("U+1F466 | U+1F3FC")); // boy + modifier - EXPECT_FALSE(IsBreak("U+1F466 | U+1F3FD")); // boy + modifier - EXPECT_FALSE(IsBreak("U+1F466 | U+1F3FE")); // boy + modifier - EXPECT_FALSE(IsBreak("U+1F466 | U+1F3FF")); // boy + modifier - EXPECT_FALSE(IsBreak("U+1F918 | U+1F3FF")); // sign of the horns + modifier - EXPECT_FALSE(IsBreak("U+1F933 | U+1F3FF")); // selfie (Unicode 9) + modifier - // Repetition of the tests above, with the knowledge that they are ligated. - const float ligated1_2[] = {1.0, 0.0, 0.0}; - const float ligated2_2[] = {1.0, 0.0, 0.0, 0.0}; - EXPECT_FALSE(IsBreakWithAdvances(ligated1_2, "U+261D | U+1F3FB")); - EXPECT_FALSE(IsBreakWithAdvances(ligated1_2, "U+270C | U+1F3FB")); - EXPECT_FALSE(IsBreakWithAdvances(ligated2_2, "U+1F466 | U+1F3FB")); - EXPECT_FALSE(IsBreakWithAdvances(ligated2_2, "U+1F466 | U+1F3FC")); - EXPECT_FALSE(IsBreakWithAdvances(ligated2_2, "U+1F466 | U+1F3FD")); - EXPECT_FALSE(IsBreakWithAdvances(ligated2_2, "U+1F466 | U+1F3FE")); - EXPECT_FALSE(IsBreakWithAdvances(ligated2_2, "U+1F466 | U+1F3FF")); - EXPECT_FALSE(IsBreakWithAdvances(ligated2_2, "U+1F918 | U+1F3FF")); - EXPECT_FALSE(IsBreakWithAdvances(ligated2_2, "U+1F933 | U+1F3FF")); - // Repetition of the tests above, with the knowledge that they are not - // ligated. - const float unligated1_2[] = {1.0, 1.0, 0.0}; - const float unligated2_2[] = {1.0, 0.0, 1.0, 0.0}; - EXPECT_TRUE(IsBreakWithAdvances(unligated1_2, "U+261D | U+1F3FB")); - EXPECT_TRUE(IsBreakWithAdvances(unligated1_2, "U+270C | U+1F3FB")); - EXPECT_TRUE(IsBreakWithAdvances(unligated2_2, "U+1F466 | U+1F3FB")); - EXPECT_TRUE(IsBreakWithAdvances(unligated2_2, "U+1F466 | U+1F3FC")); - EXPECT_TRUE(IsBreakWithAdvances(unligated2_2, "U+1F466 | U+1F3FD")); - EXPECT_TRUE(IsBreakWithAdvances(unligated2_2, "U+1F466 | U+1F3FE")); - EXPECT_TRUE(IsBreakWithAdvances(unligated2_2, "U+1F466 | U+1F3FF")); - EXPECT_TRUE(IsBreakWithAdvances(unligated2_2, "U+1F918 | U+1F3FF")); - EXPECT_TRUE(IsBreakWithAdvances(unligated2_2, "U+1F933 | U+1F3FF")); - - // adding extend characters between emoji base and modifier doesn't affect - // grapheme cluster - EXPECT_FALSE(IsBreak( - "U+270C U+FE0E | U+1F3FB")); // victory hand + text style + modifier - EXPECT_FALSE( - IsBreak("U+270C U+FE0F | U+1F3FB")); // heart + emoji style + modifier - // Repetition of the two tests above, with the knowledge that they are - // ligated. - const float ligated1_1_2[] = {1.0, 0.0, 0.0, 0.0}; - EXPECT_FALSE(IsBreakWithAdvances(ligated1_1_2, "U+270C U+FE0E | U+1F3FB")); - EXPECT_FALSE(IsBreakWithAdvances(ligated1_1_2, "U+270C U+FE0F | U+1F3FB")); - // Repetition of the first two tests, with the knowledge that they are not - // ligated. - const float unligated1_1_2[] = {1.0, 0.0, 1.0, 0.0}; - EXPECT_TRUE(IsBreakWithAdvances(unligated1_1_2, "U+270C U+FE0E | U+1F3FB")); - EXPECT_TRUE(IsBreakWithAdvances(unligated1_1_2, "U+270C U+FE0F | U+1F3FB")); - - // heart is not an emoji base - EXPECT_TRUE(IsBreak("U+2764 | U+1F3FB")); // heart + modifier - EXPECT_TRUE( - IsBreak("U+2764 U+FE0E | U+1F3FB")); // heart + emoji style + modifier - EXPECT_TRUE( - IsBreak("U+2764 U+FE0F | U+1F3FB")); // heart + emoji style + modifier - EXPECT_TRUE(IsBreak("U+1F3FB | U+1F3FB")); // modifier + modifier - - // rat is not an emoji modifer - EXPECT_TRUE(IsBreak("U+1F466 | U+1F400")); // boy + rat -} - -TEST(GraphemeBreak, DISABLED_genderBalancedEmoji) { - // U+1F469 is WOMAN, U+200D is ZWJ, U+1F4BC is BRIEFCASE. - EXPECT_FALSE(IsBreak("U+1F469 | U+200D U+1F4BC")); - EXPECT_FALSE(IsBreak("U+1F469 U+200D | U+1F4BC")); - // The above two cases, when the ligature is not supported in the font. We now - // expect a break between them. - const float unligated2_1_2[] = {1.0, 0.0, 0.0, 1.0, 0.0}; - EXPECT_FALSE(IsBreakWithAdvances(unligated2_1_2, "U+1F469 | U+200D U+1F4BC")); - EXPECT_TRUE(IsBreakWithAdvances(unligated2_1_2, "U+1F469 U+200D | U+1F4BC")); - - // U+2695 has now emoji property, so should be part of ZWJ sequence. - EXPECT_FALSE(IsBreak("U+1F469 | U+200D U+2695")); - EXPECT_FALSE(IsBreak("U+1F469 U+200D | U+2695")); - // The above two cases, when the ligature is not supported in the font. We now - // expect a break between them. - const float unligated2_1_1[] = {1.0, 0.0, 0.0, 1.0}; - EXPECT_FALSE(IsBreakWithAdvances(unligated2_1_1, "U+1F469 | U+200D U+2695")); - EXPECT_TRUE(IsBreakWithAdvances(unligated2_1_1, "U+1F469 U+200D | U+2695")); -} - -TEST(GraphemeBreak, offsets) { - uint16_t string[] = {0x0041, 0x06DD, 0x0045, 0x0301, 0x0049, 0x0301}; - EXPECT_TRUE(GraphemeBreak::isGraphemeBreak(nullptr, string, 2, 3, 2)); - EXPECT_FALSE(GraphemeBreak::isGraphemeBreak(nullptr, string, 2, 3, 3)); - EXPECT_TRUE(GraphemeBreak::isGraphemeBreak(nullptr, string, 2, 3, 4)); - EXPECT_TRUE(GraphemeBreak::isGraphemeBreak(nullptr, string, 2, 3, 5)); -} - -} // namespace minikin diff --git a/third_party/txt/tests/HbFontCacheTest.cpp b/third_party/txt/tests/HbFontCacheTest.cpp deleted file mode 100644 index afbe47432160b..0000000000000 --- a/third_party/txt/tests/HbFontCacheTest.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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 "minikin/HbFontCache.h" - -#include -#include - -#include -#include - -#include - -#include -#include "MinikinFontForTest.h" -#include "minikin/MinikinInternal.h" - -namespace minikin { - -class HbFontCacheTest : public testing::Test { - public: - virtual void TearDown() { - std::scoped_lock _l(gMinikinLock); - purgeHbFontCacheLocked(); - } -}; - -TEST_F(HbFontCacheTest, getHbFontLockedTest) { - std::shared_ptr fontA( - new MinikinFontForTest(kTestFontDir "Regular.ttf")); - - std::shared_ptr fontB( - new MinikinFontForTest(kTestFontDir "Bold.ttf")); - - std::shared_ptr fontC( - new MinikinFontForTest(kTestFontDir "BoldItalic.ttf")); - - std::scoped_lock _l(gMinikinLock); - // Never return NULL. - EXPECT_NE(nullptr, getHbFontLocked(fontA.get())); - EXPECT_NE(nullptr, getHbFontLocked(fontB.get())); - EXPECT_NE(nullptr, getHbFontLocked(fontC.get())); - - EXPECT_NE(nullptr, getHbFontLocked(nullptr)); - - // Must return same object if same font object is passed. - EXPECT_EQ(getHbFontLocked(fontA.get()), getHbFontLocked(fontA.get())); - EXPECT_EQ(getHbFontLocked(fontB.get()), getHbFontLocked(fontB.get())); - EXPECT_EQ(getHbFontLocked(fontC.get()), getHbFontLocked(fontC.get())); - - // Different object must be returned if the passed minikinFont has different - // ID. - EXPECT_NE(getHbFontLocked(fontA.get()), getHbFontLocked(fontB.get())); - EXPECT_NE(getHbFontLocked(fontA.get()), getHbFontLocked(fontC.get())); -} - -TEST_F(HbFontCacheTest, purgeCacheTest) { - std::shared_ptr minikinFont( - new MinikinFontForTest(kTestFontDir "Regular.ttf")); - - std::scoped_lock _l(gMinikinLock); - hb_font_t* font = getHbFontLocked(minikinFont.get()); - ASSERT_NE(nullptr, font); - - // Set user data to identify the font object. - hb_user_data_key_t key; - void* data = (void*)0xdeadbeef; - hb_font_set_user_data(font, &key, data, NULL, false); - ASSERT_EQ(data, hb_font_get_user_data(font, &key)); - - purgeHbFontCacheLocked(); - - // By checking user data, confirm that the object after purge is different - // from previously created one. Do not compare the returned pointer here since - // memory allocator may assign same region for new object. - font = getHbFontLocked(minikinFont.get()); - EXPECT_EQ(nullptr, hb_font_get_user_data(font, &key)); -} - -} // namespace minikin diff --git a/third_party/txt/tests/HyphenatorTest.cpp b/third_party/txt/tests/HyphenatorTest.cpp deleted file mode 100644 index 886b38dc12ed5..0000000000000 --- a/third_party/txt/tests/HyphenatorTest.cpp +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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 -#include "FileUtils.h" -#include "ICUTestBase.h" - -#ifndef NELEM -#define NELEM(x) ((sizeof(x) / sizeof((x)[0]))) -#endif - -namespace minikin { - -const char* usHyph = "/system/usr/hyphen-data/hyph-en-us.hyb"; -const char* malayalamHyph = "/system/usr/hyphen-data/hyph-ml.hyb"; - -typedef ICUTestBase HyphenatorTest; - -const icu::Locale catalanLocale("ca", "ES", nullptr, nullptr); -const icu::Locale polishLocale("pl", "PL", nullptr, nullptr); -const icu::Locale& usLocale = icu::Locale::getUS(); - -const uint16_t HYPHEN_MINUS = 0x002D; -const uint16_t SOFT_HYPHEN = 0x00AD; -const uint16_t MIDDLE_DOT = 0x00B7; -const uint16_t GREEK_LOWER_ALPHA = 0x03B1; -const uint16_t ARMENIAN_AYB = 0x0531; -const uint16_t HEBREW_ALEF = 0x05D0; -const uint16_t ARABIC_ALEF = 0x0627; -const uint16_t ARABIC_BEH = 0x0628; -const uint16_t ARABIC_ZWARAKAY = 0x0659; -const uint16_t MALAYALAM_KA = 0x0D15; -const uint16_t UCAS_E = 0x1401; -const uint16_t HYPHEN = 0x2010; -const uint16_t EN_DASH = 0x2013; - -// Simple test for US English. This tests "table", which happens to be the in -// the exceptions list. -TEST_F(HyphenatorTest, usEnglishAutomaticHyphenation) { - Hyphenator* hyphenator = - Hyphenator::loadBinary(readWholeFile(usHyph).data(), 2, 3); - const uint16_t word[] = {'t', 'a', 'b', 'l', 'e'}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), usLocale); - EXPECT_EQ((size_t)5, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::BREAK_AND_INSERT_HYPHEN, result[2]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[3]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[4]); -} - -// Catalan l·l should break as l-/l -TEST_F(HyphenatorTest, catalanMiddleDot) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {'l', 'l', MIDDLE_DOT, 'l', 'l'}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), catalanLocale); - EXPECT_EQ((size_t)5, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[2]); - EXPECT_EQ(HyphenationType::BREAK_AND_REPLACE_WITH_HYPHEN, result[3]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[4]); -} - -// Catalan l·l should not break if the word is too short. -TEST_F(HyphenatorTest, catalanMiddleDotShortWord) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {'l', MIDDLE_DOT, 'l'}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), catalanLocale); - EXPECT_EQ((size_t)3, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[2]); -} - -// If we break on a hyphen in Polish, the hyphen should be repeated on the next -// line. -TEST_F(HyphenatorTest, polishHyphen) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {'x', HYPHEN, 'y'}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), polishLocale); - EXPECT_EQ((size_t)3, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::BREAK_AND_INSERT_HYPHEN_AT_NEXT_LINE, result[2]); -} - -// If the language is Polish but the script is not Latin, don't use Polish rules -// for hyphenation. -TEST_F(HyphenatorTest, polishHyphenButNonLatinWord) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {GREEK_LOWER_ALPHA, HYPHEN, GREEK_LOWER_ALPHA}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), polishLocale); - EXPECT_EQ((size_t)3, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::BREAK_AND_DONT_INSERT_HYPHEN, result[2]); -} - -// Polish en dash doesn't repeat on next line (as far as we know), but just -// provides a break opportunity. -TEST_F(HyphenatorTest, polishEnDash) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {'x', EN_DASH, 'y'}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), polishLocale); - EXPECT_EQ((size_t)3, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::BREAK_AND_DONT_INSERT_HYPHEN, result[2]); -} - -// In Latin script text, soft hyphens should insert a visible hyphen if broken -// at. -TEST_F(HyphenatorTest, latinSoftHyphen) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {'x', SOFT_HYPHEN, 'y'}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), usLocale); - EXPECT_EQ((size_t)3, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::BREAK_AND_INSERT_HYPHEN, result[2]); -} - -// Soft hyphens at the beginning of a word are not useful in linebreaking. -TEST_F(HyphenatorTest, latinSoftHyphenStartingTheWord) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {SOFT_HYPHEN, 'y'}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), usLocale); - EXPECT_EQ((size_t)2, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); -} - -// In Malayalam script text, soft hyphens should not insert a visible hyphen if -// broken at. -TEST_F(HyphenatorTest, malayalamSoftHyphen) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {MALAYALAM_KA, SOFT_HYPHEN, MALAYALAM_KA}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), usLocale); - EXPECT_EQ((size_t)3, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::BREAK_AND_DONT_INSERT_HYPHEN, result[2]); -} - -// In automatically hyphenated Malayalam script text, we should not insert a -// visible hyphen. -TEST_F(HyphenatorTest, malayalamAutomaticHyphenation) { - Hyphenator* hyphenator = - Hyphenator::loadBinary(readWholeFile(malayalamHyph).data(), 2, 2); - const uint16_t word[] = {MALAYALAM_KA, MALAYALAM_KA, MALAYALAM_KA, - MALAYALAM_KA, MALAYALAM_KA}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), usLocale); - EXPECT_EQ((size_t)5, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::BREAK_AND_DONT_INSERT_HYPHEN, result[2]); - EXPECT_EQ(HyphenationType::BREAK_AND_DONT_INSERT_HYPHEN, result[3]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[4]); -} - -// In Armenian script text, soft hyphens should insert an Armenian hyphen if -// broken at. -TEST_F(HyphenatorTest, aremenianSoftHyphen) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {ARMENIAN_AYB, SOFT_HYPHEN, ARMENIAN_AYB}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), usLocale); - EXPECT_EQ((size_t)3, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::BREAK_AND_INSERT_ARMENIAN_HYPHEN, result[2]); -} - -// In Hebrew script text, soft hyphens should insert a normal hyphen if broken -// at, for now. We may need to change this to maqaf later. -TEST_F(HyphenatorTest, hebrewSoftHyphen) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {HEBREW_ALEF, SOFT_HYPHEN, HEBREW_ALEF}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), usLocale); - EXPECT_EQ((size_t)3, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::BREAK_AND_INSERT_HYPHEN, result[2]); -} - -// Soft hyphen between two Arabic letters that join should keep the joining -// behavior when broken across lines. -TEST_F(HyphenatorTest, arabicSoftHyphenConnecting) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {ARABIC_BEH, SOFT_HYPHEN, ARABIC_BEH}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), usLocale); - EXPECT_EQ((size_t)3, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::BREAK_AND_INSERT_HYPHEN_AND_ZWJ, result[2]); -} - -// Arabic letters may be joining on one side, but if it's the wrong side, we -// should use the normal hyphen. -TEST_F(HyphenatorTest, arabicSoftHyphenNonConnecting) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {ARABIC_ALEF, SOFT_HYPHEN, ARABIC_BEH}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), usLocale); - EXPECT_EQ((size_t)3, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::BREAK_AND_INSERT_HYPHEN, result[2]); -} - -// Skip transparent characters until you find a non-transparent one. -TEST_F(HyphenatorTest, arabicSoftHyphenSkipTransparents) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {ARABIC_BEH, ARABIC_ZWARAKAY, SOFT_HYPHEN, - ARABIC_ZWARAKAY, ARABIC_BEH}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), usLocale); - EXPECT_EQ((size_t)5, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[2]); - EXPECT_EQ(HyphenationType::BREAK_AND_INSERT_HYPHEN_AND_ZWJ, result[3]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[4]); -} - -// Skip transparent characters until you find a non-transparent one. If we get -// to one end without finding anything, we are still non-joining. -TEST_F(HyphenatorTest, arabicSoftHyphenTransparentsAtEnd) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {ARABIC_BEH, ARABIC_ZWARAKAY, SOFT_HYPHEN, - ARABIC_ZWARAKAY}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), usLocale); - EXPECT_EQ((size_t)4, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[2]); - EXPECT_EQ(HyphenationType::BREAK_AND_INSERT_HYPHEN, result[3]); -} - -// Skip transparent characters until you find a non-transparent one. If we get -// to one end without finding anything, we are still non-joining. -TEST_F(HyphenatorTest, arabicSoftHyphenTransparentsAtStart) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {ARABIC_ZWARAKAY, SOFT_HYPHEN, ARABIC_ZWARAKAY, - ARABIC_BEH}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), usLocale); - EXPECT_EQ((size_t)4, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::BREAK_AND_INSERT_HYPHEN, result[2]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[3]); -} - -// In Unified Canadian Aboriginal script (UCAS) text, soft hyphens should insert -// a UCAS hyphen. -TEST_F(HyphenatorTest, ucasSoftHyphen) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {UCAS_E, SOFT_HYPHEN, UCAS_E}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), usLocale); - EXPECT_EQ((size_t)3, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::BREAK_AND_INSERT_UCAS_HYPHEN, result[2]); -} - -// Presently, soft hyphen looks at the character after it to determine -// hyphenation type. This is a little arbitrary, but let's test it anyway. -TEST_F(HyphenatorTest, mixedScriptSoftHyphen) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {'a', SOFT_HYPHEN, UCAS_E}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), usLocale); - EXPECT_EQ((size_t)3, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::BREAK_AND_INSERT_UCAS_HYPHEN, result[2]); -} - -// Hard hyphens provide a breaking opportunity with nothing extra inserted. -TEST_F(HyphenatorTest, hardHyphen) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {'x', HYPHEN, 'y'}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), usLocale); - EXPECT_EQ((size_t)3, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::BREAK_AND_DONT_INSERT_HYPHEN, result[2]); -} - -// Hyphen-minuses also provide a breaking opportunity with nothing extra -// inserted. -TEST_F(HyphenatorTest, hyphenMinus) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {'x', HYPHEN_MINUS, 'y'}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), usLocale); - EXPECT_EQ((size_t)3, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); - EXPECT_EQ(HyphenationType::BREAK_AND_DONT_INSERT_HYPHEN, result[2]); -} - -// If the word starts with a hard hyphen or hyphen-minus, it doesn't make sense -// to break it at that point. -TEST_F(HyphenatorTest, startingHyphenMinus) { - Hyphenator* hyphenator = Hyphenator::loadBinary(nullptr, 2, 2); - const uint16_t word[] = {HYPHEN_MINUS, 'y'}; - std::vector result; - hyphenator->hyphenate(&result, word, NELEM(word), usLocale); - EXPECT_EQ((size_t)2, result.size()); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[0]); - EXPECT_EQ(HyphenationType::DONT_BREAK, result[1]); -} - -} // namespace minikin diff --git a/third_party/txt/tests/ICUTestBase.h b/third_party/txt/tests/ICUTestBase.h deleted file mode 100644 index c25b8f6daffcc..0000000000000 --- a/third_party/txt/tests/ICUTestBase.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#ifndef MINIKIN_TEST_ICU_TEST_BASE_H -#define MINIKIN_TEST_ICU_TEST_BASE_H - -#include -#include -#include - -// low level file access for mapping ICU data -#include -#include -#include - -namespace minikin { - -class ICUTestBase : public testing::Test { - protected: - virtual void SetUp() override { - const char* fn = "/system/usr/icu/" U_ICUDATA_NAME ".dat"; - int fd = open(fn, O_RDONLY); - ASSERT_NE(-1, fd); - struct stat sb; - ASSERT_EQ(0, fstat(fd, &sb)); - void* data = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); - - UErrorCode errorCode = U_ZERO_ERROR; - udata_setCommonData(data, &errorCode); - ASSERT_TRUE(U_SUCCESS(errorCode)); - u_init(&errorCode); - ASSERT_TRUE(U_SUCCESS(errorCode)); - } - - virtual void TearDown() override { u_cleanup(); } -}; - -} // namespace minikin -#endif // MINIKIN_TEST_ICU_TEST_BASE_H diff --git a/third_party/txt/tests/LayoutTest.cpp b/third_party/txt/tests/LayoutTest.cpp deleted file mode 100644 index e9ad2eb066a82..0000000000000 --- a/third_party/txt/tests/LayoutTest.cpp +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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 "../util/FontTestUtils.h" -#include "../util/UnicodeUtils.h" -#include "ICUTestBase.h" -#include "minikin/FontCollection.h" -#include "minikin/Layout.h" - -const char* SYSTEM_FONT_PATH = "/system/fonts/"; -const char* SYSTEM_FONT_XML = "/system/etc/fonts.xml"; - -namespace minikin { - -const float UNTOUCHED_MARKER = 1e+38; - -static void expectAdvances(std::vector expected, - float* advances, - size_t length) { - EXPECT_LE(expected.size(), length); - for (size_t i = 0; i < expected.size(); ++i) { - EXPECT_EQ(expected[i], advances[i]) - << i << "th element is different. Expected: " << expected[i] - << ", Actual: " << advances[i]; - } - EXPECT_EQ(UNTOUCHED_MARKER, advances[expected.size()]); -} - -static void resetAdvances(float* advances, size_t length) { - for (size_t i = 0; i < length; ++i) { - advances[i] = UNTOUCHED_MARKER; - } -} - -class LayoutTest : public ICUTestBase { - protected: - LayoutTest() : mCollection(nullptr) {} - - virtual ~LayoutTest() {} - - virtual void SetUp() override { - mCollection = std::shared_ptr( - getFontCollection(SYSTEM_FONT_PATH, SYSTEM_FONT_XML)); - } - - virtual void TearDown() override {} - - std::shared_ptr mCollection; -}; - -TEST_F(LayoutTest, doLayoutTest) { - MinikinPaint paint; - MinikinRect rect; - const size_t kMaxAdvanceLength = 32; - float advances[kMaxAdvanceLength]; - std::vector expectedValues; - - Layout layout; - std::vector text; - - // The mock implementation returns 10.0f advance and 0,0-10x10 bounds for all - // glyph. - { - SCOPED_TRACE("one word"); - text = utf8ToUtf16("oneword"); - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - EXPECT_EQ(70.0f, layout.getAdvance()); - layout.getBounds(&rect); - EXPECT_EQ(0.0f, rect.mLeft); - EXPECT_EQ(0.0f, rect.mTop); - EXPECT_EQ(70.0f, rect.mRight); - EXPECT_EQ(10.0f, rect.mBottom); - resetAdvances(advances, kMaxAdvanceLength); - layout.getAdvances(advances); - expectedValues.resize(text.size()); - for (size_t i = 0; i < expectedValues.size(); ++i) { - expectedValues[i] = 10.0f; - } - expectAdvances(expectedValues, advances, kMaxAdvanceLength); - } - { - SCOPED_TRACE("two words"); - text = utf8ToUtf16("two words"); - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - EXPECT_EQ(90.0f, layout.getAdvance()); - layout.getBounds(&rect); - EXPECT_EQ(0.0f, rect.mLeft); - EXPECT_EQ(0.0f, rect.mTop); - EXPECT_EQ(90.0f, rect.mRight); - EXPECT_EQ(10.0f, rect.mBottom); - resetAdvances(advances, kMaxAdvanceLength); - layout.getAdvances(advances); - expectedValues.resize(text.size()); - for (size_t i = 0; i < expectedValues.size(); ++i) { - expectedValues[i] = 10.0f; - } - expectAdvances(expectedValues, advances, kMaxAdvanceLength); - } - { - SCOPED_TRACE("three words"); - text = utf8ToUtf16("three words test"); - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - EXPECT_EQ(160.0f, layout.getAdvance()); - layout.getBounds(&rect); - EXPECT_EQ(0.0f, rect.mLeft); - EXPECT_EQ(0.0f, rect.mTop); - EXPECT_EQ(160.0f, rect.mRight); - EXPECT_EQ(10.0f, rect.mBottom); - resetAdvances(advances, kMaxAdvanceLength); - layout.getAdvances(advances); - expectedValues.resize(text.size()); - for (size_t i = 0; i < expectedValues.size(); ++i) { - expectedValues[i] = 10.0f; - } - expectAdvances(expectedValues, advances, kMaxAdvanceLength); - } - { - SCOPED_TRACE("two spaces"); - text = utf8ToUtf16("two spaces"); - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - EXPECT_EQ(110.0f, layout.getAdvance()); - layout.getBounds(&rect); - EXPECT_EQ(0.0f, rect.mLeft); - EXPECT_EQ(0.0f, rect.mTop); - EXPECT_EQ(110.0f, rect.mRight); - EXPECT_EQ(10.0f, rect.mBottom); - resetAdvances(advances, kMaxAdvanceLength); - layout.getAdvances(advances); - expectedValues.resize(text.size()); - for (size_t i = 0; i < expectedValues.size(); ++i) { - expectedValues[i] = 10.0f; - } - expectAdvances(expectedValues, advances, kMaxAdvanceLength); - } -} - -TEST_F(LayoutTest, doLayoutTest_wordSpacing) { - MinikinPaint paint; - MinikinRect rect; - const size_t kMaxAdvanceLength = 32; - float advances[kMaxAdvanceLength]; - std::vector expectedValues; - std::vector text; - - Layout layout; - - paint.wordSpacing = 5.0f; - - // The mock implementation returns 10.0f advance and 0,0-10x10 bounds for all - // glyph. - { - SCOPED_TRACE("one word"); - text = utf8ToUtf16("oneword"); - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - EXPECT_EQ(70.0f, layout.getAdvance()); - layout.getBounds(&rect); - EXPECT_EQ(0.0f, rect.mLeft); - EXPECT_EQ(0.0f, rect.mTop); - EXPECT_EQ(70.0f, rect.mRight); - EXPECT_EQ(10.0f, rect.mBottom); - resetAdvances(advances, kMaxAdvanceLength); - layout.getAdvances(advances); - expectedValues.resize(text.size()); - for (size_t i = 0; i < expectedValues.size(); ++i) { - expectedValues[i] = 10.0f; - } - expectAdvances(expectedValues, advances, kMaxAdvanceLength); - } - { - SCOPED_TRACE("two words"); - text = utf8ToUtf16("two words"); - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - EXPECT_EQ(95.0f, layout.getAdvance()); - layout.getBounds(&rect); - EXPECT_EQ(0.0f, rect.mLeft); - EXPECT_EQ(0.0f, rect.mTop); - EXPECT_EQ(95.0f, rect.mRight); - EXPECT_EQ(10.0f, rect.mBottom); - resetAdvances(advances, kMaxAdvanceLength); - layout.getAdvances(advances); - EXPECT_EQ(UNTOUCHED_MARKER, advances[text.size()]); - resetAdvances(advances, kMaxAdvanceLength); - layout.getAdvances(advances); - expectedValues.resize(text.size()); - for (size_t i = 0; i < expectedValues.size(); ++i) { - expectedValues[i] = 10.0f; - } - expectedValues[3] = 15.0f; - expectAdvances(expectedValues, advances, kMaxAdvanceLength); - } - { - SCOPED_TRACE("three words test"); - text = utf8ToUtf16("three words test"); - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - EXPECT_EQ(170.0f, layout.getAdvance()); - layout.getBounds(&rect); - EXPECT_EQ(0.0f, rect.mLeft); - EXPECT_EQ(0.0f, rect.mTop); - EXPECT_EQ(170.0f, rect.mRight); - EXPECT_EQ(10.0f, rect.mBottom); - resetAdvances(advances, kMaxAdvanceLength); - layout.getAdvances(advances); - expectedValues.resize(text.size()); - for (size_t i = 0; i < expectedValues.size(); ++i) { - expectedValues[i] = 10.0f; - } - expectedValues[5] = 15.0f; - expectedValues[11] = 15.0f; - expectAdvances(expectedValues, advances, kMaxAdvanceLength); - } - { - SCOPED_TRACE("two spaces"); - text = utf8ToUtf16("two spaces"); - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - EXPECT_EQ(120.0f, layout.getAdvance()); - layout.getBounds(&rect); - EXPECT_EQ(0.0f, rect.mLeft); - EXPECT_EQ(0.0f, rect.mTop); - EXPECT_EQ(120.0f, rect.mRight); - EXPECT_EQ(10.0f, rect.mBottom); - resetAdvances(advances, kMaxAdvanceLength); - layout.getAdvances(advances); - expectedValues.resize(text.size()); - for (size_t i = 0; i < expectedValues.size(); ++i) { - expectedValues[i] = 10.0f; - } - expectedValues[3] = 15.0f; - expectedValues[4] = 15.0f; - expectAdvances(expectedValues, advances, kMaxAdvanceLength); - } -} - -TEST_F(LayoutTest, doLayoutTest_negativeWordSpacing) { - MinikinPaint paint; - MinikinRect rect; - const size_t kMaxAdvanceLength = 32; - float advances[kMaxAdvanceLength]; - std::vector expectedValues; - - Layout layout; - std::vector text; - - // Negative word spacing also should work. - paint.wordSpacing = -5.0f; - - { - SCOPED_TRACE("one word"); - text = utf8ToUtf16("oneword"); - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - EXPECT_EQ(70.0f, layout.getAdvance()); - layout.getBounds(&rect); - EXPECT_EQ(0.0f, rect.mLeft); - EXPECT_EQ(0.0f, rect.mTop); - EXPECT_EQ(70.0f, rect.mRight); - EXPECT_EQ(10.0f, rect.mBottom); - resetAdvances(advances, kMaxAdvanceLength); - layout.getAdvances(advances); - expectedValues.resize(text.size()); - for (size_t i = 0; i < expectedValues.size(); ++i) { - expectedValues[i] = 10.0f; - } - expectAdvances(expectedValues, advances, kMaxAdvanceLength); - } - { - SCOPED_TRACE("two words"); - text = utf8ToUtf16("two words"); - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - EXPECT_EQ(85.0f, layout.getAdvance()); - layout.getBounds(&rect); - EXPECT_EQ(0.0f, rect.mLeft); - EXPECT_EQ(0.0f, rect.mTop); - EXPECT_EQ(85.0f, rect.mRight); - EXPECT_EQ(10.0f, rect.mBottom); - resetAdvances(advances, kMaxAdvanceLength); - layout.getAdvances(advances); - expectedValues.resize(text.size()); - for (size_t i = 0; i < expectedValues.size(); ++i) { - expectedValues[i] = 10.0f; - } - expectedValues[3] = 5.0f; - expectAdvances(expectedValues, advances, kMaxAdvanceLength); - } - { - SCOPED_TRACE("three words"); - text = utf8ToUtf16("three word test"); - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - EXPECT_EQ(140.0f, layout.getAdvance()); - layout.getBounds(&rect); - EXPECT_EQ(0.0f, rect.mLeft); - EXPECT_EQ(0.0f, rect.mTop); - EXPECT_EQ(140.0f, rect.mRight); - EXPECT_EQ(10.0f, rect.mBottom); - resetAdvances(advances, kMaxAdvanceLength); - layout.getAdvances(advances); - expectedValues.resize(text.size()); - for (size_t i = 0; i < expectedValues.size(); ++i) { - expectedValues[i] = 10.0f; - } - expectedValues[5] = 5.0f; - expectedValues[10] = 5.0f; - expectAdvances(expectedValues, advances, kMaxAdvanceLength); - } - { - SCOPED_TRACE("two spaces"); - text = utf8ToUtf16("two spaces"); - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - EXPECT_EQ(100.0f, layout.getAdvance()); - layout.getBounds(&rect); - EXPECT_EQ(0.0f, rect.mLeft); - EXPECT_EQ(0.0f, rect.mTop); - EXPECT_EQ(100.0f, rect.mRight); - EXPECT_EQ(10.0f, rect.mBottom); - resetAdvances(advances, kMaxAdvanceLength); - layout.getAdvances(advances); - expectedValues.resize(text.size()); - for (size_t i = 0; i < expectedValues.size(); ++i) { - expectedValues[i] = 10.0f; - } - expectedValues[3] = 5.0f; - expectedValues[4] = 5.0f; - expectAdvances(expectedValues, advances, kMaxAdvanceLength); - } -} - -TEST_F(LayoutTest, doLayoutTest_rtlTest) { - MinikinPaint paint; - - std::vector text = - parseUnicodeString("'a' 'b' U+3042 U+3043 'c' 'd'"); - - Layout ltrLayout; - ltrLayout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - - Layout rtlLayout; - rtlLayout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_RTL, - FontStyle(), paint, mCollection); - - ASSERT_EQ(ltrLayout.nGlyphs(), rtlLayout.nGlyphs()); - ASSERT_EQ(6u, ltrLayout.nGlyphs()); - - size_t nGlyphs = ltrLayout.nGlyphs(); - for (size_t i = 0; i < nGlyphs; ++i) { - EXPECT_EQ(ltrLayout.getFont(i), rtlLayout.getFont(nGlyphs - i - 1)); - EXPECT_EQ(ltrLayout.getGlyphId(i), rtlLayout.getGlyphId(nGlyphs - i - 1)); - } -} - -TEST_F(LayoutTest, hyphenationTest) { - Layout layout; - std::vector text; - - // The mock implementation returns 10.0f advance for all glyphs. - { - SCOPED_TRACE("one word with no hyphen edit"); - text = utf8ToUtf16("oneword"); - MinikinPaint paint; - paint.hyphenEdit = HyphenEdit::NO_EDIT; - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - EXPECT_EQ(70.0f, layout.getAdvance()); - } - { - SCOPED_TRACE("one word with hyphen insertion at the end"); - text = utf8ToUtf16("oneword"); - MinikinPaint paint; - paint.hyphenEdit = HyphenEdit::INSERT_HYPHEN_AT_END; - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - EXPECT_EQ(80.0f, layout.getAdvance()); - } - { - SCOPED_TRACE("one word with hyphen replacement at the end"); - text = utf8ToUtf16("oneword"); - MinikinPaint paint; - paint.hyphenEdit = HyphenEdit::REPLACE_WITH_HYPHEN_AT_END; - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - EXPECT_EQ(70.0f, layout.getAdvance()); - } - { - SCOPED_TRACE("one word with hyphen insertion at the start"); - text = utf8ToUtf16("oneword"); - MinikinPaint paint; - paint.hyphenEdit = HyphenEdit::INSERT_HYPHEN_AT_START; - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - EXPECT_EQ(80.0f, layout.getAdvance()); - } - { - SCOPED_TRACE("one word with hyphen insertion at the both ends"); - text = utf8ToUtf16("oneword"); - MinikinPaint paint; - paint.hyphenEdit = - HyphenEdit::INSERT_HYPHEN_AT_START | HyphenEdit::INSERT_HYPHEN_AT_END; - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, mCollection); - EXPECT_EQ(90.0f, layout.getAdvance()); - } -} - -// TODO: Add more test cases, e.g. measure text, letter spacing. - -} // namespace minikin diff --git a/third_party/txt/tests/LayoutUtilsTest.cpp b/third_party/txt/tests/LayoutUtilsTest.cpp deleted file mode 100644 index 1c57e4b9030e1..0000000000000 --- a/third_party/txt/tests/LayoutUtilsTest.cpp +++ /dev/null @@ -1,510 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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 "UnicodeUtils.h" - -#include "minikin/LayoutUtils.h" - -namespace minikin { - -void ExpectNextWordBreakForCache(size_t offset_in, const char* query_str) { - const size_t BUF_SIZE = 256U; - uint16_t buf[BUF_SIZE]; - size_t expected_breakpoint = 0U; - size_t size = 0U; - - ParseUnicode(buf, BUF_SIZE, query_str, &size, &expected_breakpoint); - EXPECT_EQ(expected_breakpoint, getNextWordBreakForCache(buf, offset_in, size)) - << "Expected position is [" << query_str << "] from offset " << offset_in; -} - -void ExpectPrevWordBreakForCache(size_t offset_in, const char* query_str) { - const size_t BUF_SIZE = 256U; - uint16_t buf[BUF_SIZE]; - size_t expected_breakpoint = 0U; - size_t size = 0U; - - ParseUnicode(buf, BUF_SIZE, query_str, &size, &expected_breakpoint); - EXPECT_EQ(expected_breakpoint, getPrevWordBreakForCache(buf, offset_in, size)) - << "Expected position is [" << query_str << "] from offset " << offset_in; -} - -TEST(WordBreakTest, goNextWordBreakTest) { - ExpectNextWordBreakForCache(0, "|"); - - // Continue for spaces. - ExpectNextWordBreakForCache(0, "'a' 'b' 'c' 'd' |"); - ExpectNextWordBreakForCache(1, "'a' 'b' 'c' 'd' |"); - ExpectNextWordBreakForCache(2, "'a' 'b' 'c' 'd' |"); - ExpectNextWordBreakForCache(3, "'a' 'b' 'c' 'd' |"); - ExpectNextWordBreakForCache(4, "'a' 'b' 'c' 'd' |"); - ExpectNextWordBreakForCache(1000, "'a' 'b' 'c' 'd' |"); - - // Space makes word break. - ExpectNextWordBreakForCache(0, "'a' 'b' | U+0020 'c' 'd'"); - ExpectNextWordBreakForCache(1, "'a' 'b' | U+0020 'c' 'd'"); - ExpectNextWordBreakForCache(2, "'a' 'b' U+0020 | 'c' 'd'"); - ExpectNextWordBreakForCache(3, "'a' 'b' U+0020 'c' 'd' |"); - ExpectNextWordBreakForCache(4, "'a' 'b' U+0020 'c' 'd' |"); - ExpectNextWordBreakForCache(5, "'a' 'b' U+0020 'c' 'd' |"); - ExpectNextWordBreakForCache(1000, "'a' 'b' U+0020 'c' 'd' |"); - - ExpectNextWordBreakForCache(0, "'a' 'b' | U+2000 'c' 'd'"); - ExpectNextWordBreakForCache(1, "'a' 'b' | U+2000 'c' 'd'"); - ExpectNextWordBreakForCache(2, "'a' 'b' U+2000 | 'c' 'd'"); - ExpectNextWordBreakForCache(3, "'a' 'b' U+2000 'c' 'd' |"); - ExpectNextWordBreakForCache(4, "'a' 'b' U+2000 'c' 'd' |"); - ExpectNextWordBreakForCache(5, "'a' 'b' U+2000 'c' 'd' |"); - ExpectNextWordBreakForCache(1000, "'a' 'b' U+2000 'c' 'd' |"); - - ExpectNextWordBreakForCache(0, "'a' 'b' | U+2000 U+2000 'c' 'd'"); - ExpectNextWordBreakForCache(1, "'a' 'b' | U+2000 U+2000 'c' 'd'"); - ExpectNextWordBreakForCache(2, "'a' 'b' U+2000 | U+2000 'c' 'd'"); - ExpectNextWordBreakForCache(3, "'a' 'b' U+2000 U+2000 | 'c' 'd'"); - ExpectNextWordBreakForCache(4, "'a' 'b' U+2000 U+2000 'c' 'd' |"); - ExpectNextWordBreakForCache(5, "'a' 'b' U+2000 U+2000 'c' 'd' |"); - ExpectNextWordBreakForCache(6, "'a' 'b' U+2000 U+2000 'c' 'd' |"); - ExpectNextWordBreakForCache(1000, "'a' 'b' U+2000 U+2000 'c' 'd' |"); - - // CJK ideographs makes word break. - ExpectNextWordBreakForCache(0, "U+4E00 | U+4E00 U+4E00 U+4E00 U+4E00"); - ExpectNextWordBreakForCache(1, "U+4E00 U+4E00 | U+4E00 U+4E00 U+4E00"); - ExpectNextWordBreakForCache(2, "U+4E00 U+4E00 U+4E00 | U+4E00 U+4E00"); - ExpectNextWordBreakForCache(3, "U+4E00 U+4E00 U+4E00 U+4E00 | U+4E00"); - ExpectNextWordBreakForCache(4, - "U+4E00 U+4E00 U+4E00 U+4E00 U+4E00 |"); - ExpectNextWordBreakForCache(5, - "U+4E00 U+4E00 U+4E00 U+4E00 U+4E00 |"); - ExpectNextWordBreakForCache(1000, - "U+4E00 U+4E00 U+4E00 U+4E00 U+4E00 |"); - - ExpectNextWordBreakForCache(0, "U+4E00 | U+4E8C U+4E09 U+56DB U+4E94"); - ExpectNextWordBreakForCache(1, "U+4E00 U+4E8C | U+4E09 U+56DB U+4E94"); - ExpectNextWordBreakForCache(2, "U+4E00 U+4E8C U+4E09 | U+56DB U+4E94"); - ExpectNextWordBreakForCache(3, "U+4E00 U+4E8C U+4E09 U+56DB | U+4E94"); - ExpectNextWordBreakForCache(4, - "U+4E00 U+4E8C U+4E09 U+56DB U+4E94 |"); - ExpectNextWordBreakForCache(5, - "U+4E00 U+4E8C U+4E09 U+56DB U+4E94 |"); - ExpectNextWordBreakForCache(1000, - "U+4E00 U+4E8C U+4E09 U+56DB U+4E94 |"); - - ExpectNextWordBreakForCache(0, "U+4E00 'a' 'b' | U+2000 'c' U+4E00"); - ExpectNextWordBreakForCache(1, "U+4E00 'a' 'b' | U+2000 'c' U+4E00"); - ExpectNextWordBreakForCache(2, "U+4E00 'a' 'b' | U+2000 'c' U+4E00"); - ExpectNextWordBreakForCache(3, "U+4E00 'a' 'b' U+2000 | 'c' U+4E00"); - ExpectNextWordBreakForCache(4, "U+4E00 'a' 'b' U+2000 'c' | U+4E00"); - ExpectNextWordBreakForCache(5, "U+4E00 'a' 'b' U+2000 'c' U+4E00 |"); - ExpectNextWordBreakForCache(1000, "U+4E00 'a' 'b' U+2000 'c' U+4E00 |"); - - // Continue if trailing characters is Unicode combining characters. - ExpectNextWordBreakForCache(0, "U+4E00 U+0332 | U+4E00"); - ExpectNextWordBreakForCache(1, "U+4E00 U+0332 | U+4E00"); - ExpectNextWordBreakForCache(2, "U+4E00 U+0332 U+4E00 |"); - ExpectNextWordBreakForCache(3, "U+4E00 U+0332 U+4E00 |"); - ExpectNextWordBreakForCache(1000, "U+4E00 U+0332 U+4E00 |"); - - // Surrogate pairs. - ExpectNextWordBreakForCache(0, "U+1F60D U+1F618 |"); - ExpectNextWordBreakForCache(1, "U+1F60D U+1F618 |"); - ExpectNextWordBreakForCache(2, "U+1F60D U+1F618 |"); - ExpectNextWordBreakForCache(3, "U+1F60D U+1F618 |"); - ExpectNextWordBreakForCache(4, "U+1F60D U+1F618 |"); - ExpectNextWordBreakForCache(1000, "U+1F60D U+1F618 |"); - - // Broken surrogate pairs. - // U+D84D is leading surrogate but there is no trailing surrogate for it. - ExpectNextWordBreakForCache(0, "U+D84D U+1F618 |"); - ExpectNextWordBreakForCache(1, "U+D84D U+1F618 |"); - ExpectNextWordBreakForCache(2, "U+D84D U+1F618 |"); - ExpectNextWordBreakForCache(3, "U+D84D U+1F618 |"); - ExpectNextWordBreakForCache(1000, "U+D84D U+1F618 |"); - - ExpectNextWordBreakForCache(0, "U+1F618 U+D84D |"); - ExpectNextWordBreakForCache(1, "U+1F618 U+D84D |"); - ExpectNextWordBreakForCache(2, "U+1F618 U+D84D |"); - ExpectNextWordBreakForCache(3, "U+1F618 U+D84D |"); - ExpectNextWordBreakForCache(1000, "U+1F618 U+D84D |"); - - // U+DE0D is trailing surrogate but there is no leading surrogate for it. - ExpectNextWordBreakForCache(0, "U+DE0D U+1F618 |"); - ExpectNextWordBreakForCache(1, "U+DE0D U+1F618 |"); - ExpectNextWordBreakForCache(2, "U+DE0D U+1F618 |"); - ExpectNextWordBreakForCache(3, "U+DE0D U+1F618 |"); - ExpectNextWordBreakForCache(1000, "U+DE0D U+1F618 |"); - - ExpectNextWordBreakForCache(0, "U+1F618 U+DE0D |"); - ExpectNextWordBreakForCache(1, "U+1F618 U+DE0D |"); - ExpectNextWordBreakForCache(2, "U+1F618 U+DE0D |"); - ExpectNextWordBreakForCache(3, "U+1F618 U+DE0D |"); - ExpectNextWordBreakForCache(1000, "U+1F618 U+DE0D |"); - - // Regional indicator pair. U+1F1FA U+1F1F8 is US national flag. - ExpectNextWordBreakForCache(0, "U+1F1FA U+1F1F8 |"); - ExpectNextWordBreakForCache(1, "U+1F1FA U+1F1F8 |"); - ExpectNextWordBreakForCache(2, "U+1F1FA U+1F1F8 |"); - ExpectNextWordBreakForCache(1000, "U+1F1FA U+1F1F8 |"); - - // Tone marks. - // CJK ideographic char + Tone mark + CJK ideographic char - ExpectNextWordBreakForCache(0, "U+4444 U+302D | U+4444"); - ExpectNextWordBreakForCache(1, "U+4444 U+302D | U+4444"); - ExpectNextWordBreakForCache(2, "U+4444 U+302D U+4444 |"); - ExpectNextWordBreakForCache(3, "U+4444 U+302D U+4444 |"); - ExpectNextWordBreakForCache(1000, "U+4444 U+302D U+4444 |"); - - // Variation Selectors. - // CJK Ideographic char + Variation Selector(VS1) + CJK Ideographic char - ExpectNextWordBreakForCache(0, "U+845B U+FE00 | U+845B"); - ExpectNextWordBreakForCache(1, "U+845B U+FE00 | U+845B"); - ExpectNextWordBreakForCache(2, "U+845B U+FE00 U+845B |"); - ExpectNextWordBreakForCache(3, "U+845B U+FE00 U+845B |"); - ExpectNextWordBreakForCache(1000, "U+845B U+FE00 U+845B |"); - - // CJK Ideographic char + Variation Selector(VS17) + CJK Ideographic char - ExpectNextWordBreakForCache(0, "U+845B U+E0100 | U+845B"); - ExpectNextWordBreakForCache(1, "U+845B U+E0100 | U+845B"); - ExpectNextWordBreakForCache(2, "U+845B U+E0100 | U+845B"); - ExpectNextWordBreakForCache(3, "U+845B U+E0100 U+845B |"); - ExpectNextWordBreakForCache(4, "U+845B U+E0100 U+845B |"); - ExpectNextWordBreakForCache(5, "U+845B U+E0100 U+845B |"); - ExpectNextWordBreakForCache(1000, "U+845B U+E0100 U+845B |"); - - // CJK ideographic char + Tone mark + Variation Character(VS1) - ExpectNextWordBreakForCache(0, "U+4444 U+302D U+FE00 | U+4444"); - ExpectNextWordBreakForCache(1, "U+4444 U+302D U+FE00 | U+4444"); - ExpectNextWordBreakForCache(2, "U+4444 U+302D U+FE00 | U+4444"); - ExpectNextWordBreakForCache(3, "U+4444 U+302D U+FE00 U+4444 |"); - ExpectNextWordBreakForCache(4, "U+4444 U+302D U+FE00 U+4444 |"); - ExpectNextWordBreakForCache(1000, "U+4444 U+302D U+FE00 U+4444 |"); - - // CJK ideographic char + Tone mark + Variation Character(VS17) - ExpectNextWordBreakForCache(0, "U+4444 U+302D U+E0100 | U+4444"); - ExpectNextWordBreakForCache(1, "U+4444 U+302D U+E0100 | U+4444"); - ExpectNextWordBreakForCache(2, "U+4444 U+302D U+E0100 | U+4444"); - ExpectNextWordBreakForCache(3, "U+4444 U+302D U+E0100 | U+4444"); - ExpectNextWordBreakForCache(4, "U+4444 U+302D U+E0100 U+4444 |"); - ExpectNextWordBreakForCache(5, "U+4444 U+302D U+E0100 U+4444 |"); - ExpectNextWordBreakForCache(1000, "U+4444 U+302D U+E0100 U+4444 |"); - - // CJK ideographic char + Variation Character(VS1) + Tone mark - ExpectNextWordBreakForCache(0, "U+4444 U+FE00 U+302D | U+4444"); - ExpectNextWordBreakForCache(1, "U+4444 U+FE00 U+302D | U+4444"); - ExpectNextWordBreakForCache(2, "U+4444 U+FE00 U+302D | U+4444"); - ExpectNextWordBreakForCache(3, "U+4444 U+FE00 U+302D U+4444 |"); - ExpectNextWordBreakForCache(4, "U+4444 U+FE00 U+302D U+4444 |"); - ExpectNextWordBreakForCache(1000, "U+4444 U+FE00 U+302D U+4444 |"); - - // CJK ideographic char + Variation Character(VS17) + Tone mark - ExpectNextWordBreakForCache(0, "U+4444 U+E0100 U+302D | U+4444"); - ExpectNextWordBreakForCache(1, "U+4444 U+E0100 U+302D | U+4444"); - ExpectNextWordBreakForCache(2, "U+4444 U+E0100 U+302D | U+4444"); - ExpectNextWordBreakForCache(3, "U+4444 U+E0100 U+302D | U+4444"); - ExpectNextWordBreakForCache(4, "U+4444 U+E0100 U+302D U+4444 |"); - ExpectNextWordBreakForCache(5, "U+4444 U+E0100 U+302D U+4444 |"); - ExpectNextWordBreakForCache(1000, "U+4444 U+E0100 U+302D U+4444 |"); - - // Following test cases are unusual usage of variation selectors and tone - // marks for caching up the further behavior changes, e.g. index of bounds - // or crashes. Please feel free to update the test expectations if the - // behavior change makes sense to you. - - // Isolated Tone marks and Variation Selectors - ExpectNextWordBreakForCache(0, "U+FE00 |"); - ExpectNextWordBreakForCache(1, "U+FE00 |"); - ExpectNextWordBreakForCache(1000, "U+FE00 |"); - ExpectNextWordBreakForCache(0, "U+E0100 |"); - ExpectNextWordBreakForCache(1000, "U+E0100 |"); - ExpectNextWordBreakForCache(0, "U+302D |"); - ExpectNextWordBreakForCache(1000, "U+302D |"); - - // CJK Ideographic char + Variation Selector(VS1) + Variation Selector(VS1) - ExpectNextWordBreakForCache(0, "U+845B U+FE00 U+FE00 | U+845B"); - ExpectNextWordBreakForCache(1, "U+845B U+FE00 U+FE00 | U+845B"); - ExpectNextWordBreakForCache(2, "U+845B U+FE00 U+FE00 | U+845B"); - ExpectNextWordBreakForCache(3, "U+845B U+FE00 U+FE00 U+845B |"); - ExpectNextWordBreakForCache(4, "U+845B U+FE00 U+FE00 U+845B |"); - ExpectNextWordBreakForCache(1000, "U+845B U+FE00 U+FE00 U+845B |"); - - // CJK Ideographic char + Variation Selector(VS17) + Variation Selector(VS17) - ExpectNextWordBreakForCache(0, "U+845B U+E0100 U+E0100 | U+845B"); - ExpectNextWordBreakForCache(1, "U+845B U+E0100 U+E0100 | U+845B"); - ExpectNextWordBreakForCache(2, "U+845B U+E0100 U+E0100 | U+845B"); - ExpectNextWordBreakForCache(3, "U+845B U+E0100 U+E0100 | U+845B"); - ExpectNextWordBreakForCache(4, "U+845B U+E0100 U+E0100 | U+845B"); - ExpectNextWordBreakForCache(5, "U+845B U+E0100 U+E0100 U+845B |"); - ExpectNextWordBreakForCache(6, "U+845B U+E0100 U+E0100 U+845B |"); - ExpectNextWordBreakForCache(1000, "U+845B U+E0100 U+E0100 U+845B |"); - - // CJK Ideographic char + Variation Selector(VS1) + Variation Selector(VS17) - ExpectNextWordBreakForCache(0, "U+845B U+FE00 U+E0100 | U+845B"); - ExpectNextWordBreakForCache(1, "U+845B U+FE00 U+E0100 | U+845B"); - ExpectNextWordBreakForCache(2, "U+845B U+FE00 U+E0100 | U+845B"); - ExpectNextWordBreakForCache(3, "U+845B U+FE00 U+E0100 | U+845B"); - ExpectNextWordBreakForCache(4, "U+845B U+FE00 U+E0100 U+845B |"); - ExpectNextWordBreakForCache(5, "U+845B U+FE00 U+E0100 U+845B |"); - ExpectNextWordBreakForCache(1000, "U+845B U+FE00 U+E0100 U+845B |"); - - // CJK Ideographic char + Variation Selector(VS17) + Variation Selector(VS1) - ExpectNextWordBreakForCache(0, "U+845B U+E0100 U+FE00 | U+845B"); - ExpectNextWordBreakForCache(1, "U+845B U+E0100 U+FE00 | U+845B"); - ExpectNextWordBreakForCache(2, "U+845B U+E0100 U+FE00 | U+845B"); - ExpectNextWordBreakForCache(3, "U+845B U+E0100 U+FE00 | U+845B"); - ExpectNextWordBreakForCache(4, "U+845B U+E0100 U+FE00 U+845B |"); - ExpectNextWordBreakForCache(5, "U+845B U+E0100 U+FE00 U+845B |"); - ExpectNextWordBreakForCache(1000, "U+845B U+E0100 U+FE00 U+845B |"); - - // Tone mark. + Tone mark - ExpectNextWordBreakForCache(0, "U+4444 U+302D U+302D | U+4444"); - ExpectNextWordBreakForCache(1, "U+4444 U+302D U+302D | U+4444"); - ExpectNextWordBreakForCache(2, "U+4444 U+302D U+302D | U+4444"); - ExpectNextWordBreakForCache(3, "U+4444 U+302D U+302D U+4444 |"); - ExpectNextWordBreakForCache(4, "U+4444 U+302D U+302D U+4444 |"); - ExpectNextWordBreakForCache(1000, "U+4444 U+302D U+302D U+4444 |"); -} - -TEST(WordBreakTest, goPrevWordBreakTest) { - ExpectPrevWordBreakForCache(0, "|"); - - // Continue for spaces. - ExpectPrevWordBreakForCache(0, "| 'a' 'b' 'c' 'd'"); - ExpectPrevWordBreakForCache(1, "| 'a' 'b' 'c' 'd'"); - ExpectPrevWordBreakForCache(2, "| 'a' 'b' 'c' 'd'"); - ExpectPrevWordBreakForCache(3, "| 'a' 'b' 'c' 'd'"); - ExpectPrevWordBreakForCache(4, "| 'a' 'b' 'c' 'd'"); - ExpectPrevWordBreakForCache(1000, "| 'a' 'b' 'c' 'd'"); - - // Space makes word break. - ExpectPrevWordBreakForCache(0, "| 'a' 'b' U+0020 'c' 'd'"); - ExpectPrevWordBreakForCache(1, "| 'a' 'b' U+0020 'c' 'd'"); - ExpectPrevWordBreakForCache(2, "| 'a' 'b' U+0020 'c' 'd'"); - ExpectPrevWordBreakForCache(3, "'a' 'b' | U+0020 'c' 'd'"); - ExpectPrevWordBreakForCache(4, "'a' 'b' U+0020 | 'c' 'd'"); - ExpectPrevWordBreakForCache(5, "'a' 'b' U+0020 | 'c' 'd'"); - ExpectPrevWordBreakForCache(1000, "'a' 'b' U+0020 | 'c' 'd'"); - - ExpectPrevWordBreakForCache(0, "| 'a' 'b' U+2000 'c' 'd'"); - ExpectPrevWordBreakForCache(1, "| 'a' 'b' U+2000 'c' 'd'"); - ExpectPrevWordBreakForCache(2, "| 'a' 'b' U+2000 'c' 'd'"); - ExpectPrevWordBreakForCache(3, "'a' 'b' | U+2000 'c' 'd'"); - ExpectPrevWordBreakForCache(4, "'a' 'b' U+2000 | 'c' 'd'"); - ExpectPrevWordBreakForCache(5, "'a' 'b' U+2000 | 'c' 'd'"); - ExpectPrevWordBreakForCache(1000, "'a' 'b' U+2000 | 'c' 'd'"); - - ExpectPrevWordBreakForCache(0, "| 'a' 'b' U+2000 U+2000 'c' 'd'"); - ExpectPrevWordBreakForCache(1, "| 'a' 'b' U+2000 U+2000 'c' 'd'"); - ExpectPrevWordBreakForCache(2, "| 'a' 'b' U+2000 U+2000 'c' 'd'"); - ExpectPrevWordBreakForCache(3, "'a' 'b' | U+2000 U+2000 'c' 'd'"); - ExpectPrevWordBreakForCache(4, "'a' 'b' U+2000 | U+2000 'c' 'd'"); - ExpectPrevWordBreakForCache(5, "'a' 'b' U+2000 U+2000 | 'c' 'd'"); - ExpectPrevWordBreakForCache(6, "'a' 'b' U+2000 U+2000 | 'c' 'd'"); - ExpectPrevWordBreakForCache(1000, "'a' 'b' U+2000 U+2000 | 'c' 'd'"); - - // CJK ideographs makes word break. - ExpectPrevWordBreakForCache(0, "| U+4E00 U+4E00 U+4E00 U+4E00 U+4E00"); - ExpectPrevWordBreakForCache(1, "| U+4E00 U+4E00 U+4E00 U+4E00 U+4E00"); - ExpectPrevWordBreakForCache(2, "U+4E00 | U+4E00 U+4E00 U+4E00 U+4E00"); - ExpectPrevWordBreakForCache(3, "U+4E00 U+4E00 | U+4E00 U+4E00 U+4E00"); - ExpectPrevWordBreakForCache(4, "U+4E00 U+4E00 U+4E00 | U+4E00 U+4E00"); - ExpectPrevWordBreakForCache(5, "U+4E00 U+4E00 U+4E00 U+4E00 | U+4E00"); - ExpectPrevWordBreakForCache(1000, "U+4E00 U+4E00 U+4E00 U+4E00 | U+4E00"); - - ExpectPrevWordBreakForCache(0, "| U+4E00 U+4E8C U+4E09 U+56DB U+4E94"); - ExpectPrevWordBreakForCache(1, "| U+4E00 U+4E8C U+4E09 U+56DB U+4E94"); - ExpectPrevWordBreakForCache(2, "U+4E00 | U+4E8C U+4E09 U+56DB U+4E94"); - ExpectPrevWordBreakForCache(3, "U+4E00 U+4E8C | U+4E09 U+56DB U+4E94"); - ExpectPrevWordBreakForCache(4, "U+4E00 U+4E8C U+4E09 | U+56DB U+4E94"); - ExpectPrevWordBreakForCache(5, "U+4E00 U+4E8C U+4E09 U+56DB | U+4E94"); - ExpectPrevWordBreakForCache(1000, "U+4E00 U+4E8C U+4E09 U+56DB | U+4E94"); - - // Mixed case. - ExpectPrevWordBreakForCache(0, "| U+4E00 'a' 'b' U+2000 'c' U+4E00"); - ExpectPrevWordBreakForCache(1, "| U+4E00 'a' 'b' U+2000 'c' U+4E00"); - ExpectPrevWordBreakForCache(2, "| U+4E00 'a' 'b' U+2000 'c' U+4E00"); - ExpectPrevWordBreakForCache(3, "| U+4E00 'a' 'b' U+2000 'c' U+4E00"); - ExpectPrevWordBreakForCache(4, "U+4E00 'a' 'b' | U+2000 'c' U+4E00"); - ExpectPrevWordBreakForCache(5, "U+4E00 'a' 'b' U+2000 | 'c' U+4E00"); - ExpectPrevWordBreakForCache(6, "U+4E00 'a' 'b' U+2000 'c' | U+4E00"); - ExpectPrevWordBreakForCache(1000, "U+4E00 'a' 'b' U+2000 'c' | U+4E00"); - - // Continue if trailing characters is Unicode combining characters. - ExpectPrevWordBreakForCache(0, "| U+4E00 U+0332 U+4E00"); - ExpectPrevWordBreakForCache(1, "| U+4E00 U+0332 U+4E00"); - ExpectPrevWordBreakForCache(2, "| U+4E00 U+0332 U+4E00"); - ExpectPrevWordBreakForCache(3, "U+4E00 U+0332 | U+4E00"); - ExpectPrevWordBreakForCache(1000, "U+4E00 U+0332 | U+4E00"); - - // Surrogate pairs. - ExpectPrevWordBreakForCache(0, "| U+1F60D U+1F618"); - ExpectPrevWordBreakForCache(1, "| U+1F60D U+1F618"); - ExpectPrevWordBreakForCache(2, "| U+1F60D U+1F618"); - ExpectPrevWordBreakForCache(3, "| U+1F60D U+1F618"); - ExpectPrevWordBreakForCache(4, "| U+1F60D U+1F618"); - ExpectPrevWordBreakForCache(1000, "| U+1F60D U+1F618"); - - // Broken surrogate pairs. - // U+D84D is leading surrogate but there is no trailing surrogate for it. - ExpectPrevWordBreakForCache(0, "| U+D84D U+1F618"); - ExpectPrevWordBreakForCache(1, "| U+D84D U+1F618"); - ExpectPrevWordBreakForCache(2, "| U+D84D U+1F618"); - ExpectPrevWordBreakForCache(3, "| U+D84D U+1F618"); - ExpectPrevWordBreakForCache(1000, "| U+D84D U+1F618"); - - ExpectPrevWordBreakForCache(0, "| U+1F618 U+D84D"); - ExpectPrevWordBreakForCache(1, "| U+1F618 U+D84D"); - ExpectPrevWordBreakForCache(2, "| U+1F618 U+D84D"); - ExpectPrevWordBreakForCache(3, "| U+1F618 U+D84D"); - ExpectPrevWordBreakForCache(1000, "| U+1F618 U+D84D"); - - // U+DE0D is trailing surrogate but there is no leading surrogate for it. - ExpectPrevWordBreakForCache(0, "| U+DE0D U+1F618"); - ExpectPrevWordBreakForCache(1, "| U+DE0D U+1F618"); - ExpectPrevWordBreakForCache(2, "| U+DE0D U+1F618"); - ExpectPrevWordBreakForCache(3, "| U+DE0D U+1F618"); - ExpectPrevWordBreakForCache(1000, "| U+DE0D U+1F618"); - - ExpectPrevWordBreakForCache(0, "| U+1F618 U+DE0D"); - ExpectPrevWordBreakForCache(1, "| U+1F618 U+DE0D"); - ExpectPrevWordBreakForCache(2, "| U+1F618 U+DE0D"); - ExpectPrevWordBreakForCache(3, "| U+1F618 U+DE0D"); - ExpectPrevWordBreakForCache(1000, "| U+1F618 U+DE0D"); - - // Regional indicator pair. U+1F1FA U+1F1F8 is US national flag. - ExpectPrevWordBreakForCache(0, "| U+1F1FA U+1F1F8"); - ExpectPrevWordBreakForCache(1, "| U+1F1FA U+1F1F8"); - ExpectPrevWordBreakForCache(2, "| U+1F1FA U+1F1F8"); - ExpectPrevWordBreakForCache(1000, "| U+1F1FA U+1F1F8"); - - // Tone marks. - // CJK ideographic char + Tone mark + CJK ideographic char - ExpectPrevWordBreakForCache(0, "| U+4444 U+302D U+4444"); - ExpectPrevWordBreakForCache(1, "| U+4444 U+302D U+4444"); - ExpectPrevWordBreakForCache(2, "| U+4444 U+302D U+4444"); - ExpectPrevWordBreakForCache(3, "U+4444 U+302D | U+4444"); - ExpectPrevWordBreakForCache(1000, "U+4444 U+302D | U+4444"); - - // Variation Selectors. - // CJK Ideographic char + Variation Selector(VS1) + CJK Ideographic char - ExpectPrevWordBreakForCache(0, "| U+845B U+FE00 U+845B"); - ExpectPrevWordBreakForCache(1, "| U+845B U+FE00 U+845B"); - ExpectPrevWordBreakForCache(2, "| U+845B U+FE00 U+845B"); - ExpectPrevWordBreakForCache(3, "U+845B U+FE00 | U+845B"); - ExpectPrevWordBreakForCache(1000, "U+845B U+FE00 | U+845B"); - - // CJK Ideographic char + Variation Selector(VS17) + CJK Ideographic char - ExpectPrevWordBreakForCache(0, "| U+845B U+E0100 U+845B"); - ExpectPrevWordBreakForCache(1, "| U+845B U+E0100 U+845B"); - ExpectPrevWordBreakForCache(2, "| U+845B U+E0100 U+845B"); - ExpectPrevWordBreakForCache(3, "| U+845B U+E0100 U+845B"); - ExpectPrevWordBreakForCache(4, "U+845B U+E0100 | U+845B"); - ExpectPrevWordBreakForCache(5, "U+845B U+E0100 | U+845B"); - ExpectPrevWordBreakForCache(1000, "U+845B U+E0100 | U+845B"); - - // CJK ideographic char + Tone mark + Variation Character(VS1) - ExpectPrevWordBreakForCache(0, "| U+4444 U+302D U+FE00 U+4444"); - ExpectPrevWordBreakForCache(1, "| U+4444 U+302D U+FE00 U+4444"); - ExpectPrevWordBreakForCache(2, "| U+4444 U+302D U+FE00 U+4444"); - ExpectPrevWordBreakForCache(3, "| U+4444 U+302D U+FE00 U+4444"); - ExpectPrevWordBreakForCache(4, "U+4444 U+302D U+FE00 | U+4444"); - ExpectPrevWordBreakForCache(1000, "U+4444 U+302D U+FE00 | U+4444"); - - // CJK ideographic char + Tone mark + Variation Character(VS17) - ExpectPrevWordBreakForCache(0, "| U+4444 U+302D U+E0100 U+4444"); - ExpectPrevWordBreakForCache(1, "| U+4444 U+302D U+E0100 U+4444"); - ExpectPrevWordBreakForCache(2, "| U+4444 U+302D U+E0100 U+4444"); - ExpectPrevWordBreakForCache(3, "| U+4444 U+302D U+E0100 U+4444"); - ExpectPrevWordBreakForCache(4, "| U+4444 U+302D U+E0100 U+4444"); - ExpectPrevWordBreakForCache(5, "U+4444 U+302D U+E0100 | U+4444"); - ExpectPrevWordBreakForCache(1000, "U+4444 U+302D U+E0100 | U+4444"); - - // CJK ideographic char + Variation Character(VS1) + Tone mark - ExpectPrevWordBreakForCache(0, "| U+4444 U+FE00 U+302D U+4444"); - ExpectPrevWordBreakForCache(1, "| U+4444 U+FE00 U+302D U+4444"); - ExpectPrevWordBreakForCache(2, "| U+4444 U+FE00 U+302D U+4444"); - ExpectPrevWordBreakForCache(3, "| U+4444 U+FE00 U+302D U+4444"); - ExpectPrevWordBreakForCache(4, "U+4444 U+FE00 U+302D | U+4444"); - ExpectPrevWordBreakForCache(1000, "U+4444 U+FE00 U+302D | U+4444"); - - // CJK ideographic char + Variation Character(VS17) + Tone mark - ExpectPrevWordBreakForCache(0, "| U+4444 U+E0100 U+302D U+4444"); - ExpectPrevWordBreakForCache(1, "| U+4444 U+E0100 U+302D U+4444"); - ExpectPrevWordBreakForCache(2, "| U+4444 U+E0100 U+302D U+4444"); - ExpectPrevWordBreakForCache(3, "| U+4444 U+E0100 U+302D U+4444"); - ExpectPrevWordBreakForCache(4, "| U+4444 U+E0100 U+302D U+4444"); - ExpectPrevWordBreakForCache(5, "U+4444 U+E0100 U+302D | U+4444"); - ExpectPrevWordBreakForCache(1000, "U+4444 U+E0100 U+302D | U+4444"); - - // Following test cases are unusual usage of variation selectors and tone - // marks for caching up the further behavior changes, e.g. index of bounds - // or crashes. Please feel free to update the test expectations if the - // behavior change makes sense to you. - - // Isolated Tone marks and Variation Selectors - ExpectPrevWordBreakForCache(0, "| U+FE00"); - ExpectPrevWordBreakForCache(1, "| U+FE00"); - ExpectPrevWordBreakForCache(1000, "| U+FE00"); - ExpectPrevWordBreakForCache(0, "| U+E0100"); - ExpectPrevWordBreakForCache(1000, "| U+E0100"); - ExpectPrevWordBreakForCache(0, "| U+302D"); - ExpectPrevWordBreakForCache(1000, "| U+302D"); - - // CJK Ideographic char + Variation Selector(VS1) + Variation Selector(VS1) - ExpectPrevWordBreakForCache(0, "| U+845B U+FE00 U+FE00 U+845B"); - ExpectPrevWordBreakForCache(1, "| U+845B U+FE00 U+FE00 U+845B"); - ExpectPrevWordBreakForCache(2, "| U+845B U+FE00 U+FE00 U+845B"); - ExpectPrevWordBreakForCache(3, "| U+845B U+FE00 U+FE00 U+845B"); - ExpectPrevWordBreakForCache(4, "U+845B U+FE00 U+FE00 | U+845B"); - ExpectPrevWordBreakForCache(1000, "U+845B U+FE00 U+FE00 | U+845B"); - - // CJK Ideographic char + Variation Selector(VS17) + Variation Selector(VS17) - ExpectPrevWordBreakForCache(0, "| U+845B U+E0100 U+E0100 U+845B"); - ExpectPrevWordBreakForCache(1, "| U+845B U+E0100 U+E0100 U+845B"); - ExpectPrevWordBreakForCache(2, "| U+845B U+E0100 U+E0100 U+845B"); - ExpectPrevWordBreakForCache(3, "| U+845B U+E0100 U+E0100 U+845B"); - ExpectPrevWordBreakForCache(4, "| U+845B U+E0100 U+E0100 U+845B"); - ExpectPrevWordBreakForCache(5, "| U+845B U+E0100 U+E0100 U+845B"); - ExpectPrevWordBreakForCache(6, "U+845B U+E0100 U+E0100 | U+845B"); - ExpectPrevWordBreakForCache(1000, "U+845B U+E0100 U+E0100 | U+845B"); - - // CJK Ideographic char + Variation Selector(VS1) + Variation Selector(VS17) - ExpectPrevWordBreakForCache(0, "| U+845B U+FE00 U+E0100 U+845B"); - ExpectPrevWordBreakForCache(1, "| U+845B U+FE00 U+E0100 U+845B"); - ExpectPrevWordBreakForCache(2, "| U+845B U+FE00 U+E0100 U+845B"); - ExpectPrevWordBreakForCache(3, "| U+845B U+FE00 U+E0100 U+845B"); - ExpectPrevWordBreakForCache(4, "| U+845B U+FE00 U+E0100 U+845B"); - ExpectPrevWordBreakForCache(5, "U+845B U+FE00 U+E0100 | U+845B"); - ExpectPrevWordBreakForCache(1000, "U+845B U+FE00 U+E0100 | U+845B"); - - // CJK Ideographic char + Variation Selector(VS17) + Variation Selector(VS1) - ExpectPrevWordBreakForCache(0, "| U+845B U+E0100 U+FE00 U+845B"); - ExpectPrevWordBreakForCache(1, "| U+845B U+E0100 U+FE00 U+845B"); - ExpectPrevWordBreakForCache(2, "| U+845B U+E0100 U+FE00 U+845B"); - ExpectPrevWordBreakForCache(3, "| U+845B U+E0100 U+FE00 U+845B"); - ExpectPrevWordBreakForCache(4, "| U+845B U+E0100 U+FE00 U+845B"); - ExpectPrevWordBreakForCache(5, "U+845B U+E0100 U+FE00 | U+845B"); - ExpectPrevWordBreakForCache(1000, "U+845B U+E0100 U+FE00 | U+845B"); - - // Tone mark. + Tone mark - ExpectPrevWordBreakForCache(0, "| U+4444 U+302D U+302D U+4444"); - ExpectPrevWordBreakForCache(1, "| U+4444 U+302D U+302D U+4444"); - ExpectPrevWordBreakForCache(2, "| U+4444 U+302D U+302D U+4444"); - ExpectPrevWordBreakForCache(3, "| U+4444 U+302D U+302D U+4444"); - ExpectPrevWordBreakForCache(4, "U+4444 U+302D U+302D | U+4444"); - ExpectPrevWordBreakForCache(1000, "U+4444 U+302D U+302D | U+4444"); -} - -} // namespace minikin diff --git a/third_party/txt/tests/MeasurementTests.cpp b/third_party/txt/tests/MeasurementTests.cpp deleted file mode 100644 index ea3b7007e3d1f..0000000000000 --- a/third_party/txt/tests/MeasurementTests.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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 -#include "UnicodeUtils.h" - -namespace minikin { - -float getAdvance(const float* advances, const char* src) { - const size_t BUF_SIZE = 256; - uint16_t buf[BUF_SIZE]; - size_t offset; - size_t size; - ParseUnicode(buf, BUF_SIZE, src, &size, &offset); - return getRunAdvance(advances, buf, 0, size, offset); -} - -// Latin fi -TEST(Measurement, getRunAdvance_fi) { - const float unligated[] = {30.0, 20.0}; - EXPECT_EQ(0.0, getAdvance(unligated, "| 'f' 'i'")); - EXPECT_EQ(30.0, getAdvance(unligated, "'f' | 'i'")); - EXPECT_EQ(50.0, getAdvance(unligated, "'f' 'i' |")); - - const float ligated[] = {40.0, 0.0}; - EXPECT_EQ(0.0, getAdvance(ligated, "| 'f' 'i'")); - EXPECT_EQ(20.0, getAdvance(ligated, "'f' | 'i'")); - EXPECT_EQ(40.0, getAdvance(ligated, "'f' 'i' |")); -} - -// Devanagari ka+virama+ka -TEST(Measurement, getRunAdvance_kka) { - const float unligated[] = {30.0, 0.0, 30.0}; - EXPECT_EQ(0.0, getAdvance(unligated, "| U+0915 U+094D U+0915")); - EXPECT_EQ(30.0, getAdvance(unligated, "U+0915 | U+094D U+0915")); - EXPECT_EQ(30.0, getAdvance(unligated, "U+0915 U+094D | U+0915")); - EXPECT_EQ(60.0, getAdvance(unligated, "U+0915 U+094D U+0915 |")); - - const float ligated[] = {30.0, 0.0, 0.0}; - EXPECT_EQ(0.0, getAdvance(ligated, "| U+0915 U+094D U+0915")); - EXPECT_EQ(30.0, getAdvance(ligated, "U+0915 | U+094D U+0915")); - EXPECT_EQ(30.0, getAdvance(ligated, "U+0915 U+094D | U+0915")); - EXPECT_EQ(30.0, getAdvance(ligated, "U+0915 U+094D U+0915 |")); -} - -} // namespace minikin diff --git a/third_party/txt/tests/MinikinFontForTest.cpp b/third_party/txt/tests/MinikinFontForTest.cpp deleted file mode 100644 index 88f1a63c313bc..0000000000000 --- a/third_party/txt/tests/MinikinFontForTest.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "Minikin" - -#include "MinikinFontForTest.h" - -#include - -#include -#include -#include -#include -#include - -#include - -#include - -namespace minikin { - -static int uniqueId = 0; // TODO: make thread safe if necessary. - -MinikinFontForTest::MinikinFontForTest( - const std::string& font_path, - int index, - const std::vector& variations) - : MinikinFont(uniqueId++), - mFontPath(font_path), - mVariations(variations), - mFontIndex(index) { - int fd = open(font_path.c_str(), O_RDONLY); - LOG_ALWAYS_FATAL_IF(fd == -1); - struct stat st = {}; - LOG_ALWAYS_FATAL_IF(fstat(fd, &st) != 0); - mFontSize = st.st_size; - mFontData = mmap(NULL, mFontSize, PROT_READ, MAP_SHARED, fd, 0); - LOG_ALWAYS_FATAL_IF(mFontData == nullptr); - close(fd); -} - -MinikinFontForTest::~MinikinFontForTest() { - munmap(mFontData, mFontSize); -} - -float MinikinFontForTest::GetHorizontalAdvance( - uint32_t /* glyph_id */, - const MinikinPaint& /* paint */) const { - // TODO: Make mock value configurable if necessary. - return 10.0f; -} - -void MinikinFontForTest::GetBounds(MinikinRect* bounds, - uint32_t /* glyph_id */, - const MinikinPaint& /* paint */) const { - // TODO: Make mock values configurable if necessary. - bounds->mLeft = 0.0f; - bounds->mTop = 0.0f; - bounds->mRight = 10.0f; - bounds->mBottom = 10.0f; -} - -std::shared_ptr MinikinFontForTest::createFontWithVariation( - const std::vector& variations) const { - return std::shared_ptr( - new MinikinFontForTest(mFontPath, mFontIndex, variations)); -} - -} // namespace minikin diff --git a/third_party/txt/tests/MinikinFontForTest.h b/third_party/txt/tests/MinikinFontForTest.h deleted file mode 100644 index 1da817b9c50e0..0000000000000 --- a/third_party/txt/tests/MinikinFontForTest.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#ifndef MINIKIN_TEST_MINIKIN_FONT_FOR_TEST_H -#define MINIKIN_TEST_MINIKIN_FONT_FOR_TEST_H - -#include - -class SkTypeface; - -namespace minikin { - -class MinikinFontForTest : public MinikinFont { - public: - MinikinFontForTest(const std::string& font_path, - int index, - const std::vector& variations); - MinikinFontForTest(const std::string& font_path, int index) - : MinikinFontForTest(font_path, index, std::vector()) {} - MinikinFontForTest(const std::string& font_path) - : MinikinFontForTest(font_path, 0) {} - virtual ~MinikinFontForTest(); - - // MinikinFont overrides. - float GetHorizontalAdvance(uint32_t glyph_id, - const MinikinPaint& paint) const; - void GetBounds(MinikinRect* bounds, - uint32_t glyph_id, - const MinikinPaint& paint) const; - - const std::string& fontPath() const { return mFontPath; } - - const void* GetFontData() const { return mFontData; } - size_t GetFontSize() const { return mFontSize; } - int GetFontIndex() const { return mFontIndex; } - const std::vector& GetAxes() const { - return mVariations; - } - std::shared_ptr createFontWithVariation( - const std::vector& variations) const; - - private: - MinikinFontForTest() = delete; - MinikinFontForTest(const MinikinFontForTest&) = delete; - MinikinFontForTest& operator=(MinikinFontForTest&) = delete; - - const std::string mFontPath; - const std::vector mVariations; - const int mFontIndex; - void* mFontData; - size_t mFontSize; -}; - -} // namespace minikin - -#endif // MINIKIN_TEST_MINIKIN_FONT_FOR_TEST_H diff --git a/third_party/txt/tests/SparseBitSetTest.cpp b/third_party/txt/tests/SparseBitSetTest.cpp deleted file mode 100644 index 80856ee66e00d..0000000000000 --- a/third_party/txt/tests/SparseBitSetTest.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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 -#include - -namespace minikin { - -TEST(SparseBitSetTest, randomTest) { - const uint32_t kTestRangeNum = 4096; - - std::mt19937 mt; // Fix seeds to be able to reproduce the result. - std::uniform_int_distribution distribution(1, 512); - - std::vector range{distribution(mt)}; - for (size_t i = 1; i < kTestRangeNum * 2; ++i) { - range.push_back((range.back() - 1) + distribution(mt)); - } - - SparseBitSet bitset(range.data(), range.size() / 2); - - uint32_t ch = 0; - for (size_t i = 0; i < range.size() / 2; ++i) { - uint32_t start = range[i * 2]; - uint32_t end = range[i * 2 + 1]; - - for (; ch < start; ch++) { - ASSERT_FALSE(bitset.get(ch)) << std::hex << ch; - } - for (; ch < end; ch++) { - ASSERT_TRUE(bitset.get(ch)) << std::hex << ch; - } - } - for (; ch < 0x1FFFFFF; ++ch) { - ASSERT_FALSE(bitset.get(ch)) << std::hex << ch; - } -} - -} // namespace minikin diff --git a/third_party/txt/tests/UnicodeUtils.cpp b/third_party/txt/tests/UnicodeUtils.cpp deleted file mode 100644 index c52417f83fe49..0000000000000 --- a/third_party/txt/tests/UnicodeUtils.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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 -#include -#include -#include -#include -#include - -namespace minikin { - -// src is of the form "U+1F431 | 'h' 'i'". Position of "|" gets saved to offset -// if non-null. Size is returned in an out parameter because gtest needs a void -// return for ASSERT to work. -void ParseUnicode(uint16_t* buf, - size_t buf_size, - const char* src, - size_t* result_size, - size_t* offset) { - size_t input_ix = 0; - size_t output_ix = 0; - bool seen_offset = false; - - while (src[input_ix] != 0) { - switch (src[input_ix]) { - case '\'': - // single ASCII char - LOG_ALWAYS_FATAL_IF(static_cast(src[input_ix]) >= 0x80); - input_ix++; - LOG_ALWAYS_FATAL_IF(src[input_ix] == 0); - LOG_ALWAYS_FATAL_IF(output_ix >= buf_size); - buf[output_ix++] = (uint16_t)src[input_ix++]; - LOG_ALWAYS_FATAL_IF(src[input_ix] != '\''); - input_ix++; - break; - case 'u': - case 'U': { - // Unicode codepoint in hex syntax - input_ix++; - LOG_ALWAYS_FATAL_IF(src[input_ix] != '+'); - input_ix++; - char* endptr = (char*)src + input_ix; - unsigned long int codepoint = strtoul(src + input_ix, &endptr, 16); - size_t num_hex_digits = endptr - (src + input_ix); - - // also triggers on invalid number syntax, digits = 0 - LOG_ALWAYS_FATAL_IF(num_hex_digits < 4u); - LOG_ALWAYS_FATAL_IF(num_hex_digits > 6u); - LOG_ALWAYS_FATAL_IF(codepoint > 0x10FFFFu); - input_ix += num_hex_digits; - if (U16_LENGTH(codepoint) == 1) { - LOG_ALWAYS_FATAL_IF(output_ix + 1 > buf_size); - buf[output_ix++] = codepoint; - } else { - // UTF-16 encoding - LOG_ALWAYS_FATAL_IF(output_ix + 2 > buf_size); - buf[output_ix++] = U16_LEAD(codepoint); - buf[output_ix++] = U16_TRAIL(codepoint); - } - break; - } - case ' ': - input_ix++; - break; - case '|': - LOG_ALWAYS_FATAL_IF(seen_offset); - LOG_ALWAYS_FATAL_IF(offset == nullptr); - *offset = output_ix; - seen_offset = true; - input_ix++; - break; - default: - LOG_ALWAYS_FATAL("Unexpected Character"); - } - } - LOG_ALWAYS_FATAL_IF(result_size == nullptr); - *result_size = output_ix; - LOG_ALWAYS_FATAL_IF(!seen_offset && offset != nullptr); -} - -std::vector parseUnicodeStringWithOffset(const std::string& in, - size_t* offset) { - std::unique_ptr buffer = std::make_unique(in.size()); - size_t result_size = 0; - ParseUnicode(buffer.get(), in.size(), in.c_str(), &result_size, offset); - return std::vector(buffer.get(), buffer.get() + result_size); -} - -std::vector parseUnicodeString(const std::string& in) { - return parseUnicodeStringWithOffset(in, nullptr); -} - -std::vector utf8ToUtf16(const std::string& text) { - std::vector result; - int32_t i = 0; - const int32_t textLength = static_cast(text.size()); - uint32_t c = 0; - while (i < textLength) { - U8_NEXT(text.c_str(), i, textLength, c); - if (U16_LENGTH(c) == 1) { - result.push_back(c); - } else { - result.push_back(U16_LEAD(c)); - result.push_back(U16_TRAIL(c)); - } - } - return result; -} - -} // namespace minikin diff --git a/third_party/txt/tests/UnicodeUtils.h b/third_party/txt/tests/UnicodeUtils.h deleted file mode 100644 index 24f7acc34373f..0000000000000 --- a/third_party/txt/tests/UnicodeUtils.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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 - -namespace minikin { - -void ParseUnicode(uint16_t* buf, - size_t buf_size, - const char* src, - size_t* result_size, - size_t* offset); - -std::vector parseUnicodeStringWithOffset(const std::string& in, - size_t* offset); -std::vector parseUnicodeString(const std::string& in); - -// Converts UTF-8 to UTF-16. -std::vector utf8ToUtf16(const std::string& text); - -} // namespace minikin diff --git a/third_party/txt/tests/UnicodeUtilsTest.cpp b/third_party/txt/tests/UnicodeUtilsTest.cpp deleted file mode 100644 index 1ab59718d64e2..0000000000000 --- a/third_party/txt/tests/UnicodeUtilsTest.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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 "UnicodeUtils.h" - -namespace minikin { - -TEST(UnicodeUtils, parse) { - const size_t BUF_SIZE = 256; - uint16_t buf[BUF_SIZE]; - size_t offset; - size_t size; - ParseUnicode(buf, BUF_SIZE, "U+000D U+1F431 | 'a'", &size, &offset); - EXPECT_EQ(size, 4u); - EXPECT_EQ(offset, 3u); - EXPECT_EQ(buf[0], 0x000D); - EXPECT_EQ(buf[1], 0xD83D); - EXPECT_EQ(buf[2], 0xDC31); - EXPECT_EQ(buf[3], 'a'); -} - -} // namespace minikin diff --git a/third_party/txt/tests/WordBreakerTests.cpp b/third_party/txt/tests/WordBreakerTests.cpp deleted file mode 100644 index f4bb239fc0915..0000000000000 --- a/third_party/txt/tests/WordBreakerTests.cpp +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "Minikin" - -#include -#include - -#include -#include -#include -#include -#include "ICUTestBase.h" -#include "UnicodeUtils.h" - -#ifndef NELEM -#define NELEM(x) ((sizeof(x) / sizeof((x)[0]))) -#endif - -#define UTF16(codepoint) U16_LEAD(codepoint), U16_TRAIL(codepoint) - -namespace minikin { - -typedef ICUTestBase WordBreakerTest; - -TEST_F(WordBreakerTest, basic) { - uint16_t buf[] = {'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'}; - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ(6, breaker.next()); // after "hello " - EXPECT_EQ(0, breaker.wordStart()); // "hello" - EXPECT_EQ(5, breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); - EXPECT_EQ(6, breaker.current()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); // end - EXPECT_EQ(6, breaker.wordStart()); // "world" - EXPECT_EQ(11, breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); - EXPECT_EQ(11, breaker.current()); -} - -TEST_F(WordBreakerTest, softHyphen) { - uint16_t buf[] = {'h', 'e', 'l', 0x00AD, 'l', 'o', - ' ', 'w', 'o', 'r', 'l', 'd'}; - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ(7, breaker.next()); // after "hel{SOFT HYPHEN}lo " - EXPECT_EQ(0, breaker.wordStart()); // "hel{SOFT HYPHEN}lo" - EXPECT_EQ(6, breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); // end - EXPECT_EQ(7, breaker.wordStart()); // "world" - EXPECT_EQ(12, breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); -} - -TEST_F(WordBreakerTest, hardHyphen) { - // Hyphens should not allow breaks anymore. - uint16_t buf[] = {'s', 'u', 'g', 'a', 'r', '-', 'f', 'r', 'e', 'e'}; - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); - EXPECT_EQ(0, breaker.wordStart()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); -} - -TEST_F(WordBreakerTest, postfixAndPrefix) { - uint16_t buf[] = {'U', 'S', 0x00A2, ' ', 'J', 'P', 0x00A5}; // US¢ JP¥ - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - - EXPECT_EQ(4, breaker.next()); // after CENT SIGN - EXPECT_EQ(0, breaker.wordStart()); // "US¢" - EXPECT_EQ(3, breaker.wordEnd()); - - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); // end of string - EXPECT_EQ(4, breaker.wordStart()); // "JP¥" - EXPECT_EQ((ssize_t)NELEM(buf), breaker.wordEnd()); -} - -TEST_F(WordBreakerTest, myanmarKinzi) { - uint16_t buf[] = {0x1004, 0x103A, 0x1039, 0x1000, - 0x102C}; // NGA, ASAT, VIRAMA, KA, UU - WordBreaker breaker; - icu::Locale burmese("my"); - breaker.setLocale(burmese); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); // end of string - EXPECT_EQ(0, breaker.wordStart()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.wordEnd()); -} - -TEST_F(WordBreakerTest, zwjEmojiSequences) { - uint16_t buf[] = { - // man + zwj + heart + zwj + man - UTF16(0x1F468), - 0x200D, - 0x2764, - 0x200D, - UTF16(0x1F468), - // woman + zwj + heart + zwj + kiss mark + zwj + woman - UTF16(0x1F469), - 0x200D, - 0x2764, - 0x200D, - UTF16(0x1F48B), - 0x200D, - UTF16(0x1F469), - // eye + zwj + left speech bubble - UTF16(0x1F441), - 0x200D, - UTF16(0x1F5E8), - // CAT FACE + zwj + BUST IN SILHOUETTE - UTF16(0x1F431), - 0x200D, - UTF16(0x1F464), - }; - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ(7, breaker.next()); // after man + zwj + heart + zwj + man - EXPECT_EQ(0, breaker.wordStart()); - EXPECT_EQ(7, breaker.wordEnd()); - EXPECT_EQ(17, breaker.next()); // after woman + zwj + heart + zwj + woman - EXPECT_EQ(7, breaker.wordStart()); - EXPECT_EQ(17, breaker.wordEnd()); - EXPECT_EQ(22, breaker.next()); // after eye + zwj + left speech bubble - EXPECT_EQ(17, breaker.wordStart()); - EXPECT_EQ(22, breaker.wordEnd()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); // end - EXPECT_EQ(22, breaker.wordStart()); - EXPECT_EQ(27, breaker.wordEnd()); -} - -TEST_F(WordBreakerTest, emojiWithModifier) { - uint16_t buf[] = { - UTF16(0x1F466), UTF16(0x1F3FB), // boy + type 1-2 fitzpatrick modifier - 0x270C, 0xFE0F, - UTF16( - 0x1F3FF) // victory hand + emoji style + type 6 fitzpatrick modifier - }; - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ(4, breaker.next()); // after boy + type 1-2 fitzpatrick modifier - EXPECT_EQ(0, breaker.wordStart()); - EXPECT_EQ(4, breaker.wordEnd()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); // end - EXPECT_EQ(4, breaker.wordStart()); - EXPECT_EQ(8, breaker.wordEnd()); -} - -TEST_F(WordBreakerTest, unicode10Emoji) { - // Should break between emojis. - uint16_t buf[] = { - // SLED + SLED - UTF16(0x1F6F7), - UTF16(0x1F6F7), - // SLED + VS15 + SLED - UTF16(0x1F6F7), - 0xFE0E, - UTF16(0x1F6F7), - // WHITE SMILING FACE + SLED - 0x263A, - UTF16(0x1F6F7), - // WHITE SMILING FACE + VS16 + SLED - 0x263A, - 0xFE0F, - UTF16(0x1F6F7), - }; - WordBreaker breaker; - breaker.setLocale(icu::Locale::getEnglish()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ(2, breaker.next()); - EXPECT_EQ(0, breaker.wordStart()); - EXPECT_EQ(2, breaker.wordEnd()); - - EXPECT_EQ(4, breaker.next()); - EXPECT_EQ(2, breaker.wordStart()); - EXPECT_EQ(4, breaker.wordEnd()); - - EXPECT_EQ(7, breaker.next()); - EXPECT_EQ(4, breaker.wordStart()); - EXPECT_EQ(7, breaker.wordEnd()); - - EXPECT_EQ(9, breaker.next()); - EXPECT_EQ(7, breaker.wordStart()); - EXPECT_EQ(9, breaker.wordEnd()); - - EXPECT_EQ(10, breaker.next()); - EXPECT_EQ(9, breaker.wordStart()); - EXPECT_EQ(10, breaker.wordEnd()); - - EXPECT_EQ(12, breaker.next()); - EXPECT_EQ(10, breaker.wordStart()); - EXPECT_EQ(12, breaker.wordEnd()); - - EXPECT_EQ(14, breaker.next()); - EXPECT_EQ(12, breaker.wordStart()); - EXPECT_EQ(14, breaker.wordEnd()); - - EXPECT_EQ(16, breaker.next()); - EXPECT_EQ(14, breaker.wordStart()); - EXPECT_EQ(16, breaker.wordEnd()); -} - -TEST_F(WordBreakerTest, flagsSequenceSingleFlag) { - const std::string kFlag = "U+1F3F4"; - const std::string flags = kFlag + " " + kFlag; - - const int kFlagLength = 2; - const size_t BUF_SIZE = kFlagLength * 2; - - uint16_t buf[BUF_SIZE]; - size_t size; - ParseUnicode(buf, BUF_SIZE, flags.c_str(), &size, nullptr); - - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, size); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ(kFlagLength, breaker.next()); // end of the first flag - EXPECT_EQ(0, breaker.wordStart()); - EXPECT_EQ(kFlagLength, breaker.wordEnd()); - EXPECT_EQ(static_cast(size), breaker.next()); - EXPECT_EQ(kFlagLength, breaker.wordStart()); - EXPECT_EQ(kFlagLength * 2, breaker.wordEnd()); -} - -TEST_F(WordBreakerTest, flagsSequence) { - // U+1F3F4 U+E0067 U+E0062 U+E0073 U+E0063 U+E0074 U+E007F is emoji tag - // sequence for the flag of Scotland. - const std::string kFlagSequence = - "U+1F3F4 U+E0067 U+E0062 U+E0073 U+E0063 U+E0074 U+E007F"; - const std::string flagSequence = kFlagSequence + " " + kFlagSequence; - - const int kFlagLength = 14; - const size_t BUF_SIZE = kFlagLength * 2; - - uint16_t buf[BUF_SIZE]; - size_t size; - ParseUnicode(buf, BUF_SIZE, flagSequence.c_str(), &size, nullptr); - - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, size); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ(kFlagLength, breaker.next()); // end of the first flag sequence - EXPECT_EQ(0, breaker.wordStart()); - EXPECT_EQ(kFlagLength, breaker.wordEnd()); - EXPECT_EQ(static_cast(size), breaker.next()); - EXPECT_EQ(kFlagLength, breaker.wordStart()); - EXPECT_EQ(kFlagLength * 2, breaker.wordEnd()); -} - -TEST_F(WordBreakerTest, punct) { - uint16_t buf[] = {0x00A1, 0x00A1, 'h', 'e', 'l', 'l', 'o', ',', - ' ', 'w', 'o', 'r', 'l', 'd', '!', '!'}; - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ(9, breaker.next()); // after "¡¡hello, " - EXPECT_EQ(2, breaker.wordStart()); // "hello" - EXPECT_EQ(7, breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); // end - EXPECT_EQ(9, breaker.wordStart()); // "world" - EXPECT_EQ(14, breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); -} - -TEST_F(WordBreakerTest, email) { - uint16_t buf[] = {'f', 'o', 'o', '@', 'e', 'x', 'a', 'm', 'p', - 'l', 'e', '.', 'c', 'o', 'm', ' ', 'x'}; - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ(11, breaker.next()); // after "foo@example" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(16, breaker.next()); // after ".com " - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); // end - EXPECT_EQ(16, breaker.wordStart()); // "x" - EXPECT_EQ(17, breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); -} - -TEST_F(WordBreakerTest, mailto) { - uint16_t buf[] = {'m', 'a', 'i', 'l', 't', 'o', ':', 'f', 'o', 'o', '@', 'e', - 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm', ' ', 'x'}; - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ(7, breaker.next()); // after "mailto:" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(18, breaker.next()); // after "foo@example" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(23, breaker.next()); // after ".com " - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); // end - EXPECT_EQ(23, breaker.wordStart()); // "x" - EXPECT_EQ(24, breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); -} - -// The current logic always places a line break after a detected email address -// or URL and an immediately following non-ASCII character. -TEST_F(WordBreakerTest, emailNonAscii) { - uint16_t buf[] = {'f', 'o', 'o', '@', 'e', 'x', 'a', 'm', - 'p', 'l', 'e', '.', 'c', 'o', 'm', 0x4E00}; - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ(11, breaker.next()); // after "foo@example" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(15, breaker.next()); // after ".com" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); // end - EXPECT_EQ(15, breaker.wordStart()); // "一" - EXPECT_EQ(16, breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); -} - -TEST_F(WordBreakerTest, emailCombining) { - uint16_t buf[] = {'f', 'o', 'o', '@', 'e', 'x', 'a', 'm', 'p', - 'l', 'e', '.', 'c', 'o', 'm', 0x0303, ' ', 'x'}; - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ(11, breaker.next()); // after "foo@example" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(17, breaker.next()); // after ".com̃ " - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); // end - EXPECT_EQ(17, breaker.wordStart()); // "x" - EXPECT_EQ(18, breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); -} - -TEST_F(WordBreakerTest, lonelyAt) { - uint16_t buf[] = {'a', ' ', '@', ' ', 'b'}; - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ(2, breaker.next()); // after "a " - EXPECT_EQ(0, breaker.wordStart()); // "a" - EXPECT_EQ(1, breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); - EXPECT_EQ(4, breaker.next()); // after "@ " - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); // end - EXPECT_EQ(4, breaker.wordStart()); // "b" - EXPECT_EQ(5, breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); -} - -TEST_F(WordBreakerTest, url) { - uint16_t buf[] = {'h', 't', 't', 'p', ':', '/', '/', 'e', 'x', 'a', - 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm', ' ', 'x'}; - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ(5, breaker.next()); // after "http:" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(7, breaker.next()); // after "//" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(14, breaker.next()); // after "example" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(19, breaker.next()); // after ".com " - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); // end - EXPECT_EQ(19, breaker.wordStart()); // "x" - EXPECT_EQ(20, breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); -} - -// Breaks according to section 14.12 of Chicago Manual of Style, *URLs or DOIs -// and line breaks* -TEST_F(WordBreakerTest, urlBreakChars) { - uint16_t buf[] = {'h', 't', 't', 'p', ':', '/', '/', 'a', '.', 'b', '/', - '~', 'c', ',', 'd', '-', 'e', '?', 'f', '=', 'g', '&', - 'h', '#', 'i', '%', 'j', '_', 'k', '/', 'l'}; - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ(5, breaker.next()); // after "http:" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(7, breaker.next()); // after "//" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(8, breaker.next()); // after "a" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(10, breaker.next()); // after ".b" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(11, breaker.next()); // after "/" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(13, breaker.next()); // after "~c" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(15, breaker.next()); // after ",d" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(17, breaker.next()); // after "-e" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(19, breaker.next()); // after "?f" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(20, breaker.next()); // after "=" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(21, breaker.next()); // after "g" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(22, breaker.next()); // after "&" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(23, breaker.next()); // after "h" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(25, breaker.next()); // after "#i" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(27, breaker.next()); // after "%j" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ(29, breaker.next()); // after "_k" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(1, breaker.breakBadness()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); // end - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(0, breaker.breakBadness()); -} - -TEST_F(WordBreakerTest, urlNoHyphenBreak) { - uint16_t buf[] = {'h', 't', 't', 'p', ':', '/', '/', 'a', '-', '/', 'b'}; - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ(5, breaker.next()); // after "http:" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(7, breaker.next()); // after "//" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(8, breaker.next()); // after "a" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); // end - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); -} - -TEST_F(WordBreakerTest, urlEndsWithSlash) { - uint16_t buf[] = {'h', 't', 't', 'p', ':', '/', '/', 'a', '/'}; - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ(5, breaker.next()); // after "http:" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(7, breaker.next()); // after "//" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ(8, breaker.next()); // after "a" - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); // end - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); -} - -TEST_F(WordBreakerTest, emailStartsWithSlash) { - uint16_t buf[] = {'/', 'a', '@', 'b'}; - WordBreaker breaker; - breaker.setLocale(icu::Locale::getUS()); - breaker.setText(buf, NELEM(buf)); - EXPECT_EQ(0, breaker.current()); - EXPECT_EQ((ssize_t)NELEM(buf), breaker.next()); // end - EXPECT_TRUE(breaker.wordStart() >= breaker.wordEnd()); -} - -} // namespace minikin diff --git a/third_party/txt/tests/fake_provider.h b/third_party/txt/tests/fake_provider.h deleted file mode 100644 index 2f749655ec679..0000000000000 --- a/third_party/txt/tests/fake_provider.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2021 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 -#include - -#include "flutter/fml/logging.h" - -namespace txt { - -class FakeProvider : public fuchsia::fonts::testing::Provider_TestBase { - public: - FakeProvider() : binding_(this) {} - - fidl::InterfaceHandle Bind( - async_dispatcher_t* dispatcher) { - FML_CHECK(!binding_.is_bound()); - - fidl::InterfaceHandle provider; - binding_.Bind(provider.NewRequest(), dispatcher); - - return provider; - } - - virtual void NotImplemented_(const std::string& name) override { - FML_LOG(ERROR) << "A fidl call for " << name - << " on fake_provider is not implemented! This likely means" - "that your test will hang."; - } - - void GetFontFamilyInfo(fuchsia::fonts::FamilyName family, - GetFontFamilyInfoCallback callback) override { - was_invoked_ = true; - callback(fuchsia::fonts::FontFamilyInfo()); - } - - bool WasInvoked() { return was_invoked_; } - - private: - fidl::Binding binding_; - bool was_invoked_ = false; -}; - -} // namespace txt diff --git a/third_party/txt/tests/font_collection_unittests.cc b/third_party/txt/tests/font_collection_unittests.cc deleted file mode 100644 index 05c055809f607..0000000000000 --- a/third_party/txt/tests/font_collection_unittests.cc +++ /dev/null @@ -1,218 +0,0 @@ -/* - * 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 "flutter/fml/logging.h" -#include "gtest/gtest.h" -#include "third_party/skia/include/utils/SkCustomTypeface.h" -#include "txt/font_collection.h" -#include "txt_test_utils.h" - -namespace txt { - -// We don't really need a fixture but a class in a namespace is needed for -// the FRIEND_TEST macro. -class FontCollectionTest : public ::testing::Test {}; - -namespace { -// This function does some boilerplate to fill a builder with enough real -// font-like data. Otherwise, detach won't actually build an SkTypeface. -void PopulateUserTypefaceBoilerplate(SkCustomTypefaceBuilder* builder) { - constexpr float upem = 200; - - { - SkFontMetrics metrics; - metrics.fFlags = 0; - metrics.fTop = -200; - metrics.fAscent = -150; - metrics.fDescent = 50; - metrics.fBottom = -75; - metrics.fLeading = 10; - metrics.fAvgCharWidth = 150; - metrics.fMaxCharWidth = 300; - metrics.fXMin = -20; - metrics.fXMax = 290; - metrics.fXHeight = -100; - metrics.fCapHeight = 0; - metrics.fUnderlineThickness = 5; - metrics.fUnderlinePosition = 2; - metrics.fStrikeoutThickness = 5; - metrics.fStrikeoutPosition = -50; - builder->setMetrics(metrics, 1.0f / upem); - } - - const SkMatrix scale = SkMatrix::Scale(1.0f / upem, 1.0f / upem); - for (SkGlyphID index = 0; index <= 67; ++index) { - SkScalar width; - width = 100; - SkPath path; - path.addCircle(50, -50, 75); - - builder->setGlyph(index, width / upem, path.makeTransform(scale)); - } -} -} // namespace - -TEST(FontCollectionTest, CheckSkTypefacesSorting) { - // We have to make a real SkTypeface here. Not all the structs from the - // SkTypeface headers are fully declared to be able to gmock. - // SkCustomTypefaceBuilder is the simplest way to get a simple SkTypeface. - SkCustomTypefaceBuilder typefaceBuilder1; - typefaceBuilder1.setFontStyle(SkFontStyle(SkFontStyle::kThin_Weight, - SkFontStyle::kExpanded_Width, - SkFontStyle::kItalic_Slant)); - // For the purpose of this test, we need to fill this to make the SkTypeface - // build but it doesn't matter. We only care about the SkFontStyle. - PopulateUserTypefaceBoilerplate(&typefaceBuilder1); - sk_sp typeface1{typefaceBuilder1.detach()}; - - SkCustomTypefaceBuilder typefaceBuilder2; - typefaceBuilder2.setFontStyle(SkFontStyle(SkFontStyle::kLight_Weight, - SkFontStyle::kNormal_Width, - SkFontStyle::kUpright_Slant)); - PopulateUserTypefaceBoilerplate(&typefaceBuilder2); - sk_sp typeface2{typefaceBuilder2.detach()}; - - SkCustomTypefaceBuilder typefaceBuilder3; - typefaceBuilder3.setFontStyle(SkFontStyle(SkFontStyle::kNormal_Weight, - SkFontStyle::kNormal_Width, - SkFontStyle::kUpright_Slant)); - PopulateUserTypefaceBoilerplate(&typefaceBuilder3); - sk_sp typeface3{typefaceBuilder3.detach()}; - - SkCustomTypefaceBuilder typefaceBuilder4; - typefaceBuilder4.setFontStyle(SkFontStyle(SkFontStyle::kThin_Weight, - SkFontStyle::kCondensed_Width, - SkFontStyle::kUpright_Slant)); - PopulateUserTypefaceBoilerplate(&typefaceBuilder4); - sk_sp typeface4{typefaceBuilder4.detach()}; - - std::vector> candidateTypefaces = {typeface1, typeface2, - typeface3, typeface4}; - - // This sorts the vector in-place. - txt::FontCollection::SortSkTypefaces(candidateTypefaces); - - // The second one is first because it's both the most normal width font - // with the lightest weight. - ASSERT_EQ(candidateTypefaces[0].get(), typeface2.get()); - // Then the most normal width font with normal weight. - ASSERT_EQ(candidateTypefaces[1].get(), typeface3.get()); - // Then a less normal (condensed) width font. - ASSERT_EQ(candidateTypefaces[2].get(), typeface4.get()); - // All things equal, 4 came before 1 because we arbitrarily chose to make the - // narrower font come first. - ASSERT_EQ(candidateTypefaces[3].get(), typeface1.get()); - - // Double check. - ASSERT_EQ(candidateTypefaces[0]->fontStyle().weight(), - SkFontStyle::kLight_Weight); - ASSERT_EQ(candidateTypefaces[0]->fontStyle().width(), - SkFontStyle::kNormal_Width); - - ASSERT_EQ(candidateTypefaces[1]->fontStyle().weight(), - SkFontStyle::kNormal_Weight); - ASSERT_EQ(candidateTypefaces[1]->fontStyle().width(), - SkFontStyle::kNormal_Width); - - ASSERT_EQ(candidateTypefaces[2]->fontStyle().weight(), - SkFontStyle::kThin_Weight); - ASSERT_EQ(candidateTypefaces[2]->fontStyle().width(), - SkFontStyle::kCondensed_Width); - - ASSERT_EQ(candidateTypefaces[3]->fontStyle().weight(), - SkFontStyle::kThin_Weight); - ASSERT_EQ(candidateTypefaces[3]->fontStyle().width(), - SkFontStyle::kExpanded_Width); -} - -#if 0 - -TEST(FontCollection, HasDefaultRegistrations) { - std::string defaultFamilyName = txt::FontCollection::GetDefaultFamilyName(); - - auto collection = txt::FontCollection::GetFontCollection(txt::GetFontDir()) - .GetMinikinFontCollectionForFamily(""); - ASSERT_EQ(defaultFamilyName, - txt::FontCollection::GetFontCollection(txt::GetFontDir()) - .ProcessFamilyName("")); - ASSERT_NE(defaultFamilyName, - txt::FontCollection::GetFontCollection(txt::GetFontDir()) - .ProcessFamilyName("NotARealFont!")); - ASSERT_EQ("NotARealFont!", - txt::FontCollection::GetFontCollection(txt::GetFontDir()) - .ProcessFamilyName("NotARealFont!")); - ASSERT_NE(collection.get(), nullptr); -} - -TEST(FontCollection, GetMinikinFontCollections) { - std::string defaultFamilyName = txt::FontCollection::GetDefaultFamilyName(); - - auto collectionDef = txt::FontCollection::GetFontCollection(txt::GetFontDir()) - .GetMinikinFontCollectionForFamily(""); - auto collectionRoboto = - txt::FontCollection::GetFontCollection(txt::GetFontDir()) - .GetMinikinFontCollectionForFamily("Roboto"); - auto collectionHomemadeApple = - txt::FontCollection::GetFontCollection(txt::GetFontDir()) - .GetMinikinFontCollectionForFamily("Homemade Apple"); - 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); -} - -TEST(FontCollection, GetFamilyNames) { - std::set names = - txt::FontCollection::GetFontCollection(txt::GetFontDir()) - .GetFamilyNames(); - - ASSERT_TRUE(names.size() >= 19ull); - - ASSERT_EQ(names.count("Roboto"), 1ull); - ASSERT_EQ(names.count("Homemade Apple"), 1ull); - - ASSERT_EQ(names.count("KoreanFont Test"), 1ull); - ASSERT_EQ(names.count("JapaneseFont Test"), 1ull); - ASSERT_EQ(names.count("EmojiFont Test"), 1ull); - ASSERT_EQ(names.count("ItalicFont Test"), 1ull); - ASSERT_EQ(names.count("VariationSelector Test"), 1ull); - ASSERT_EQ(names.count("ColorEmojiFont Test"), 1ull); - ASSERT_EQ(names.count("TraditionalChinese Test"), 1ull); - ASSERT_EQ(names.count("Sample Font"), 1ull); - ASSERT_EQ(names.count("MultiAxisFont Test"), 1ull); - ASSERT_EQ(names.count("TextEmojiFont Test"), 1ull); - ASSERT_EQ(names.count("No Cmap Format 14 Subtable Test"), 1ull); - ASSERT_EQ(names.count("ColorTextMixedEmojiFont Test"), 1ull); - ASSERT_EQ(names.count("BoldFont Test"), 1ull); - ASSERT_EQ(names.count("EmptyFont Test"), 1ull); - ASSERT_EQ(names.count("SimplifiedChinese Test"), 1ull); - ASSERT_EQ(names.count("BoldItalicFont Test"), 1ull); - ASSERT_EQ(names.count("RegularFont Test"), 1ull); - - ASSERT_EQ(names.count("Not a real font!"), 0ull); - ASSERT_EQ(names.count(""), 0ull); - ASSERT_EQ(names.count("Another Fake Font"), 0ull); -} - -#endif // 0 - -} // namespace txt diff --git a/third_party/txt/tests/old/perftests/FontCollection.cpp b/third_party/txt/tests/old/perftests/FontCollection.cpp deleted file mode 100644 index eb5592894d838..0000000000000 --- a/third_party/txt/tests/old/perftests/FontCollection.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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 - -#include -#include -#include -#include - -namespace minikin { - -const char* SYSTEM_FONT_PATH = "/system/fonts/"; -const char* SYSTEM_FONT_XML = "/system/etc/fonts.xml"; - -static void BM_FontCollection_construct(benchmark::State& state) { - std::vector> families = - getFontFamilies(SYSTEM_FONT_PATH, SYSTEM_FONT_XML); - while (state.KeepRunning()) { - std::make_shared(families); - } -} - -BENCHMARK(BM_FontCollection_construct); - -static void BM_FontCollection_hasVariationSelector(benchmark::State& state) { - std::shared_ptr collection( - getFontCollection(SYSTEM_FONT_PATH, SYSTEM_FONT_XML)); - - uint32_t baseCp = state.range(0); - uint32_t vsCp = state.range(1); - - char titleBuffer[64]; - snprintf(titleBuffer, 64, "hasVariationSelector U+%04X,U+%04X", baseCp, vsCp); - state.SetLabel(titleBuffer); - - while (state.KeepRunning()) { - collection->hasVariationSelector(baseCp, vsCp); - } -} - -// TODO: Rewrite with BENCHMARK_CAPTURE for better test name. -BENCHMARK(BM_FontCollection_hasVariationSelector) - ->ArgPair(0x2708, 0xFE0F) - ->ArgPair(0x2708, 0xFE0E) - ->ArgPair(0x3402, 0xE0100); - -struct ItemizeTestCases { - std::string itemizeText; - std::string languageTag; - std::string labelText; -} ITEMIZE_TEST_CASES[] = { - {"'A' 'n' 'd' 'r' 'o' 'i' 'd'", "en", "English"}, - {"U+4E16", "zh-Hans", "CJK Ideograph"}, - {"U+4E16", "zh-Hans,zh-Hant,ja,en,es,pt,fr,de", - "CJK Ideograph with many language fallback"}, - {"U+3402 U+E0100", "ja", "CJK Ideograph with variation selector"}, - {"'A' 'n' U+0E1A U+0E31 U+0645 U+062D U+0648", "en", - "Mixture of English, Thai and Arabic"}, - {"U+2708 U+FE0E", "en", "Emoji with variation selector"}, - {"U+0031 U+FE0F U+20E3", "en", "KEYCAP"}, -}; - -static void BM_FontCollection_itemize(benchmark::State& state) { - std::shared_ptr collection( - getFontCollection(SYSTEM_FONT_PATH, SYSTEM_FONT_XML)); - - size_t testIndex = state.range(0); - state.SetLabel("Itemize: " + ITEMIZE_TEST_CASES[testIndex].labelText); - - uint16_t buffer[64]; - size_t utf16_length = 0; - ParseUnicode(buffer, 64, ITEMIZE_TEST_CASES[testIndex].itemizeText.c_str(), - &utf16_length, nullptr); - std::vector result; - FontStyle style(FontStyle::registerLanguageList( - ITEMIZE_TEST_CASES[testIndex].languageTag)); - - std::scoped_lock _l(gMinikinLock); - while (state.KeepRunning()) { - result.clear(); - collection->itemize(buffer, utf16_length, style, &result); - } -} - -// TODO: Rewrite with BENCHMARK_CAPTURE once it is available in Android. -BENCHMARK(BM_FontCollection_itemize) - ->Arg(0) - ->Arg(1) - ->Arg(2) - ->Arg(3) - ->Arg(4) - ->Arg(5) - ->Arg(6); - -} // namespace minikin diff --git a/third_party/txt/tests/old/perftests/FontFamily.cpp b/third_party/txt/tests/old/perftests/FontFamily.cpp deleted file mode 100644 index 9331ce92c65d7..0000000000000 --- a/third_party/txt/tests/old/perftests/FontFamily.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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 -#include "../util/MinikinFontForTest.h" - -namespace minikin { - -static void BM_FontFamily_create(benchmark::State& state) { - std::shared_ptr minikinFont = - std::make_shared( - "/system/fonts/NotoSansCJK-Regular.ttc", 0); - - while (state.KeepRunning()) { - std::shared_ptr family = std::make_shared( - std::vector({Font(minikinFont, FontStyle())})); - } -} - -BENCHMARK(BM_FontFamily_create); - -} // namespace minikin diff --git a/third_party/txt/tests/old/perftests/FontLanguage.cpp b/third_party/txt/tests/old/perftests/FontLanguage.cpp deleted file mode 100644 index 8919699b9b255..0000000000000 --- a/third_party/txt/tests/old/perftests/FontLanguage.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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 "FontLanguage.h" - -namespace minikin { - -static void BM_FontLanguage_en_US(benchmark::State& state) { - while (state.KeepRunning()) { - FontLanguage language("en-US", 5); - } -} -BENCHMARK(BM_FontLanguage_en_US); - -static void BM_FontLanguage_en_Latn_US(benchmark::State& state) { - while (state.KeepRunning()) { - FontLanguage language("en-Latn-US", 10); - } -} -BENCHMARK(BM_FontLanguage_en_Latn_US); - -static void BM_FontLanguage_en_Latn_US_u_em_emoji(benchmark::State& state) { - while (state.KeepRunning()) { - FontLanguage language("en-Latn-US-u-em-emoji", 21); - } -} -BENCHMARK(BM_FontLanguage_en_Latn_US_u_em_emoji); - -} // namespace minikin diff --git a/third_party/txt/tests/old/perftests/GraphemeBreak.cpp b/third_party/txt/tests/old/perftests/GraphemeBreak.cpp deleted file mode 100644 index 5fc1e3cbf6a44..0000000000000 --- a/third_party/txt/tests/old/perftests/GraphemeBreak.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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 - -#include "UnicodeUtils.h" -#include "minikin/GraphemeBreak.h" - -namespace minikin { - -const char* ASCII_TEST_STR = "'L' 'o' 'r' 'e' 'm' ' ' 'i' 'p' 's' 'u' 'm' '.'"; -// U+261D: WHITE UP POINTING INDEX -// U+1F3FD: EMOJI MODIFIER FITZPATRICK TYPE-4 -const char* EMOJI_TEST_STR = - "U+261D U+1F3FD U+261D U+1F3FD U+261D U+1F3FD U+261D U+1F3FD"; -// U+1F1FA: REGIONAL INDICATOR SYMBOL LETTER U -// U+1F1F8: REGIONAL INDICATOR SYMBOL LETTER S -const char* FLAGS_TEST_STR = "U+1F1FA U+1F1F8 U+1F1FA U+1F1F8 U+1F1FA U+1F1F8"; - -// TODO: Migrate BENCHMARK_CAPTURE for parameterizing. -static void BM_GraphemeBreak_Ascii(benchmark::State& state) { - size_t result_size; - uint16_t buffer[12]; - ParseUnicode(buffer, 12, ASCII_TEST_STR, &result_size, nullptr); - LOG_ALWAYS_FATAL_IF(result_size != 12); - const size_t testIndex = state.range(0); - while (state.KeepRunning()) { - GraphemeBreak::isGraphemeBreak(nullptr, buffer, 0, result_size, testIndex); - } -} -BENCHMARK(BM_GraphemeBreak_Ascii) - ->Arg(0) // Beginning of the text. - ->Arg(1) // Middle of the text. - ->Arg(12); // End of the text. - -static void BM_GraphemeBreak_Emoji(benchmark::State& state) { - size_t result_size; - uint16_t buffer[12]; - ParseUnicode(buffer, 12, EMOJI_TEST_STR, &result_size, nullptr); - LOG_ALWAYS_FATAL_IF(result_size != 12); - const size_t testIndex = state.range(0); - while (state.KeepRunning()) { - GraphemeBreak::isGraphemeBreak(nullptr, buffer, 0, result_size, testIndex); - } -} -BENCHMARK(BM_GraphemeBreak_Emoji) - ->Arg(1) // Middle of emoji modifier sequence. - ->Arg(2) // Middle of the surrogate pairs. - ->Arg(3); // After emoji modifier sequence. Here is boundary of grapheme - // cluster. - -static void BM_GraphemeBreak_Emoji_Flags(benchmark::State& state) { - size_t result_size; - uint16_t buffer[12]; - ParseUnicode(buffer, 12, FLAGS_TEST_STR, &result_size, nullptr); - LOG_ALWAYS_FATAL_IF(result_size != 12); - const size_t testIndex = state.range(0); - while (state.KeepRunning()) { - GraphemeBreak::isGraphemeBreak(nullptr, buffer, 0, result_size, testIndex); - } -} -BENCHMARK(BM_GraphemeBreak_Emoji_Flags) - ->Arg(2) // Middle of flag sequence. - ->Arg(4) // After flag sequence. Here is boundary of grapheme cluster. - ->Arg(10); // Middle of 3rd flag sequence. - -} // namespace minikin diff --git a/third_party/txt/tests/old/perftests/Hyphenator.cpp b/third_party/txt/tests/old/perftests/Hyphenator.cpp deleted file mode 100644 index 2c87c3555a1db..0000000000000 --- a/third_party/txt/tests/old/perftests/Hyphenator.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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 -#include -#include - -namespace minikin { - -const char* enUsHyph = "/system/usr/hyphen-data/hyph-en-us.hyb"; -const int enUsMinPrefix = 2; -const int enUsMinSuffix = 3; -const icu::Locale& usLocale = icu::Locale::getUS(); - -static void BM_Hyphenator_short_word(benchmark::State& state) { - Hyphenator* hyphenator = Hyphenator::loadBinary( - readWholeFile(enUsHyph).data(), enUsMinPrefix, enUsMinSuffix); - std::vector word = utf8ToUtf16("hyphen"); - std::vector result; - while (state.KeepRunning()) { - hyphenator->hyphenate(&result, word.data(), word.size(), usLocale); - } - Hyphenator::loadBinary(nullptr, 2, 2); -} - -// TODO: Use BENCHMARK_CAPTURE for parametrise. -BENCHMARK(BM_Hyphenator_short_word); - -static void BM_Hyphenator_long_word(benchmark::State& state) { - Hyphenator* hyphenator = Hyphenator::loadBinary( - readWholeFile(enUsHyph).data(), enUsMinPrefix, enUsMinSuffix); - std::vector word = - utf8ToUtf16("Pneumonoultramicroscopicsilicovolcanoconiosis"); - std::vector result; - while (state.KeepRunning()) { - hyphenator->hyphenate(&result, word.data(), word.size(), usLocale); - } - Hyphenator::loadBinary(nullptr, 2, 2); -} - -// TODO: Use BENCHMARK_CAPTURE for parametrise. -BENCHMARK(BM_Hyphenator_long_word); - -// TODO: Add more tests for other languages. - -} // namespace minikin diff --git a/third_party/txt/tests/old/perftests/WordBreaker.cpp b/third_party/txt/tests/old/perftests/WordBreaker.cpp deleted file mode 100644 index 70661e1076118..0000000000000 --- a/third_party/txt/tests/old/perftests/WordBreaker.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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 "UnicodeUtils.h" -#include "minikin/WordBreaker.h" - -namespace minikin { - -static void BM_WordBreaker_English(benchmark::State& state) { - const char* kLoremIpsum = - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do " - "eiusmod tempor incididunt ut labore et dolore magna aliqua."; - - WordBreaker wb; - wb.setLocale(icu::Locale::getEnglish()); - std::vector text = utf8ToUtf16(kLoremIpsum); - while (state.KeepRunning()) { - wb.setText(text.data(), text.size()); - while (wb.next() != -1) { - } - } -} -BENCHMARK(BM_WordBreaker_English); - -// TODO: Add more tests for other languages. - -} // namespace minikin diff --git a/third_party/txt/tests/old/perftests/main.cpp b/third_party/txt/tests/old/perftests/main.cpp deleted file mode 100644 index 7110ddff4eb86..0000000000000 --- a/third_party/txt/tests/old/perftests/main.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * 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 - -#include -#include - -#include -#include -#include - -int main(int argc, char** argv) { - const char* fn = "/system/usr/icu/" U_ICUDATA_NAME ".dat"; - int fd = open(fn, O_RDONLY); - LOG_ALWAYS_FATAL_IF(fd == -1); - struct stat st; - LOG_ALWAYS_FATAL_IF(fstat(fd, &st) != 0); - void* data = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); - - UErrorCode errorCode = U_ZERO_ERROR; - udata_setCommonData(data, &errorCode); - LOG_ALWAYS_FATAL_IF(U_FAILURE(errorCode)); - u_init(&errorCode); - LOG_ALWAYS_FATAL_IF(U_FAILURE(errorCode)); - - benchmark::Initialize(&argc, argv); - benchmark::RunSpecifiedBenchmarks(); - - u_cleanup(); - return 0; -} diff --git a/third_party/txt/tests/old/stresstest/MultithreadTest.cpp b/third_party/txt/tests/old/stresstest/MultithreadTest.cpp deleted file mode 100644 index 3475345e3d24c..0000000000000 --- a/third_party/txt/tests/old/stresstest/MultithreadTest.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * 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 -#include -#include -#include - -#include - -#include "../util/FontTestUtils.h" -#include "MinikinInternal.h" -#include "minikin/FontCollection.h" -#include "minikin/Layout.h" - -namespace minikin { - -const char* SYSTEM_FONT_PATH = "/system/fonts/"; -const char* SYSTEM_FONT_XML = "/system/etc/fonts.xml"; - -constexpr int LAYOUT_COUNT_PER_COLLECTION = 500; -constexpr int COLLECTION_COUNT_PER_THREAD = 15; -constexpr int NUM_THREADS = 10; - -std::mutex gMutex; -std::condition_variable gCv; -bool gReady = false; - -static std::vector generateTestText(std::mt19937* mt, - int lettersInWord, - int wordsInText) { - std::uniform_int_distribution dist('A', 'Z'); - - std::vector text; - text.reserve((lettersInWord + 1) * wordsInText - 1); - for (int i = 0; i < wordsInText; ++i) { - if (i != 0) { - text.emplace_back(' '); - } - for (int j = 0; j < lettersInWord; ++j) { - text.emplace_back(dist(*mt)); - } - } - return text; -} - -static void thread_main(int tid) { - { - // Wait until all threads are created. - std::unique_lock lock(gMutex); - gCv.wait(lock, [] { return gReady; }); - } - - std::mt19937 mt(tid); - MinikinPaint paint; - - for (int i = 0; i < COLLECTION_COUNT_PER_THREAD; ++i) { - std::shared_ptr collection( - getFontCollection(SYSTEM_FONT_PATH, SYSTEM_FONT_XML)); - - for (int j = 0; j < LAYOUT_COUNT_PER_COLLECTION; ++j) { - // Generates 10 of 3-letter words so that the word sometimes hit the - // cache. - Layout layout; - std::vector text = generateTestText(&mt, 3, 10); - layout.doLayout(text.data(), 0, text.size(), text.size(), kBidi_LTR, - FontStyle(), paint, collection); - std::vector advances(text.size()); - layout.getAdvances(advances.data()); - for (size_t k = 0; k < advances.size(); ++k) { - // MinikinFontForTest always returns 10.0f for horizontal advance. - LOG_ALWAYS_FATAL_IF(advances[k] != 10.0f, - "Memory corruption detected."); - } - } - } -} - -TEST(MultithreadTest, ThreadSafeStressTest) { - std::vector threads; - - { - std::unique_lock lock(gMutex); - threads.reserve(NUM_THREADS); - for (int i = 0; i < NUM_THREADS; ++i) { - threads.emplace_back(&thread_main, i); - } - gReady = true; - } - gCv.notify_all(); - - for (auto& thread : threads) { - thread.join(); - } -} - -} // namespace minikin diff --git a/third_party/txt/tests/paragraph_unittests.cc b/third_party/txt/tests/paragraph_unittests.cc deleted file mode 100644 index 979c0079ffb33..0000000000000 --- a/third_party/txt/tests/paragraph_unittests.cc +++ /dev/null @@ -1,7114 +0,0 @@ -/* - * 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 - -#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) -#define DISABLE_ON_MAC(TEST) DISABLE_TEST_MAC(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()); -} - -TEST_F(ParagraphTest, SimpleParagraphSmall) { - const char* text = - "Hello World Text Dialog. This is a very small text in order to check " - "for constant advance additions that are only visible when the advance " - "of the glyphs are small."; - 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_size = 6; - // 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()); -} - -// Check that GetGlyphPositionAtCoordinate computes correct text positions for -// a paragraph containing multiple styled runs. -TEST_F(ParagraphTest, GetGlyphPositionAtCoordinateMultiRun) { - txt::ParagraphStyle paragraph_style; - txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); - - txt::TextStyle text_style; - text_style.font_families = std::vector(1, "Ahem"); - text_style.color = SK_ColorBLACK; - text_style.font_size = 10; - builder.PushStyle(text_style); - builder.AddText(u"A"); - text_style.font_size = 20; - builder.PushStyle(text_style); - builder.AddText(u"B"); - text_style.font_size = 30; - builder.PushStyle(text_style); - builder.AddText(u"C"); - - auto paragraph = BuildParagraph(builder); - paragraph->Layout(GetTestCanvasWidth()); - - paragraph->Paint(GetCanvas(), 10.0, 15.0); - - ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(2.0, 5.0).position, 0ull); - ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(12.0, 5.0).position, 1ull); - ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(32.0, 5.0).position, 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.72266); - 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.0625); - 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, DISABLE_ON_MAC(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, 348.61328); - 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.945312); - EXPECT_FLOAT_EQ(boxes[1].rect.top(), 50); - EXPECT_FLOAT_EQ(boxes[1].rect.right(), 140.94531); - EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 100); - - EXPECT_FLOAT_EQ(boxes[3].rect.left(), 231.39062); - EXPECT_FLOAT_EQ(boxes[3].rect.top(), 50); - EXPECT_FLOAT_EQ(boxes[3].rect.right(), 231.39062 + 50); - EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 100); - - EXPECT_FLOAT_EQ(boxes[4].rect.left(), 281.39062); - EXPECT_FLOAT_EQ(boxes[4].rect.top(), 0); - EXPECT_FLOAT_EQ(boxes[4].rect.right(), 281.39062 + 5); - EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 50); - - EXPECT_FLOAT_EQ(boxes[6].rect.left(), 336.39062); - EXPECT_FLOAT_EQ(boxes[6].rect.top(), 0); - EXPECT_FLOAT_EQ(boxes[6].rect.right(), 336.39062 + 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.945312); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.94531); - 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 accommodate it. - EXPECT_FLOAT_EQ(boxes[0].rect.left(), 75.34375); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 14.226246); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.945312); - 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.945312); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.34765625); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.94531); - 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 accommodate it. - EXPECT_FLOAT_EQ(boxes[0].rect.left(), 75.34375); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 25.53125); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.945312); - 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.945312); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 24); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.94531); - 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 accommodate it. - EXPECT_FLOAT_EQ(boxes[0].rect.left(), 75.34375); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.12109375); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.945312); - 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.945312); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.94531); - 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 accommodate 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.101562); - 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.945312); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.94531); - 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 accommodate 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.101562); - 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.945312); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 145.94531); - 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 accommodate it. - EXPECT_FLOAT_EQ(boxes[0].rect.left(), 75.34375); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 9.765625); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.945312); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 40.234375); - - ASSERT_TRUE(Snapshot()); -} - -TEST_F(ParagraphTest, - DISABLE_ON_MAC( - 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 accommodate 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.703125); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 218.53125); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 47.304688); - 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.742188); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 26.378906); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 90.945312); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 56.847656); - - EXPECT_FLOAT_EQ(boxes[11].rect.left(), 606.39062); - EXPECT_FLOAT_EQ(boxes[11].rect.top(), 38); - EXPECT_FLOAT_EQ(boxes[11].rect.right(), 631.39062); - 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.945312); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 140.94531); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 50); - - EXPECT_FLOAT_EQ(boxes[16].rect.left(), 800.94531); - EXPECT_FLOAT_EQ(boxes[16].rect.top(), 0); - EXPECT_FLOAT_EQ(boxes[16].rect.right(), 850.94531); - EXPECT_FLOAT_EQ(boxes[16].rect.bottom(), 50); - - EXPECT_FLOAT_EQ(boxes[33].rect.left(), 503.48438); - EXPECT_FLOAT_EQ(boxes[33].rect.top(), 160); - EXPECT_FLOAT_EQ(boxes[33].rect.right(), 508.48438); - 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.10156); - // Top should be taller than "tight" - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 60); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 290.94531); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 120); - - EXPECT_FLOAT_EQ(boxes[1].rect.left(), 290.94531); - EXPECT_FLOAT_EQ(boxes[1].rect.top(), 60); - EXPECT_FLOAT_EQ(boxes[1].rect.right(), 340.94531); - EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 120); - - EXPECT_FLOAT_EQ(boxes[2].rect.left(), 340.94531); - EXPECT_FLOAT_EQ(boxes[2].rect.top(), 60); - EXPECT_FLOAT_EQ(boxes[2].rect.right(), 345.94531); - EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 120); - - ASSERT_TRUE(Snapshot()); -} - -TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderLongestLine)) { - txt::ParagraphStyle paragraph_style; - paragraph_style.max_lines = 1; - 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); - - txt::PlaceholderRun placeholder_run(50, 50, PlaceholderAlignment::kBaseline, - TextBaseline::kAlphabetic, 0); - builder.AddPlaceholder(placeholder_run); - builder.Pop(); - - auto paragraph = BuildParagraph(builder); - paragraph->Layout(GetTestCanvasWidth()); - - ASSERT_DOUBLE_EQ(paragraph->width_, GetTestCanvasWidth()); - ASSERT_TRUE(paragraph->longest_line_ < GetTestCanvasWidth()); - ASSERT_TRUE(paragraph->longest_line_ >= 50); -} - -TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(InlinePlaceholderIntrinsicWidth)) { - const char* text = "A "; - auto icu_text = icu::UnicodeString::fromUTF8(text); - std::u16string u16_text(icu_text.getBuffer(), - icu_text.getBuffer() + icu_text.length()); - - txt::PlaceholderRun placeholder_run(50, 50, PlaceholderAlignment::kBaseline, - TextBaseline::kAlphabetic, 0); - - 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 = 20; - text_style.decoration_color = SK_ColorBLACK; - builder.PushStyle(text_style); - - builder.AddText(u16_text); - builder.AddPlaceholder(placeholder_run); - - builder.Pop(); - - auto paragraph = BuildParagraph(builder); - paragraph->Layout(GetTestCanvasWidth()); - - ASSERT_DOUBLE_EQ(paragraph->GetMinIntrinsicWidth(), 50); - ASSERT_DOUBLE_EQ(paragraph->GetMaxIntrinsicWidth(), 68); -} - -#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.851562); - EXPECT_NEAR(boxes[1].rect.bottom(), 165.49578857421875, 0.0001); - - ASSERT_TRUE(Snapshot()); -} - -TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(HeightOverrideHalfLeadingTextStyle)) { - // All 3 lines will have the same typeface. - 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.text_height_behavior = TextHeightBehavior::kAll; - 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; - // Override paragraph_style.text_height_behavior: - text_style.half_leading = 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::kTight; - Paragraph::RectHeightStyle rect_height_style_max = - Paragraph::RectHeightStyle::kMax; - Paragraph::RectWidthStyle rect_width_style = - Paragraph::RectWidthStyle::kTight; - paint.setColor(SK_ColorRED); - - std::vector 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); - } - - std::vector line_boxes = paragraph->GetRectsForRange( - 0, 40, rect_height_style_max, rect_width_style); - EXPECT_EQ(boxes.size(), 3ull); - EXPECT_EQ(line_boxes.size(), 3ull); - - const double line_spacing1 = boxes[1].rect.top() - boxes[0].rect.bottom(); - const double line_spacing2 = boxes[2].rect.top() - boxes[1].rect.bottom(); - - EXPECT_EQ(line_spacing1, line_spacing2); - - // half leading. - EXPECT_EQ(line_boxes[0].rect.top() - boxes[0].rect.top(), - boxes[0].rect.bottom() - line_boxes[0].rect.bottom()); - EXPECT_EQ(line_boxes[1].rect.top() - boxes[1].rect.top(), - boxes[1].rect.bottom() - line_boxes[1].rect.bottom()); - EXPECT_EQ(line_boxes[2].rect.top() - boxes[2].rect.top(), - boxes[2].rect.bottom() - line_boxes[2].rect.bottom()); - // With half-leadding, the x coordinates should remain the same. - EXPECT_FLOAT_EQ(boxes[1].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[1].rect.right(), 43.851562); - - ASSERT_TRUE(Snapshot()); -} - -TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(MixedTextHeightBehaviorSameLine)) { - // Both runs will still have the same typeface, but with different text height - // behaviors. - const char* text = "01234満毎冠行来昼本可abcd"; - auto icu_text = icu::UnicodeString::fromUTF8(text); - std::u16string u16_text(icu_text.getBuffer(), - icu_text.getBuffer() + icu_text.length()); - - std::u16string u16_text2(icu_text.getBuffer(), - icu_text.getBuffer() + icu_text.length()); - - txt::ParagraphStyle paragraph_style; - paragraph_style.max_lines = 10; - paragraph_style.text_height_behavior = TextHeightBehavior::kAll; - 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; - // First run, with half-leading. - text_style.half_leading = true; - builder.PushStyle(text_style); - builder.AddText(u16_text); - - // Second run with AD-scaling. - text_style.half_leading = false; - - builder.PushStyle(text_style); - builder.AddText(u16_text2); - 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_style_max = - Paragraph::RectHeightStyle::kMax; - Paragraph::RectWidthStyle rect_width_style = - Paragraph::RectWidthStyle::kTight; - paint.setColor(SK_ColorRED); - - std::vector boxes = paragraph->GetRectsForRange( - 0, icu_text.length(), rect_height_style, rect_width_style); - for (size_t i = 0; i < boxes.size(); ++i) { - GetCanvas()->drawRect(boxes[i].rect, paint); - } - - std::vector line_boxes = paragraph->GetRectsForRange( - 0, icu_text.length(), rect_height_style_max, rect_width_style); - // The runs has the same typeface so they should be grouped together. - EXPECT_EQ(boxes.size(), 1ull); - EXPECT_EQ(line_boxes.size(), 1ull); - - const double glyphHeight = boxes[0].rect.height(); - const double metricsAscent = 18.5546875; - const double metricsDescent = 4.8828125; - EXPECT_DOUBLE_EQ(glyphHeight, metricsAscent + metricsDescent); - - const double line_height = 3.6345 * 20; - const double leading = line_height - glyphHeight; - - // Overall descent is from half-leading and overall ascent is from AD-scaling. - EXPECT_NEAR(boxes[0].rect.top() - line_boxes[0].rect.top(), - leading * metricsAscent / (metricsAscent + metricsDescent), - 0.001); - - EXPECT_NEAR(line_boxes[0].rect.bottom() - boxes[0].rect.bottom(), - leading * 0.5, 0.001); -} - -TEST_F(ParagraphTest, - DISABLE_ON_WINDOWS(MixedTextHeightBehaviorSameLineWithZeroHeight)) { - // Both runs will still have the same typeface, but with different text height - // behaviors. - const char* text = "01234満毎冠行来昼本可abcd"; - 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_height_behavior = TextHeightBehavior::kAll; - 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; - // Set height to 0 - text_style.height = 0; - text_style.has_height_override = true; - // First run, with half-leading. - text_style.half_leading = true; - builder.PushStyle(text_style); - builder.AddText(u16_text); - - // Second run with AD-scaling. - text_style.half_leading = false; - - 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_style_max = - Paragraph::RectHeightStyle::kMax; - Paragraph::RectWidthStyle rect_width_style = - Paragraph::RectWidthStyle::kTight; - paint.setColor(SK_ColorRED); - - std::vector boxes = paragraph->GetRectsForRange( - 0, icu_text.length(), rect_height_style, rect_width_style); - for (size_t i = 0; i < boxes.size(); ++i) { - GetCanvas()->drawRect(boxes[i].rect, paint); - } - - std::vector line_boxes = paragraph->GetRectsForRange( - 0, icu_text.length(), rect_height_style_max, rect_width_style); - // The runs has the same typeface so they should be grouped together. - EXPECT_EQ(boxes.size(), 1ull); - EXPECT_EQ(line_boxes.size(), 1ull); - - const double glyphHeight = boxes[0].rect.height(); - const double metricsAscent = 18.5546875; - const double metricsDescent = 4.8828125; - EXPECT_DOUBLE_EQ(glyphHeight, metricsAscent + metricsDescent); - - // line_height for both styled runs is 0, but the overall line height is not - // 0. - EXPECT_DOUBLE_EQ(line_boxes[0].rect.height(), - metricsAscent - (metricsAscent + metricsDescent) / 2); - EXPECT_LT(boxes[0].rect.top(), 0.0); - EXPECT_GT(boxes[0].rect.bottom(), 0.0); -} - -TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(HeightOverrideHalfLeadingStrut)) { - // All 3 lines will have the same typeface. - 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_enabled = true; - paragraph_style.strut_has_height_override = true; - paragraph_style.strut_height = 3.6345; - paragraph_style.strut_font_size = 20; - paragraph_style.strut_font_families.push_back("Roboto"); - paragraph_style.strut_half_leading = true; - 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; - text_style.half_leading = 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::kTight; - Paragraph::RectHeightStyle rect_height_style_max = - Paragraph::RectHeightStyle::kMax; - Paragraph::RectWidthStyle rect_width_style = - Paragraph::RectWidthStyle::kTight; - paint.setColor(SK_ColorRED); - - std::vector 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); - } - - std::vector line_boxes = paragraph->GetRectsForRange( - 0, 40, rect_height_style_max, rect_width_style); - EXPECT_EQ(boxes.size(), 3ull); - EXPECT_EQ(line_boxes.size(), 3ull); - - const double line_spacing1 = boxes[1].rect.top() - boxes[0].rect.bottom(); - const double line_spacing2 = boxes[2].rect.top() - boxes[1].rect.bottom(); - - EXPECT_EQ(line_spacing1, line_spacing2); - - // Strut half leading. - EXPECT_EQ(line_boxes[0].rect.top() - boxes[0].rect.top(), - boxes[0].rect.bottom() - line_boxes[0].rect.bottom()); - EXPECT_EQ(line_boxes[1].rect.top() - boxes[1].rect.top(), - boxes[1].rect.bottom() - line_boxes[1].rect.bottom()); - EXPECT_EQ(line_boxes[2].rect.top() - boxes[2].rect.top(), - boxes[2].rect.bottom() - line_boxes[2].rect.bottom()); - - EXPECT_FLOAT_EQ(boxes[1].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[1].rect.right(), 43.851562); - - ASSERT_TRUE(Snapshot()); -} - -TEST_F(ParagraphTest, - DISABLE_ON_WINDOWS(ZeroHeightHalfLeadingStrutForceHeight)) { - // All 3 lines will have the same typeface. - const char* text = "01234満毎冠行来昼本可abcdn満毎冠行来昼本可"; - 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_enabled = true; - paragraph_style.strut_has_height_override = true; - paragraph_style.strut_height = 0; - // Force strut height. - paragraph_style.force_strut_height = true; - paragraph_style.strut_font_size = 20; - paragraph_style.strut_font_families.push_back("Roboto"); - paragraph_style.strut_half_leading = true; - 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 = 0; - text_style.has_height_override = true; - - // First run, with half-leading. - text_style.half_leading = true; - builder.PushStyle(text_style); - builder.AddText(u16_text); - - // Second run with AD-scaling. - text_style.half_leading = false; - - 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_style_max = - Paragraph::RectHeightStyle::kMax; - Paragraph::RectWidthStyle rect_width_style = - Paragraph::RectWidthStyle::kTight; - paint.setColor(SK_ColorRED); - - std::vector boxes = paragraph->GetRectsForRange( - 0, icu_text.length(), rect_height_style, rect_width_style); - for (size_t i = 0; i < boxes.size(); ++i) { - GetCanvas()->drawRect(boxes[i].rect, paint); - } - - std::vector line_boxes = paragraph->GetRectsForRange( - 0, icu_text.length(), rect_height_style_max, rect_width_style); - // The runs has the same typeface so they should be grouped together. - EXPECT_EQ(boxes.size(), 1ull); - EXPECT_EQ(line_boxes.size(), 1ull); - - const double glyphHeight = boxes[0].rect.height(); - const double metricsAscent = 18.5546875; - const double metricsDescent = 4.8828125; - EXPECT_DOUBLE_EQ(glyphHeight, metricsAscent + metricsDescent); - - EXPECT_DOUBLE_EQ(line_boxes[0].rect.height(), 0.0); - - 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(LeftAlignRTLParagraphHitTest)) { - // Regression test for https://github.com/flutter/flutter/issues/54969. - 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 = 1; - paragraph_style.text_align = TextAlign::left; - paragraph_style.text_direction = TextDirection::rtl; - 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()); - - paragraph->Paint(GetCanvas(), 0, 0); - - ASSERT_TRUE(Snapshot()); - - // Tests for GetGlyphPositionAtCoordinate() - ASSERT_EQ( - paragraph->GetGlyphPositionAtCoordinate(GetTestCanvasWidth() - 0.5, 0.5) - .position, - 0ull); - - 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->line_widths_[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.87109375); - - 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->line_widths_[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->line_widths_[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->line_widths_[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->line_widths_[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->line_widths_[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->line_widths_[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->line_widths_[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->line_widths_[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->line_widths_[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, LINUX_ONLY(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, DISABLE_ON_WINDOWS(JustifyPlaceholder)) { - const char* text1 = "A "; - auto icu_text1 = icu::UnicodeString::fromUTF8(text1); - std::u16string u16_text1(icu_text1.getBuffer(), - icu_text1.getBuffer() + icu_text1.length()); - - txt::PlaceholderRun placeholder_run(60, 60, PlaceholderAlignment::kBaseline, - TextBaseline::kAlphabetic, 0); - - const char* text2 = " B CCCCC"; - 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.text_align = TextAlign::justify; - txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); - - txt::TextStyle text_style; - text_style.font_families = std::vector(1, "Ahem"); - text_style.font_size = 20; - text_style.decoration_color = SK_ColorBLACK; - builder.PushStyle(text_style); - - builder.AddText(u16_text1); - builder.AddPlaceholder(placeholder_run); - builder.AddText(u16_text2); - - builder.Pop(); - - auto paragraph = BuildParagraph(builder); - paragraph->Layout(200); - - Paragraph::RectHeightStyle rect_height_style = - Paragraph::RectHeightStyle::kTight; - Paragraph::RectWidthStyle rect_width_style = - Paragraph::RectWidthStyle::kTight; - - // Check location of placeholder at the center of the line. - std::vector boxes = - paragraph->GetRectsForRange(2, 3, rect_height_style, rect_width_style); - EXPECT_FLOAT_EQ(boxes[0].rect.left(), 70); - - // Check location of character B at the end of the line. - boxes = - paragraph->GetRectsForRange(4, 5, rect_height_style, rect_width_style); - EXPECT_FLOAT_EQ(boxes[0].rect.left(), 180); -} - -TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(LeadingSpaceRTL)) { - const char* text = " leading 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 = 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); - - 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(), 2ull); - - // This test should crash if behavior regresses. -} - -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.48438); - 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.03125); - EXPECT_FLOAT_EQ(boxes[1].rect.top(), -0.26855469); - EXPECT_FLOAT_EQ(boxes[1].rect.right(), 556.98438); - 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.425781); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.26855469); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 121.90625); - 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.48438); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.26855469); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 577.72656); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 44); - - EXPECT_FLOAT_EQ(boxes[1].rect.left(), 545.24609); - EXPECT_FLOAT_EQ(boxes[1].rect.top(), -0.26855469); - EXPECT_FLOAT_EQ(boxes[1].rect.right(), 556.98438); - 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.98438); - 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.98438); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 507.03906); - 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.37891); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 59.40625); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 463.62891); - 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.20312); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 519.49219); - 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, LINUX_ONLY(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.09766); - 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.09766); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 595.09375); - 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.433594); - 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.433594); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.01953); - 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.01953); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.09375); - 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.01953); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 88.473312); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.72266); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 168.47331); - - EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.72266); - EXPECT_FLOAT_EQ(boxes[1].rect.top(), 88.473312); - EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.05859); - 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.60547); - EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 248.47331); - - EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.60547); - EXPECT_FLOAT_EQ(boxes[3].rect.top(), 168.4733); - EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.05859); - 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.05859); - 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.05859); - 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.75781); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.26172); - 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.433594); - 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.433594); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.01953); - 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.01953); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.09375); - 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.01953); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 80); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.72266); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 160); - - EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.72266); - EXPECT_FLOAT_EQ(boxes[1].rect.top(), 80); - EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.05859); - 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.60547); - EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 240); - - EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.60547); - EXPECT_FLOAT_EQ(boxes[3].rect.top(), 160); - EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.05859); - 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.05859); - 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.05859); - 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.75781); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.26172); - 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.433594); - 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.433594); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.01953); - 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.01953); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.09375); - 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.01953); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 96.946617); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.72266); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 176.94661); - - EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.72266); - EXPECT_FLOAT_EQ(boxes[1].rect.top(), 96.946617); - EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.05859); - 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.60547); - EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 256.94662); - - EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.60547); - EXPECT_FLOAT_EQ(boxes[3].rect.top(), 176.94661); - EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.05859); - 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.05859); - 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.05859); - 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.75781); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.26172); - 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.49805); - 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, LINUX_ONLY(GetRectsForRangeParagraphNewlineLeftAlign)) { - const char* text = "01234\n\nعab\naعلی\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.font_family = "Roboto"; - paragraph_style.max_lines = 10; - paragraph_style.text_direction = TextDirection::ltr; - paragraph_style.text_align = TextAlign::left; - txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); - - txt::TextStyle text_style; - text_style.font_families = {"Roboto", "Noto Naskh Arabic"}; - 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(), 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_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(), 0); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 0); - 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. - - boxes = - paragraph->GetRectsForRange(10, 11, 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(), 85); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 85); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 160); - - boxes = - paragraph->GetRectsForRange(15, 16, 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(), 27); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 27); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 245); - - ASSERT_TRUE(Snapshot()); -} - -TEST_F(ParagraphTest, LINUX_ONLY(GetRectsForRangeParagraphNewlineRightAlign)) { - const char* text = "01234\n\nعab\naعلی\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.font_family = "Roboto"; - paragraph_style.max_lines = 10; - paragraph_style.text_direction = TextDirection::ltr; - paragraph_style.text_align = TextAlign::right; - txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); - - txt::TextStyle text_style; - text_style.font_families = {"Roboto", "Noto Naskh Arabic"}; - 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(), 407.91016); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 436.32812); - 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(), 550); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 550); - 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. - - boxes = - paragraph->GetRectsForRange(10, 11, 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(), 550); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 550); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 160); - - boxes = - paragraph->GetRectsForRange(15, 16, 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(), 478); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 478); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 245); - - ASSERT_TRUE(Snapshot()); -} - -TEST_F(ParagraphTest, - LINUX_ONLY(GetRectsForRangeCenterParagraphNewlineCentered)) { - const char* text = "01234\n\nعab\naعلی\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.font_family = "Roboto"; - paragraph_style.max_lines = 10; - paragraph_style.text_direction = TextDirection::ltr; - paragraph_style.text_align = TextAlign::center; - txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); - - txt::TextStyle text_style; - text_style.font_families = {"Roboto", "Noto Naskh Arabic"}; - 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. - - boxes = - paragraph->GetRectsForRange(10, 11, 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(), 317); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 317); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 160); - - boxes = - paragraph->GetRectsForRange(15, 16, 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(), 252); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 252); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 245); - - ASSERT_TRUE(Snapshot()); -} - -TEST_F(ParagraphTest, - LINUX_ONLY(GetRectsForRangeParagraphNewlineRTLLeftAlign)) { - const char* text = "01234\n\nعab\naعلی\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.font_family = "Roboto"; - paragraph_style.max_lines = 10; - paragraph_style.text_direction = TextDirection::rtl; - paragraph_style.text_align = TextAlign::left; - txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); - - txt::TextStyle text_style; - text_style.font_families = {"Roboto", "Noto Naskh Arabic"}; - 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(), 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_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(), 0); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 0); - 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. - - boxes = - paragraph->GetRectsForRange(10, 11, 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(), 55); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 55); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 160); - - boxes = - paragraph->GetRectsForRange(15, 16, 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.right(), 0); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 245); - - ASSERT_TRUE(Snapshot()); -} - -TEST_F(ParagraphTest, - LINUX_ONLY(GetRectsForRangeParagraphNewlineRTLRightAlign)) { - const char* text = "01234\n\nعab\naعلی\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.font_family = "Roboto"; - paragraph_style.max_lines = 10; - paragraph_style.text_direction = TextDirection::rtl; - paragraph_style.text_align = TextAlign::right; - txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); - - txt::TextStyle text_style; - text_style.font_families = {"Roboto", "Noto Naskh Arabic"}; - 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(), 407.91016); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 436.32812); - 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(), 550); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 550); - 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. - - boxes = - paragraph->GetRectsForRange(10, 11, 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(), 519); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 519); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 160); - - boxes = - paragraph->GetRectsForRange(15, 16, 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(), 451); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 451); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 245); - - ASSERT_TRUE(Snapshot()); -} - -TEST_F(ParagraphTest, - LINUX_ONLY(GetRectsForRangeCenterParagraphNewlineRTLCentered)) { - const char* text = "01234\n\nعab\naعلی\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.font_family = "Roboto"; - paragraph_style.max_lines = 10; - paragraph_style.text_direction = TextDirection::rtl; - paragraph_style.text_align = TextAlign::center; - txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); - - txt::TextStyle text_style; - text_style.font_families = {"Roboto", "Noto Naskh Arabic"}; - 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. - - boxes = - paragraph->GetRectsForRange(10, 11, 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(), 287); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 287); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 160); - - boxes = - paragraph->GetRectsForRange(15, 16, 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(), 225); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 225); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 245); - - 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.49805); - 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.19531); - 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, LINUX_ONLY(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.61719); - 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, LINUX_ONLY(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.3671875f); - EXPECT_DOUBLE_EQ(paragraph->records_[3].offset().x(), 230.8671875f); - EXPECT_DOUBLE_EQ(paragraph->records_[4].offset().x(), 253.35546875f); -} - -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, LINUX_ONLY(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, LINUX_ONLY(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); - - // 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); - EXPECT_FLOAT_EQ(boxes[1].rect.right(), 622.53906); - - 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); - EXPECT_FLOAT_EQ(boxes[1].rect.right(), 560.28516); - - ASSERT_TRUE(Snapshot()); -} - -TEST_F(ParagraphTest, LINUX_ONLY(LigatureCharacters)) { - const char* text = "Office"; - 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; - builder.PushStyle(text_style); - builder.AddText(u16_text); - - builder.Pop(); - - auto paragraph = BuildParagraph(builder); - paragraph->Layout(GetTestCanvasWidth()); - - // The "ffi" characters will be combined into one glyph in the Roboto font. - // Verify that the graphemes within the glyph have distinct boxes. - std::vector boxes = - paragraph->GetRectsForRange(1, 2, Paragraph::RectHeightStyle::kTight, - Paragraph::RectWidthStyle::kTight); - EXPECT_FLOAT_EQ(boxes[0].rect.left(), 9.625); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 13.608073); - - boxes = paragraph->GetRectsForRange(2, 4, Paragraph::RectHeightStyle::kTight, - Paragraph::RectWidthStyle::kTight); - EXPECT_FLOAT_EQ(boxes[0].rect.left(), 13.608073); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 21.574219); -} - -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, DISABLE_ON_MAC(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.2109375); - ASSERT_DOUBLE_EQ(paragraph->records_[1].GetRunWidth(), 139.1328125); - ASSERT_DOUBLE_EQ(paragraph->records_[2].GetRunWidth(), 28); - ASSERT_DOUBLE_EQ(paragraph->records_[3].GetRunWidth(), 62.25); - 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, LINUX_ONLY(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(), 0, 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(), 0, 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(), 190, 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(), 285); - 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(), 0, 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(), 0, 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(), 160, 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(), 240); - 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(), 0, 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(), 0, 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(), 120); - 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(), 180); - 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(), 0, 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(), 0, 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(), 160, 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(), 240); - 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()); -} - -TEST_F(ParagraphTest, KhmerLineBreaker) { - 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.font_families = std::vector(1, "Noto Sans Khmer"); - text_style.font_size = 24; - text_style.color = SK_ColorBLACK; - builder.PushStyle(text_style); - - builder.AddText(u16_text); - - builder.Pop(); - - auto paragraph = BuildParagraph(builder); - paragraph->Layout(200); - paragraph->Paint(GetCanvas(), 0, 0); - - ASSERT_EQ(paragraph->glyph_lines_.size(), 3ull); - EXPECT_EQ(paragraph->glyph_lines_[0].positions.size(), 7ul); - EXPECT_EQ(paragraph->glyph_lines_[1].positions.size(), 7ul); - EXPECT_EQ(paragraph->glyph_lines_[2].positions.size(), 3ul); - - ASSERT_TRUE(Snapshot()); -} - -TEST_F(ParagraphTest, TextHeightBehaviorRectsParagraph) { - // clang-format off - const char* text = - "line1\nline2\nline3"; - // 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; - paragraph_style.text_height_behavior = - txt::TextHeightBehavior::kDisableFirstAscent | - txt::TextHeightBehavior::kDisableLastDescent; - - txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); - - txt::TextStyle text_style; - text_style.color = SK_ColorBLACK; - text_style.font_families = std::vector(1, "Roboto"); - text_style.font_size = 30; - text_style.height = 5; - text_style.has_height_override = true; - 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(), 3ull); - - 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); - - // First line. Shorter due to disabled height modifications on first ascent. - 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); - EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 31.117188); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.08203125); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom() - boxes[0].rect.top(), 59.082031); - - // Second line. Normal. - 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(), 0); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 47.011719); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 59); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 209); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom() - boxes[0].rect.top(), 150); - - // Third line. Shorter due to disabled height modifications on last descent - boxes = - paragraph->GetRectsForRange(12, 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(), 1ull); - EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 63.859375); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 208.92578); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 335); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom() - boxes[0].rect.top(), 126.07422); - - ASSERT_TRUE(Snapshot()); -} - -TEST_F(ParagraphTest, MixedTextHeightBehaviorRectsParagraph) { - const char* text = "0123456789"; - auto icu_text = icu::UnicodeString::fromUTF8(text); - std::u16string u16_text(icu_text.getBuffer(), - icu_text.getBuffer() + icu_text.length()); - - txt::ParagraphStyle paragraph_style; - // The paragraph's first line and the last line use the font's ascent/descent. - paragraph_style.text_height_behavior = - txt::TextHeightBehavior::kDisableFirstAscent | - txt::TextHeightBehavior::kDisableLastDescent; - - txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); - - txt::TextStyle text_style; - text_style.color = SK_ColorBLACK; - text_style.font_families = std::vector(1, "Roboto"); - text_style.font_size = 30; - text_style.height = 5; - text_style.has_height_override = true; - text_style.half_leading = true; - - builder.PushStyle(text_style); - builder.AddText(u16_text); - - text_style.half_leading = false; - builder.PushStyle(text_style); - builder.AddText(u16_text); - - // 2 identical runs except the first run has half-leading enabled. - builder.Pop(); - - auto paragraph = BuildParagraph(builder); - paragraph->Layout(GetTestCanvasWidth() - 300); - - 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, 20, rect_height_style, rect_width_style); - - for (size_t i = 0; i < boxes.size(); ++i) { - GetCanvas()->drawRect(boxes[i].rect, paint); - } - // The kDisableAll flag is applied. - EXPECT_GT(boxes.size(), 1ull); - // The height of the line equals to the metrics height of the font - // (ascent + descent). - EXPECT_FLOAT_EQ(boxes[0].rect.bottom() - boxes[0].rect.top(), - 27.8320312 + 7.32421875); - - ASSERT_TRUE(Snapshot()); -} -} // namespace txt diff --git a/third_party/txt/tests/platform_fuchsia_unittests.cc b/third_party/txt/tests/platform_fuchsia_unittests.cc deleted file mode 100644 index 38746670a0acf..0000000000000 --- a/third_party/txt/tests/platform_fuchsia_unittests.cc +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2021 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 -#include - -#include "fake_provider.h" -#include "gtest/gtest.h" -#include "txt/platform.h" - -namespace txt { - -class PlatformFuchsiaTest : public ::testing::Test { - protected: - PlatformFuchsiaTest() : loop_(&kAsyncLoopConfigNoAttachToCurrentThread) { - loop_.StartThread(); - } - - async::Loop& loop() { return loop_; } - - FakeProvider& fake_provider() { return fake_provider_; } - - fidl::InterfaceHandle GetProvider() { - return fake_provider_.Bind(loop_.dispatcher()); - } - - void TearDown() override { - loop_.Quit(); - loop_.JoinThreads(); - } - - private: - async::Loop loop_; // Must come before FIDL bindings. - FakeProvider fake_provider_; -}; - -TEST_F(PlatformFuchsiaTest, GetDefaultFontManager) { - zx_handle_t handle = GetProvider().TakeChannel().release(); - auto font_manager = GetDefaultFontManager(handle); - - // Nonnull font initialization data should not create SkFontMgr::RefDefault(). - EXPECT_NE(font_manager, SkFontMgr::RefDefault()); - - // Check to see that our font provider was called. - EXPECT_FALSE(fake_provider().WasInvoked()); - font_manager->matchFamily("Invalid font."); - EXPECT_TRUE(fake_provider().WasInvoked()); -} - -TEST_F(PlatformFuchsiaTest, GetDefaultFontManagerFail) { - // Null font initialization data should create SkFontMgr::RefDefault(). - EXPECT_EQ(GetDefaultFontManager(0), SkFontMgr::RefDefault()); -} - -} // namespace txt diff --git a/third_party/txt/tests/render_test.cc b/third_party/txt/tests/render_test.cc deleted file mode 100644 index 17730da022e4a..0000000000000 --- a/third_party/txt/tests/render_test.cc +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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 "render_test.h" - -#include - -#include "flutter/fml/logging.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkEncodedImageFormat.h" -#include "third_party/skia/include/core/SkImageEncoder.h" -#include "third_party/skia/include/core/SkStream.h" -#include "txt/asset_font_manager.h" -#include "txt/font_collection.h" -#include "txt_test_utils.h" - -namespace txt { - -RenderTest::RenderTest() - : snapshots_(0), font_collection_(txt::GetTestFontCollection()) {} - -RenderTest::~RenderTest() = default; - -SkCanvas* RenderTest::GetCanvas() { - return canvas_ == nullptr ? nullptr : canvas_.get(); -} - -std::string RenderTest::GetNextSnapshotName() { - const auto& test_info = - ::testing::UnitTest::GetInstance()->current_test_info(); - - std::stringstream stream; - stream << "snapshots/" << test_info->test_case_name() << "_" - << test_info->name(); - stream << "_" << ++snapshots_ << ".png"; - - return stream.str(); -} - -bool RenderTest::Snapshot() { - if (!canvas_ || !bitmap_) { - return false; - } - std::string snapshot_dir = "snapshots"; - int error = 0; -// _WIN32 defined by Windows Visual compiler. -#if defined(_WIN32) - // Handle windows path creation. - error = _mkdir(snapshot_dir.c_str()); -#else - // Handle non-windows path creation with Unix permissions. - mode_t permissions = 0733; - error = mkdir(snapshot_dir.c_str(), permissions); -#endif - if (error > 0) { - FML_LOG(ERROR) << "'snapshot/' Directory not available and could not be " - "created. Please create manually to save snapshot."; - return false; - } - auto file_name = GetNextSnapshotName(); - SkFILEWStream file(file_name.c_str()); - return SkEncodeImage(&file, *bitmap_, SkEncodedImageFormat::kPNG, 100); -} - -size_t RenderTest::GetTestCanvasWidth() const { - return 1000; -} - -size_t RenderTest::GetTestCanvasHeight() const { - return 600; -} - -void RenderTest::SetUp() { - bitmap_ = std::make_unique(); - bitmap_->allocN32Pixels(GetTestCanvasWidth(), GetTestCanvasHeight()); - canvas_ = std::make_unique(*bitmap_); - canvas_->clear(SK_ColorWHITE); -} - -std::shared_ptr RenderTest::GetTestFontCollection() const { - return font_collection_; -} - -void RenderTest::TearDown() { - canvas_ = nullptr; - bitmap_ = nullptr; -} - -} // namespace txt diff --git a/third_party/txt/tests/render_test.h b/third_party/txt/tests/render_test.h deleted file mode 100644 index 104842ab031b8..0000000000000 --- a/third_party/txt/tests/render_test.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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 - -#include "flutter/fml/macros.h" -#include "gtest/gtest.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkCanvas.h" -#include "txt/font_collection.h" - -namespace txt { - -class RenderTest : public ::testing::Test { - public: - RenderTest(); - - ~RenderTest(); - - SkCanvas* GetCanvas(); - - bool Snapshot(); - - size_t GetTestCanvasWidth() const; - - size_t GetTestCanvasHeight() const; - - std::shared_ptr GetTestFontCollection() const; - - protected: - void SetUp() override; - - void TearDown() override; - - private: - size_t snapshots_; - std::unique_ptr bitmap_; - std::unique_ptr canvas_; - std::shared_ptr font_collection_; - - std::string GetNextSnapshotName(); - - FML_DISALLOW_COPY_AND_ASSIGN(RenderTest); -}; - -} // namespace txt diff --git a/third_party/txt/tests/txt_run_all_unittests.cc b/third_party/txt/tests/txt_run_all_unittests.cc index f0d2bcf54f6ce..bc1629fe42ba9 100644 --- a/third_party/txt/tests/txt_run_all_unittests.cc +++ b/third_party/txt/tests/txt_run_all_unittests.cc @@ -14,34 +14,14 @@ * limitations under the License. */ -#include - #include "flutter/fml/backtrace.h" #include "flutter/fml/command_line.h" -#include "flutter/fml/icu_util.h" #include "flutter/fml/logging.h" #include "flutter/testing/testing.h" -#include "third_party/skia/include/core/SkGraphics.h" -#include "txt_test_utils.h" int main(int argc, char** argv) { fml::InstallCrashHandler(); fml::CommandLine cmd = fml::CommandLineFromPlatformOrArgcArgv(argc, argv); - txt::SetCommandLine(cmd); - txt::SetFontDir(flutter::testing::GetFixturesPath()); - if (txt::GetFontDir().length() <= 0) { - FML_LOG(ERROR) << "Font directory not set via txt::SetFontDir."; - return EXIT_FAILURE; - } - FML_DCHECK(txt::GetFontDir().length() > 0); -#if defined(OS_FUCHSIA) - fml::icu::InitializeICU("/pkg/data/icudtl.dat"); -#else - std::string icudtl_path = - cmd.GetOptionValueWithDefault("icu-data-file-path", "icudtl.dat"); - fml::icu::InitializeICU(icudtl_path); -#endif - SkGraphics::Init(); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/third_party/txt/tests/txt_test_utils.cc b/third_party/txt/tests/txt_test_utils.cc index 2382fd59e1430..62bae34f39a88 100644 --- a/third_party/txt/tests/txt_test_utils.cc +++ b/third_party/txt/tests/txt_test_utils.cc @@ -16,22 +16,9 @@ #include "txt_test_utils.h" -#include - -#include "third_party/skia/include/core/SkTypeface.h" -#include "txt/asset_font_manager.h" -#include "txt/typeface_font_asset_provider.h" -#include "utils/MacUtils.h" -#include "utils/WindowsUtils.h" - -#if !defined(_WIN32) -#include -#endif - namespace txt { static std::string gFontDir; -static fml::CommandLine gCommandLine; const std::string& GetFontDir() { return gFontDir; @@ -41,90 +28,4 @@ void SetFontDir(const std::string& dir) { gFontDir = dir; } -const fml::CommandLine& GetCommandLineForProcess() { - return gCommandLine; -} - -void SetCommandLine(fml::CommandLine cmd) { - gCommandLine = std::move(cmd); -} - -void RegisterFontsFromPath(TypefaceFontAssetProvider& font_provider, - std::string directory_path) { -#if defined(_WIN32) - std::string path = directory_path + "\\*"; - WIN32_FIND_DATAA ffd; - HANDLE directory = FindFirstFileA(path.c_str(), &ffd); - if (directory == INVALID_HANDLE_VALUE) { - return; - } - - do { - if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { - continue; - } - - std::string file_name(ffd.cFileName); - - std::stringstream file_path; - file_path << directory_path << "/" << file_name; - - font_provider.RegisterTypeface( - SkTypeface::MakeFromFile(file_path.str().c_str())); - } while (FindNextFileA(directory, &ffd) != 0); - - // TODO(bkonyi): check for error here? - FindClose(directory); -#else - auto directory_closer = [](DIR* directory) { - if (directory != nullptr) { - ::closedir(directory); - } - }; - - std::unique_ptr directory( - ::opendir(directory_path.c_str()), directory_closer); - - if (directory == nullptr) { - return; - } - - for (struct dirent* entry = ::readdir(directory.get()); entry != nullptr; - entry = ::readdir(directory.get())) { - if (entry->d_type != DT_REG) { - continue; - } - - std::string file_name(entry->d_name); - - std::stringstream file_path; - file_path << directory_path << "/" << file_name; - - font_provider.RegisterTypeface( - SkTypeface::MakeFromFile(file_path.str().c_str())); - } -#endif -} - -std::shared_ptr GetTestFontCollection() { - std::unique_ptr font_provider = - std::make_unique(); - RegisterFontsFromPath(*font_provider, GetFontDir()); - - std::shared_ptr collection = - std::make_shared(); - collection->SetAssetFontManager( - sk_make_sp(std::move(font_provider))); - - return collection; -} - -// Build a paragraph and return it as a ParagraphTxt usable by tests that need -// access to ParagraphTxt internals. -std::unique_ptr BuildParagraph( - txt::ParagraphBuilderTxt& builder) { - return std::unique_ptr( - static_cast(builder.Build().release())); -} - } // namespace txt diff --git a/third_party/txt/tests/txt_test_utils.h b/third_party/txt/tests/txt_test_utils.h index 096f8f630a5ce..897020fa054cf 100644 --- a/third_party/txt/tests/txt_test_utils.h +++ b/third_party/txt/tests/txt_test_utils.h @@ -16,23 +16,10 @@ #include -#include "flutter/fml/command_line.h" -#include "txt/font_collection.h" -#include "txt/paragraph_builder_txt.h" -#include "txt/paragraph_txt.h" - namespace txt { const std::string& GetFontDir(); void SetFontDir(const std::string& dir); -const fml::CommandLine& GetCommandLineForProcess(); - -void SetCommandLine(fml::CommandLine cmd); - -std::shared_ptr GetTestFontCollection(); - -std::unique_ptr BuildParagraph(ParagraphBuilderTxt& builder); - } // namespace txt diff --git a/third_party/txt/third_party/fonts/Bold.ttf b/third_party/txt/third_party/fonts/Bold.ttf deleted file mode 100644 index 44ef33cf89e6e..0000000000000 Binary files a/third_party/txt/third_party/fonts/Bold.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Bold.ttx b/third_party/txt/third_party/fonts/Bold.ttx deleted file mode 100644 index a595ea58b66c6..0000000000000 --- a/third_party/txt/third_party/fonts/Bold.ttx +++ /dev/null @@ -1,254 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BoldFont Test - - - Bold - - - BoldFont Test - - - BoldFontTest-Bold - - - BoldFont Test - - - Bold - - - BoldFont Test - - - BoldFontTest-Bold - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/BoldItalic.ttf b/third_party/txt/third_party/fonts/BoldItalic.ttf deleted file mode 100644 index 10c7b02b955c0..0000000000000 Binary files a/third_party/txt/third_party/fonts/BoldItalic.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/BoldItalic.ttx b/third_party/txt/third_party/fonts/BoldItalic.ttx deleted file mode 100644 index 5de79fcb7f162..0000000000000 --- a/third_party/txt/third_party/fonts/BoldItalic.ttx +++ /dev/null @@ -1,254 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BoldItalicFont Test - - - BoldItalic - - - BoldItalicFont Test - - - BoldItalicFontTest-BoldItalic - - - BoldItalicFont Test - - - BoldItalic - - - BoldItalicFont Test - - - BoldItalicFontTest-BoldItalic - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/ColorEmojiFont.ttf b/third_party/txt/third_party/fonts/ColorEmojiFont.ttf deleted file mode 100644 index eee1c379f0314..0000000000000 Binary files a/third_party/txt/third_party/fonts/ColorEmojiFont.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/ColorEmojiFont.ttx b/third_party/txt/third_party/fonts/ColorEmojiFont.ttx deleted file mode 100644 index 5e16574d87dc9..0000000000000 --- a/third_party/txt/third_party/fonts/ColorEmojiFont.ttx +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ColorEmojiFont Test - - - Regular - - - ColorEmojiFont Test - - - ColorEmojiFontTest-Regular - - - ColorEmojiFont Test - - - Regular - - - ColorEmojiFont Test - - - ColorEmojiFontTest-Regular - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/ColorTextMixedEmojiFont.ttf b/third_party/txt/third_party/fonts/ColorTextMixedEmojiFont.ttf deleted file mode 100644 index 57ee330b79f66..0000000000000 Binary files a/third_party/txt/third_party/fonts/ColorTextMixedEmojiFont.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/ColorTextMixedEmojiFont.ttx b/third_party/txt/third_party/fonts/ColorTextMixedEmojiFont.ttx deleted file mode 100644 index 461210bfd882d..0000000000000 --- a/third_party/txt/third_party/fonts/ColorTextMixedEmojiFont.ttx +++ /dev/null @@ -1,212 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ColorTextMixedEmojiFont Test - - - Regular - - - ColorTextMixedEmojiFont Test - - - ColorTextMixedEmojiFontTest-Regular - - - ColorTextMixedEmojiFont Test - - - Regular - - - ColorTextMixedEmojiFont Test - - - ColorTextMixedEmojiFontTest-Regular - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/DroidSerif.ttf b/third_party/txt/third_party/fonts/DroidSerif.ttf deleted file mode 100644 index 90cdfffe540c8..0000000000000 Binary files a/third_party/txt/third_party/fonts/DroidSerif.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Emoji.ttf b/third_party/txt/third_party/fonts/Emoji.ttf deleted file mode 100644 index a3413b3e08f96..0000000000000 Binary files a/third_party/txt/third_party/fonts/Emoji.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Emoji.ttx b/third_party/txt/third_party/fonts/Emoji.ttx deleted file mode 100644 index 3318c594ae1ed..0000000000000 --- a/third_party/txt/third_party/fonts/Emoji.ttx +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EmojiFont Test - - - Regular - - - EmojiFont Test - - - EmojiFontTest-Regular - - - EmojiFont Test - - - Regular - - - EmojiFont Test - - - EmojiFontTest-Regular - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/HomemadeApple-LICENSE.txt b/third_party/txt/third_party/fonts/HomemadeApple-LICENSE.txt deleted file mode 100644 index d645695673349..0000000000000 --- a/third_party/txt/third_party/fonts/HomemadeApple-LICENSE.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/third_party/txt/third_party/fonts/Italic.ttf b/third_party/txt/third_party/fonts/Italic.ttf deleted file mode 100644 index 9593229f925d5..0000000000000 Binary files a/third_party/txt/third_party/fonts/Italic.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Italic.ttx b/third_party/txt/third_party/fonts/Italic.ttx deleted file mode 100644 index 1853bb6b2681f..0000000000000 --- a/third_party/txt/third_party/fonts/Italic.ttx +++ /dev/null @@ -1,254 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ItalicFont Test - - - Italic - - - ItalicFont Test - - - ItalicFontTest-Italic - - - ItalicFont Test - - - Italic - - - ItalicFont Test - - - ItalicFontTest-Italic - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/Ja.ttf b/third_party/txt/third_party/fonts/Ja.ttf deleted file mode 100644 index b3d4e848ecf02..0000000000000 Binary files a/third_party/txt/third_party/fonts/Ja.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Ja.ttx b/third_party/txt/third_party/fonts/Ja.ttx deleted file mode 100644 index 562ff04ca5bee..0000000000000 --- a/third_party/txt/third_party/fonts/Ja.ttx +++ /dev/null @@ -1,306 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - JapaneseFont Test - - - Regular - - - JapaneseFont Test - - - JapaneseFontTest-Regular - - - JapaneseFont Test - - - Regular - - - JapaneseFont Test - - - JapaneseFontTest-Regular - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/Katibeh-LICENSE.txt b/third_party/txt/third_party/fonts/Katibeh-LICENSE.txt deleted file mode 100644 index b66a0c31aab4b..0000000000000 --- a/third_party/txt/third_party/fonts/Katibeh-LICENSE.txt +++ /dev/null @@ -1,92 +0,0 @@ -Copyright 2015, 2016 KB-Studio (www.k-b-studio.com|tarobish@gmail.com). Copyright 2015, 2016 Lasse Fister (lasse@graphicore.de). Copyright 2015, 2016 Eduardo Tunni(edu@tipo.net.ar). -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/third_party/txt/third_party/fonts/Katibeh-Regular.ttf b/third_party/txt/third_party/fonts/Katibeh-Regular.ttf deleted file mode 100644 index ccbb8f0de2ad5..0000000000000 Binary files a/third_party/txt/third_party/fonts/Katibeh-Regular.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Ko.ttf b/third_party/txt/third_party/fonts/Ko.ttf deleted file mode 100644 index 51f6c4ede8b4d..0000000000000 Binary files a/third_party/txt/third_party/fonts/Ko.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Ko.ttx b/third_party/txt/third_party/fonts/Ko.ttx deleted file mode 100644 index 06f12ecf54b53..0000000000000 --- a/third_party/txt/third_party/fonts/Ko.ttx +++ /dev/null @@ -1,224 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - KoreanFont Test - - - Regular - - - KoreanFont Test - - - KoreanFontTest-Regular - - - KoreanFont Test - - - Regular - - - KoreanFont Test - - - KoreanFontTest-Regular - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/MultiAxis.ttf b/third_party/txt/third_party/fonts/MultiAxis.ttf deleted file mode 100644 index 1d687cb367d74..0000000000000 Binary files a/third_party/txt/third_party/fonts/MultiAxis.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/MultiAxis.ttx b/third_party/txt/third_party/fonts/MultiAxis.ttx deleted file mode 100644 index 7c17198c5c805..0000000000000 --- a/third_party/txt/third_party/fonts/MultiAxis.ttx +++ /dev/null @@ -1,223 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - wdth - -1.0 - 0.0 - 1.0 - 256 - - - wght - -1.0 - 0.0 - 1.0 - 256 - - - - - - MultiAxisFont Test - - - MultiAxis - - - MultiAxisFont Test - - - MultiAxisFontTest-Regular - - - MultiAxisFont Test - - - MultiAxis - - - MultiAxisFont Test - - - MultiAxisFontTest-Regular - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/NoCmapFormat14.ttf b/third_party/txt/third_party/fonts/NoCmapFormat14.ttf deleted file mode 100644 index 2a0c46c7aca19..0000000000000 Binary files a/third_party/txt/third_party/fonts/NoCmapFormat14.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/NoCmapFormat14.ttx b/third_party/txt/third_party/fonts/NoCmapFormat14.ttx deleted file mode 100644 index e034f77d32a8f..0000000000000 --- a/third_party/txt/third_party/fonts/NoCmapFormat14.ttx +++ /dev/null @@ -1,207 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - No Cmap Format 14 Subtable Test - - - Regular - - - No Cmap Format 14 Subtable Test - - - No Cmap Format 14 SubtableTest-Regular - - - No Cmap Format 14 Subtable Test - - - Regular - - - No Cmap Format 14 Subtable Test - - - No Cmap Format 14 SubtableTest-Regular - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/NoGlyphFont.ttf b/third_party/txt/third_party/fonts/NoGlyphFont.ttf deleted file mode 100644 index 0243f820408af..0000000000000 Binary files a/third_party/txt/third_party/fonts/NoGlyphFont.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/NoGlyphFont.ttx b/third_party/txt/third_party/fonts/NoGlyphFont.ttx deleted file mode 100644 index 72c9f292f05ee..0000000000000 --- a/third_party/txt/third_party/fonts/NoGlyphFont.ttx +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EmptyFont Test - - - Regular - - - EmptyFont Test - - - EmptyFontTest-Regular - - - EmptyFont Test - - - Regular - - - EmptyFont Test - - - EmptyFontTest-Regular - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/NotoColorEmoji-LICENSE.txt b/third_party/txt/third_party/fonts/NotoColorEmoji-LICENSE.txt deleted file mode 100644 index 88cbb72152efe..0000000000000 --- a/third_party/txt/third_party/fonts/NotoColorEmoji-LICENSE.txt +++ /dev/null @@ -1,93 +0,0 @@ - -This Font Software is licensed under the SIL Open Font License, -Version 1.1. - -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font -creation efforts of academic and linguistic communities, and to -provide a free and open framework in which fonts may be shared and -improved in partnership with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply to -any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software -components as distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, -deleting, or substituting -- in part or in whole -- any of the -components of the Original Version, by changing formats or by porting -the Font Software to a new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, -modify, redistribute, and sell modified and unmodified copies of the -Font Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, in -Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the -corresponding Copyright Holder. This restriction only applies to the -primary font name as presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created using -the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file diff --git a/third_party/txt/third_party/fonts/NotoNaskhArabic-LICENSE.txt b/third_party/txt/third_party/fonts/NotoNaskhArabic-LICENSE.txt deleted file mode 100644 index d952d62c065f3..0000000000000 --- a/third_party/txt/third_party/fonts/NotoNaskhArabic-LICENSE.txt +++ /dev/null @@ -1,92 +0,0 @@ -This Font Software is licensed under the SIL Open Font License, -Version 1.1. - -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font -creation efforts of academic and linguistic communities, and to -provide a free and open framework in which fonts may be shared and -improved in partnership with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply to -any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software -components as distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, -deleting, or substituting -- in part or in whole -- any of the -components of the Original Version, by changing formats or by porting -the Font Software to a new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, -modify, redistribute, and sell modified and unmodified copies of the -Font Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, in -Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the -corresponding Copyright Holder. This restriction only applies to the -primary font name as presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created using -the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/third_party/txt/third_party/fonts/NotoSansCJK-Regular.ttc b/third_party/txt/third_party/fonts/NotoSansCJK-Regular.ttc deleted file mode 100755 index 2dd4a60625dbf..0000000000000 Binary files a/third_party/txt/third_party/fonts/NotoSansCJK-Regular.ttc and /dev/null differ diff --git a/third_party/txt/third_party/fonts/NotoSansKhmer-Regular.ttf b/third_party/txt/third_party/fonts/NotoSansKhmer-Regular.ttf deleted file mode 100644 index 9aaea35610f1f..0000000000000 Binary files a/third_party/txt/third_party/fonts/NotoSansKhmer-Regular.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Regular.ttf b/third_party/txt/third_party/fonts/Regular.ttf deleted file mode 100644 index ab638f58de03b..0000000000000 Binary files a/third_party/txt/third_party/fonts/Regular.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Regular.ttx b/third_party/txt/third_party/fonts/Regular.ttx deleted file mode 100644 index a5f3ebac2653e..0000000000000 --- a/third_party/txt/third_party/fonts/Regular.ttx +++ /dev/null @@ -1,263 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RegularFont Test - - - Regular - - - RegularFont Test - - - RegularFontTest-Regular - - - RegularFont Test - - - Regular - - - RegularFont Test - - - RegularFontTest-Regular - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/Roboto-Black.ttf b/third_party/txt/third_party/fonts/Roboto-Black.ttf deleted file mode 100644 index 689fe5cb3c715..0000000000000 Binary files a/third_party/txt/third_party/fonts/Roboto-Black.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Roboto-BlackItalic.ttf b/third_party/txt/third_party/fonts/Roboto-BlackItalic.ttf deleted file mode 100644 index 0b4e0ee108899..0000000000000 Binary files a/third_party/txt/third_party/fonts/Roboto-BlackItalic.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Roboto-Bold.ttf b/third_party/txt/third_party/fonts/Roboto-Bold.ttf deleted file mode 100644 index d3f01ad245b62..0000000000000 Binary files a/third_party/txt/third_party/fonts/Roboto-Bold.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Roboto-BoldItalic.ttf b/third_party/txt/third_party/fonts/Roboto-BoldItalic.ttf deleted file mode 100644 index 41cc1e753153e..0000000000000 Binary files a/third_party/txt/third_party/fonts/Roboto-BoldItalic.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Roboto-Italic.ttf b/third_party/txt/third_party/fonts/Roboto-Italic.ttf deleted file mode 100644 index 6a1cee5b2948d..0000000000000 Binary files a/third_party/txt/third_party/fonts/Roboto-Italic.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Roboto-Light.ttf b/third_party/txt/third_party/fonts/Roboto-Light.ttf deleted file mode 100644 index 219063a578a48..0000000000000 Binary files a/third_party/txt/third_party/fonts/Roboto-Light.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Roboto-LightItalic.ttf b/third_party/txt/third_party/fonts/Roboto-LightItalic.ttf deleted file mode 100644 index 0e81e876fcab8..0000000000000 Binary files a/third_party/txt/third_party/fonts/Roboto-LightItalic.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Roboto-MediumItalic.ttf b/third_party/txt/third_party/fonts/Roboto-MediumItalic.ttf deleted file mode 100644 index 003029527cc65..0000000000000 Binary files a/third_party/txt/third_party/fonts/Roboto-MediumItalic.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Roboto-Thin.ttf b/third_party/txt/third_party/fonts/Roboto-Thin.ttf deleted file mode 100644 index b74a4fd1a2ed1..0000000000000 Binary files a/third_party/txt/third_party/fonts/Roboto-Thin.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/Roboto-ThinItalic.ttf b/third_party/txt/third_party/fonts/Roboto-ThinItalic.ttf deleted file mode 100644 index dd0ddb852645d..0000000000000 Binary files a/third_party/txt/third_party/fonts/Roboto-ThinItalic.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/SourceHanSerif-LICENSE.txt b/third_party/txt/third_party/fonts/SourceHanSerif-LICENSE.txt deleted file mode 100644 index d952d62c065f3..0000000000000 --- a/third_party/txt/third_party/fonts/SourceHanSerif-LICENSE.txt +++ /dev/null @@ -1,92 +0,0 @@ -This Font Software is licensed under the SIL Open Font License, -Version 1.1. - -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font -creation efforts of academic and linguistic communities, and to -provide a free and open framework in which fonts may be shared and -improved in partnership with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply to -any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software -components as distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, -deleting, or substituting -- in part or in whole -- any of the -components of the Original Version, by changing formats or by porting -the Font Software to a new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, -modify, redistribute, and sell modified and unmodified copies of the -Font Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, in -Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the -corresponding Copyright Holder. This restriction only applies to the -primary font name as presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created using -the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/third_party/txt/third_party/fonts/SourceHanSerifCN-Bold.otf b/third_party/txt/third_party/fonts/SourceHanSerifCN-Bold.otf deleted file mode 100644 index 77656b1999c62..0000000000000 Binary files a/third_party/txt/third_party/fonts/SourceHanSerifCN-Bold.otf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/SourceHanSerifCN-Regular.otf b/third_party/txt/third_party/fonts/SourceHanSerifCN-Regular.otf deleted file mode 100644 index c5930e7d2774c..0000000000000 Binary files a/third_party/txt/third_party/fonts/SourceHanSerifCN-Regular.otf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/TextEmojiFont.ttf b/third_party/txt/third_party/fonts/TextEmojiFont.ttf deleted file mode 100644 index 6a5e9d94ec165..0000000000000 Binary files a/third_party/txt/third_party/fonts/TextEmojiFont.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/TextEmojiFont.ttx b/third_party/txt/third_party/fonts/TextEmojiFont.ttx deleted file mode 100644 index eb49422cd0aff..0000000000000 --- a/third_party/txt/third_party/fonts/TextEmojiFont.ttx +++ /dev/null @@ -1,239 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TextEmojiFont Test - - - Regular - - - TextEmojiFont Test - - - TextEmojiFontTest-Regular - - - TextEmojiFont Test - - - Regular - - - TextEmojiFont Test - - - TextEmojiFontTest-Regular - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/UnicodeBMPOnly.ttf b/third_party/txt/third_party/fonts/UnicodeBMPOnly.ttf deleted file mode 100644 index 8196669fa18c5..0000000000000 Binary files a/third_party/txt/third_party/fonts/UnicodeBMPOnly.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/UnicodeBMPOnly.ttx b/third_party/txt/third_party/fonts/UnicodeBMPOnly.ttx deleted file mode 100644 index b50a3f027c4f0..0000000000000 --- a/third_party/txt/third_party/fonts/UnicodeBMPOnly.ttx +++ /dev/null @@ -1,177 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Sample Font - - - Regular - - - Sample Font - - - SampleFont-Regular - - - Sample Font - - - Regular - - - Sample Font - - - SampleFont-Regular - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/UnicodeBMPOnly2.ttf b/third_party/txt/third_party/fonts/UnicodeBMPOnly2.ttf deleted file mode 100644 index c14b195005499..0000000000000 Binary files a/third_party/txt/third_party/fonts/UnicodeBMPOnly2.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/UnicodeBMPOnly2.ttx b/third_party/txt/third_party/fonts/UnicodeBMPOnly2.ttx deleted file mode 100644 index e43ebf80144f0..0000000000000 --- a/third_party/txt/third_party/fonts/UnicodeBMPOnly2.ttx +++ /dev/null @@ -1,177 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Sample Font - - - Regular - - - Sample Font - - - SampleFont-Regular - - - Sample Font - - - Regular - - - Sample Font - - - SampleFont-Regular - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/UnicodeUCS4.ttf b/third_party/txt/third_party/fonts/UnicodeUCS4.ttf deleted file mode 100644 index 354e1a370f4bf..0000000000000 Binary files a/third_party/txt/third_party/fonts/UnicodeUCS4.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/UnicodeUCS4.ttx b/third_party/txt/third_party/fonts/UnicodeUCS4.ttx deleted file mode 100644 index da5575d5b061f..0000000000000 --- a/third_party/txt/third_party/fonts/UnicodeUCS4.ttx +++ /dev/null @@ -1,181 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Sample Font - - - Regular - - - Sample Font - - - SampleFont-Regular - - - Sample Font - - - Regular - - - Sample Font - - - SampleFont-Regular - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/VariationSelectorTest-Regular.ttf b/third_party/txt/third_party/fonts/VariationSelectorTest-Regular.ttf deleted file mode 100644 index 0504c67fb7a64..0000000000000 Binary files a/third_party/txt/third_party/fonts/VariationSelectorTest-Regular.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/VariationSelectorTest-Regular.ttx b/third_party/txt/third_party/fonts/VariationSelectorTest-Regular.ttx deleted file mode 100644 index f86f008b08144..0000000000000 --- a/third_party/txt/third_party/fonts/VariationSelectorTest-Regular.ttx +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VariationSelector Test - - - Regular - - - VariationSelector Test - - - VariationSelectorTest-Regular - - - VariationSelector Test - - - Regular - - - VariationSelector Test - - - VariationSelectorTest-Regular - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/ZhHans.ttf b/third_party/txt/third_party/fonts/ZhHans.ttf deleted file mode 100644 index 08adc1b300f80..0000000000000 Binary files a/third_party/txt/third_party/fonts/ZhHans.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/ZhHans.ttx b/third_party/txt/third_party/fonts/ZhHans.ttx deleted file mode 100644 index 238bd5e6d006e..0000000000000 --- a/third_party/txt/third_party/fonts/ZhHans.ttx +++ /dev/null @@ -1,282 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SimplifiedChinese Test - - - Regular - - - SimplifiedChinese Test - - - SimplifiedChineseTest-Regular - - - SimplifiedChinese Test - - - Regular - - - SimplifiedChinese Test - - - SimplifiedChineseTest-Regular - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/ZhHant.ttf b/third_party/txt/third_party/fonts/ZhHant.ttf deleted file mode 100644 index 592117d5a782f..0000000000000 Binary files a/third_party/txt/third_party/fonts/ZhHant.ttf and /dev/null differ diff --git a/third_party/txt/third_party/fonts/ZhHant.ttx b/third_party/txt/third_party/fonts/ZhHant.ttx deleted file mode 100644 index 31fada959779a..0000000000000 --- a/third_party/txt/third_party/fonts/ZhHant.ttx +++ /dev/null @@ -1,240 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TraditionalChinese Test - - - Regular - - - TraditionalChinese Test - - - TraditionalChineseTest-Regular - - - TraditionalChinese Test - - - Regular - - - TraditionalChinese Test - - - TraditionalChineseTest-Regular - - - - - - - - - - - - - - - - diff --git a/third_party/txt/third_party/fonts/emoji.xml b/third_party/txt/third_party/fonts/emoji.xml deleted file mode 100644 index 796a0f1ea0383..0000000000000 --- a/third_party/txt/third_party/fonts/emoji.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - NoGlyphFont.ttf - - - TextEmojiFont.ttf - - - ColorEmojiFont.ttf - - - ColorTextMixedEmojiFont.ttf - - diff --git a/third_party/txt/third_party/fonts/itemize.xml b/third_party/txt/third_party/fonts/itemize.xml deleted file mode 100644 index 32a5ab02b711c..0000000000000 --- a/third_party/txt/third_party/fonts/itemize.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - Regular.ttf - Italic.ttf - Bold.ttf - BoldItalic.ttf - - - - ZhHans.ttf - - - Ja.ttf - - - ZhHant.ttf - - - Ko.ttf - - - Emoji.ttf - - diff --git a/tools/gn b/tools/gn index 9215fd6d835c3..8a37d176b5061 100755 --- a/tools/gn +++ b/tools/gn @@ -282,10 +282,7 @@ def to_gn_args(args): gn_args['skia_use_fontconfig'] = args.enable_fontconfig gn_args['skia_use_legacy_layer_bounds' ] = True # Temporary: See skbug.com/12083, skbug.com/12303. - - if args.enable_skshaper: - gn_args['skia_use_icu'] = True - gn_args['flutter_always_use_skshaper'] = args.always_use_skshaper + gn_args['skia_use_icu'] = True gn_args['is_official_build'] = True # Disable Skia test utilities. gn_args['android_full_debug' ] = args.target_os == 'android' and args.unoptimized @@ -371,7 +368,6 @@ def to_gn_args(args): gn_args['dart_debug_optimization_level'] = '0' gn_args['flutter_use_fontconfig'] = args.enable_fontconfig - gn_args['flutter_enable_skshaper'] = args.enable_skshaper gn_args['dart_component_kind' ] = 'static_library' # Always link Dart in statically. gn_args['embedder_for_target'] = args.embedder_for_target @@ -829,14 +825,6 @@ def parse_args(args): '--enable-vulkan-validation-layers', action='store_true', default=False ) - parser.add_argument('--enable-skshaper', action='store_true', default=True) - parser.add_argument( - '--no-enable-skshaper', dest='enable_skshaper', action='store_false' - ) - parser.add_argument( - '--always-use-skshaper', action='store_true', default=False - ) - parser.add_argument( '--embedder-for-target', dest='embedder_for_target',