├── tests ├── data │ ├── Ja.ttf │ ├── Ko.ttf │ ├── Arabic.ttf │ ├── Ascii.ttf │ ├── Bold.ttf │ ├── Emoji.ttf │ ├── Italic.ttf │ ├── ZhHans.ttf │ ├── ZhHant.ttf │ ├── Cherokee.ttf │ ├── Hiragana.ttf │ ├── Ligature.ttf │ ├── Regular.ttf │ ├── BoldItalic.ttf │ ├── MultiAxis.ttf │ ├── NoGlyphFont.ttf │ ├── UnicodeUCS4.ttf │ ├── CustomExtent.ttf │ ├── TextEmojiFont.ttf │ ├── ColorEmojiFont.ttf │ ├── LayoutTestFont.ttf │ ├── NoCmapFormat14.ttf │ ├── UnicodeBMPOnly.ttf │ ├── UnicodeBMPOnly2.ttf │ ├── ColorTextMixedEmojiFont.ttf │ ├── VariationSelectorTest-Regular.ttf │ ├── emoji.xml │ └── itemize.xml ├── unittest │ ├── how_to_run.txt │ ├── TestMain.cpp │ ├── UnicodeUtilsTest.cpp │ ├── AndroidTest.xml │ ├── HasherTest.cpp │ ├── FontTest.cpp │ ├── SparseBitSetTest.cpp │ ├── AndroidLineBreakerHelperTest.cpp │ ├── ICUEnvironment.h │ ├── LocaleListTest.cpp │ ├── MeasurementTests.cpp │ ├── SystemFontsTest.cpp │ ├── Android.bp │ ├── FontLanguageListCacheTest.cpp │ ├── FontUtilsTest.cpp │ └── EmojiTest.cpp ├── stresstest │ ├── how_to_run.txt │ ├── Android.bp │ ├── FontFamilyTest.cpp │ └── MultithreadTest.cpp ├── perftests │ ├── how_to_run.txt │ ├── AndroidTest.xml │ ├── Android.bp │ ├── FontLanguage.cpp │ ├── WordBreaker.cpp │ ├── main.cpp │ ├── Hyphenator.cpp │ ├── GraphemeBreak.cpp │ └── FontCollection.cpp ├── util │ ├── Android.bp │ ├── FileUtils.h │ ├── PathUtils.h │ ├── FileUtils.cpp │ ├── UnicodeUtils.h │ ├── PathUtils.cpp │ ├── FreeTypeMinikinFontForTest.h │ ├── FontTestUtils.h │ └── FreeTypeMinikinFontForTest.cpp └── Android.bp ├── PREUPLOAD.cfg ├── .clang-format ├── Android.bp ├── include └── minikin │ ├── IcuUtils.h │ ├── FontVariation.h │ ├── LocaleList.h │ ├── Emoji.h │ ├── CmapCoverage.h │ ├── Measurement.h │ ├── FamilyVariant.h │ ├── Characters.h │ ├── MinikinExtent.h │ ├── GraphemeBreak.h │ ├── HbUtils.h │ ├── FontStyle.h │ ├── U16StringPiece.h │ ├── MinikinRect.h │ ├── Hasher.h │ ├── Macros.h │ ├── SystemFonts.h │ ├── MinikinFont.h │ ├── FontFamily.h │ ├── LayoutCore.h │ ├── SparseBitSet.h │ ├── MinikinPaint.h │ ├── LineBreaker.h │ ├── LayoutPieces.h │ ├── AndroidLineBreakerHelper.h │ ├── Font.h │ └── Range.h ├── libs └── minikin │ ├── FontUtils.h │ ├── OptimalLineBreaker.h │ ├── GreedyLineBreaker.h │ ├── SystemFonts.cpp │ ├── LineBreaker.cpp │ ├── MinikinInternal.cpp │ ├── LayoutUtils.h │ ├── LocaleListCache.h │ ├── LineBreakerUtil.cpp │ ├── MinikinInternal.h │ ├── BidiUtils.h │ ├── Android.bp │ ├── Emoji.cpp │ ├── FontUtils.cpp │ ├── LayoutUtils.cpp │ ├── HyphenatorMap.h │ ├── StringPiece.h │ ├── BidiUtils.cpp │ ├── Measurement.cpp │ └── HyphenatorMap.cpp ├── app ├── Android.bp └── HyphTool.cpp └── doc └── minikin_style.md /tests/data/Ja.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/Ja.ttf -------------------------------------------------------------------------------- /tests/data/Ko.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/Ko.ttf -------------------------------------------------------------------------------- /tests/data/Arabic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/Arabic.ttf -------------------------------------------------------------------------------- /tests/data/Ascii.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/Ascii.ttf -------------------------------------------------------------------------------- /tests/data/Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/Bold.ttf -------------------------------------------------------------------------------- /tests/data/Emoji.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/Emoji.ttf -------------------------------------------------------------------------------- /tests/data/Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/Italic.ttf -------------------------------------------------------------------------------- /tests/data/ZhHans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/ZhHans.ttf -------------------------------------------------------------------------------- /tests/data/ZhHant.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/ZhHant.ttf -------------------------------------------------------------------------------- /tests/data/Cherokee.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/Cherokee.ttf -------------------------------------------------------------------------------- /tests/data/Hiragana.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/Hiragana.ttf -------------------------------------------------------------------------------- /tests/data/Ligature.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/Ligature.ttf -------------------------------------------------------------------------------- /tests/data/Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/Regular.ttf -------------------------------------------------------------------------------- /tests/data/BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/BoldItalic.ttf -------------------------------------------------------------------------------- /tests/data/MultiAxis.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/MultiAxis.ttf -------------------------------------------------------------------------------- /tests/data/NoGlyphFont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/NoGlyphFont.ttf -------------------------------------------------------------------------------- /tests/data/UnicodeUCS4.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/UnicodeUCS4.ttf -------------------------------------------------------------------------------- /tests/data/CustomExtent.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/CustomExtent.ttf -------------------------------------------------------------------------------- /tests/data/TextEmojiFont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/TextEmojiFont.ttf -------------------------------------------------------------------------------- /tests/data/ColorEmojiFont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/ColorEmojiFont.ttf -------------------------------------------------------------------------------- /tests/data/LayoutTestFont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/LayoutTestFont.ttf -------------------------------------------------------------------------------- /tests/data/NoCmapFormat14.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/NoCmapFormat14.ttf -------------------------------------------------------------------------------- /tests/data/UnicodeBMPOnly.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/UnicodeBMPOnly.ttf -------------------------------------------------------------------------------- /tests/data/UnicodeBMPOnly2.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/UnicodeBMPOnly2.ttf -------------------------------------------------------------------------------- /tests/data/ColorTextMixedEmojiFont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/ColorTextMixedEmojiFont.ttf -------------------------------------------------------------------------------- /tests/unittest/how_to_run.txt: -------------------------------------------------------------------------------- 1 | mmm -j frameworks/minikin/tests/unittest && 2 | adb sync data && 3 | adb shell /data/nativetest/minikin_tests/minikin_tests 4 | -------------------------------------------------------------------------------- /tests/data/VariationSelectorTest-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_frameworks_minikin/arrow-10.0/tests/data/VariationSelectorTest-Regular.ttf -------------------------------------------------------------------------------- /tests/stresstest/how_to_run.txt: -------------------------------------------------------------------------------- 1 | mmm -j frameworks/minikin/tests/stresstest && 2 | adb sync data && 3 | adb shell /data/nativetest/minikin_tests/minikin_stress_tests 4 | -------------------------------------------------------------------------------- /PREUPLOAD.cfg: -------------------------------------------------------------------------------- 1 | [Builtin Hooks] 2 | clang_format = true 3 | 4 | [Builtin Hooks Options] 5 | clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions h,cpp 6 | -------------------------------------------------------------------------------- /tests/perftests/how_to_run.txt: -------------------------------------------------------------------------------- 1 | mmm -j frameworks/minikin/tests/perftests && 2 | adb sync data && 3 | adb shell /data/benchmarktest/minikin_perftests/minikin_perftests 4 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | DerivePointerAlignment: false 3 | IndentWidth: 4 4 | ConstructorInitializerIndentWidth: 8 5 | ContinuationIndentWidth: 8 6 | ColumnLimit: 100 7 | AllowShortFunctionsOnASingleLine: Inline 8 | AccessModifierOffset: -4 9 | -------------------------------------------------------------------------------- /Android.bp: -------------------------------------------------------------------------------- 1 | cc_library_headers { 2 | name: "libminikin_headers", 3 | host_supported: true, 4 | export_include_dirs: ["include"], 5 | target: { 6 | windows: { 7 | enabled: true, 8 | }, 9 | }, 10 | } 11 | 12 | subdirs = [ 13 | "app", 14 | "libs/minikin", 15 | "tests", 16 | ] 17 | -------------------------------------------------------------------------------- /tests/util/Android.bp: -------------------------------------------------------------------------------- 1 | cc_library_static { 2 | name: "libminikin-tests-util", 3 | srcs: [ 4 | "FileUtils.cpp", 5 | "FontTestUtils.cpp", 6 | "FreeTypeMinikinFontForTest.cpp", 7 | "PathUtils.cpp", 8 | "UnicodeUtils.cpp", 9 | ], 10 | cflags: ["-Wall", "-Werror"], 11 | export_include_dirs: ["."], 12 | shared_libs: ["libxml2", "libft2"], 13 | static_libs: ["libminikin"], 14 | header_libs: ["libminikin-headers-for-tests"], 15 | } 16 | -------------------------------------------------------------------------------- /tests/util/FileUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | std::vector readWholeFile(const std::string& filePath); 21 | -------------------------------------------------------------------------------- /tests/unittest/TestMain.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "ICUEnvironment.h" 18 | 19 | #include 20 | 21 | int main(int argc, char** argv) { 22 | ::testing::InitGoogleTest(&argc, argv); 23 | ::testing::AddGlobalTestEnvironment(new minikin::ICUEnvironment); 24 | return RUN_ALL_TESTS(); 25 | } 26 | -------------------------------------------------------------------------------- /include/minikin/IcuUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_ICUUTILS_H 18 | #define MINIKIN_ICUUTILS_H 19 | 20 | #include 21 | #include 22 | 23 | namespace minikin { 24 | 25 | struct IcuUbrkDeleter { 26 | void operator()(UBreakIterator* v) { ubrk_close(v); } 27 | }; 28 | 29 | using IcuUbrkUniquePtr = std::unique_ptr; 30 | 31 | } // namespace minikin 32 | 33 | #endif // MINIKIN_ICUUTILS_H 34 | -------------------------------------------------------------------------------- /include/minikin/FontVariation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_FONT_VARIATION_H 18 | #define MINIKIN_FONT_VARIATION_H 19 | 20 | #include 21 | 22 | namespace minikin { 23 | 24 | typedef uint32_t AxisTag; 25 | 26 | struct FontVariation { 27 | FontVariation(AxisTag axisTag, float value) : axisTag(axisTag), value(value) {} 28 | AxisTag axisTag; 29 | float value; 30 | }; 31 | 32 | } // namespace minikin 33 | 34 | #endif // MINIKIN_FONT_VARIATION_H 35 | -------------------------------------------------------------------------------- /libs/minikin/FontUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_FONT_UTILS_H 18 | #define MINIKIN_FONT_UTILS_H 19 | 20 | #include 21 | #include 22 | 23 | namespace minikin { 24 | 25 | bool analyzeStyle(const uint8_t* os2_data, size_t os2_size, int* weight, bool* italic); 26 | bool analyzeAxes(const uint8_t* fvar_data, size_t fvar_size, std::unordered_set* axes); 27 | 28 | } // namespace minikin 29 | 30 | #endif // MINIKIN_ANALYZE_STYLE_H 31 | -------------------------------------------------------------------------------- /include/minikin/LocaleList.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_LOCALE_H 18 | #define MINIKIN_LOCALE_H 19 | 20 | #include 21 | 22 | namespace minikin { 23 | 24 | // Looks up a locale list from an internal cache and returns its ID. 25 | // If the passed locale list is not in the cache, registers it and returns newly assigned ID. 26 | // TODO: Introduce LocaleId type. 27 | uint32_t registerLocaleList(const std::string& locales); 28 | 29 | } // namespace minikin 30 | 31 | #endif // MINIKIN_LOCALE_H 32 | -------------------------------------------------------------------------------- /include/minikin/Emoji.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | 19 | namespace minikin { 20 | 21 | // Returns true if c is emoji. 22 | bool isEmoji(uint32_t c); 23 | 24 | // Returns true if c is emoji modifier base. 25 | bool isEmojiBase(uint32_t c); 26 | 27 | // Returns true if c is emoji modifier. 28 | bool isEmojiModifier(uint32_t c); 29 | 30 | // Bidi override for ICU that knows about new emoji. 31 | UCharDirection emojiBidiOverride(const void* context, UChar32 c); 32 | 33 | } // namespace minikin 34 | -------------------------------------------------------------------------------- /app/Android.bp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 The Android Open Source Project 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // see how_to_run.txt for instructions on running these tests 16 | 17 | cc_binary_host { 18 | name: "hyphtool", 19 | 20 | static_libs: ["libminikin"], 21 | 22 | // Shared libraries which are dependencies of minikin; these are not automatically 23 | // pulled in by the build system (and thus sadly must be repeated). 24 | shared_libs: [ 25 | "liblog", 26 | "libandroidicu", 27 | ], 28 | 29 | srcs: ["HyphTool.cpp"], 30 | 31 | cflags: ["-Wall", "-Werror"], 32 | } 33 | -------------------------------------------------------------------------------- /tests/Android.bp: -------------------------------------------------------------------------------- 1 | filegroup { 2 | name: "minikin-test-data", 3 | srcs: [ 4 | "data/Arabic.ttf", 5 | "data/Ascii.ttf", 6 | "data/Bold.ttf", 7 | "data/BoldItalic.ttf", 8 | "data/Cherokee.ttf", 9 | "data/ColorEmojiFont.ttf", 10 | "data/ColorTextMixedEmojiFont.ttf", 11 | "data/CustomExtent.ttf", 12 | "data/Emoji.ttf", 13 | "data/Hiragana.ttf", 14 | "data/Italic.ttf", 15 | "data/Ja.ttf", 16 | "data/Ko.ttf", 17 | "data/Ligature.ttf", 18 | "data/LayoutTestFont.ttf", 19 | "data/MultiAxis.ttf", 20 | "data/NoCmapFormat14.ttf", 21 | "data/NoGlyphFont.ttf", 22 | "data/Regular.ttf", 23 | "data/TextEmojiFont.ttf", 24 | "data/UnicodeBMPOnly.ttf", 25 | "data/UnicodeBMPOnly2.ttf", 26 | "data/UnicodeUCS4.ttf", 27 | "data/VariationSelectorTest-Regular.ttf", 28 | "data/ZhHans.ttf", 29 | "data/ZhHant.ttf", 30 | "data/emoji.xml", 31 | "data/itemize.xml", 32 | ], 33 | } 34 | 35 | subdirs = [ 36 | "perftests", 37 | "stresstest", 38 | "unittest", 39 | "util", 40 | ] 41 | -------------------------------------------------------------------------------- /include/minikin/CmapCoverage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_CMAP_COVERAGE_H 18 | #define MINIKIN_CMAP_COVERAGE_H 19 | 20 | #include "minikin/SparseBitSet.h" 21 | 22 | #include 23 | #include 24 | 25 | namespace minikin { 26 | 27 | class CmapCoverage { 28 | public: 29 | static SparseBitSet getCoverage(const uint8_t* cmap_data, size_t cmap_size, 30 | std::vector>* out); 31 | }; 32 | 33 | } // namespace minikin 34 | 35 | #endif // MINIKIN_CMAP_COVERAGE_H 36 | -------------------------------------------------------------------------------- /include/minikin/Measurement.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_MEASUREMENT_H 18 | #define MINIKIN_MEASUREMENT_H 19 | 20 | #include 21 | #include 22 | 23 | namespace minikin { 24 | 25 | float getRunAdvance(const float* advances, const uint16_t* buf, size_t start, size_t count, 26 | size_t offset); 27 | 28 | size_t getOffsetForAdvance(const float* advances, const uint16_t* buf, size_t start, size_t count, 29 | float advance); 30 | 31 | } // namespace minikin 32 | 33 | #endif // MINIKIN_MEASUREMENT_H 34 | -------------------------------------------------------------------------------- /tests/util/PathUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef TEST_UTILS_PATH_UTILS_H 18 | #define TEST_UTILS_PATH_UTILS_H 19 | 20 | #include 21 | 22 | namespace minikin { 23 | 24 | std::string getDirname(const std::string& path); 25 | std::string getBasename(const std::string& path); 26 | 27 | // Returns test data directory. 28 | std::string getTestDataDir(); 29 | 30 | inline std::string getTestFontPath(const std::string& fontFilePath) { 31 | return getTestDataDir() + fontFilePath; 32 | } 33 | 34 | } // namespace minikin 35 | 36 | #endif // TEST_UTILS_PATH_UTILS_H 37 | -------------------------------------------------------------------------------- /include/minikin/FamilyVariant.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_FAMILY_VARIANT_H 18 | #define MINIKIN_FAMILY_VARIANT_H 19 | 20 | #include 21 | 22 | namespace minikin { 23 | 24 | // Must be the same value as FontConfig.java 25 | enum class FamilyVariant : uint8_t { 26 | DEFAULT = 0, // Must be the same as FontConfig.VARIANT_DEFAULT 27 | COMPACT = 1, // Must be the same as FontConfig.VARIANT_COMPACT 28 | ELEGANT = 2, // Must be the same as FontConfig.VARIANT_ELEGANT 29 | }; 30 | 31 | } // namespace minikin 32 | 33 | #endif // MINIKIN_FAMILY_VARIANT_H 34 | -------------------------------------------------------------------------------- /tests/unittest/UnicodeUtilsTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "UnicodeUtils.h" 18 | 19 | #include 20 | 21 | namespace minikin { 22 | 23 | TEST(UnicodeUtils, parse) { 24 | const size_t BUF_SIZE = 256; 25 | uint16_t buf[BUF_SIZE]; 26 | size_t offset; 27 | size_t size; 28 | ParseUnicode(buf, BUF_SIZE, "U+000D U+1F431 | 'a'", &size, &offset); 29 | EXPECT_EQ(size, 4u); 30 | EXPECT_EQ(offset, 3u); 31 | EXPECT_EQ(buf[0], 0x000D); 32 | EXPECT_EQ(buf[1], 0xD83D); 33 | EXPECT_EQ(buf[2], 0xDC31); 34 | EXPECT_EQ(buf[3], 'a'); 35 | } 36 | 37 | } // namespace minikin 38 | -------------------------------------------------------------------------------- /libs/minikin/OptimalLineBreaker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_OPTIMAL_LINE_BREAKER_H 18 | #define MINIKIN_OPTIMAL_LINE_BREAKER_H 19 | 20 | #include "minikin/LineBreaker.h" 21 | #include "minikin/MeasuredText.h" 22 | #include "minikin/U16StringPiece.h" 23 | 24 | namespace minikin { 25 | 26 | LineBreakResult breakLineOptimal(const U16StringPiece& textBuf, const MeasuredText& measured, 27 | const LineWidth& lineWidthLimits, BreakStrategy strategy, 28 | HyphenationFrequency frequency, bool justified); 29 | 30 | } // namespace minikin 31 | 32 | #endif // MINIKIN_OPTIMAL_LINE_BREAKER_H 33 | -------------------------------------------------------------------------------- /libs/minikin/GreedyLineBreaker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_GREEDY_LINE_BREAKER_H 18 | #define MINIKIN_GREEDY_LINE_BREAKER_H 19 | 20 | #include "minikin/LineBreaker.h" 21 | #include "minikin/MeasuredText.h" 22 | #include "minikin/U16StringPiece.h" 23 | 24 | #include "WordBreaker.h" 25 | 26 | namespace minikin { 27 | 28 | LineBreakResult breakLineGreedy(const U16StringPiece& textBuf, const MeasuredText& measured, 29 | const LineWidth& lineWidthLimits, const TabStops& tabStops, 30 | bool enableHyphenation); 31 | 32 | } // namespace minikin 33 | 34 | #endif // MINIKIN_GREEDY_LINE_BREAKER_H 35 | -------------------------------------------------------------------------------- /tests/util/FileUtils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "FileUtils.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | std::vector readWholeFile(const std::string& filePath) { 27 | FILE* fp = fopen(filePath.c_str(), "r"); 28 | LOG_ALWAYS_FATAL_IF(fp == nullptr); 29 | struct stat st; 30 | LOG_ALWAYS_FATAL_IF(fstat(fileno(fp), &st) != 0); 31 | 32 | std::vector result(st.st_size); 33 | LOG_ALWAYS_FATAL_IF(fread(result.data(), 1, st.st_size, fp) != static_cast(st.st_size)); 34 | fclose(fp); 35 | return result; 36 | } 37 | -------------------------------------------------------------------------------- /doc/minikin_style.md: -------------------------------------------------------------------------------- 1 | ### Minikin Style Guide 2 | 3 | The C++ style in Minikin follows Android Framework C++ Code Style Guide except for following rules: 4 | 5 | * Order of include 6 | 7 | In dir/foo.cc or dir/foo_test.cc, whose main purpose is to implement or test the stuff in 8 | dir2/foo2.h, order your includes as follows: 9 | 10 | 1. dir2/foo.h 11 | 2. A blank line 12 | 3. C system files 13 | 4. C++ system files 14 | 5. A blank line 15 | 6. Other libraries' files 16 | 7. A blank line 17 | 8. Minikin public files 18 | 9. A blank line 19 | 10. Minikin private files 20 | 21 | For example, 22 | ``` 23 | #include "minikin/Layout.h" // The corresponding header file. 24 | 25 | #include // C system header files. 26 | #include // C++ system header files. 27 | 28 | #include // Other library, HarfBuzz, header file. 29 | #include // Other library, Android, header file. 30 | #include // Other library, ICU, header file. 31 | 32 | #include "minikin/Emoji.h" // The minikin public header file. 33 | #include "HbFontCache.h" // The minikin private header file. 34 | ``` 35 | 36 | * "<>" vs "" 37 | 38 | * `#include <...>` should be used for non local library files. 39 | * `#include "..."` should be used for minikin header files. 40 | -------------------------------------------------------------------------------- /libs/minikin/SystemFonts.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #define LOG_TAG "Minikin" 18 | 19 | #include "minikin/SystemFonts.h" 20 | 21 | namespace minikin { 22 | 23 | SystemFonts& SystemFonts::getInstance() { 24 | static SystemFonts systemFonts; 25 | return systemFonts; 26 | } 27 | 28 | std::shared_ptr SystemFonts::findFontCollectionInternal( 29 | const std::string& familyName) const { 30 | auto it = mSystemFallbacks.find(familyName); 31 | if (it != mSystemFallbacks.end()) { 32 | return it->second; 33 | } 34 | // TODO: Lookup by PostScript name. 35 | return mDefaultFallback; 36 | } 37 | 38 | } // namespace minikin 39 | -------------------------------------------------------------------------------- /tests/unittest/AndroidTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 21 | -------------------------------------------------------------------------------- /tests/util/UnicodeUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "minikin/U16StringPiece.h" 22 | 23 | namespace minikin { 24 | 25 | void ParseUnicode(uint16_t* buf, size_t buf_size, const char* src, size_t* result_size, 26 | size_t* offset); 27 | 28 | std::vector parseUnicodeStringWithOffset(const std::string& in, size_t* offset); 29 | std::vector parseUnicodeString(const std::string& in); 30 | 31 | // Converts UTF-8 to UTF-16. 32 | std::vector utf8ToUtf16(const std::string& text); 33 | std::string utf16ToUtf8(const U16StringPiece& u16String); 34 | 35 | } // namespace minikin 36 | -------------------------------------------------------------------------------- /tests/data/emoji.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 19 | 20 | NoGlyphFont.ttf 21 | 22 | 23 | TextEmojiFont.ttf 24 | 25 | 26 | ColorEmojiFont.ttf 27 | 28 | 29 | ColorTextMixedEmojiFont.ttf 30 | 31 | 32 | -------------------------------------------------------------------------------- /tests/unittest/HasherTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "minikin/Hasher.h" 18 | 19 | #include 20 | 21 | namespace minikin { 22 | 23 | TEST(HasherTest, hasherTest) { 24 | EXPECT_EQ(Hasher().hash(), Hasher().hash()); 25 | EXPECT_EQ(Hasher().update(1).hash(), Hasher().update(1).hash()); 26 | 27 | uint16_t shorts1[] = {1, 2, 3, 4, 5}; 28 | uint16_t shorts2[] = {1, 2, 3, 4, 5}; 29 | EXPECT_EQ(Hasher().updateShorts(shorts1, 5).hash(), Hasher().updateShorts(shorts2, 5).hash()); 30 | 31 | Hasher hasher; 32 | hasher.update(1); 33 | EXPECT_EQ(hasher.hash(), hasher.hash()); 34 | hasher.update(2); 35 | EXPECT_EQ(hasher.hash(), hasher.hash()); 36 | } 37 | 38 | } // namespace minikin 39 | -------------------------------------------------------------------------------- /tests/perftests/AndroidTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 21 | 27 | -------------------------------------------------------------------------------- /tests/perftests/Android.bp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2016 The Android Open Source Project 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | cc_benchmark { 18 | name: "minikin_perftests", 19 | test_suites: ["device-tests"], 20 | cppflags: [ 21 | "-Werror", 22 | "-Wall", 23 | "-Wextra", 24 | ], 25 | srcs: [ 26 | "FontCollection.cpp", 27 | "FontLanguage.cpp", 28 | "GraphemeBreak.cpp", 29 | "Hyphenator.cpp", 30 | "WordBreaker.cpp", 31 | "main.cpp", 32 | ], 33 | 34 | header_libs: ["libminikin-headers-for-tests"], 35 | 36 | static_libs: [ 37 | "libminikin-tests-util", 38 | "libminikin", 39 | "libxml2", 40 | ], 41 | 42 | shared_libs: [ 43 | "libft2", 44 | "libharfbuzz_ng", 45 | "libandroidicu", 46 | "liblog", 47 | 48 | ], 49 | } 50 | -------------------------------------------------------------------------------- /include/minikin/Characters.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_CHARACTERS_H 18 | #define MINIKIN_CHARACTERS_H 19 | 20 | #include 21 | 22 | namespace minikin { 23 | 24 | // Code point order 25 | constexpr uint32_t CHAR_LINE_FEED = 0x000A; 26 | constexpr uint32_t CHAR_CARRIAGE_RETURN = 0x000D; 27 | constexpr uint32_t CHAR_TAB = 0x0009; 28 | constexpr uint32_t CHAR_HYPHEN_MINUS = 0x002D; 29 | constexpr uint32_t CHAR_NBSP = 0x00A0; 30 | constexpr uint32_t CHAR_SOFT_HYPHEN = 0x00AD; 31 | constexpr uint32_t CHAR_MIDDLE_DOT = 0x00B7; 32 | constexpr uint32_t CHAR_ARMENIAN_HYPHEN = 0x058A; 33 | constexpr uint32_t CHAR_MAQAF = 0x05BE; 34 | constexpr uint32_t CHAR_UCAS_HYPHEN = 0x1400; 35 | constexpr uint32_t CHAR_ZWJ = 0x200D; 36 | constexpr uint32_t CHAR_HYPHEN = 0x2010; 37 | 38 | } // namespace minikin 39 | 40 | #endif // MINIKIN_CHARACTERS_H 41 | -------------------------------------------------------------------------------- /tests/perftests/FontLanguage.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #include "Locale.h" 17 | 18 | #include 19 | 20 | namespace minikin { 21 | 22 | static void BM_Locale_en_US(benchmark::State& state) { 23 | while (state.KeepRunning()) { 24 | Locale language(StringPiece("en-US", 5)); 25 | } 26 | } 27 | BENCHMARK(BM_Locale_en_US); 28 | 29 | static void BM_Locale_en_Latn_US(benchmark::State& state) { 30 | while (state.KeepRunning()) { 31 | Locale language(StringPiece("en-Latn-US", 10)); 32 | } 33 | } 34 | BENCHMARK(BM_Locale_en_Latn_US); 35 | 36 | static void BM_Locale_en_Latn_US_u_em_emoji(benchmark::State& state) { 37 | while (state.KeepRunning()) { 38 | Locale language(StringPiece("en-Latn-US-u-em-emoji", 21)); 39 | } 40 | } 41 | BENCHMARK(BM_Locale_en_Latn_US_u_em_emoji); 42 | 43 | } // namespace minikin 44 | -------------------------------------------------------------------------------- /tests/perftests/WordBreaker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #include "WordBreaker.h" 17 | 18 | #include 19 | 20 | #include "Locale.h" 21 | #include "UnicodeUtils.h" 22 | 23 | namespace minikin { 24 | 25 | static void BM_WordBreaker_English(benchmark::State& state) { 26 | const char* kLoremIpsum = 27 | "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do " 28 | "eiusmod tempor incididunt ut labore et dolore magna aliqua."; 29 | 30 | WordBreaker wb; 31 | wb.followingWithLocale(Locale("en-US"), 0); 32 | std::vector text = utf8ToUtf16(kLoremIpsum); 33 | while (state.KeepRunning()) { 34 | wb.setText(text.data(), text.size()); 35 | while (wb.next() != -1) { 36 | } 37 | } 38 | } 39 | BENCHMARK(BM_WordBreaker_English); 40 | 41 | // TODO: Add more tests for other languages. 42 | 43 | } // namespace minikin 44 | -------------------------------------------------------------------------------- /tests/util/PathUtils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "PathUtils.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | namespace minikin { 24 | 25 | const char* SELF_EXE_PATH = "/proc/self/exe"; 26 | 27 | std::string getDirname(const std::string& path) { 28 | const char* result = dirname(path.c_str()); 29 | LOG_ALWAYS_FATAL_IF(result == nullptr, "dirname failed."); 30 | return std::string(result); 31 | } 32 | 33 | std::string getBasename(const std::string& path) { 34 | const char* result = basename(path.c_str()); 35 | LOG_ALWAYS_FATAL_IF(result == nullptr, "basename failed."); 36 | return std::string(result); 37 | } 38 | 39 | std::string getTestDataDir() { 40 | char buf[PATH_MAX] = {}; 41 | LOG_ALWAYS_FATAL_IF(readlink(SELF_EXE_PATH, buf, PATH_MAX) == -1, "readlink failed."); 42 | return getDirname(buf) + "/data/"; 43 | } 44 | 45 | } // namespace minikin 46 | -------------------------------------------------------------------------------- /tests/stresstest/Android.bp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Android Open Source Project 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // see how_to_run.txt for instructions on running these tests 16 | 17 | cc_test { 18 | name: "minikin_stress_tests", 19 | 20 | header_libs: ["libminikin-headers-for-tests"], 21 | data: [":minikin-test-data"], 22 | 23 | static_libs: [ 24 | "libminikin-tests-util", 25 | "libminikin", 26 | "libxml2", 27 | ], 28 | 29 | // Shared libraries which are dependencies of minikin; these are not automatically 30 | // pulled in by the build system (and thus sadly must be repeated). 31 | shared_libs: [ 32 | 33 | "libft2", 34 | "libharfbuzz_ng", 35 | "libandroidicu", 36 | "liblog", 37 | "libutils", 38 | "libz", 39 | ], 40 | 41 | srcs: [ 42 | "FontFamilyTest.cpp", 43 | "MultithreadTest.cpp", 44 | ], 45 | 46 | cflags: [ 47 | "-Werror", 48 | "-Wall", 49 | "-Wextra", 50 | ], 51 | } 52 | -------------------------------------------------------------------------------- /libs/minikin/LineBreaker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "minikin/LineBreaker.h" 18 | 19 | #include "GreedyLineBreaker.h" 20 | #include "OptimalLineBreaker.h" 21 | 22 | namespace minikin { 23 | 24 | LineBreakResult breakIntoLines(const U16StringPiece& textBuffer, BreakStrategy strategy, 25 | HyphenationFrequency frequency, bool justified, 26 | const MeasuredText& measuredText, const LineWidth& lineWidth, 27 | const TabStops& tabStops) { 28 | if (strategy == BreakStrategy::Greedy || textBuffer.hasChar(CHAR_TAB)) { 29 | return breakLineGreedy(textBuffer, measuredText, lineWidth, tabStops, 30 | frequency != HyphenationFrequency::None); 31 | } else { 32 | return breakLineOptimal(textBuffer, measuredText, lineWidth, strategy, frequency, 33 | justified); 34 | } 35 | } 36 | 37 | } // namespace minikin 38 | -------------------------------------------------------------------------------- /tests/perftests/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | int main(int argc, char** argv) { 26 | const char* fn = "/apex/com.google.runtime/etc/icu/" U_ICUDATA_NAME ".dat"; 27 | int fd = open(fn, O_RDONLY); 28 | LOG_ALWAYS_FATAL_IF(fd == -1); 29 | struct stat st; 30 | LOG_ALWAYS_FATAL_IF(fstat(fd, &st) != 0); 31 | void* data = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); 32 | 33 | UErrorCode errorCode = U_ZERO_ERROR; 34 | udata_setCommonData(data, &errorCode); 35 | LOG_ALWAYS_FATAL_IF(U_FAILURE(errorCode)); 36 | u_init(&errorCode); 37 | LOG_ALWAYS_FATAL_IF(U_FAILURE(errorCode)); 38 | 39 | benchmark::Initialize(&argc, argv); 40 | benchmark::RunSpecifiedBenchmarks(); 41 | 42 | u_cleanup(); 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /tests/unittest/FontTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "minikin/Font.h" 18 | 19 | #include 20 | 21 | #include "FontTestUtils.h" 22 | #include "FreeTypeMinikinFontForTest.h" 23 | 24 | namespace minikin { 25 | 26 | TEST(FontTest, CopyTest) { 27 | auto minikinFont = std::make_shared(getTestFontPath("Ascii.ttf")); 28 | { 29 | Font font = Font::Builder(minikinFont).build(); 30 | { 31 | Font copied(font); 32 | EXPECT_EQ(font.typeface(), copied.typeface()); 33 | EXPECT_EQ(font.style(), copied.style()); 34 | EXPECT_EQ(font.baseFont(), copied.baseFont()); 35 | } 36 | { 37 | Font copied = font; 38 | EXPECT_EQ(font.typeface(), copied.typeface()); 39 | EXPECT_EQ(font.style(), copied.style()); 40 | EXPECT_EQ(font.baseFont(), copied.baseFont()); 41 | } 42 | } 43 | } 44 | 45 | } // namespace minikin 46 | -------------------------------------------------------------------------------- /libs/minikin/MinikinInternal.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | // Definitions internal to Minikin 17 | 18 | #define LOG_TAG "Minikin" 19 | 20 | #include 21 | 22 | #include "MinikinInternal.h" 23 | 24 | namespace minikin { 25 | 26 | inline static bool isBMPVariationSelector(uint32_t codePoint) { 27 | return VS1 <= codePoint && codePoint <= VS16; 28 | } 29 | 30 | inline static bool isVariationSelectorSupplement(uint32_t codePoint) { 31 | return VS17 <= codePoint && codePoint <= VS256; 32 | } 33 | 34 | uint16_t getVsIndex(uint32_t codePoint) { 35 | if (isBMPVariationSelector(codePoint)) { 36 | return codePoint - VS1; 37 | } else if (isVariationSelectorSupplement(codePoint)) { 38 | return codePoint - VS17 + 16; 39 | } else { 40 | return INVALID_VS_INDEX; 41 | } 42 | } 43 | 44 | bool isVariationSelector(uint32_t codePoint) { 45 | return isBMPVariationSelector(codePoint) || isVariationSelectorSupplement(codePoint); 46 | } 47 | 48 | } // namespace minikin 49 | -------------------------------------------------------------------------------- /include/minikin/MinikinExtent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_MINIKIN_EXTENT_H 18 | #define MINIKIN_MINIKIN_EXTENT_H 19 | 20 | #include 21 | 22 | namespace minikin { 23 | 24 | // For holding vertical extents. 25 | struct MinikinExtent { 26 | MinikinExtent() : ascent(0), descent(0) {} 27 | MinikinExtent(float ascent, float descent) : ascent(ascent), descent(descent) {} 28 | bool operator==(const MinikinExtent& o) const { 29 | return ascent == o.ascent && descent == o.descent; 30 | } 31 | float ascent; // negative 32 | float descent; // positive 33 | 34 | void reset() { ascent = descent = 0.0; } 35 | 36 | void extendBy(const MinikinExtent& e) { 37 | ascent = std::min(ascent, e.ascent); 38 | descent = std::max(descent, e.descent); 39 | } 40 | }; 41 | 42 | // For gtest output 43 | inline std::ostream& operator<<(std::ostream& os, const MinikinExtent& e) { 44 | return os << e.ascent << ", " << e.descent; 45 | } 46 | } // namespace minikin 47 | 48 | #endif // MINIKIN_MINIKIN_EXTENT_H 49 | -------------------------------------------------------------------------------- /include/minikin/GraphemeBreak.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_GRAPHEME_BREAK_H 18 | #define MINIKIN_GRAPHEME_BREAK_H 19 | 20 | #include 21 | #include 22 | 23 | namespace minikin { 24 | 25 | class GraphemeBreak { 26 | public: 27 | // These values must be kept in sync with CURSOR_AFTER etc in Paint.java 28 | enum MoveOpt { AFTER = 0, AT_OR_AFTER = 1, BEFORE = 2, AT_OR_BEFORE = 3, AT = 4 }; 29 | 30 | // Determine whether the given offset is a grapheme break. 31 | // This implementation generally follows Unicode's UTR #29 extended 32 | // grapheme break, with various tweaks. 33 | static bool isGraphemeBreak(const float* advances, const uint16_t* buf, size_t start, 34 | size_t count, size_t offset); 35 | 36 | // Matches Android's Java API. Note, return (size_t)-1 for AT to 37 | // signal non-break because unsigned return type. 38 | static size_t getTextRunCursor(const float* advances, const uint16_t* buf, size_t start, 39 | size_t count, size_t offset, MoveOpt opt); 40 | }; 41 | 42 | } // namespace minikin 43 | 44 | #endif // MINIKIN_GRAPHEME_BREAK_H 45 | -------------------------------------------------------------------------------- /include/minikin/HbUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_HB_UTILS_H 18 | #define MINIKIN_HB_UTILS_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace minikin { 25 | 26 | inline float HBFixedToFloat(hb_position_t v) { 27 | return scalbnf(v, -8); 28 | } 29 | 30 | inline hb_position_t HBFloatToFixed(float v) { 31 | return scalbnf(v, +8); 32 | } 33 | 34 | struct HbBlobDeleter { 35 | void operator()(hb_blob_t* v) { hb_blob_destroy(v); } 36 | }; 37 | 38 | struct HbFaceDeleter { 39 | void operator()(hb_face_t* v) { hb_face_destroy(v); } 40 | }; 41 | 42 | struct HbFontDeleter { 43 | void operator()(hb_font_t* v) { hb_font_destroy(v); } 44 | }; 45 | 46 | struct HbBufferDeleter { 47 | void operator()(hb_buffer_t* v) { hb_buffer_destroy(v); } 48 | }; 49 | 50 | using HbBlobUniquePtr = std::unique_ptr; 51 | using HbFaceUniquePtr = std::unique_ptr; 52 | using HbFontUniquePtr = std::unique_ptr; 53 | using HbBufferUniquePtr = std::unique_ptr; 54 | 55 | } // namespace minikin 56 | 57 | #endif // MINIKIN_HB_UTILS_H 58 | -------------------------------------------------------------------------------- /libs/minikin/LayoutUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_LAYOUT_UTILS_H 18 | #define MINIKIN_LAYOUT_UTILS_H 19 | 20 | #include 21 | 22 | #include "minikin/U16StringPiece.h" 23 | 24 | namespace minikin { 25 | 26 | /* 27 | * Determine whether the code unit is a word space for the purposes of justification. 28 | */ 29 | bool isWordSpace(uint16_t code_unit); 30 | 31 | /** 32 | * Return offset of previous word break. It is either < offset or == 0. 33 | * 34 | * For the purpose of layout, a word break is a boundary with no 35 | * kerning or complex script processing. This is necessarily a 36 | * heuristic, but should be accurate most of the time. 37 | */ 38 | uint32_t getPrevWordBreakForCache(const U16StringPiece& textBuf, uint32_t offset); 39 | 40 | /** 41 | * Return offset of next word break. It is either > offset or == len. 42 | * 43 | * For the purpose of layout, a word break is a boundary with no 44 | * kerning or complex script processing. This is necessarily a 45 | * heuristic, but should be accurate most of the time. 46 | */ 47 | uint32_t getNextWordBreakForCache(const U16StringPiece& textBuf, uint32_t offset); 48 | 49 | } // namespace minikin 50 | #endif // MINIKIN_LAYOUT_UTILS_H 51 | -------------------------------------------------------------------------------- /tests/data/itemize.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | Regular.ttf 19 | Italic.ttf 20 | Bold.ttf 21 | BoldItalic.ttf 22 | 23 | 24 | 25 | Arabic.ttf 26 | 27 | 28 | Cherokee.ttf 29 | 30 | 31 | ZhHans.ttf 32 | 33 | 34 | Ja.ttf 35 | 36 | 37 | ZhHant.ttf 38 | 39 | 40 | Ko.ttf 41 | 42 | 43 | Emoji.ttf 44 | 45 | 46 | -------------------------------------------------------------------------------- /tests/unittest/SparseBitSetTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "minikin/SparseBitSet.h" 18 | 19 | #include 20 | 21 | #include 22 | 23 | namespace minikin { 24 | 25 | TEST(SparseBitSetTest, randomTest) { 26 | const uint32_t kTestRangeNum = 4096; 27 | 28 | std::mt19937 mt; // Fix seeds to be able to reproduce the result. 29 | std::uniform_int_distribution distribution(1, 512); 30 | 31 | std::vector range{distribution(mt)}; 32 | for (size_t i = 1; i < kTestRangeNum * 2; ++i) { 33 | range.push_back((range.back() - 1) + distribution(mt)); 34 | } 35 | 36 | SparseBitSet bitset(range.data(), range.size() / 2); 37 | 38 | uint32_t ch = 0; 39 | for (size_t i = 0; i < range.size() / 2; ++i) { 40 | uint32_t start = range[i * 2]; 41 | uint32_t end = range[i * 2 + 1]; 42 | 43 | for (; ch < start; ch++) { 44 | ASSERT_FALSE(bitset.get(ch)) << std::hex << ch; 45 | } 46 | for (; ch < end; ch++) { 47 | ASSERT_TRUE(bitset.get(ch)) << std::hex << ch; 48 | } 49 | } 50 | for (; ch < 0x1FFFFFF; ++ch) { 51 | ASSERT_FALSE(bitset.get(ch)) << std::hex << ch; 52 | } 53 | } 54 | 55 | } // namespace minikin 56 | -------------------------------------------------------------------------------- /app/HyphTool.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include "minikin/Hyphenator.h" 9 | 10 | using minikin::HyphenationType; 11 | using minikin::Hyphenator; 12 | 13 | Hyphenator* loadHybFile(const char* fn, int minPrefix, int minSuffix, const char* language) { 14 | struct stat statbuf; 15 | int status = stat(fn, &statbuf); 16 | if (status < 0) { 17 | fprintf(stderr, "error opening %s\n", fn); 18 | return nullptr; 19 | } 20 | size_t size = statbuf.st_size; 21 | FILE* f = fopen(fn, "rb"); 22 | if (f == NULL) { 23 | fprintf(stderr, "error opening %s\n", fn); 24 | return nullptr; 25 | } 26 | uint8_t* buf = new uint8_t[size]; 27 | size_t read_size = fread(buf, 1, size, f); 28 | fclose(f); 29 | if (read_size < size) { 30 | fprintf(stderr, "error reading %s\n", fn); 31 | delete[] buf; 32 | return nullptr; 33 | } 34 | return Hyphenator::loadBinary(buf, minPrefix, minSuffix, language); 35 | } 36 | 37 | int main(int argc, char** argv) { 38 | Hyphenator* hyph = loadHybFile("/tmp/en.hyb", 2, 3, "en"); // should also be configurable 39 | std::vector result; 40 | std::vector word; 41 | if (argc < 2) { 42 | fprintf(stderr, "usage: hyphtool word\n"); 43 | return 1; 44 | } 45 | char* asciiword = argv[1]; 46 | size_t len = strlen(asciiword); 47 | for (size_t i = 0; i < len; i++) { 48 | uint32_t c = asciiword[i]; 49 | if (c == '-') { 50 | c = 0x00AD; 51 | } 52 | // ASCII (or possibly ISO Latin 1), but kinda painful to do utf conversion :( 53 | word.push_back(c); 54 | } 55 | hyph->hyphenate(word, &result); 56 | for (size_t i = 0; i < len; i++) { 57 | if (result[i] != HyphenationType::DONT_BREAK) { 58 | printf("-"); 59 | } 60 | printf("%c", word[i]); 61 | } 62 | printf("\n"); 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /tests/unittest/AndroidLineBreakerHelperTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "minikin/AndroidLineBreakerHelper.h" 18 | 19 | #include 20 | 21 | namespace minikin { 22 | namespace android { 23 | 24 | TEST(AndroidLineWidth, negativeWidthTest) { 25 | const int LINE_COUNT = 10; 26 | const std::vector EMPTY; 27 | { 28 | AndroidLineWidth lineWidth(-10 /* first width */, 1 /* first count */, 0 /* rest width */, 29 | EMPTY, 0); 30 | 31 | EXPECT_LE(0.0f, lineWidth.getMin()); 32 | for (int i = 0; i < LINE_COUNT; ++i) { 33 | EXPECT_LE(0.0f, lineWidth.getAt(i)); 34 | } 35 | } 36 | { 37 | AndroidLineWidth lineWidth(0 /* first width */, 0 /* first count */, -10 /* rest width */, 38 | EMPTY, 0); 39 | 40 | EXPECT_LE(0.0f, lineWidth.getMin()); 41 | for (int i = 0; i < LINE_COUNT; ++i) { 42 | EXPECT_LE(0.0f, lineWidth.getAt(i)); 43 | } 44 | } 45 | { 46 | std::vector indents = {10}; 47 | AndroidLineWidth lineWidth(0 /* first width */, 0 /* first count */, 0 /* rest width */, 48 | indents, 0); 49 | 50 | EXPECT_LE(0.0f, lineWidth.getMin()); 51 | for (int i = 0; i < LINE_COUNT; ++i) { 52 | EXPECT_LE(0.0f, lineWidth.getAt(i)); 53 | } 54 | } 55 | } 56 | 57 | } // namespace android 58 | } // namespace minikin 59 | -------------------------------------------------------------------------------- /tests/unittest/ICUEnvironment.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_TEST_ICU_ENVIRONMENT_H 18 | #define MINIKIN_TEST_ICU_ENVIRONMENT_H 19 | 20 | // low level file access for mapping ICU data 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | namespace minikin { 31 | 32 | class ICUEnvironment : public testing::Environment { 33 | public: 34 | ICUEnvironment() : testing::Environment(), mData(nullptr), mSize(0) {} 35 | 36 | void* mData; 37 | size_t mSize; 38 | 39 | virtual void SetUp() override { 40 | const char* fn = "/apex/com.android.runtime/etc/icu/" U_ICUDATA_NAME ".dat"; 41 | int fd = open(fn, O_RDONLY); 42 | LOG_ALWAYS_FATAL_IF(fd == -1); 43 | struct stat sb; 44 | LOG_ALWAYS_FATAL_IF(fstat(fd, &sb) != 0); 45 | 46 | mSize = sb.st_size; 47 | void* mData = mmap(nullptr, mSize, PROT_READ, MAP_SHARED, fd, 0); 48 | close(fd); 49 | 50 | UErrorCode errorCode = U_ZERO_ERROR; 51 | udata_setCommonData(mData, &errorCode); 52 | LOG_ALWAYS_FATAL_IF(U_FAILURE(errorCode)); 53 | 54 | errorCode = U_ZERO_ERROR; 55 | u_init(&errorCode); 56 | LOG_ALWAYS_FATAL_IF(U_FAILURE(errorCode)); 57 | } 58 | 59 | virtual void TearDown() override { 60 | u_cleanup(); 61 | munmap(mData, mSize); 62 | } 63 | }; 64 | 65 | } // namespace minikin 66 | #endif // MINIKIN_TEST_ICU_ENVIRONMENT_H 67 | -------------------------------------------------------------------------------- /tests/perftests/Hyphenator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #include "minikin/Hyphenator.h" 17 | 18 | #include 19 | 20 | #include "FileUtils.h" 21 | #include "UnicodeUtils.h" 22 | 23 | namespace minikin { 24 | 25 | const char* enUsHyph = "/system/usr/hyphen-data/hyph-en-us.hyb"; 26 | const int enUsMinPrefix = 2; 27 | const int enUsMinSuffix = 3; 28 | 29 | static void BM_Hyphenator_short_word(benchmark::State& state) { 30 | Hyphenator* hyphenator = Hyphenator::loadBinary(readWholeFile(enUsHyph).data(), enUsMinPrefix, 31 | enUsMinSuffix, "en"); 32 | std::vector word = utf8ToUtf16("hyphen"); 33 | std::vector result; 34 | while (state.KeepRunning()) { 35 | hyphenator->hyphenate(word, &result); 36 | } 37 | } 38 | 39 | // TODO: Use BENCHMARK_CAPTURE for parametrise. 40 | BENCHMARK(BM_Hyphenator_short_word); 41 | 42 | static void BM_Hyphenator_long_word(benchmark::State& state) { 43 | Hyphenator* hyphenator = Hyphenator::loadBinary(readWholeFile(enUsHyph).data(), enUsMinPrefix, 44 | enUsMinSuffix, "en"); 45 | std::vector word = utf8ToUtf16("Pneumonoultramicroscopicsilicovolcanoconiosis"); 46 | std::vector result; 47 | while (state.KeepRunning()) { 48 | hyphenator->hyphenate(word, &result); 49 | } 50 | } 51 | 52 | // TODO: Use BENCHMARK_CAPTURE for parametrise. 53 | BENCHMARK(BM_Hyphenator_long_word); 54 | 55 | // TODO: Add more tests for other languages. 56 | 57 | } // namespace minikin 58 | -------------------------------------------------------------------------------- /include/minikin/FontStyle.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_FONT_STYLE_H 18 | #define MINIKIN_FONT_STYLE_H 19 | 20 | namespace minikin { 21 | 22 | // FontStyle represents style information. 23 | class FontStyle { 24 | public: 25 | enum class Weight : uint16_t { 26 | THIN = 100, 27 | EXTRA_LIGHT = 200, 28 | LIGHT = 300, 29 | NORMAL = 400, 30 | MEDIUM = 500, 31 | SEMI_BOLD = 600, 32 | BOLD = 700, 33 | EXTRA_BOLD = 800, 34 | BLACK = 900, 35 | EXTRA_BLACK = 1000, 36 | }; 37 | 38 | enum class Slant : bool { 39 | ITALIC = true, 40 | UPRIGHT = false, 41 | }; 42 | 43 | constexpr FontStyle() : FontStyle(Weight::NORMAL, Slant::UPRIGHT) {} 44 | constexpr explicit FontStyle(Weight weight) : FontStyle(weight, Slant::UPRIGHT) {} 45 | constexpr explicit FontStyle(Slant slant) : FontStyle(Weight::NORMAL, slant) {} 46 | constexpr FontStyle(Weight weight, Slant slant) 47 | : FontStyle(static_cast(weight), slant) {} 48 | constexpr FontStyle(uint16_t weight, Slant slant) : mWeight(weight), mSlant(slant) {} 49 | 50 | constexpr uint16_t weight() const { return mWeight; } 51 | constexpr Slant slant() const { return mSlant; } 52 | 53 | constexpr bool operator==(const FontStyle& other) const { 54 | return weight() == other.weight() && slant() == other.slant(); 55 | } 56 | 57 | constexpr uint32_t identifier() const { 58 | return (static_cast(weight()) << 16) | static_cast(slant()); 59 | } 60 | 61 | private: 62 | uint16_t mWeight; 63 | Slant mSlant; 64 | }; 65 | 66 | } // namespace minikin 67 | 68 | #endif // MINIKIN_FONT_STYLE_H 69 | -------------------------------------------------------------------------------- /include/minikin/U16StringPiece.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_U16STRING_PIECE_H 18 | #define MINIKIN_U16STRING_PIECE_H 19 | 20 | #include 21 | 22 | #include "minikin/Range.h" 23 | 24 | namespace minikin { 25 | 26 | class U16StringPiece { 27 | public: 28 | U16StringPiece() : mData(nullptr), mLength(0) {} 29 | U16StringPiece(const uint16_t* data, uint32_t length) : mData(data), mLength(length) {} 30 | U16StringPiece(const std::vector& v) // Intentionally not explicit. 31 | : mData(v.data()), mLength(static_cast(v.size())) {} 32 | template 33 | U16StringPiece(uint16_t const (&data)[length]) : mData(data), mLength(length) {} 34 | 35 | U16StringPiece(const U16StringPiece&) = default; 36 | U16StringPiece& operator=(const U16StringPiece&) = default; 37 | 38 | inline const uint16_t* data() const { return mData; } 39 | inline uint32_t size() const { return mLength; } 40 | inline uint32_t length() const { return mLength; } 41 | 42 | // Undefined behavior if pos is out of range. 43 | inline const uint16_t& at(uint32_t pos) const { return mData[pos]; } 44 | inline const uint16_t& operator[](uint32_t pos) const { return mData[pos]; } 45 | 46 | inline U16StringPiece substr(const Range& range) const { 47 | return U16StringPiece(mData + range.getStart(), range.getLength()); 48 | } 49 | 50 | inline bool hasChar(uint16_t c) const { 51 | const uint16_t* end = mData + mLength; 52 | return std::find(mData, end, c) != end; 53 | } 54 | 55 | private: 56 | const uint16_t* mData; 57 | uint32_t mLength; 58 | }; 59 | 60 | } // namespace minikin 61 | 62 | #endif // MINIKIN_U16STRING_PIECE_H 63 | -------------------------------------------------------------------------------- /tests/unittest/LocaleListTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | 19 | #include "minikin/Hyphenator.h" 20 | 21 | #include "GreedyLineBreaker.h" 22 | #include "LocaleListCache.h" 23 | #include "MinikinInternal.h" 24 | 25 | namespace minikin { 26 | namespace { 27 | 28 | const LocaleList& getLocaleList(const std::string& localeStr) { 29 | return LocaleListCache::getById(LocaleListCache::getId(localeStr)); 30 | } 31 | 32 | TEST(LocaleListTest, basicTest) { 33 | std::string langTag = "en-US"; 34 | EXPECT_EQ(1U, getLocaleList(langTag).size()); 35 | EXPECT_EQ("en-Latn-US", getLocaleList(langTag)[0].getString()); 36 | 37 | langTag = "en-US,fr-FR"; 38 | EXPECT_EQ(2U, getLocaleList(langTag).size()); 39 | EXPECT_EQ("en-Latn-US", getLocaleList(langTag)[0].getString()); 40 | EXPECT_EQ("fr-Latn-FR", getLocaleList(langTag)[1].getString()); 41 | 42 | langTag = "en-US,en-US,fr-FR"; 43 | EXPECT_EQ(2U, getLocaleList(langTag).size()); 44 | EXPECT_EQ("en-Latn-US", getLocaleList(langTag)[0].getString()); 45 | EXPECT_EQ("fr-Latn-FR", getLocaleList(langTag)[1].getString()); 46 | 47 | EXPECT_EQ(0U, getLocaleList("").size()); 48 | } 49 | 50 | TEST(LocaleListTest, bogusLanguageTest) { 51 | std::string langTag = "en-US,THISISBOGUSLANGUAGE"; 52 | EXPECT_EQ(1U, getLocaleList(langTag).size()); 53 | EXPECT_EQ("en-Latn-US", getLocaleList(langTag)[0].getString()); 54 | 55 | langTag = "THISISBOGUSLANGUAGE,en-US"; 56 | EXPECT_EQ(1U, getLocaleList(langTag).size()); 57 | EXPECT_EQ("en-Latn-US", getLocaleList(langTag)[0].getString()); 58 | 59 | langTag = "THISISBOGUSLANGUAGE,THISISANOTHERBOGUSLANGUAGE"; 60 | EXPECT_EQ(0U, getLocaleList(langTag).size()); 61 | } 62 | 63 | } // namespace 64 | } // namespace minikin 65 | -------------------------------------------------------------------------------- /include/minikin/MinikinRect.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_MINIKIN_RECT_H 18 | #define MINIKIN_MINIKIN_RECT_H 19 | 20 | #include 21 | 22 | namespace minikin { 23 | 24 | struct MinikinRect { 25 | MinikinRect() : mLeft(0), mTop(0), mRight(0), mBottom(0) {} 26 | MinikinRect(float left, float top, float right, float bottom) 27 | : mLeft(left), mTop(top), mRight(right), mBottom(bottom) {} 28 | bool operator==(const MinikinRect& o) const { 29 | return mLeft == o.mLeft && mTop == o.mTop && mRight == o.mRight && mBottom == o.mBottom; 30 | } 31 | float mLeft; 32 | float mTop; 33 | float mRight; 34 | float mBottom; 35 | 36 | bool isEmpty() const { return mLeft == mRight || mTop == mBottom; } 37 | void set(const MinikinRect& r) { 38 | mLeft = r.mLeft; 39 | mTop = r.mTop; 40 | mRight = r.mRight; 41 | mBottom = r.mBottom; 42 | } 43 | void offset(float dx, float dy) { 44 | mLeft += dx; 45 | mTop += dy; 46 | mRight += dx; 47 | mBottom += dy; 48 | } 49 | void setEmpty() { mLeft = mTop = mRight = mBottom = 0.0; } 50 | void join(const MinikinRect& r) { 51 | if (isEmpty()) { 52 | set(r); 53 | } else if (!r.isEmpty()) { 54 | mLeft = std::min(mLeft, r.mLeft); 55 | mTop = std::min(mTop, r.mTop); 56 | mRight = std::max(mRight, r.mRight); 57 | mBottom = std::max(mBottom, r.mBottom); 58 | } 59 | } 60 | }; 61 | 62 | // For gtest output 63 | inline std::ostream& operator<<(std::ostream& os, const MinikinRect& r) { 64 | return os << "(" << r.mLeft << ", " << r.mTop << ")-(" << r.mRight << ", " << r.mBottom << ")"; 65 | } 66 | 67 | } // namespace minikin 68 | 69 | #endif // MINIKIN_MINIKIN_RECT_H 70 | -------------------------------------------------------------------------------- /tests/unittest/MeasurementTests.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "minikin/Measurement.h" 18 | 19 | #include 20 | 21 | #include "UnicodeUtils.h" 22 | 23 | namespace minikin { 24 | 25 | float getAdvance(const float* advances, const char* src) { 26 | const size_t BUF_SIZE = 256; 27 | uint16_t buf[BUF_SIZE]; 28 | size_t offset; 29 | size_t size; 30 | ParseUnicode(buf, BUF_SIZE, src, &size, &offset); 31 | return getRunAdvance(advances, buf, 0, size, offset); 32 | } 33 | 34 | // Latin fi 35 | TEST(Measurement, getRunAdvance_fi) { 36 | const float unligated[] = {30.0, 20.0}; 37 | EXPECT_EQ(0.0, getAdvance(unligated, "| 'f' 'i'")); 38 | EXPECT_EQ(30.0, getAdvance(unligated, "'f' | 'i'")); 39 | EXPECT_EQ(50.0, getAdvance(unligated, "'f' 'i' |")); 40 | 41 | const float ligated[] = {40.0, 0.0}; 42 | EXPECT_EQ(0.0, getAdvance(ligated, "| 'f' 'i'")); 43 | EXPECT_EQ(20.0, getAdvance(ligated, "'f' | 'i'")); 44 | EXPECT_EQ(40.0, getAdvance(ligated, "'f' 'i' |")); 45 | } 46 | 47 | // Devanagari ka+virama+ka 48 | TEST(Measurement, getRunAdvance_kka) { 49 | const float unligated[] = {30.0, 0.0, 30.0}; 50 | EXPECT_EQ(0.0, getAdvance(unligated, "| U+0915 U+094D U+0915")); 51 | EXPECT_EQ(30.0, getAdvance(unligated, "U+0915 | U+094D U+0915")); 52 | EXPECT_EQ(30.0, getAdvance(unligated, "U+0915 U+094D | U+0915")); 53 | EXPECT_EQ(60.0, getAdvance(unligated, "U+0915 U+094D U+0915 |")); 54 | 55 | const float ligated[] = {30.0, 0.0, 0.0}; 56 | EXPECT_EQ(0.0, getAdvance(ligated, "| U+0915 U+094D U+0915")); 57 | EXPECT_EQ(30.0, getAdvance(ligated, "U+0915 | U+094D U+0915")); 58 | EXPECT_EQ(30.0, getAdvance(ligated, "U+0915 U+094D | U+0915")); 59 | EXPECT_EQ(30.0, getAdvance(ligated, "U+0915 U+094D U+0915 |")); 60 | } 61 | 62 | } // namespace minikin 63 | -------------------------------------------------------------------------------- /tests/unittest/SystemFontsTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "minikin/SystemFonts.h" 18 | 19 | #include 20 | 21 | #include "minikin/FontCollection.h" 22 | 23 | #include "FontTestUtils.h" 24 | 25 | namespace minikin { 26 | namespace { 27 | 28 | class TestableSystemFonts : public SystemFonts { 29 | public: 30 | TestableSystemFonts() : SystemFonts() {} 31 | virtual ~TestableSystemFonts() {} 32 | 33 | std::shared_ptr findFontCollection(const std::string& familyName) const { 34 | return findFontCollectionInternal(familyName); 35 | } 36 | 37 | void registerFallback(const std::string& familyName, 38 | const std::shared_ptr& fc) { 39 | registerFallbackInternal(familyName, fc); 40 | } 41 | 42 | void registerDefault(const std::shared_ptr& fc) { registerDefaultInternal(fc); } 43 | }; 44 | 45 | TEST(SystemFontsTest, registerAndLookup) { 46 | TestableSystemFonts systemFonts; 47 | auto fc = buildFontCollection("Ascii.ttf"); 48 | systemFonts.registerFallback("sans", fc); 49 | EXPECT_EQ(fc, systemFonts.findFontCollection("sans")); 50 | } 51 | 52 | TEST(SystemFontsTest, registerDefaultAndLookup) { 53 | TestableSystemFonts systemFonts; 54 | auto fc = buildFontCollection("Ascii.ttf"); 55 | systemFonts.registerDefault(fc); 56 | EXPECT_EQ(fc, systemFonts.findFontCollection("unknown-name")); 57 | } 58 | 59 | TEST(SystemFontsTest, registerDefaultAndFallback) { 60 | TestableSystemFonts systemFonts; 61 | auto fc1 = buildFontCollection("Ascii.ttf"); 62 | auto fc2 = buildFontCollection("Bold.ttf"); 63 | systemFonts.registerDefault(fc1); 64 | systemFonts.registerFallback("sans", fc2); 65 | EXPECT_EQ(fc1, systemFonts.findFontCollection("unknown-name")); 66 | EXPECT_EQ(fc2, systemFonts.findFontCollection("sans")); 67 | } 68 | 69 | } // namespace 70 | } // namespace minikin 71 | -------------------------------------------------------------------------------- /libs/minikin/LocaleListCache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_LOCALE_LIST_CACHE_H 18 | #define MINIKIN_LOCALE_LIST_CACHE_H 19 | 20 | #include 21 | #include 22 | 23 | #include "minikin/Macros.h" 24 | 25 | #include "Locale.h" 26 | 27 | namespace minikin { 28 | 29 | class LocaleListCache { 30 | public: 31 | // A special ID for the empty locale list. 32 | // This value must be 0 since the empty locale list is inserted into mLocaleLists by 33 | // default. 34 | const static uint32_t kEmptyListId = 0; 35 | 36 | // A special ID for the invalid locale list. 37 | const static uint32_t kInvalidListId = (uint32_t)(-1); 38 | 39 | // Returns the locale list ID for the given string representation of LocaleList. 40 | // Caller should acquire a lock before calling the method. 41 | static inline uint32_t getId(const std::string& locales) { 42 | return getInstance().getIdInternal(locales); 43 | } 44 | 45 | // Caller should acquire a lock before calling the method. 46 | static inline const LocaleList& getById(uint32_t id) { 47 | return getInstance().getByIdInternal(id); 48 | } 49 | 50 | private: 51 | LocaleListCache(); // Singleton 52 | ~LocaleListCache() {} 53 | 54 | uint32_t getIdInternal(const std::string& locales); 55 | const LocaleList& getByIdInternal(uint32_t id); 56 | 57 | // Caller should acquire a lock before calling the method. 58 | static LocaleListCache& getInstance() { 59 | static LocaleListCache instance; 60 | return instance; 61 | } 62 | 63 | std::vector mLocaleLists GUARDED_BY(mMutex); 64 | 65 | // A map from the string representation of the font locale list to the ID. 66 | std::unordered_map mLocaleListLookupTable GUARDED_BY(mMutex); 67 | 68 | std::mutex mMutex; 69 | }; 70 | 71 | } // namespace minikin 72 | 73 | #endif // MINIKIN_LOCALE_LIST_CACHE_H 74 | -------------------------------------------------------------------------------- /tests/util/FreeTypeMinikinFontForTest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_TEST_FREE_TYPE_MINIKIN_FONT_FOR_TEST_H 18 | #define MINIKIN_TEST_FREE_TYPE_MINIKIN_FONT_FOR_TEST_H 19 | 20 | #include 21 | 22 | #include "minikin/MinikinFont.h" 23 | 24 | #include 25 | #include FT_FREETYPE_H 26 | 27 | #include "minikin/Macros.h" 28 | 29 | namespace minikin { 30 | 31 | class FreeTypeMinikinFontForTest : public MinikinFont { 32 | public: 33 | FreeTypeMinikinFontForTest(const std::string& font_path, int index); 34 | FreeTypeMinikinFontForTest(const std::string& font_path) 35 | : FreeTypeMinikinFontForTest(font_path, 0) {} 36 | virtual ~FreeTypeMinikinFontForTest(); 37 | 38 | // MinikinFont overrides. 39 | float GetHorizontalAdvance(uint32_t glyph_id, const MinikinPaint& paint, 40 | const FontFakery& fakery) const override; 41 | void GetBounds(MinikinRect* bounds, uint32_t glyph_id, const MinikinPaint& paint, 42 | const FontFakery& fakery) const override; 43 | void GetFontExtent(MinikinExtent* extent, const MinikinPaint& paint, 44 | const FontFakery& fakery) const override; 45 | 46 | const std::string& fontPath() const { return mFontPath; } 47 | 48 | const void* GetFontData() const { return mFontData; } 49 | size_t GetFontSize() const { return mFontSize; } 50 | int GetFontIndex() const { return mFontIndex; } 51 | const std::vector& GetAxes() const { return mAxes; } 52 | 53 | private: 54 | const std::string mFontPath; 55 | const int mFontIndex; 56 | void* mFontData; 57 | size_t mFontSize; 58 | std::vector mAxes; 59 | 60 | FT_Library mFtLibrary; 61 | FT_Face mFtFace; 62 | 63 | MINIKIN_PREVENT_COPY_AND_ASSIGN(FreeTypeMinikinFontForTest); 64 | }; 65 | 66 | } // namespace minikin 67 | 68 | #endif // MINIKIN_TEST_FREE_TYPE_MINIKIN_FONT_FOR_TEST_H 69 | -------------------------------------------------------------------------------- /libs/minikin/LineBreakerUtil.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "LineBreakerUtil.h" 18 | 19 | namespace minikin { 20 | 21 | // Very long words trigger O(n^2) behavior in hyphenation, so we disable hyphenation for 22 | // unreasonably long words. This is somewhat of a heuristic because extremely long words are 23 | // possible in some languages. This does mean that very long real words can get broken by 24 | // desperate breaks, with no hyphens. 25 | constexpr size_t LONGEST_HYPHENATED_WORD = 45; 26 | 27 | // Hyphenates a string potentially containing non-breaking spaces. 28 | std::vector hyphenate(const U16StringPiece& str, const Hyphenator& hyphenator) { 29 | std::vector out; 30 | const size_t len = str.size(); 31 | out.resize(len); 32 | 33 | // A word here is any consecutive string of non-NBSP characters. 34 | bool inWord = false; 35 | size_t wordStart = 0; // The initial value will never be accessed, but just in case. 36 | for (size_t i = 0; i <= len; i++) { 37 | if (i == len || str[i] == CHAR_NBSP) { 38 | if (inWord) { 39 | // A word just ended. Hyphenate it. 40 | const U16StringPiece word = str.substr(Range(wordStart, i)); 41 | if (word.size() <= LONGEST_HYPHENATED_WORD) { 42 | hyphenator.hyphenate(word, out.data() + wordStart); 43 | } else { // Word is too long. Inefficient to hyphenate. 44 | out.insert(out.end(), word.size(), HyphenationType::DONT_BREAK); 45 | } 46 | inWord = false; 47 | } 48 | if (i < len) { 49 | // Insert one DONT_BREAK for the NBSP. 50 | out.push_back(HyphenationType::DONT_BREAK); 51 | } 52 | } else if (!inWord) { 53 | inWord = true; 54 | wordStart = i; 55 | } 56 | } 57 | return out; 58 | } 59 | 60 | } // namespace minikin 61 | -------------------------------------------------------------------------------- /tests/unittest/Android.bp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 The Android Open Source Project 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // see how_to_run.txt for instructions on running these tests 16 | 17 | cc_test { 18 | name: "minikin_tests", 19 | test_suites: ["device-tests"], 20 | data: [":minikin-test-data"], 21 | 22 | header_libs: ["libminikin-headers-for-tests"], 23 | 24 | static_libs: [ 25 | "libminikin-tests-util", 26 | "libminikin", 27 | "libxml2", 28 | ], 29 | 30 | // Shared libraries which are dependencies of minikin; these are not automatically 31 | // pulled in by the build system (and thus sadly must be repeated). 32 | shared_libs: [ 33 | "libft2", 34 | "libharfbuzz_ng", 35 | "libandroidicu", 36 | "liblog", 37 | "libutils", 38 | "libz", 39 | ], 40 | 41 | srcs: [ 42 | "AndroidLineBreakerHelperTest.cpp", 43 | "BidiUtilsTest.cpp", 44 | "CmapCoverageTest.cpp", 45 | "EmojiTest.cpp", 46 | "FontTest.cpp", 47 | "FontCollectionTest.cpp", 48 | "FontCollectionItemizeTest.cpp", 49 | "FontFamilyTest.cpp", 50 | "FontLanguageListCacheTest.cpp", 51 | "FontUtilsTest.cpp", 52 | "HasherTest.cpp", 53 | "HyphenatorMapTest.cpp", 54 | "HyphenatorTest.cpp", 55 | "GraphemeBreakTests.cpp", 56 | "GreedyLineBreakerTest.cpp", 57 | "LayoutCacheTest.cpp", 58 | "LayoutCoreTest.cpp", 59 | "LayoutSplitterTest.cpp", 60 | "LayoutTest.cpp", 61 | "LayoutUtilsTest.cpp", 62 | "LocaleListTest.cpp", 63 | "MeasuredTextTest.cpp", 64 | "MeasurementTests.cpp", 65 | "OptimalLineBreakerTest.cpp", 66 | "SparseBitSetTest.cpp", 67 | "StringPieceTest.cpp", 68 | "SystemFontsTest.cpp", 69 | "TestMain.cpp", 70 | "UnicodeUtilsTest.cpp", 71 | "WordBreakerTests.cpp", 72 | ], 73 | 74 | cflags: [ 75 | "-Werror", 76 | "-Wall", 77 | "-Wextra", 78 | ], 79 | } 80 | -------------------------------------------------------------------------------- /include/minikin/Hasher.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_HASHER_H 18 | #define MINIKIN_HASHER_H 19 | 20 | #include 21 | 22 | #include 23 | 24 | #include "minikin/Macros.h" 25 | 26 | namespace minikin { 27 | 28 | // Provides a Jenkins hash implementation. 29 | class Hasher { 30 | public: 31 | Hasher() : mHash(0u) {} 32 | 33 | IGNORE_INTEGER_OVERFLOW inline Hasher& update(uint32_t data) { 34 | mHash += data; 35 | mHash += (mHash << 10); 36 | mHash ^= (mHash >> 6); 37 | return *this; 38 | } 39 | 40 | inline Hasher& updateShorts(const uint16_t* data, uint32_t length) { 41 | update(length); 42 | uint32_t i; 43 | for (i = 0; i < (length & -2); i += 2) { 44 | update((uint32_t)data[i] | ((uint32_t)data[i + 1] << 16)); 45 | } 46 | if (length & 1) { 47 | update((uint32_t)data[i]); 48 | } 49 | return *this; 50 | } 51 | 52 | inline Hasher& updateString(const std::string& str) { 53 | uint32_t size = str.size(); 54 | update(size); 55 | uint32_t i; 56 | for (i = 0; i < (size & -4); i += 4) { 57 | update((uint32_t)str[i] | ((uint32_t)str[i + 1] << 8) | ((uint32_t)str[i + 2] << 16) | 58 | ((uint32_t)str[i + 3] << 24)); 59 | } 60 | if (size & 3) { 61 | uint32_t data = str[i]; 62 | data |= ((size & 3) > 1) ? ((uint32_t)str[i + 1] << 8) : 0; 63 | data |= ((size & 3) > 2) ? ((uint32_t)str[i + 2] << 16) : 0; 64 | update(data); 65 | } 66 | return *this; 67 | } 68 | 69 | IGNORE_INTEGER_OVERFLOW inline uint32_t hash() { 70 | uint32_t hash = mHash; 71 | hash += (hash << 3); 72 | hash ^= (hash >> 11); 73 | hash += (hash << 15); 74 | return hash; 75 | } 76 | 77 | private: 78 | uint32_t mHash; 79 | }; 80 | 81 | } // namespace minikin 82 | 83 | #endif // MINIKIN_HASHER_H 84 | -------------------------------------------------------------------------------- /tests/unittest/FontLanguageListCacheTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "minikin/FontFamily.h" 18 | 19 | #include 20 | 21 | #include "minikin/LocaleList.h" 22 | 23 | #include "LocaleListCache.h" 24 | #include "MinikinInternal.h" 25 | 26 | namespace minikin { 27 | 28 | TEST(LocaleListCacheTest, getId) { 29 | EXPECT_NE(0UL, registerLocaleList("en")); 30 | EXPECT_NE(0UL, registerLocaleList("jp")); 31 | EXPECT_NE(0UL, registerLocaleList("en,zh-Hans")); 32 | 33 | EXPECT_EQ(0UL, LocaleListCache::getId("")); 34 | 35 | EXPECT_EQ(LocaleListCache::getId("en"), LocaleListCache::getId("en")); 36 | EXPECT_NE(LocaleListCache::getId("en"), LocaleListCache::getId("jp")); 37 | 38 | EXPECT_EQ(LocaleListCache::getId("en,zh-Hans"), LocaleListCache::getId("en,zh-Hans")); 39 | EXPECT_NE(LocaleListCache::getId("en,zh-Hans"), LocaleListCache::getId("zh-Hans,en")); 40 | EXPECT_NE(LocaleListCache::getId("en,zh-Hans"), LocaleListCache::getId("jp")); 41 | EXPECT_NE(LocaleListCache::getId("en,zh-Hans"), LocaleListCache::getId("en")); 42 | EXPECT_NE(LocaleListCache::getId("en,zh-Hans"), LocaleListCache::getId("en,zh-Hant")); 43 | } 44 | 45 | TEST(LocaleListCacheTest, getById) { 46 | uint32_t enLangId = LocaleListCache::getId("en"); 47 | uint32_t jpLangId = LocaleListCache::getId("jp"); 48 | Locale english = LocaleListCache::getById(enLangId)[0]; 49 | Locale japanese = LocaleListCache::getById(jpLangId)[0]; 50 | 51 | const LocaleList& defLangs = LocaleListCache::getById(0); 52 | EXPECT_TRUE(defLangs.empty()); 53 | 54 | const LocaleList& locales = LocaleListCache::getById(LocaleListCache::getId("en")); 55 | ASSERT_EQ(1UL, locales.size()); 56 | EXPECT_EQ(english, locales[0]); 57 | 58 | const LocaleList& locales2 = LocaleListCache::getById(LocaleListCache::getId("en,jp")); 59 | ASSERT_EQ(2UL, locales2.size()); 60 | EXPECT_EQ(english, locales2[0]); 61 | EXPECT_EQ(japanese, locales2[1]); 62 | } 63 | 64 | } // namespace minikin 65 | -------------------------------------------------------------------------------- /include/minikin/Macros.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #ifndef MINIKIN_MACROS_H 17 | #define MINIKIN_MACROS_H 18 | 19 | #if defined(__clang__) 20 | #define IGNORE_INTEGER_OVERFLOW __attribute__((no_sanitize("integer"))) 21 | #else 22 | #define IGNORE_INTEGER_OVERFLOW // no-op 23 | #endif // __clang__ 24 | 25 | #define MINIKIN_PREVENT_COPY_AND_ASSIGN(Type) \ 26 | Type(const Type&) = delete; \ 27 | Type& operator=(const Type&) = delete 28 | 29 | #define MINIKIN_PREVENT_COPY_ASSIGN_AND_MOVE(Type) \ 30 | Type(const Type&) = delete; \ 31 | Type& operator=(const Type&) = delete; \ 32 | Type(Type&&) = delete; \ 33 | Type& operator=(Type&&) = delete 34 | 35 | // Following thread annotations are partially copied from Abseil thread_annotations.h file. 36 | // https://github.com/abseil/abseil-cpp/blob/master/absl/base/thread_annotations.h 37 | 38 | #if defined(__clang__) 39 | #define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) 40 | #else 41 | #define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op 42 | #endif 43 | 44 | // GUARDED_BY() 45 | // 46 | // Documents if a shared field or global variable needs to be protected by a 47 | // mutex. GUARDED_BY() allows the user to specify a particular mutex that 48 | // should be held when accessing the annotated variable. 49 | // 50 | // Example: 51 | // 52 | // Mutex mu; 53 | // int p1 GUARDED_BY(mu); 54 | #define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) 55 | 56 | // EXCLUSIVE_LOCKS_REQUIRED() 57 | // 58 | // Documents a function that expects a mutex to be held prior to entry. 59 | // The mutex is expected to be held both on entry to, and exit from, the 60 | // function. 61 | // 62 | // Example: 63 | // 64 | // Mutex mu1, mu2; 65 | // int a GUARDED_BY(mu1); 66 | // int b GUARDED_BY(mu2); 67 | // 68 | // void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }; 69 | #define EXCLUSIVE_LOCKS_REQUIRED(...) \ 70 | THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__)) 71 | 72 | #endif // MINIKIN_MACROS_H 73 | -------------------------------------------------------------------------------- /include/minikin/SystemFonts.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_SYSTEM_FONTS_H 18 | #define MINIKIN_SYSTEM_FONTS_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "minikin/FontCollection.h" 25 | #include "minikin/U16StringPiece.h" 26 | 27 | namespace minikin { 28 | 29 | // Provides a system font mapping. 30 | class SystemFonts { 31 | public: 32 | static std::shared_ptr findFontCollection(const std::string& familyName) { 33 | return getInstance().findFontCollectionInternal(familyName); 34 | } 35 | 36 | // Do not call this function outside Zygote process. 37 | static void registerFallback(const std::string& familyName, 38 | const std::shared_ptr& fc) { 39 | return getInstance().registerFallbackInternal(familyName, fc); 40 | } 41 | 42 | // Do not call this function outside Zygote process. 43 | static void registerDefault(const std::shared_ptr& fc) { 44 | return getInstance().registerDefaultInternal(fc); 45 | } 46 | 47 | protected: 48 | // Visible for testing purposes. 49 | SystemFonts() {} 50 | virtual ~SystemFonts() {} 51 | 52 | std::shared_ptr findFontCollectionInternal(const std::string& familyName) const; 53 | void registerFallbackInternal(const std::string& familyName, 54 | const std::shared_ptr& fc) { 55 | mSystemFallbacks.insert(std::make_pair(familyName, fc)); 56 | } 57 | 58 | void registerDefaultInternal(const std::shared_ptr& fc) { 59 | mDefaultFallback = fc; 60 | } 61 | 62 | private: 63 | static SystemFonts& getInstance(); 64 | 65 | // There is no mutex guard here since registerFallback is designed to be 66 | // called only in Zygote. 67 | std::map> mSystemFallbacks; 68 | std::shared_ptr mDefaultFallback; 69 | }; 70 | 71 | } // namespace minikin 72 | 73 | #endif // MINIKIN_SYSTEM_FONTS_H 74 | -------------------------------------------------------------------------------- /tests/util/FontTestUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_FONT_TEST_UTILS_H 18 | #define MINIKIN_FONT_TEST_UTILS_H 19 | 20 | #include 21 | 22 | #include "minikin/FontCollection.h" 23 | 24 | #include "PathUtils.h" 25 | 26 | namespace minikin { 27 | 28 | /** 29 | * Returns list of FontFamily from installed fonts. 30 | * 31 | * This function reads an XML file and makes font families. 32 | */ 33 | std::vector> getFontFamilies(const std::string& fontDir, 34 | const std::string& xmlAbsPath); 35 | 36 | /** 37 | * Returns FontCollection from installed fonts. 38 | * 39 | * This function reads an XML file and makes font families and collections of them. 40 | * The XML path and font files are needed to be in the test data directory. 41 | */ 42 | inline std::shared_ptr buildFontCollectionFromXml(const std::string& xmlPath) { 43 | return std::make_shared( 44 | getFontFamilies(getTestDataDir(), getTestDataDir() + xmlPath)); 45 | } 46 | 47 | /** 48 | * Build new FontCollection from single file. 49 | * The font file needs to be in the test data directory. 50 | */ 51 | std::shared_ptr buildFontCollection(const std::string& filePath); 52 | 53 | /** 54 | * Build new FontFamily from single file. 55 | * The font file needs to be in the test data directory. 56 | */ 57 | std::shared_ptr buildFontFamily(const std::string& filePath); 58 | 59 | /** 60 | * Build new FontFamily from single file with locale. 61 | */ 62 | std::shared_ptr buildFontFamily(const std::string& filePath, const std::string& lang, 63 | bool isCustomFallback); 64 | 65 | /** 66 | * Build new FontFamily from single file with locale. 67 | */ 68 | inline std::shared_ptr buildFontFamily(const std::string& filePath, 69 | const std::string& lang) { 70 | return buildFontFamily(filePath, lang, false /* isCustomFallback */); 71 | } 72 | 73 | } // namespace minikin 74 | #endif // MINIKIN_FONT_TEST_UTILS_H 75 | -------------------------------------------------------------------------------- /libs/minikin/MinikinInternal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Definitions internal to Minikin 18 | 19 | #ifndef MINIKIN_INTERNAL_H 20 | #define MINIKIN_INTERNAL_H 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "minikin/HbUtils.h" 27 | #include "minikin/MinikinFont.h" 28 | 29 | namespace minikin { 30 | 31 | #ifdef ENABLE_ASSERTION 32 | #define MINIKIN_ASSERT(cond, ...) LOG_ALWAYS_FATAL_IF(!(cond), __VA_ARGS__) 33 | #else 34 | #define MINIKIN_ASSERT(cond, ...) ((void)0) 35 | #endif 36 | 37 | #define MINIKIN_NOT_REACHED(...) MINIKIN_ASSERT(false, __VA_ARGS__); 38 | 39 | constexpr uint32_t MAX_UNICODE_CODE_POINT = 0x10FFFF; 40 | 41 | constexpr uint32_t VS1 = 0xFE00; 42 | constexpr uint32_t VS16 = 0xFE0F; 43 | constexpr uint32_t VS17 = 0xE0100; 44 | constexpr uint32_t VS256 = 0xE01EF; 45 | 46 | // Returns variation selector index. This is one unit less than the variation selector number. For 47 | // example, VARIATION SELECTOR-25 maps to 24. 48 | // [0x00-0x0F] for U+FE00..U+FE0F 49 | // [0x10-0xFF] for U+E0100..U+E01EF 50 | // INVALID_VS_INDEX for other input. 51 | constexpr uint16_t INVALID_VS_INDEX = 0xFFFF; 52 | uint16_t getVsIndex(uint32_t codePoint); 53 | 54 | // Returns true if the code point is a variation selector. 55 | // Note that this function returns false for Mongolian free variation selectors. 56 | bool isVariationSelector(uint32_t codePoint); 57 | 58 | // An RAII accessor for hb_blob_t 59 | class HbBlob { 60 | public: 61 | HbBlob(const HbFaceUniquePtr& face, uint32_t tag) 62 | : mBlob(hb_face_reference_table(face.get(), tag)) {} 63 | HbBlob(const HbFontUniquePtr& font, uint32_t tag) 64 | : mBlob(hb_face_reference_table(hb_font_get_face(font.get()), tag)) {} 65 | 66 | inline const uint8_t* get() const { 67 | return reinterpret_cast(hb_blob_get_data(mBlob.get(), nullptr)); 68 | } 69 | 70 | inline size_t size() const { return (size_t)hb_blob_get_length(mBlob.get()); } 71 | 72 | inline operator bool() const { return size() > 0; } 73 | 74 | private: 75 | HbBlobUniquePtr mBlob; 76 | }; 77 | 78 | } // namespace minikin 79 | 80 | #endif // MINIKIN_INTERNAL_H 81 | -------------------------------------------------------------------------------- /libs/minikin/BidiUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_BIDI_UTILS_H 18 | #define MINIKIN_BIDI_UTILS_H 19 | 20 | #define LOG_TAG "Minikin" 21 | 22 | #include "minikin/Layout.h" 23 | 24 | #include 25 | 26 | #include 27 | 28 | #include "minikin/Macros.h" 29 | #include "minikin/U16StringPiece.h" 30 | 31 | namespace minikin { 32 | 33 | struct UBiDiDeleter { 34 | void operator()(UBiDi* v) { ubidi_close(v); } 35 | }; 36 | 37 | using UBiDiUniquePtr = std::unique_ptr; 38 | 39 | // A helper class for iterating the bidi run transitions. 40 | class BidiText { 41 | public: 42 | struct RunInfo { 43 | Range range; 44 | bool isRtl; 45 | }; 46 | 47 | BidiText(const U16StringPiece& textBuf, const Range& range, Bidi bidiFlags); 48 | 49 | RunInfo getRunInfoAt(uint32_t runOffset) const; 50 | 51 | class iterator { 52 | public: 53 | inline bool operator==(const iterator& o) const { 54 | return mRunOffset == o.mRunOffset && mParent == o.mParent; 55 | } 56 | 57 | inline bool operator!=(const iterator& o) const { return !(*this == o); } 58 | 59 | inline RunInfo operator*() const { return mParent->getRunInfoAt(mRunOffset); } 60 | 61 | inline iterator& operator++() { 62 | mRunOffset++; 63 | return *this; 64 | } 65 | 66 | private: 67 | friend class BidiText; 68 | 69 | iterator(const BidiText* parent, uint32_t runOffset) 70 | : mParent(parent), mRunOffset(runOffset) {} 71 | 72 | const BidiText* mParent; 73 | uint32_t mRunOffset; 74 | }; 75 | 76 | inline iterator begin() const { return iterator(this, 0); } 77 | inline iterator end() const { return iterator(this, mRunCount); } 78 | 79 | private: 80 | UBiDiUniquePtr mBidi; // Maybe null for single run. 81 | const Range mRange; // The range in the original buffer. Used for range check. 82 | bool mIsRtl; // The paragraph direction. 83 | uint32_t mRunCount; // The number of the bidi run in this text. 84 | 85 | MINIKIN_PREVENT_COPY_AND_ASSIGN(BidiText); 86 | }; 87 | 88 | } // namespace minikin 89 | 90 | #endif // MINIKIN_BIDI_UTILS_H 91 | -------------------------------------------------------------------------------- /libs/minikin/Android.bp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 The Android Open Source Project 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | cc_library_headers { 16 | name: "libminikin-headers-for-tests", 17 | export_include_dirs: ["."], 18 | shared_libs: ["libharfbuzz_ng"], 19 | export_shared_lib_headers: ["libharfbuzz_ng"], 20 | } 21 | 22 | cc_library { 23 | name: "libminikin", 24 | host_supported: true, 25 | srcs: [ 26 | "BidiUtils.cpp", 27 | "CmapCoverage.cpp", 28 | "Emoji.cpp", 29 | "FontCollection.cpp", 30 | "FontFamily.cpp", 31 | "FontUtils.cpp", 32 | "GraphemeBreak.cpp", 33 | "GreedyLineBreaker.cpp", 34 | "Hyphenator.cpp", 35 | "HyphenatorMap.cpp", 36 | "Layout.cpp", 37 | "LayoutCore.cpp", 38 | "LayoutUtils.cpp", 39 | "LineBreaker.cpp", 40 | "LineBreakerUtil.cpp", 41 | "Locale.cpp", 42 | "LocaleListCache.cpp", 43 | "MeasuredText.cpp", 44 | "Measurement.cpp", 45 | "MinikinInternal.cpp", 46 | "OptimalLineBreaker.cpp", 47 | "SparseBitSet.cpp", 48 | "SystemFonts.cpp", 49 | "WordBreaker.cpp", 50 | ], 51 | cflags: ["-Wall", "-Werror"], 52 | sanitize: { 53 | misc_undefined: [ 54 | "signed-integer-overflow", 55 | "unsigned-integer-overflow", 56 | ], 57 | }, 58 | cppflags: [ 59 | "-Werror", 60 | "-Wall", 61 | "-Wextra", 62 | "-Wthread-safety", 63 | ], 64 | product_variables: { 65 | debuggable: { 66 | // Enable assertion on eng and userdebug build. 67 | cppflags: ["-DENABLE_ASSERTION"], 68 | }, 69 | }, 70 | shared_libs: [ 71 | "liblog", 72 | "libandroidicu", 73 | "libharfbuzz_ng", 74 | ], 75 | header_libs: [ 76 | "libbase_headers", 77 | "libminikin_headers", 78 | "libutils_headers", 79 | ], 80 | export_header_lib_headers: ["libminikin_headers"], 81 | export_shared_lib_headers: ["libandroidicu"], 82 | whole_static_libs: ["libgtest_prod"], 83 | 84 | clang: true, 85 | 86 | target: { 87 | windows: { 88 | enabled: true, 89 | cppflags: [ 90 | "-Wno-thread-safety", 91 | ], 92 | }, 93 | }, 94 | } 95 | -------------------------------------------------------------------------------- /libs/minikin/Emoji.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "minikin/Emoji.h" 18 | 19 | namespace minikin { 20 | 21 | bool isNewEmoji(uint32_t c) { 22 | // Emoji characters new in Unicode emoji 12 23 | // From https://www.unicode.org/Public/emoji/12.0/emoji-data.txt 24 | // TODO: Remove once emoji-data.text 12 is in ICU or update to 12. 25 | if (c < 0x1F6D5 || c > 0x1FA95) { 26 | // Optimization for characters outside the new emoji range. 27 | return false; 28 | } 29 | return c == 0x1F6D5 || c == 0x1F6FA || c == 0x1F93F || c == 0x1F971 || c == 0x1F97B || 30 | (0x1F7E0 <= c && c <= 0x1F7EB) || (0x1F90D <= c && c <= 0x1F90F) || 31 | (0x1F9A5 <= c && c <= 0x1F9AA) || (0x1F9AE <= c && c <= 0x1F9AF) || 32 | (0x1F9BA <= c && c <= 0x1F9BF) || (0x1F9C3 <= c && c <= 0x1F9CA) || 33 | (0x1F9CD <= c && c <= 0x1F9CF) || (0x1FA70 <= c && c <= 0x1FA73) || 34 | (0x1FA78 <= c && c <= 0x1FA7A) || (0x1FA80 <= c && c <= 0x1FA82) || 35 | (0x1FA90 <= c && c <= 0x1FA95); 36 | } 37 | 38 | bool isEmoji(uint32_t c) { 39 | return isNewEmoji(c) || u_hasBinaryProperty(c, UCHAR_EMOJI); 40 | } 41 | 42 | bool isEmojiModifier(uint32_t c) { 43 | // Emoji modifier are not expected to change, so there's a small change we need to customize 44 | // this. 45 | return u_hasBinaryProperty(c, UCHAR_EMOJI_MODIFIER); 46 | } 47 | 48 | bool isEmojiBase(uint32_t c) { 49 | // These two characters were removed from Emoji_Modifier_Base in Emoji 4.0, but we need to keep 50 | // them as emoji modifier bases since there are fonts and user-generated text out there that 51 | // treats these as potential emoji bases. 52 | if (c == 0x1F91D || c == 0x1F93C) { 53 | return true; 54 | } 55 | // Emoji Modifier Base characters new in Unicode emoji 11 56 | // From https://www.unicode.org/Public/emoji/11.0/emoji-data.txt 57 | // TODO: Remove once emoji-data.text 11 is in ICU or update to 11. 58 | if ((0x1F9B5 <= c && c <= 0x1F9B6) || (0x1F9B8 <= c && c <= 0x1F9B9)) { 59 | return true; 60 | } 61 | return u_hasBinaryProperty(c, UCHAR_EMOJI_MODIFIER_BASE); 62 | } 63 | 64 | UCharDirection emojiBidiOverride(const void* /* context */, UChar32 c) { 65 | if (isNewEmoji(c)) { 66 | // All new emoji characters in Unicode 10.0 are of the bidi class ON. 67 | return U_OTHER_NEUTRAL; 68 | } else { 69 | return u_charDirection(c); 70 | } 71 | } 72 | 73 | } // namespace minikin 74 | -------------------------------------------------------------------------------- /tests/stresstest/FontFamilyTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "minikin/FontFamily.h" 18 | 19 | #include 20 | #include 21 | 22 | #include "minikin/FontCollection.h" 23 | 24 | #include "FontTestUtils.h" 25 | #include "FreeTypeMinikinFontForTest.h" 26 | #include "MinikinInternal.h" 27 | 28 | namespace minikin { 29 | 30 | typedef std::pair TestParam; 31 | 32 | class FontFamilyHarfBuzzCompatibilityTest : public ::testing::TestWithParam {}; 33 | 34 | TEST_P(FontFamilyHarfBuzzCompatibilityTest, CoverageTest) { 35 | const std::string& fontPath = GetParam().first; 36 | int ttcIndex = GetParam().second; 37 | 38 | auto font = std::make_shared(fontPath); 39 | std::vector fonts; 40 | fonts.push_back(Font::Builder(font).build()); 41 | std::shared_ptr family = std::make_shared(std::move(fonts)); 42 | 43 | hb_font_t* hbFont = family->getFont(0)->baseFont().get(); 44 | 45 | for (uint32_t codePoint = 0; codePoint < MAX_UNICODE_CODE_POINT; ++codePoint) { 46 | uint32_t unusedGlyph; 47 | EXPECT_EQ(family->hasGlyph(codePoint, 0 /* variation selector */), 48 | static_cast(hb_font_get_glyph(hbFont, codePoint, 0 /* variation selector */, 49 | &unusedGlyph))); 50 | } 51 | 52 | for (uint32_t vs = VS1; vs < VS256; ++vs) { 53 | // Move to variation selectors supplements after variation selectors. 54 | if (vs == VS16 + 1) { 55 | vs = VS17; 56 | } 57 | for (uint32_t codePoint = 0; codePoint < MAX_UNICODE_CODE_POINT; ++codePoint) { 58 | uint32_t unusedGlyph; 59 | ASSERT_EQ(family->hasGlyph(codePoint, vs), 60 | static_cast(hb_font_get_glyph(hbFont, codePoint, vs, &unusedGlyph))) 61 | << "Inconsistent Result: " << fontPath << "#" << ttcIndex << ": U+" << std::hex 62 | << codePoint << " U+" << std::hex << vs 63 | << " Minikin: " << family->hasGlyph(codePoint, vs) << " HarfBuzz: " 64 | << static_cast(hb_font_get_glyph(hbFont, codePoint, vs, &unusedGlyph)); 65 | } 66 | } 67 | hb_font_destroy(hbFont); 68 | } 69 | 70 | INSTANTIATE_TEST_CASE_P(FontFamilyTest, FontFamilyHarfBuzzCompatibilityTest, 71 | ::testing::Values(TestParam("/system/fonts/NotoSansCJK-Regular.ttc", 0), 72 | TestParam("/system/fonts/NotoColorEmoji.ttf", 0))); 73 | } // namespace minikin 74 | -------------------------------------------------------------------------------- /include/minikin/MinikinFont.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_MINIKIN_FONT_H 18 | #define MINIKIN_MINIKIN_FONT_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "minikin/FontVariation.h" 25 | 26 | namespace minikin { 27 | 28 | class FontFakery; 29 | struct MinikinExtent; 30 | struct MinikinPaint; 31 | struct MinikinRect; 32 | 33 | // An abstraction for platform fonts, allowing Minikin to be used with 34 | // multiple actual implementations of fonts. 35 | class MinikinFont { 36 | public: 37 | explicit MinikinFont(int32_t uniqueId) : mUniqueId(uniqueId) {} 38 | 39 | virtual ~MinikinFont() {} 40 | 41 | virtual float GetHorizontalAdvance(uint32_t glyph_id, const MinikinPaint& paint, 42 | const FontFakery& fakery) const = 0; 43 | virtual void GetHorizontalAdvances(uint16_t* glyph_ids, uint32_t count, 44 | const MinikinPaint& paint, const FontFakery& fakery, 45 | float* outAdvances) const { 46 | for (uint32_t i = 0; i < count; ++i) { 47 | outAdvances[i] = GetHorizontalAdvance(glyph_ids[i], paint, fakery); 48 | } 49 | } 50 | 51 | virtual void GetBounds(MinikinRect* bounds, uint32_t glyph_id, const MinikinPaint& paint, 52 | const FontFakery& fakery) const = 0; 53 | 54 | virtual void GetFontExtent(MinikinExtent* extent, const MinikinPaint& paint, 55 | const FontFakery& fakery) const = 0; 56 | 57 | // Override if font can provide access to raw data 58 | virtual const void* GetFontData() const { return nullptr; } 59 | 60 | // Override if font can provide access to raw data 61 | virtual size_t GetFontSize() const { return 0; } 62 | 63 | // Override if font can provide access to raw data. 64 | // Returns index within OpenType collection 65 | virtual int GetFontIndex() const { return 0; } 66 | 67 | virtual const std::vector& GetAxes() const = 0; 68 | 69 | virtual std::shared_ptr createFontWithVariation( 70 | const std::vector&) const { 71 | return nullptr; 72 | } 73 | 74 | static uint32_t MakeTag(char c1, char c2, char c3, char c4) { 75 | return ((uint32_t)c1 << 24) | ((uint32_t)c2 << 16) | ((uint32_t)c3 << 8) | (uint32_t)c4; 76 | } 77 | 78 | int32_t GetUniqueId() const { return mUniqueId; } 79 | 80 | private: 81 | const int32_t mUniqueId; 82 | }; 83 | 84 | } // namespace minikin 85 | 86 | #endif // MINIKIN_MINIKIN_FONT_H 87 | -------------------------------------------------------------------------------- /libs/minikin/FontUtils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "FontUtils.h" 18 | 19 | #include 20 | 21 | #include 22 | 23 | namespace minikin { 24 | 25 | static uint16_t readU16(const uint8_t* data, size_t offset) { 26 | return data[offset] << 8 | data[offset + 1]; 27 | } 28 | 29 | static uint32_t readU32(const uint8_t* data, size_t offset) { 30 | return ((uint32_t)data[offset]) << 24 | ((uint32_t)data[offset + 1]) << 16 | 31 | ((uint32_t)data[offset + 2]) << 8 | ((uint32_t)data[offset + 3]); 32 | } 33 | 34 | bool analyzeStyle(const uint8_t* os2_data, size_t os2_size, int* weight, bool* italic) { 35 | const size_t kUsWeightClassOffset = 4; 36 | const size_t kFsSelectionOffset = 62; 37 | const uint16_t kItalicFlag = (1 << 0); 38 | if (os2_size < kFsSelectionOffset + 2) { 39 | return false; 40 | } 41 | uint16_t weightClass = readU16(os2_data, kUsWeightClassOffset); 42 | *weight = weightClass; 43 | uint16_t fsSelection = readU16(os2_data, kFsSelectionOffset); 44 | *italic = (fsSelection & kItalicFlag) != 0; 45 | return true; 46 | } 47 | 48 | bool analyzeAxes(const uint8_t* fvar_data, size_t fvar_size, std::unordered_set* axes) { 49 | const size_t kMajorVersionOffset = 0; 50 | const size_t kMinorVersionOffset = 2; 51 | const size_t kOffsetToAxesArrayOffset = 4; 52 | const size_t kAxisCountOffset = 8; 53 | const size_t kAxisSizeOffset = 10; 54 | 55 | axes->clear(); 56 | 57 | if (fvar_size < kAxisSizeOffset + 2) { 58 | return false; 59 | } 60 | const uint16_t majorVersion = readU16(fvar_data, kMajorVersionOffset); 61 | const uint16_t minorVersion = readU16(fvar_data, kMinorVersionOffset); 62 | const uint32_t axisOffset = readU16(fvar_data, kOffsetToAxesArrayOffset); 63 | const uint32_t axisCount = readU16(fvar_data, kAxisCountOffset); 64 | const uint32_t axisSize = readU16(fvar_data, kAxisSizeOffset); 65 | 66 | if (majorVersion != 1 || minorVersion != 0 || axisOffset != 0x10 || axisSize != 0x14) { 67 | return false; // Unsupported version. 68 | } 69 | if (fvar_size < axisOffset + axisSize * axisCount) { 70 | if (axisOffset > axisSize) { 71 | android_errorWriteLog(0x534e4554, "77822336"); 72 | } 73 | return false; // Invalid table size. 74 | } 75 | for (uint32_t i = 0; i < axisCount; ++i) { 76 | size_t axisRecordOffset = axisOffset + i * axisSize; 77 | uint32_t tag = readU32(fvar_data, axisRecordOffset); 78 | axes->insert(tag); 79 | } 80 | return true; 81 | } 82 | } // namespace minikin 83 | -------------------------------------------------------------------------------- /libs/minikin/LayoutUtils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "LayoutUtils.h" 18 | 19 | namespace minikin { 20 | 21 | /* 22 | * Determine whether the code unit is a word space for the purposes of justification. 23 | * TODO: Support NBSP and other stretchable whitespace (b/34013491 and b/68204709). 24 | */ 25 | bool isWordSpace(uint16_t code_unit) { 26 | return code_unit == ' '; 27 | } 28 | 29 | /** 30 | * For the purpose of layout, a word break is a boundary with no 31 | * kerning or complex script processing. This is necessarily a 32 | * heuristic, but should be accurate most of the time. 33 | */ 34 | static bool isWordBreakAfter(uint16_t c) { 35 | if (c == ' ' || (0x2000 <= c && c <= 0x200A) || c == 0x3000) { 36 | // spaces 37 | return true; 38 | } 39 | // Break layout context before and after BiDi control character. 40 | if ((0x2066 <= c && c <= 0x2069) || (0x202A <= c && c <= 0x202E) || c == 0x200E || 41 | c == 0x200F) { 42 | return true; 43 | } 44 | // Note: kana is not included, as sophisticated fonts may kern kana 45 | return false; 46 | } 47 | 48 | static bool isWordBreakBefore(uint16_t c) { 49 | // CJK ideographs (and yijing hexagram symbols) 50 | return isWordBreakAfter(c) || (0x3400 <= c && c <= 0x9FFF); 51 | } 52 | 53 | /** 54 | * Return offset of previous word break. It is either < offset or == 0. 55 | */ 56 | uint32_t getPrevWordBreakForCache(const U16StringPiece& textBuf, uint32_t offset) { 57 | if (offset == 0) return 0; 58 | if (offset > textBuf.size()) offset = textBuf.size(); 59 | if (isWordBreakBefore(textBuf[offset - 1])) { 60 | return offset - 1; 61 | } 62 | for (uint32_t i = offset - 1; i > 0; i--) { 63 | if (isWordBreakBefore(textBuf[i]) || isWordBreakAfter(textBuf[i - 1])) { 64 | return i; 65 | } 66 | } 67 | return 0; 68 | } 69 | 70 | /** 71 | * Return offset of next word break. It is either > offset or == len. 72 | */ 73 | uint32_t getNextWordBreakForCache(const U16StringPiece& textBuf, uint32_t offset) { 74 | if (offset >= textBuf.size()) return textBuf.size(); 75 | if (isWordBreakAfter(textBuf[offset])) { 76 | return offset + 1; 77 | } 78 | for (uint32_t i = offset + 1; i < textBuf.size(); i++) { 79 | // No need to check isWordBreakAfter(chars[i - 1]) since it is checked 80 | // in previous iteration. Note that isWordBreakBefore returns true 81 | // whenever isWordBreakAfter returns true. 82 | if (isWordBreakBefore(textBuf[i])) { 83 | return i; 84 | } 85 | } 86 | return textBuf.size(); 87 | } 88 | 89 | } // namespace minikin 90 | -------------------------------------------------------------------------------- /tests/perftests/GraphemeBreak.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "minikin/GraphemeBreak.h" 18 | 19 | #include 20 | #include 21 | 22 | #include "UnicodeUtils.h" 23 | 24 | namespace minikin { 25 | 26 | const char* ASCII_TEST_STR = "'L' 'o' 'r' 'e' 'm' ' ' 'i' 'p' 's' 'u' 'm' '.'"; 27 | // U+261D: WHITE UP POINTING INDEX 28 | // U+1F3FD: EMOJI MODIFIER FITZPATRICK TYPE-4 29 | const char* EMOJI_TEST_STR = "U+261D U+1F3FD U+261D U+1F3FD U+261D U+1F3FD U+261D U+1F3FD"; 30 | // U+1F1FA: REGIONAL INDICATOR SYMBOL LETTER U 31 | // U+1F1F8: REGIONAL INDICATOR SYMBOL LETTER S 32 | const char* FLAGS_TEST_STR = "U+1F1FA U+1F1F8 U+1F1FA U+1F1F8 U+1F1FA U+1F1F8"; 33 | 34 | // TODO: Migrate BENCHMARK_CAPTURE for parameterizing. 35 | static void BM_GraphemeBreak_Ascii(benchmark::State& state) { 36 | size_t result_size; 37 | uint16_t buffer[12]; 38 | ParseUnicode(buffer, 12, ASCII_TEST_STR, &result_size, nullptr); 39 | LOG_ALWAYS_FATAL_IF(result_size != 12); 40 | const size_t testIndex = state.range(0); 41 | while (state.KeepRunning()) { 42 | GraphemeBreak::isGraphemeBreak(nullptr, buffer, 0, result_size, testIndex); 43 | } 44 | } 45 | BENCHMARK(BM_GraphemeBreak_Ascii) 46 | ->Arg(0) // Begining of the text. 47 | ->Arg(1) // Middle of the text. 48 | ->Arg(12); // End of the text. 49 | 50 | static void BM_GraphemeBreak_Emoji(benchmark::State& state) { 51 | size_t result_size; 52 | uint16_t buffer[12]; 53 | ParseUnicode(buffer, 12, EMOJI_TEST_STR, &result_size, nullptr); 54 | LOG_ALWAYS_FATAL_IF(result_size != 12); 55 | const size_t testIndex = state.range(0); 56 | while (state.KeepRunning()) { 57 | GraphemeBreak::isGraphemeBreak(nullptr, buffer, 0, result_size, testIndex); 58 | } 59 | } 60 | BENCHMARK(BM_GraphemeBreak_Emoji) 61 | ->Arg(1) // Middle of emoji modifier sequence. 62 | ->Arg(2) // Middle of the surrogate pairs. 63 | ->Arg(3); // After emoji modifier sequence. Here is boundary of grapheme cluster. 64 | 65 | static void BM_GraphemeBreak_Emoji_Flags(benchmark::State& state) { 66 | size_t result_size; 67 | uint16_t buffer[12]; 68 | ParseUnicode(buffer, 12, FLAGS_TEST_STR, &result_size, nullptr); 69 | LOG_ALWAYS_FATAL_IF(result_size != 12); 70 | const size_t testIndex = state.range(0); 71 | while (state.KeepRunning()) { 72 | GraphemeBreak::isGraphemeBreak(nullptr, buffer, 0, result_size, testIndex); 73 | } 74 | } 75 | BENCHMARK(BM_GraphemeBreak_Emoji_Flags) 76 | ->Arg(2) // Middle of flag sequence. 77 | ->Arg(4) // After flag sequence. Here is boundary of grapheme cluster. 78 | ->Arg(10); // Middle of 3rd flag sequence. 79 | 80 | } // namespace minikin 81 | -------------------------------------------------------------------------------- /include/minikin/FontFamily.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_FONT_FAMILY_H 18 | #define MINIKIN_FONT_FAMILY_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "minikin/FamilyVariant.h" 26 | #include "minikin/Font.h" 27 | #include "minikin/FontStyle.h" 28 | #include "minikin/HbUtils.h" 29 | #include "minikin/Macros.h" 30 | #include "minikin/SparseBitSet.h" 31 | 32 | namespace minikin { 33 | 34 | class FontFamily { 35 | public: 36 | explicit FontFamily(std::vector&& fonts); 37 | FontFamily(FamilyVariant variant, std::vector&& fonts); 38 | FontFamily(uint32_t localeListId, FamilyVariant variant, std::vector&& fonts, 39 | bool isCustomFallback); 40 | 41 | FakedFont getClosestMatch(FontStyle style) const; 42 | 43 | uint32_t localeListId() const { return mLocaleListId; } 44 | FamilyVariant variant() const { return mVariant; } 45 | 46 | // API's for enumerating the fonts in a family. These don't guarantee any particular order 47 | size_t getNumFonts() const { return mFonts.size(); } 48 | const Font* getFont(size_t index) const { return &mFonts[index]; } 49 | FontStyle getStyle(size_t index) const { return mFonts[index].style(); } 50 | bool isColorEmojiFamily() const { return mIsColorEmoji; } 51 | const std::unordered_set& supportedAxes() const { return mSupportedAxes; } 52 | bool isCustomFallback() const { return mIsCustomFallback; } 53 | 54 | // Get Unicode coverage. 55 | const SparseBitSet& getCoverage() const { return mCoverage; } 56 | 57 | // Returns true if the font has a glyph for the code point and variation selector pair. 58 | // Caller should acquire a lock before calling the method. 59 | bool hasGlyph(uint32_t codepoint, uint32_t variationSelector) const; 60 | 61 | // Returns true if this font family has a variaion sequence table (cmap format 14 subtable). 62 | bool hasVSTable() const { return !mCmapFmt14Coverage.empty(); } 63 | 64 | // Creates new FontFamily based on this family while applying font variations. Returns nullptr 65 | // if none of variations apply to this family. 66 | std::shared_ptr createFamilyWithVariation( 67 | const std::vector& variations) const; 68 | 69 | private: 70 | void computeCoverage(); 71 | 72 | uint32_t mLocaleListId; 73 | FamilyVariant mVariant; 74 | std::vector mFonts; 75 | std::unordered_set mSupportedAxes; 76 | bool mIsColorEmoji; 77 | bool mIsCustomFallback; 78 | 79 | SparseBitSet mCoverage; 80 | std::vector> mCmapFmt14Coverage; 81 | 82 | MINIKIN_PREVENT_COPY_AND_ASSIGN(FontFamily); 83 | }; 84 | 85 | } // namespace minikin 86 | 87 | #endif // MINIKIN_FONT_FAMILY_H 88 | -------------------------------------------------------------------------------- /libs/minikin/HyphenatorMap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_HYPHENATOR_MAP_H 18 | #define MINIKIN_HYPHENATOR_MAP_H 19 | 20 | #include 21 | #include 22 | 23 | #include "minikin/Hyphenator.h" 24 | #include "minikin/Macros.h" 25 | 26 | #include "Locale.h" 27 | 28 | namespace minikin { 29 | 30 | class HyphenatorMap { 31 | public: 32 | // This map doesn't take ownership of the hyphenator but we don't need to care about the 33 | // ownership. In Android, the Hyphenator is allocated in Zygote and never gets released. 34 | static void add(const std::string& localeStr, const Hyphenator* hyphenator) { 35 | getInstance().addInternal(localeStr, hyphenator); 36 | } 37 | 38 | static void addAlias(const std::string& fromLocaleStr, const std::string& toLocaleStr) { 39 | getInstance().addAliasInternal(fromLocaleStr, toLocaleStr); 40 | } 41 | 42 | // Remove all hyphenators from the map. This is test only method. 43 | static void clear() { getInstance().clearInternal(); } 44 | 45 | // The returned pointer is never a dangling pointer. If nothing found for a given locale, 46 | // returns a hyphenator which only processes soft hyphens. 47 | // 48 | // The Hyphenator lookup works with the following rules: 49 | // 1. Search for the Hyphenator with the given locale. 50 | // 2. If not found, try again with language + script + region + variant. 51 | // 3. If not found, try again with language + region + variant. 52 | // 4. If not found, try again with language + variant. 53 | // 5. If not found, try again with language. 54 | // 6. If not found, try again with script. 55 | static const Hyphenator* lookup(const Locale& locale) { 56 | return getInstance().lookupInternal(locale); 57 | } 58 | 59 | protected: 60 | // The following five methods are protected for testing purposes. 61 | HyphenatorMap(); // Use getInstance() instead. 62 | void addInternal(const std::string& localeStr, const Hyphenator* hyphenator); 63 | void addAliasInternal(const std::string& fromLocaleStr, const std::string& toLocaleStr); 64 | const Hyphenator* lookupInternal(const Locale& locale); 65 | 66 | private: 67 | static HyphenatorMap& getInstance() { // Singleton. 68 | static HyphenatorMap map; 69 | return map; 70 | } 71 | 72 | void clearInternal(); 73 | 74 | const Hyphenator* lookupByIdentifier(uint64_t id) const EXCLUSIVE_LOCKS_REQUIRED(mMutex); 75 | const Hyphenator* lookupBySubtag(const Locale& locale, SubtagBits bits) const 76 | EXCLUSIVE_LOCKS_REQUIRED(mMutex); 77 | 78 | const Hyphenator* mSoftHyphenOnlyHyphenator; 79 | std::map mMap GUARDED_BY(mMutex); 80 | 81 | std::mutex mMutex; 82 | }; 83 | 84 | } // namespace minikin 85 | 86 | #endif // MINIKIN_HYPHENATOR_MAP_H 87 | -------------------------------------------------------------------------------- /include/minikin/LayoutCore.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_LAYOUT_CORE_H 18 | #define MINIKIN_LAYOUT_CORE_H 19 | 20 | #include 21 | 22 | #include 23 | 24 | #include "minikin/FontFamily.h" 25 | #include "minikin/Hyphenator.h" 26 | #include "minikin/MinikinExtent.h" 27 | #include "minikin/MinikinFont.h" 28 | #include "minikin/MinikinRect.h" 29 | #include "minikin/Range.h" 30 | #include "minikin/U16StringPiece.h" 31 | 32 | namespace minikin { 33 | 34 | struct MinikinPaint; 35 | 36 | struct Point { 37 | Point() : x(0), y(0) {} 38 | Point(float x, float y) : x(x), y(y) {} 39 | bool operator==(const Point& o) const { return x == o.x && y == o.y; } 40 | float x; 41 | float y; 42 | }; 43 | 44 | // Immutable, recycle-able layout result. 45 | class LayoutPiece { 46 | public: 47 | LayoutPiece(const U16StringPiece& textBuf, const Range& range, bool isRtl, 48 | const MinikinPaint& paint, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen); 49 | 50 | // Low level accessors. 51 | const std::vector& fontIndices() const { return mFontIndices; } 52 | const std::vector glyphIds() const { return mGlyphIds; } 53 | const std::vector points() const { return mPoints; } 54 | const std::vector advances() const { return mAdvances; } 55 | float advance() const { return mAdvance; } 56 | const MinikinRect& bounds() const { return mBounds; } 57 | const MinikinExtent& extent() const { return mExtent; } 58 | const std::vector& fonts() const { return mFonts; } 59 | 60 | // Helper accessors 61 | uint32_t glyphCount() const { return mGlyphIds.size(); } 62 | const FakedFont& fontAt(int glyphPos) const { return mFonts[mFontIndices[glyphPos]]; } 63 | uint32_t glyphIdAt(int glyphPos) const { return mGlyphIds[glyphPos]; } 64 | const Point& pointAt(int glyphPos) const { return mPoints[glyphPos]; } 65 | 66 | uint32_t getMemoryUsage() const { 67 | return sizeof(uint8_t) * mFontIndices.size() + sizeof(uint32_t) * mGlyphIds.size() + 68 | sizeof(Point) * mPoints.size() + sizeof(float) * mAdvances.size() + sizeof(float) + 69 | sizeof(MinikinRect) + sizeof(MinikinExtent); 70 | } 71 | 72 | private: 73 | FRIEND_TEST(LayoutTest, doLayoutWithPrecomputedPiecesTest); 74 | 75 | std::vector mFontIndices; // per glyph 76 | std::vector mGlyphIds; // per glyph 77 | std::vector mPoints; // per glyph 78 | 79 | std::vector mAdvances; // per code units 80 | 81 | float mAdvance; 82 | MinikinRect mBounds; 83 | MinikinExtent mExtent; 84 | 85 | std::vector mFonts; 86 | }; 87 | 88 | // For gtest output 89 | inline std::ostream& operator<<(std::ostream& os, const Point& p) { 90 | return os << "(" << p.x << ", " << p.y << ")"; 91 | } 92 | } // namespace minikin 93 | 94 | #endif // MINIKIN_LAYOUT_CORE_H 95 | -------------------------------------------------------------------------------- /tests/stresstest/MultithreadTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "minikin/Layout.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #include "minikin/FontCollection.h" 28 | #include "minikin/Macros.h" 29 | #include "minikin/MinikinPaint.h" 30 | 31 | #include "FontTestUtils.h" 32 | #include "MinikinInternal.h" 33 | #include "PathUtils.h" 34 | 35 | namespace minikin { 36 | 37 | constexpr int LAYOUT_COUNT_PER_COLLECTION = 500; 38 | constexpr int COLLECTION_COUNT_PER_THREAD = 15; 39 | constexpr int NUM_THREADS = 10; 40 | 41 | std::mutex gMutex; 42 | std::condition_variable gCv; 43 | bool gReady GUARDED_BY(gMutex) = false; 44 | 45 | static std::vector generateTestText(std::mt19937* mt, int lettersInWord, 46 | int wordsInText) { 47 | std::uniform_int_distribution dist('A', 'Z'); 48 | 49 | std::vector text; 50 | text.reserve((lettersInWord + 1) * wordsInText - 1); 51 | for (int i = 0; i < wordsInText; ++i) { 52 | if (i != 0) { 53 | text.emplace_back(' '); 54 | } 55 | for (int j = 0; j < lettersInWord; ++j) { 56 | text.emplace_back(dist(*mt)); 57 | } 58 | } 59 | return text; 60 | } 61 | 62 | static void thread_main(int tid) { 63 | { 64 | // Wait until all threads are created. 65 | std::unique_lock lock(gMutex); 66 | gCv.wait(lock, [] { return gReady; }); 67 | } 68 | 69 | std::mt19937 mt(tid); 70 | 71 | for (int i = 0; i < COLLECTION_COUNT_PER_THREAD; ++i) { 72 | MinikinPaint paint(buildFontCollection("Ascii.ttf")); 73 | paint.size = 10.0f; // Make 1em = 10px 74 | 75 | for (int j = 0; j < LAYOUT_COUNT_PER_COLLECTION; ++j) { 76 | // Generates 10 of 3-letter words so that the word sometimes hit the cache. 77 | std::vector text = generateTestText(&mt, 3, 10); 78 | Layout layout(text, Range(0, text.size()), Bidi::LTR, paint, StartHyphenEdit::NO_EDIT, 79 | EndHyphenEdit::NO_EDIT); 80 | for (size_t k = 0; k < text.size(); ++k) { 81 | // All characters in Ascii.ttf has 1.0em horizontal advance. 82 | LOG_ALWAYS_FATAL_IF(layout.getCharAdvance(k) != 10.0f, 83 | "Memory corruption detected."); 84 | } 85 | } 86 | } 87 | } 88 | 89 | TEST(MultithreadTest, ThreadSafeStressTest) { 90 | std::vector threads; 91 | 92 | { 93 | std::unique_lock lock(gMutex); 94 | threads.reserve(NUM_THREADS); 95 | for (int i = 0; i < NUM_THREADS; ++i) { 96 | threads.emplace_back(&thread_main, i); 97 | } 98 | gReady = true; 99 | } 100 | gCv.notify_all(); 101 | 102 | for (auto& thread : threads) { 103 | thread.join(); 104 | } 105 | } 106 | 107 | } // namespace minikin 108 | -------------------------------------------------------------------------------- /include/minikin/SparseBitSet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_SPARSE_BIT_SET_H 18 | #define MINIKIN_SPARSE_BIT_SET_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | // --------------------------------------------------------------------------- 25 | 26 | namespace minikin { 27 | 28 | // This is an implementation of a set of integers. It is optimized for 29 | // values that are somewhat sparse, in the ballpark of a maximum value 30 | // of thousands to millions. It is particularly efficient when there are 31 | // large gaps. The motivating example is Unicode coverage of a font, but 32 | // the abstraction itself is fully general. 33 | class SparseBitSet { 34 | public: 35 | // Create an empty bit set. 36 | SparseBitSet() : mMaxVal(0) {} 37 | 38 | // Initialize the set to a new value, represented by ranges. For 39 | // simplicity, these ranges are arranged as pairs of values, 40 | // inclusive of start, exclusive of end, laid out in a uint32 array. 41 | SparseBitSet(const uint32_t* ranges, size_t nRanges) : SparseBitSet() { 42 | initFromRanges(ranges, nRanges); 43 | } 44 | 45 | SparseBitSet(SparseBitSet&&) = default; 46 | SparseBitSet& operator=(SparseBitSet&&) = default; 47 | 48 | // Determine whether the value is included in the set 49 | bool get(uint32_t ch) const { 50 | if (ch >= mMaxVal) return false; 51 | const uint32_t* bitmap = &mBitmaps[mIndices[ch >> kLogValuesPerPage]]; 52 | uint32_t index = ch & kPageMask; 53 | return (bitmap[index >> kLogBitsPerEl] & (kElFirst >> (index & kElMask))) != 0; 54 | } 55 | 56 | // One more than the maximum value in the set, or zero if empty 57 | uint32_t length() const { return mMaxVal; } 58 | 59 | // The next set bit starting at fromIndex, inclusive, or kNotFound 60 | // if none exists. 61 | uint32_t nextSetBit(uint32_t fromIndex) const; 62 | 63 | static const uint32_t kNotFound = ~0u; 64 | 65 | private: 66 | void initFromRanges(const uint32_t* ranges, size_t nRanges); 67 | 68 | static const uint32_t kMaximumCapacity = 0xFFFFFF; 69 | static const int kLogValuesPerPage = 8; 70 | static const int kPageMask = (1 << kLogValuesPerPage) - 1; 71 | static const int kLogBytesPerEl = 2; 72 | static const int kLogBitsPerEl = kLogBytesPerEl + 3; 73 | static const int kElMask = (1 << kLogBitsPerEl) - 1; 74 | // invariant: sizeof(element) == (1 << kLogBytesPerEl) 75 | typedef uint32_t element; 76 | static const element kElAllOnes = ~((element)0); 77 | static const element kElFirst = ((element)1) << kElMask; 78 | static const uint16_t noZeroPage = 0xFFFF; 79 | 80 | static uint32_t calcNumPages(const uint32_t* ranges, size_t nRanges); 81 | static int CountLeadingZeros(element x); 82 | 83 | uint32_t mMaxVal; 84 | 85 | std::unique_ptr mIndices; 86 | std::unique_ptr mBitmaps; 87 | uint16_t mZeroPageIndex; 88 | 89 | // Forbid copy and assign. 90 | SparseBitSet(const SparseBitSet&) = delete; 91 | void operator=(const SparseBitSet&) = delete; 92 | }; 93 | 94 | } // namespace minikin 95 | 96 | #endif // MINIKIN_SPARSE_BIT_SET_H 97 | -------------------------------------------------------------------------------- /libs/minikin/StringPiece.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_STRING_PIECE_H 18 | #define MINIKIN_STRING_PIECE_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace minikin { 25 | 26 | class StringPiece { 27 | public: 28 | StringPiece() : mData(nullptr), mLength(0) {} 29 | StringPiece(const char* data) : mData(data), mLength(data == nullptr ? 0 : strlen(data)) {} 30 | StringPiece(const char* data, size_t length) : mData(data), mLength(length) {} 31 | StringPiece(const std::string& str) : mData(str.data()), mLength(str.size()) {} 32 | 33 | inline const char* data() const { return mData; } 34 | inline size_t length() const { return mLength; } 35 | inline size_t size() const { return mLength; } 36 | inline bool empty() const { return mLength == 0; } 37 | 38 | inline char operator[](size_t i) const { return mData[i]; } 39 | 40 | inline StringPiece substr(size_t from, size_t length) const { 41 | return StringPiece(mData + from, length); 42 | } 43 | 44 | inline size_t find(size_t from, char c) const { 45 | if (from >= mLength) { 46 | return mLength; 47 | } 48 | const char* p = static_cast(memchr(mData + from, c, mLength - from)); 49 | return p == nullptr ? mLength : p - mData; 50 | } 51 | 52 | std::string toString() const { return std::string(mData, mData + mLength); } 53 | 54 | private: 55 | const char* mData; 56 | size_t mLength; 57 | }; 58 | 59 | inline bool operator==(const StringPiece& l, const StringPiece& r) { 60 | const size_t len = l.size(); 61 | if (len != r.size()) { 62 | return false; 63 | } 64 | const char* lData = l.data(); 65 | const char* rData = r.data(); 66 | if (lData == rData) { 67 | return true; 68 | } 69 | return memcmp(lData, rData, len) == 0; 70 | } 71 | 72 | inline bool operator==(const StringPiece& l, const char* s) { 73 | const size_t len = l.size(); 74 | if (len != strlen(s)) { 75 | return false; 76 | } 77 | return memcmp(l.data(), s, len) == 0; 78 | } 79 | 80 | inline bool operator!=(const StringPiece& l, const StringPiece& r) { 81 | return !(l == r); 82 | } 83 | 84 | inline bool operator!=(const StringPiece& l, const char* s) { 85 | return !(l == s); 86 | } 87 | 88 | class SplitIterator { 89 | public: 90 | SplitIterator(const StringPiece& string, char delimiter) 91 | : mStarted(false), mCurrent(0), mString(string), mDelimiter(delimiter) {} 92 | 93 | inline StringPiece next() { 94 | if (!hasNext()) { 95 | return StringPiece(); 96 | } 97 | const size_t searchFrom = mStarted ? mCurrent + 1 : 0; 98 | mStarted = true; 99 | mCurrent = mString.find(searchFrom, mDelimiter); 100 | return mString.substr(searchFrom, mCurrent - searchFrom); 101 | } 102 | inline bool hasNext() const { return mCurrent < mString.size(); } 103 | 104 | private: 105 | bool mStarted; 106 | size_t mCurrent; 107 | StringPiece mString; 108 | char mDelimiter; 109 | }; 110 | 111 | } // namespace minikin 112 | 113 | #endif // MINIKIN_STRING_PIECE_H 114 | -------------------------------------------------------------------------------- /include/minikin/MinikinPaint.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_MINIKIN_PAINT_H 18 | #define MINIKIN_MINIKIN_PAINT_H 19 | 20 | #include 21 | #include 22 | 23 | #include "minikin/FamilyVariant.h" 24 | #include "minikin/FontCollection.h" 25 | #include "minikin/FontFamily.h" 26 | #include "minikin/Hasher.h" 27 | 28 | namespace minikin { 29 | 30 | class FontCollection; 31 | 32 | // These describe what is stored in MinikinPaint.fontFlags. 33 | enum MinikinFontFlags { 34 | Embolden_Shift = 0, 35 | LinearMetrics_Shift = 1, 36 | Subpixel_Shift = 2, 37 | EmbeddedBitmaps_Shift = 3, 38 | ForceAutoHinting_Shift = 4, 39 | 40 | Embolden_Flag = 1 << Embolden_Shift, 41 | LinearMetrics_Flag = 1 << LinearMetrics_Shift, 42 | Subpixel_Flag = 1 << Subpixel_Shift, 43 | EmbeddedBitmaps_Flag = 1 << EmbeddedBitmaps_Shift, 44 | ForceAutoHinting_Flag = 1 << ForceAutoHinting_Shift, 45 | }; 46 | 47 | // Possibly move into own .h file? 48 | // Note: if you add a field here, either add it to LayoutCacheKey or to skipCache() 49 | struct MinikinPaint { 50 | MinikinPaint(const std::shared_ptr& font) 51 | : size(0), 52 | scaleX(0), 53 | skewX(0), 54 | letterSpacing(0), 55 | wordSpacing(0), 56 | fontFlags(0), 57 | localeListId(0), 58 | familyVariant(FamilyVariant::DEFAULT), 59 | fontFeatureSettings(), 60 | font(font) {} 61 | 62 | bool skipCache() const { return !fontFeatureSettings.empty(); } 63 | 64 | float size; 65 | float scaleX; 66 | float skewX; 67 | float letterSpacing; 68 | float wordSpacing; 69 | uint32_t fontFlags; 70 | uint32_t localeListId; 71 | FontStyle fontStyle; 72 | FamilyVariant familyVariant; 73 | std::string fontFeatureSettings; 74 | std::shared_ptr font; 75 | 76 | void copyFrom(const MinikinPaint& paint) { *this = paint; } 77 | 78 | MinikinPaint(const MinikinPaint&) = default; 79 | MinikinPaint& operator=(const MinikinPaint&) = default; 80 | 81 | MinikinPaint(MinikinPaint&&) = default; 82 | MinikinPaint& operator=(MinikinPaint&&) = default; 83 | 84 | inline bool operator==(const MinikinPaint& paint) const { 85 | return size == paint.size && scaleX == paint.scaleX && skewX == paint.skewX && 86 | letterSpacing == paint.letterSpacing && wordSpacing == paint.wordSpacing && 87 | fontFlags == paint.fontFlags && localeListId == paint.localeListId && 88 | fontStyle == paint.fontStyle && familyVariant == paint.familyVariant && 89 | fontFeatureSettings == paint.fontFeatureSettings && font.get() == paint.font.get(); 90 | } 91 | 92 | uint32_t hash() const { 93 | return Hasher() 94 | .update(size) 95 | .update(scaleX) 96 | .update(skewX) 97 | .update(letterSpacing) 98 | .update(wordSpacing) 99 | .update(fontFlags) 100 | .update(localeListId) 101 | .update(fontStyle.identifier()) 102 | .update(static_cast(familyVariant)) 103 | .updateString(fontFeatureSettings) 104 | .update(font->getId()) 105 | .hash(); 106 | } 107 | }; 108 | 109 | } // namespace minikin 110 | 111 | #endif // MINIKIN_MINIKIN_PAINT_H 112 | -------------------------------------------------------------------------------- /include/minikin/LineBreaker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * A module for breaking paragraphs into lines, supporting high quality 19 | * hyphenation and justification. 20 | */ 21 | 22 | #ifndef MINIKIN_LINE_BREAKER_H 23 | #define MINIKIN_LINE_BREAKER_H 24 | 25 | #include 26 | #include 27 | 28 | #include "minikin/FontCollection.h" 29 | #include "minikin/Layout.h" 30 | #include "minikin/Macros.h" 31 | #include "minikin/MeasuredText.h" 32 | #include "minikin/MinikinFont.h" 33 | #include "minikin/Range.h" 34 | #include "minikin/U16StringPiece.h" 35 | 36 | namespace minikin { 37 | 38 | enum class BreakStrategy : uint8_t { 39 | Greedy = 0, 40 | HighQuality = 1, 41 | Balanced = 2, 42 | }; 43 | 44 | enum class HyphenationFrequency : uint8_t { 45 | None = 0, 46 | Normal = 1, 47 | Full = 2, 48 | }; 49 | 50 | class Hyphenator; 51 | class WordBreaker; 52 | 53 | class TabStops { 54 | public: 55 | // Caller must free stops. stops can be nullprt. 56 | TabStops(const float* stops, size_t nStops, float tabWidth) 57 | : mStops(stops), mStopsSize(nStops), mTabWidth(tabWidth) {} 58 | 59 | float nextTab(float widthSoFar) const { 60 | for (size_t i = 0; i < mStopsSize; i++) { 61 | if (mStops[i] > widthSoFar) { 62 | return mStops[i]; 63 | } 64 | } 65 | return floor(widthSoFar / mTabWidth + 1) * mTabWidth; 66 | } 67 | 68 | private: 69 | const float* mStops; 70 | size_t mStopsSize; 71 | float mTabWidth; 72 | }; 73 | 74 | // Implement this for the additional information during line breaking. 75 | // The functions in this class's interface may be called several times. The implementation 76 | // must return the same value for the same input. 77 | class LineWidth { 78 | public: 79 | virtual ~LineWidth() {} 80 | 81 | // Called to find out the width for the line. This must not return negative values. 82 | virtual float getAt(size_t lineNo) const = 0; 83 | 84 | // Called to find out the minimum line width. This mut not return negative values. 85 | virtual float getMin() const = 0; 86 | }; 87 | 88 | struct LineBreakResult { 89 | public: 90 | LineBreakResult() = default; 91 | 92 | // Following five vectors have the same length. 93 | // TODO: Introduce individual line info struct if copy cost in JNI is negligible. 94 | std::vector breakPoints; 95 | std::vector widths; 96 | std::vector ascents; 97 | std::vector descents; 98 | std::vector flags; 99 | 100 | LineBreakResult(LineBreakResult&&) = default; 101 | LineBreakResult& operator=(LineBreakResult&&) = default; 102 | 103 | void reverse() { 104 | std::reverse(breakPoints.begin(), breakPoints.end()); 105 | std::reverse(widths.begin(), widths.end()); 106 | std::reverse(ascents.begin(), ascents.end()); 107 | std::reverse(descents.begin(), descents.end()); 108 | std::reverse(flags.begin(), flags.end()); 109 | } 110 | 111 | private: 112 | MINIKIN_PREVENT_COPY_AND_ASSIGN(LineBreakResult); 113 | }; 114 | 115 | LineBreakResult breakIntoLines(const U16StringPiece& textBuffer, BreakStrategy strategy, 116 | HyphenationFrequency frequency, bool justified, 117 | const MeasuredText& measuredText, const LineWidth& lineWidth, 118 | const TabStops& tabStops); 119 | 120 | } // namespace minikin 121 | 122 | #endif // MINIKIN_LINE_BREAKER_H 123 | -------------------------------------------------------------------------------- /tests/perftests/FontCollection.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "minikin/FontCollection.h" 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "minikin/LocaleList.h" 24 | #include "minikin/MinikinPaint.h" 25 | 26 | #include "FontTestUtils.h" 27 | #include "MinikinInternal.h" 28 | #include "UnicodeUtils.h" 29 | 30 | namespace minikin { 31 | 32 | const char* SYSTEM_FONT_PATH = "/system/fonts/"; 33 | const char* SYSTEM_FONT_XML = "/system/etc/fonts.xml"; 34 | 35 | static void BM_FontCollection_construct(benchmark::State& state) { 36 | std::vector> families = 37 | getFontFamilies(SYSTEM_FONT_PATH, SYSTEM_FONT_XML); 38 | while (state.KeepRunning()) { 39 | std::make_shared(families); 40 | } 41 | } 42 | 43 | BENCHMARK(BM_FontCollection_construct); 44 | 45 | static void BM_FontCollection_hasVariationSelector(benchmark::State& state) { 46 | auto collection = 47 | std::make_shared(getFontFamilies(SYSTEM_FONT_PATH, SYSTEM_FONT_XML)); 48 | 49 | uint32_t baseCp = state.range(0); 50 | uint32_t vsCp = state.range(1); 51 | 52 | char titleBuffer[64]; 53 | snprintf(titleBuffer, 64, "hasVariationSelector U+%04X,U+%04X", baseCp, vsCp); 54 | state.SetLabel(titleBuffer); 55 | 56 | while (state.KeepRunning()) { 57 | collection->hasVariationSelector(baseCp, vsCp); 58 | } 59 | } 60 | 61 | // TODO: Rewrite with BENCHMARK_CAPTURE for better test name. 62 | BENCHMARK(BM_FontCollection_hasVariationSelector) 63 | ->ArgPair(0x2708, 0xFE0F) 64 | ->ArgPair(0x2708, 0xFE0E) 65 | ->ArgPair(0x3402, 0xE0100); 66 | 67 | struct ItemizeTestCases { 68 | std::string itemizeText; 69 | std::string languageTag; 70 | std::string labelText; 71 | } ITEMIZE_TEST_CASES[] = { 72 | {"'A' 'n' 'd' 'r' 'o' 'i' 'd'", "en", "English"}, 73 | {"U+4E16", "zh-Hans", "CJK Ideograph"}, 74 | {"U+4E16", "zh-Hans,zh-Hant,ja,en,es,pt,fr,de", 75 | "CJK Ideograph with many language fallback"}, 76 | {"U+3402 U+E0100", "ja", "CJK Ideograph with variation selector"}, 77 | {"'A' 'n' U+0E1A U+0E31 U+0645 U+062D U+0648", "en", "Mixture of English, Thai and Arabic"}, 78 | {"U+2708 U+FE0E", "en", "Emoji with variation selector"}, 79 | {"U+0031 U+FE0F U+20E3", "en", "KEYCAP"}, 80 | }; 81 | 82 | static void BM_FontCollection_itemize(benchmark::State& state) { 83 | auto collection = 84 | std::make_shared(getFontFamilies(SYSTEM_FONT_PATH, SYSTEM_FONT_XML)); 85 | 86 | size_t testIndex = state.range(0); 87 | state.SetLabel("Itemize: " + ITEMIZE_TEST_CASES[testIndex].labelText); 88 | 89 | uint16_t buffer[64]; 90 | size_t utf16_length = 0; 91 | ParseUnicode(buffer, 64, ITEMIZE_TEST_CASES[testIndex].itemizeText.c_str(), &utf16_length, 92 | nullptr); 93 | std::vector result; 94 | MinikinPaint paint(collection); 95 | paint.localeListId = registerLocaleList(ITEMIZE_TEST_CASES[testIndex].languageTag); 96 | 97 | while (state.KeepRunning()) { 98 | result.clear(); 99 | collection->itemize(U16StringPiece(buffer, utf16_length), paint.fontStyle, 100 | paint.localeListId, paint.familyVariant); 101 | } 102 | } 103 | 104 | // TODO: Rewrite with BENCHMARK_CAPTURE once it is available in Android. 105 | BENCHMARK(BM_FontCollection_itemize)->Arg(0)->Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(5)->Arg(6); 106 | 107 | } // namespace minikin 108 | -------------------------------------------------------------------------------- /include/minikin/LayoutPieces.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_LAYOUT_PIECES_H 18 | #define MINIKIN_LAYOUT_PIECES_H 19 | 20 | #include 21 | 22 | #include "minikin/LayoutCache.h" 23 | #include "minikin/LayoutCore.h" 24 | #include "minikin/MinikinPaint.h" 25 | 26 | namespace minikin { 27 | 28 | struct LayoutPieces { 29 | const static uint32_t kNoPaintId = static_cast(-1); 30 | 31 | struct Key { 32 | Key(const Range& range, HyphenEdit hyphenEdit, bool dir, uint32_t paintId) 33 | : range(range), hyphenEdit(hyphenEdit), dir(dir), paintId(paintId) {} 34 | 35 | Range range; 36 | HyphenEdit hyphenEdit; 37 | bool dir; 38 | uint32_t paintId; 39 | 40 | uint32_t hash() const { 41 | return Hasher() 42 | .update(range.getStart()) 43 | .update(range.getEnd()) 44 | .update(hyphenEdit) 45 | .update(dir) 46 | .update(paintId) 47 | .hash(); 48 | } 49 | 50 | bool operator==(const Key& o) const { 51 | return range == o.range && hyphenEdit == o.hyphenEdit && dir == o.dir && 52 | paintId == o.paintId; 53 | } 54 | 55 | uint32_t getMemoryUsage() const { 56 | return sizeof(Range) + sizeof(HyphenEdit) + sizeof(bool) + sizeof(uint32_t); 57 | } 58 | }; 59 | 60 | struct KeyHasher { 61 | std::size_t operator()(const Key& key) const { return key.hash(); } 62 | }; 63 | 64 | struct PaintHasher { 65 | std::size_t operator()(const MinikinPaint& paint) const { return paint.hash(); } 66 | }; 67 | 68 | LayoutPieces() : nextPaintId(0) {} 69 | ~LayoutPieces() {} 70 | 71 | uint32_t nextPaintId; 72 | std::unordered_map paintMap; 73 | std::unordered_map offsetMap; 74 | 75 | void insert(const Range& range, HyphenEdit edit, const LayoutPiece& layout, bool dir, 76 | const MinikinPaint& paint) { 77 | uint32_t paintId = findPaintId(paint); 78 | if (paintId == kNoPaintId) { 79 | paintId = nextPaintId++; 80 | paintMap.insert(std::make_pair(paint, paintId)); 81 | } 82 | offsetMap.emplace(std::piecewise_construct, 83 | std::forward_as_tuple(range, edit, dir, paintId), 84 | std::forward_as_tuple(layout)); 85 | } 86 | 87 | template 88 | void getOrCreate(const U16StringPiece& textBuf, const Range& range, const Range& context, 89 | const MinikinPaint& paint, bool dir, StartHyphenEdit startEdit, 90 | EndHyphenEdit endEdit, uint32_t paintId, F& f) const { 91 | const HyphenEdit edit = packHyphenEdit(startEdit, endEdit); 92 | auto it = offsetMap.find(Key(range, edit, dir, paintId)); 93 | if (it == offsetMap.end()) { 94 | LayoutCache::getInstance().getOrCreate(textBuf.substr(context), 95 | range - context.getStart(), paint, dir, 96 | startEdit, endEdit, f); 97 | } else { 98 | f(it->second, paint); 99 | } 100 | } 101 | 102 | uint32_t findPaintId(const MinikinPaint& paint) const { 103 | auto paintIt = paintMap.find(paint); 104 | return paintIt == paintMap.end() ? kNoPaintId : paintIt->second; 105 | } 106 | 107 | uint32_t getMemoryUsage() const { 108 | uint32_t result = 0; 109 | for (const auto& i : offsetMap) { 110 | result += i.first.getMemoryUsage() + i.second.getMemoryUsage(); 111 | } 112 | result += (sizeof(MinikinPaint) + sizeof(uint32_t)) * paintMap.size(); 113 | return result; 114 | } 115 | }; 116 | 117 | } // namespace minikin 118 | 119 | #endif // MINIKIN_LAYOUT_PIECES_H 120 | -------------------------------------------------------------------------------- /tests/util/FreeTypeMinikinFontForTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #define LOG_TAG "Minikin" 18 | 19 | #include "FreeTypeMinikinFontForTest.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include FT_OUTLINE_H 31 | 32 | #include "minikin/MinikinExtent.h" 33 | #include "minikin/MinikinFont.h" 34 | #include "minikin/MinikinPaint.h" 35 | #include "minikin/MinikinRect.h" 36 | 37 | namespace minikin { 38 | namespace { 39 | 40 | static int uniqueId = 0; 41 | 42 | constexpr FT_Int32 LOAD_FLAG = 43 | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; 44 | 45 | constexpr float FTPosToFloat(FT_Pos x) { 46 | return x / 64.0; 47 | } 48 | 49 | constexpr FT_F26Dot6 FTFloatToF26Dot6(float x) { 50 | return static_cast(x * 64); 51 | } 52 | 53 | void loadGlyphOrDie(uint32_t glyphId, float size, FT_Face face) { 54 | const FT_F26Dot6 scale = FTFloatToF26Dot6(size); 55 | LOG_ALWAYS_FATAL_IF(FT_Set_Char_Size(face, scale, scale, 72 /* dpi */, 72 /* dpi */), 56 | "Failed to set character size."); 57 | LOG_ALWAYS_FATAL_IF(FT_Load_Glyph(face, glyphId, LOAD_FLAG), "Failed to load glyph"); 58 | LOG_ALWAYS_FATAL_IF(face->glyph->format != FT_GLYPH_FORMAT_OUTLINE, 59 | "Only outline font is supported."); 60 | } 61 | 62 | } // namespace 63 | 64 | FreeTypeMinikinFontForTest::FreeTypeMinikinFontForTest(const std::string& font_path, int index) 65 | : MinikinFont(uniqueId++), mFontPath(font_path), mFontIndex(index) { 66 | int fd = open(font_path.c_str(), O_RDONLY); 67 | LOG_ALWAYS_FATAL_IF(fd == -1, "Open failed: %s", font_path.c_str()); 68 | struct stat st = {}; 69 | LOG_ALWAYS_FATAL_IF(fstat(fd, &st) != 0); 70 | mFontSize = st.st_size; 71 | mFontData = mmap(NULL, mFontSize, PROT_READ, MAP_SHARED, fd, 0); 72 | LOG_ALWAYS_FATAL_IF(mFontData == nullptr); 73 | close(fd); 74 | 75 | LOG_ALWAYS_FATAL_IF(FT_Init_FreeType(&mFtLibrary), "Failed to initialize FreeType"); 76 | 77 | FT_Open_Args args; 78 | args.flags = FT_OPEN_MEMORY; 79 | args.memory_base = static_cast(mFontData); 80 | args.memory_size = mFontSize; 81 | LOG_ALWAYS_FATAL_IF(FT_Open_Face(mFtLibrary, &args, index, &mFtFace), "Failed to open FT_Face"); 82 | } 83 | 84 | FreeTypeMinikinFontForTest::~FreeTypeMinikinFontForTest() { 85 | FT_Done_Face(mFtFace); 86 | FT_Done_FreeType(mFtLibrary); 87 | munmap(mFontData, mFontSize); 88 | } 89 | 90 | float FreeTypeMinikinFontForTest::GetHorizontalAdvance(uint32_t glyphId, const MinikinPaint& paint, 91 | const FontFakery& /* fakery */) const { 92 | loadGlyphOrDie(glyphId, paint.size, mFtFace); 93 | return FTPosToFloat(mFtFace->glyph->advance.x); 94 | } 95 | 96 | void FreeTypeMinikinFontForTest::GetBounds(MinikinRect* bounds, uint32_t glyphId, 97 | const MinikinPaint& paint, 98 | const FontFakery& /* fakery */) const { 99 | loadGlyphOrDie(glyphId, paint.size, mFtFace); 100 | 101 | FT_BBox bbox; 102 | FT_Outline_Get_CBox(&mFtFace->glyph->outline, &bbox); 103 | 104 | bounds->mLeft = FTPosToFloat(bbox.xMin); 105 | bounds->mTop = FTPosToFloat(bbox.yMax); 106 | bounds->mRight = FTPosToFloat(bbox.xMax); 107 | bounds->mBottom = FTPosToFloat(bbox.yMin); 108 | } 109 | 110 | void FreeTypeMinikinFontForTest::GetFontExtent(MinikinExtent* extent, const MinikinPaint& paint, 111 | const FontFakery& /* fakery */) const { 112 | float upem = mFtFace->units_per_EM; 113 | extent->ascent = -static_cast(mFtFace->ascender) * paint.size / upem; 114 | extent->descent = -static_cast(mFtFace->descender) * paint.size / upem; 115 | } 116 | 117 | } // namespace minikin 118 | -------------------------------------------------------------------------------- /libs/minikin/BidiUtils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #define LOG_TAG "Minikin" 18 | 19 | #include "BidiUtils.h" 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include "minikin/Emoji.h" 27 | 28 | #include "MinikinInternal.h" 29 | 30 | namespace minikin { 31 | 32 | static inline UBiDiLevel bidiToUBidiLevel(Bidi bidi) { 33 | switch (bidi) { 34 | case Bidi::LTR: 35 | return 0x00; 36 | case Bidi::RTL: 37 | return 0x01; 38 | case Bidi::DEFAULT_LTR: 39 | return UBIDI_DEFAULT_LTR; 40 | case Bidi::DEFAULT_RTL: 41 | return UBIDI_DEFAULT_RTL; 42 | case Bidi::FORCE_LTR: 43 | case Bidi::FORCE_RTL: 44 | MINIKIN_NOT_REACHED("FORCE_LTR/FORCE_RTL can not be converted to UBiDiLevel."); 45 | return 0x00; 46 | default: 47 | MINIKIN_NOT_REACHED("Unknown Bidi value."); 48 | return 0x00; 49 | } 50 | } 51 | 52 | BidiText::RunInfo BidiText::getRunInfoAt(uint32_t runOffset) const { 53 | MINIKIN_ASSERT(runOffset < mRunCount, "Out of range access. %d/%d", runOffset, mRunCount); 54 | if (mRunCount == 1) { 55 | // Single run. No need to iteract with UBiDi. 56 | return {mRange, mIsRtl}; 57 | } 58 | 59 | int32_t startRun = -1; 60 | int32_t lengthRun = -1; 61 | const UBiDiDirection runDir = ubidi_getVisualRun(mBidi.get(), runOffset, &startRun, &lengthRun); 62 | if (startRun == -1 || lengthRun == -1) { 63 | ALOGE("invalid visual run"); 64 | return {Range::invalidRange(), false}; 65 | } 66 | const uint32_t runStart = std::max(static_cast(startRun), mRange.getStart()); 67 | const uint32_t runEnd = std::min(static_cast(startRun + lengthRun), mRange.getEnd()); 68 | if (runEnd <= runStart) { 69 | // skip the empty run. 70 | return {Range::invalidRange(), false}; 71 | } 72 | return {Range(runStart, runEnd), (runDir == UBIDI_RTL)}; 73 | } 74 | 75 | BidiText::BidiText(const U16StringPiece& textBuf, const Range& range, Bidi bidiFlags) 76 | : mRange(range), mIsRtl(isRtl(bidiFlags)), mRunCount(1 /* by default, single run */) { 77 | if (isOverride(bidiFlags)) { 78 | // force single run. 79 | return; 80 | } 81 | 82 | mBidi.reset(ubidi_open()); 83 | if (!mBidi) { 84 | ALOGE("error creating bidi object"); 85 | return; 86 | } 87 | UErrorCode status = U_ZERO_ERROR; 88 | // Set callbacks to override bidi classes of new emoji 89 | ubidi_setClassCallback(mBidi.get(), emojiBidiOverride, nullptr, nullptr, nullptr, &status); 90 | if (!U_SUCCESS(status)) { 91 | ALOGE("error setting bidi callback function, status = %d", status); 92 | return; 93 | } 94 | 95 | const UBiDiLevel bidiReq = bidiToUBidiLevel(bidiFlags); 96 | ubidi_setPara(mBidi.get(), reinterpret_cast(textBuf.data()), textBuf.size(), 97 | bidiReq, nullptr, &status); 98 | if (!U_SUCCESS(status)) { 99 | ALOGE("error calling ubidi_setPara, status = %d", status); 100 | return; 101 | } 102 | // RTL paragraphs get an odd level, while LTR paragraphs get an even level, 103 | const bool paraIsRTL = ubidi_getParaLevel(mBidi.get()) & 0x01; 104 | const ssize_t rc = ubidi_countRuns(mBidi.get(), &status); 105 | if (!U_SUCCESS(status) || rc < 0) { 106 | ALOGW("error counting bidi runs, status = %d", status); 107 | return; 108 | } 109 | if (rc == 0) { 110 | mIsRtl = paraIsRTL; 111 | return; 112 | } 113 | if (rc == 1) { 114 | // If the paragraph is a single run, override the paragraph dirction with the run 115 | // (actually the whole text) direction. 116 | const UBiDiDirection runDir = ubidi_getVisualRun(mBidi.get(), 0, nullptr, nullptr); 117 | mIsRtl = (runDir == UBIDI_RTL); 118 | return; 119 | } 120 | mRunCount = rc; 121 | } 122 | 123 | } // namespace minikin 124 | -------------------------------------------------------------------------------- /tests/unittest/FontUtilsTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "FontUtils.h" 18 | 19 | #include 20 | 21 | namespace minikin { 22 | namespace { 23 | 24 | constexpr uint32_t MakeTag(char c1, char c2, char c3, char c4) { 25 | return ((uint32_t)c1 << 24) | ((uint32_t)c2 << 16) | ((uint32_t)c3 << 8) | (uint32_t)c4; 26 | } 27 | 28 | static size_t writeU16(uint16_t x, uint8_t* out, size_t offset) { 29 | out[offset] = x >> 8; 30 | out[offset + 1] = x; 31 | return offset + 2; 32 | } 33 | 34 | static size_t writeU32(uint32_t x, uint8_t* out, size_t offset) { 35 | out[offset] = x >> 24; 36 | out[offset + 1] = x >> 16; 37 | out[offset + 2] = x >> 8; 38 | out[offset + 3] = x; 39 | return offset + 4; 40 | } 41 | 42 | static uint32_t floatToFixed(float x) { 43 | return (uint32_t)(x * 65536); 44 | } 45 | 46 | struct Fvar { 47 | Fvar(uint32_t tag, float minValue, float defaultValue, float maxValue) 48 | : tag(tag), minValue(minValue), defaultValue(defaultValue), maxValue(maxValue) {} 49 | 50 | uint32_t tag; 51 | float minValue; 52 | float defaultValue; 53 | float maxValue; 54 | }; 55 | 56 | // Returns valid fvar table contents. No InstanceRecord are filled. 57 | static std::vector buildFvarTable(const std::vector& fvars) { 58 | const uint32_t HEADER_SIZE = 0x10; 59 | const uint32_t AXIS_RECORD_SIZE = 0x14; 60 | std::vector out(HEADER_SIZE + fvars.size() * AXIS_RECORD_SIZE); 61 | size_t head = writeU16(1, out.data(), 0); // major version 62 | head = writeU16(0, out.data(), head); // minor version 63 | head = writeU16(HEADER_SIZE, out.data(), head); // axes array offset 64 | head = writeU16(2, out.data(), head); // reserved 65 | head = writeU16(fvars.size(), out.data(), head); // count of axes 66 | head = writeU16(AXIS_RECORD_SIZE, out.data(), head); // size of variaiton axis record 67 | head = writeU16(0, out.data(), head); // number of instance record count 68 | head = writeU16(0, out.data(), head); // instance record size 69 | 70 | for (const Fvar& fvar : fvars) { 71 | head = writeU32(fvar.tag, out.data(), head); 72 | head = writeU32(floatToFixed(fvar.minValue), out.data(), head); 73 | head = writeU32(floatToFixed(fvar.defaultValue), out.data(), head); 74 | head = writeU32(floatToFixed(fvar.maxValue), out.data(), head); 75 | head = writeU16(0, out.data(), head); // flags 76 | head = writeU16(0, out.data(), head); // axis name ID 77 | } 78 | 79 | return out; 80 | } 81 | 82 | TEST(FontUtilsTest, analyzeAxes_tagCount) { 83 | std::vector fvarTable = buildFvarTable({ 84 | Fvar(MakeTag('w', 'd', 't', 'h'), 0.0f, 1.0f, 2.0f), 85 | Fvar(MakeTag('w', 'g', 'h', 't'), 0.0f, 1.0f, 2.0f), 86 | }); 87 | 88 | std::unordered_set axes; 89 | ASSERT_TRUE(analyzeAxes(fvarTable.data(), fvarTable.size(), &axes)); 90 | ASSERT_EQ(2u, axes.size()); 91 | EXPECT_EQ(1u, axes.count(MakeTag('w', 'd', 't', 'h'))); 92 | EXPECT_EQ(1u, axes.count(MakeTag('w', 'g', 'h', 't'))); 93 | EXPECT_EQ(0u, axes.count(MakeTag('s', 'l', 'n', 't'))); 94 | } 95 | 96 | TEST(FontUtilsTest, analyzeAxes_emptyBuffer) { 97 | std::vector fvarTable; 98 | std::unordered_set axes; 99 | ASSERT_FALSE(analyzeAxes(fvarTable.data(), fvarTable.size(), &axes)); 100 | } 101 | 102 | TEST(FontUtilsTest, analyzeAxes_invalidTableSize) { 103 | std::vector fvarTable = buildFvarTable({ 104 | Fvar(MakeTag('w', 'd', 't', 'h'), 0.0f, 1.0f, 2.0f), 105 | Fvar(MakeTag('w', 'g', 'h', 't'), 0.0f, 1.0f, 2.0f), 106 | }); 107 | 108 | fvarTable.resize(1000); 109 | writeU16(50, fvarTable.data(), 8); // Set axisCount = 50 110 | 111 | std::unordered_set axes; 112 | ASSERT_FALSE(analyzeAxes(fvarTable.data(), fvarTable.size(), &axes)); 113 | } 114 | 115 | } // namespace 116 | } // namespace minikin 117 | -------------------------------------------------------------------------------- /include/minikin/AndroidLineBreakerHelper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_ANDROID_LINE_BREAKER_HELPERS_H 18 | #define MINIKIN_ANDROID_LINE_BREAKER_HELPERS_H 19 | 20 | #include 21 | 22 | #include "minikin/LineBreaker.h" 23 | 24 | namespace minikin { 25 | namespace android { 26 | 27 | class AndroidLineWidth : public LineWidth { 28 | public: 29 | AndroidLineWidth(float firstWidth, int32_t firstLineCount, float restWidth, 30 | const std::vector& indents, int32_t indentsOffset) 31 | : mFirstWidth(firstWidth), 32 | mFirstLineCount(firstLineCount), 33 | mRestWidth(restWidth), 34 | mIndents(indents), 35 | mOffset(indentsOffset) {} 36 | 37 | float getAt(size_t lineNo) const override { 38 | const float width = ((ssize_t)lineNo < (ssize_t)mFirstLineCount) ? mFirstWidth : mRestWidth; 39 | return std::max(0.0f, width - get(mIndents, lineNo)); 40 | } 41 | 42 | float getMin() const override { 43 | // A simpler algorithm would have been simply looping until the larger of 44 | // mFirstLineCount and mIndents.size()-mOffset, but that does unnecessary calculations 45 | // when mFirstLineCount is large. Instead, we measure the first line, all the lines that 46 | // have an indent, and the first line after firstWidth ends and restWidth starts. 47 | float minWidth = std::min(getAt(0), getAt(mFirstLineCount)); 48 | for (size_t lineNo = 1; lineNo + mOffset < mIndents.size(); lineNo++) { 49 | minWidth = std::min(minWidth, getAt(lineNo)); 50 | } 51 | return minWidth; 52 | } 53 | 54 | private: 55 | float get(const std::vector& vec, size_t lineNo) const { 56 | if (vec.empty()) { 57 | return 0; 58 | } 59 | const size_t index = lineNo + mOffset; 60 | if (index < vec.size()) { 61 | return vec[index]; 62 | } else { 63 | return vec.back(); 64 | } 65 | } 66 | 67 | const float mFirstWidth; 68 | const int32_t mFirstLineCount; 69 | const float mRestWidth; 70 | const std::vector& mIndents; 71 | const int32_t mOffset; 72 | }; 73 | 74 | class StaticLayoutNative { 75 | public: 76 | StaticLayoutNative(BreakStrategy strategy, HyphenationFrequency frequency, bool isJustified, 77 | std::vector&& indents) 78 | : mStrategy(strategy), 79 | mFrequency(frequency), 80 | mIsJustified(isJustified), 81 | mIndents(std::move(indents)) {} 82 | 83 | LineBreakResult computeBreaks(const U16StringPiece& textBuf, const MeasuredText& measuredText, 84 | // Line width arguments 85 | float firstWidth, int32_t firstWidthLineCount, float restWidth, 86 | int32_t indentsOffset, 87 | // Tab stop arguments 88 | const float* tabStops, int32_t tabStopSize, 89 | float defaultTabStopWidth) const { 90 | AndroidLineWidth lineWidth(firstWidth, firstWidthLineCount, restWidth, mIndents, 91 | indentsOffset); 92 | return breakIntoLines(textBuf, mStrategy, mFrequency, mIsJustified, measuredText, lineWidth, 93 | TabStops(tabStops, tabStopSize, defaultTabStopWidth)); 94 | } 95 | 96 | inline BreakStrategy getStrategy() const { return mStrategy; } 97 | inline HyphenationFrequency getFrequency() const { return mFrequency; } 98 | inline bool isJustified() const { return mIsJustified; } 99 | 100 | private: 101 | const BreakStrategy mStrategy; 102 | const HyphenationFrequency mFrequency; 103 | const bool mIsJustified; 104 | const std::vector mIndents; 105 | const std::vector mLeftPaddings; 106 | const std::vector mRightPaddings; 107 | }; 108 | 109 | } // namespace android 110 | } // namespace minikin 111 | 112 | #endif // MINIKIN_ANDROID_LINE_BREAKER_HELPERS_H 113 | -------------------------------------------------------------------------------- /include/minikin/Font.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_FONT_H 18 | #define MINIKIN_FONT_H 19 | 20 | #include 21 | #include 22 | 23 | #include "minikin/FontStyle.h" 24 | #include "minikin/FontVariation.h" 25 | #include "minikin/HbUtils.h" 26 | #include "minikin/Macros.h" 27 | #include "minikin/MinikinFont.h" 28 | 29 | namespace minikin { 30 | 31 | class Font; 32 | 33 | // attributes representing transforms (fake bold, fake italic) to match styles 34 | class FontFakery { 35 | public: 36 | FontFakery() : mFakeBold(false), mFakeItalic(false) {} 37 | FontFakery(bool fakeBold, bool fakeItalic) : mFakeBold(fakeBold), mFakeItalic(fakeItalic) {} 38 | // TODO: want to support graded fake bolding 39 | bool isFakeBold() { return mFakeBold; } 40 | bool isFakeItalic() { return mFakeItalic; } 41 | inline bool operator==(const FontFakery& o) const { 42 | return mFakeBold == o.mFakeBold && mFakeItalic == o.mFakeItalic; 43 | } 44 | inline bool operator!=(const FontFakery& o) const { return !(*this == o); } 45 | 46 | private: 47 | bool mFakeBold; 48 | bool mFakeItalic; 49 | }; 50 | 51 | struct FakedFont { 52 | inline bool operator==(const FakedFont& o) const { 53 | return font == o.font && fakery == o.fakery; 54 | } 55 | inline bool operator!=(const FakedFont& o) const { return !(*this == o); } 56 | 57 | // ownership is the enclosing FontCollection 58 | const Font* font; 59 | FontFakery fakery; 60 | }; 61 | 62 | // Represents a single font file. 63 | class Font { 64 | public: 65 | class Builder { 66 | public: 67 | Builder(const std::shared_ptr& typeface) : mTypeface(typeface) {} 68 | 69 | // Override the font style. If not called, info from OS/2 table is used. 70 | Builder& setStyle(FontStyle style) { 71 | mWeight = style.weight(); 72 | mSlant = style.slant(); 73 | mIsWeightSet = mIsSlantSet = true; 74 | return *this; 75 | } 76 | 77 | // Override the font weight. If not called, info from OS/2 table is used. 78 | Builder& setWeight(uint16_t weight) { 79 | mWeight = weight; 80 | mIsWeightSet = true; 81 | return *this; 82 | } 83 | 84 | // Override the font slant. If not called, info from OS/2 table is used. 85 | Builder& setSlant(FontStyle::Slant slant) { 86 | mSlant = slant; 87 | mIsSlantSet = true; 88 | return *this; 89 | } 90 | 91 | Font build(); 92 | 93 | private: 94 | std::shared_ptr mTypeface; 95 | uint16_t mWeight = static_cast(FontStyle::Weight::NORMAL); 96 | FontStyle::Slant mSlant = FontStyle::Slant::UPRIGHT; 97 | bool mIsWeightSet = false; 98 | bool mIsSlantSet = false; 99 | }; 100 | 101 | Font(Font&& o) = default; 102 | Font& operator=(Font&& o) = default; 103 | 104 | Font& operator=(const Font& o) { 105 | mTypeface = o.mTypeface; 106 | mStyle = o.mStyle; 107 | mBaseFont = HbFontUniquePtr(hb_font_reference(o.mBaseFont.get())); 108 | return *this; 109 | } 110 | Font(const Font& o) { *this = o; } 111 | 112 | inline const std::shared_ptr& typeface() const { return mTypeface; } 113 | inline FontStyle style() const { return mStyle; } 114 | inline const HbFontUniquePtr& baseFont() const { return mBaseFont; } 115 | 116 | std::unordered_set getSupportedAxes() const; 117 | 118 | private: 119 | // Use Builder instead. 120 | Font(std::shared_ptr&& typeface, FontStyle style, HbFontUniquePtr&& baseFont) 121 | : mTypeface(std::move(typeface)), mStyle(style), mBaseFont(std::move(baseFont)) {} 122 | 123 | static HbFontUniquePtr prepareFont(const std::shared_ptr& typeface); 124 | static FontStyle analyzeStyle(const HbFontUniquePtr& font); 125 | 126 | std::shared_ptr mTypeface; 127 | FontStyle mStyle; 128 | HbFontUniquePtr mBaseFont; 129 | }; 130 | 131 | } // namespace minikin 132 | 133 | #endif // MINIKIN_FONT_H 134 | -------------------------------------------------------------------------------- /include/minikin/Range.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MINIKIN_RANGE_H 18 | #define MINIKIN_RANGE_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace minikin { 25 | 26 | // An undirected range. 27 | class Range { 28 | public: 29 | static constexpr uint32_t NOWHERE = std::numeric_limits::max(); 30 | 31 | // start must be smaller than or equal to end otherwise the behavior is undefined. 32 | Range(uint32_t start, uint32_t end) : mStart(start), mEnd(end) {} 33 | Range() : Range(NOWHERE, NOWHERE) {} 34 | 35 | Range(const Range&) = default; 36 | Range& operator=(const Range&) = default; 37 | 38 | static Range invalidRange() { return Range(NOWHERE, NOWHERE); } 39 | inline bool isValid() const { return mStart != NOWHERE && mEnd != NOWHERE; } 40 | 41 | inline uint32_t getStart() const { return mStart; } // inclusive 42 | inline void setStart(uint32_t start) { mStart = start; } // inclusive 43 | 44 | inline uint32_t getEnd() const { return mEnd; } // exclusive 45 | inline void setEnd(uint32_t end) { mEnd = end; } // exclusive 46 | 47 | inline uint32_t getLength() const { return mEnd - mStart; } 48 | 49 | inline bool isEmpty() const { return mStart == mEnd; } 50 | 51 | inline uint32_t toRangeOffset(uint32_t globalPos) const { return globalPos - mStart; } 52 | inline uint32_t toGlobalOffset(uint32_t rangePos) const { return mStart + rangePos; } 53 | 54 | // The behavior is undefined if pos is out of range. 55 | inline std::pair split(uint32_t pos) const { 56 | return std::make_pair(Range(mStart, pos), Range(pos, mEnd)); 57 | } 58 | 59 | inline bool contains(const Range& other) const { 60 | return mStart <= other.mStart && other.mEnd <= mEnd; 61 | } 62 | 63 | // Returns true if the pos is in this range. 64 | // For example, 65 | // const Range range(1, 2); // 1 is inclusive, 2 is exclusive. 66 | // range.contains(0); // false 67 | // range.contains(1); // true 68 | // range.contains(2); // false 69 | inline bool contains(uint32_t pos) const { return mStart <= pos && pos < mEnd; } 70 | 71 | // Returns true if left and right intersect. 72 | inline static bool intersects(const Range& left, const Range& right) { 73 | return left.isValid() && right.isValid() && left.mStart < right.mEnd && 74 | right.mStart < left.mEnd; 75 | } 76 | inline static Range intersection(const Range& left, const Range& right) { 77 | return Range(std::max(left.mStart, right.mStart), std::min(left.mEnd, right.mEnd)); 78 | } 79 | 80 | // Returns merged range. This method assumes left and right are not invalid ranges and they have 81 | // an intersection. 82 | static Range merge(const Range& left, const Range& right) { 83 | return Range({std::min(left.mStart, right.mStart), std::max(left.mEnd, right.mEnd)}); 84 | } 85 | 86 | inline bool operator==(const Range& o) const { return mStart == o.mStart && mEnd == o.mEnd; } 87 | 88 | inline bool operator!=(const Range& o) const { return !(*this == o); } 89 | 90 | inline Range operator+(int32_t shift) const { return Range(mStart + shift, mEnd + shift); } 91 | 92 | inline Range operator-(int32_t shift) const { return Range(mStart - shift, mEnd - shift); } 93 | 94 | private: 95 | // Helper class for "for (uint32_t i : range)" style for-loop. 96 | class RangeIterator { 97 | public: 98 | RangeIterator(uint32_t pos) : mPos(pos) {} 99 | 100 | inline bool operator!=(const RangeIterator& o) const { return o.mPos != mPos; } 101 | inline uint32_t operator*() const { return mPos; } 102 | inline RangeIterator& operator++() { 103 | mPos++; 104 | return *this; 105 | } 106 | 107 | private: 108 | uint32_t mPos; 109 | }; 110 | 111 | public: 112 | inline RangeIterator begin() const { return RangeIterator(mStart); } 113 | inline RangeIterator end() const { return RangeIterator(mEnd); } 114 | 115 | private: 116 | uint32_t mStart; 117 | uint32_t mEnd; 118 | }; 119 | 120 | } // namespace minikin 121 | 122 | #endif // MINIKIN_RANGE_H 123 | -------------------------------------------------------------------------------- /tests/unittest/EmojiTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "minikin/Emoji.h" 18 | 19 | #include 20 | #include 21 | 22 | namespace minikin { 23 | 24 | TEST(EmojiTest, isEmojiTest) { 25 | EXPECT_TRUE(isEmoji(0x0023)); // NUMBER SIGN 26 | EXPECT_TRUE(isEmoji(0x0035)); // DIGIT FIVE 27 | EXPECT_TRUE(isEmoji(0x2640)); // FEMALE SIGN 28 | EXPECT_TRUE(isEmoji(0x2642)); // MALE SIGN 29 | EXPECT_TRUE(isEmoji(0x2695)); // STAFF OF AESCULAPIUS 30 | EXPECT_TRUE(isEmoji(0x1F0CF)); // PLAYING CARD BLACK JOKER 31 | EXPECT_TRUE(isEmoji(0x1F1E9)); // REGIONAL INDICATOR SYMBOL LETTER D 32 | EXPECT_TRUE(isEmoji(0x1F6F7)); // SLED 33 | EXPECT_TRUE(isEmoji(0x1F9E6)); // SOCKS 34 | 35 | EXPECT_TRUE(isEmoji(0x1F6D5)); // HINDU TEMPLE 36 | EXPECT_TRUE(isEmoji(0x1F7E7)); // ORANGE SQUARE 37 | EXPECT_TRUE(isEmoji(0x1F9CF)); // DEAF PERSON 38 | EXPECT_TRUE(isEmoji(0x1F9CE)); // PERSON KNEELING 39 | EXPECT_TRUE(isEmoji(0x1F9A6)); // OTTER 40 | EXPECT_TRUE(isEmoji(0x1F9A9)); // FLAMINGO 41 | EXPECT_TRUE(isEmoji(0x1F9C6)); // FALAFEL 42 | EXPECT_TRUE(isEmoji(0x1F9AA)); // OYSTER 43 | EXPECT_TRUE(isEmoji(0x1FA82)); // PARACHUTE 44 | EXPECT_TRUE(isEmoji(0x1FA80)); // YO-YO 45 | EXPECT_TRUE(isEmoji(0x1FA70)); // BALLET SHOES 46 | EXPECT_TRUE(isEmoji(0x1FA79)); // ADHESIVE BANDAGE 47 | 48 | EXPECT_FALSE(isEmoji(0x0000)); // 49 | EXPECT_FALSE(isEmoji(0x0061)); // LATIN SMALL LETTER A 50 | EXPECT_FALSE(isEmoji(0x1F93B)); // MODERN PENTATHLON 51 | EXPECT_FALSE(isEmoji(0x1F946)); // RIFLE 52 | EXPECT_FALSE(isEmoji(0x29E3D)); // A han character. 53 | } 54 | 55 | TEST(EmojiTest, isEmojiModifierTest) { 56 | EXPECT_TRUE(isEmojiModifier(0x1F3FB)); // EMOJI MODIFIER FITZPATRICK TYPE-1-2 57 | EXPECT_TRUE(isEmojiModifier(0x1F3FC)); // EMOJI MODIFIER FITZPATRICK TYPE-3 58 | EXPECT_TRUE(isEmojiModifier(0x1F3FD)); // EMOJI MODIFIER FITZPATRICK TYPE-4 59 | EXPECT_TRUE(isEmojiModifier(0x1F3FE)); // EMOJI MODIFIER FITZPATRICK TYPE-5 60 | EXPECT_TRUE(isEmojiModifier(0x1F3FF)); // EMOJI MODIFIER FITZPATRICK TYPE-6 61 | 62 | EXPECT_FALSE(isEmojiModifier(0x0000)); // 63 | EXPECT_FALSE(isEmojiModifier(0x1F3FA)); // AMPHORA 64 | EXPECT_FALSE(isEmojiModifier(0x1F400)); // RAT 65 | EXPECT_FALSE(isEmojiModifier(0x29E3D)); // A han character. 66 | } 67 | 68 | TEST(EmojiTest, isEmojiBaseTest) { 69 | EXPECT_TRUE(isEmojiBase(0x261D)); // WHITE UP POINTING INDEX 70 | EXPECT_TRUE(isEmojiBase(0x270D)); // WRITING HAND 71 | EXPECT_TRUE(isEmojiBase(0x1F385)); // FATHER CHRISTMAS 72 | EXPECT_TRUE(isEmojiBase(0x1F3C2)); // SNOWBOARDER 73 | EXPECT_TRUE(isEmojiBase(0x1F3C7)); // HORSE RACING 74 | EXPECT_TRUE(isEmojiBase(0x1F3CC)); // GOLFER 75 | EXPECT_TRUE(isEmojiBase(0x1F574)); // MAN IN BUSINESS SUIT LEVITATING 76 | EXPECT_TRUE(isEmojiBase(0x1F6CC)); // SLEEPING ACCOMMODATION 77 | EXPECT_TRUE(isEmojiBase(0x1F91D)); // HANDSHAKE (removed from Emoji 4.0, but we need it) 78 | EXPECT_TRUE(isEmojiBase(0x1F91F)); // I LOVE YOU HAND SIGN 79 | EXPECT_TRUE(isEmojiBase(0x1F931)); // BREAST-FEEDING 80 | EXPECT_TRUE(isEmojiBase(0x1F932)); // PALMS UP TOGETHER 81 | EXPECT_TRUE(isEmojiBase(0x1F93C)); // WRESTLERS (removed from Emoji 4.0, but we need it) 82 | EXPECT_TRUE(isEmojiBase(0x1F9D1)); // ADULT 83 | EXPECT_TRUE(isEmojiBase(0x1F9DD)); // ELF 84 | 85 | EXPECT_FALSE(isEmojiBase(0x0000)); // 86 | EXPECT_FALSE(isEmojiBase(0x261C)); // WHITE LEFT POINTING INDEX 87 | EXPECT_FALSE(isEmojiBase(0x1F384)); // CHRISTMAS TREE 88 | EXPECT_FALSE(isEmojiBase(0x1F9DE)); // GENIE 89 | EXPECT_FALSE(isEmojiBase(0x29E3D)); // A han character. 90 | } 91 | 92 | TEST(EmojiTest, emojiBidiOverrideTest) { 93 | EXPECT_EQ(U_RIGHT_TO_LEFT, emojiBidiOverride(nullptr, 0x05D0)); // HEBREW LETTER ALEF 94 | EXPECT_EQ(U_LEFT_TO_RIGHT, 95 | emojiBidiOverride(nullptr, 0x1F170)); // NEGATIVE SQUARED LATIN CAPITAL LETTER A 96 | EXPECT_EQ(U_OTHER_NEUTRAL, emojiBidiOverride(nullptr, 0x1F6F7)); // SLED 97 | EXPECT_EQ(U_OTHER_NEUTRAL, emojiBidiOverride(nullptr, 0x1F9E6)); // SOCKS 98 | } 99 | 100 | } // namespace minikin 101 | -------------------------------------------------------------------------------- /libs/minikin/Measurement.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "minikin/Measurement.h" 18 | 19 | #include 20 | #include 21 | 22 | #include "minikin/GraphemeBreak.h" 23 | 24 | namespace minikin { 25 | 26 | // These could be considered helper methods of layout, but need only be loosely coupled, so 27 | // are separate. 28 | 29 | static float getRunAdvance(const float* advances, const uint16_t* buf, size_t layoutStart, 30 | size_t start, size_t count, size_t offset) { 31 | float advance = 0.0f; 32 | size_t lastCluster = start; 33 | float clusterWidth = 0.0f; 34 | for (size_t i = start; i < offset; i++) { 35 | float charAdvance = advances[i - layoutStart]; 36 | if (charAdvance != 0.0f) { 37 | advance += charAdvance; 38 | lastCluster = i; 39 | clusterWidth = charAdvance; 40 | } 41 | } 42 | if (offset < start + count && advances[offset - layoutStart] == 0.0f) { 43 | // In the middle of a cluster, distribute width of cluster so that each grapheme cluster 44 | // gets an equal share. 45 | // TODO: get caret information out of font when that's available 46 | size_t nextCluster; 47 | for (nextCluster = offset + 1; nextCluster < start + count; nextCluster++) { 48 | if (advances[nextCluster - layoutStart] != 0.0f) break; 49 | } 50 | int numGraphemeClusters = 0; 51 | int numGraphemeClustersAfter = 0; 52 | for (size_t i = lastCluster; i < nextCluster; i++) { 53 | bool isAfter = i >= offset; 54 | if (GraphemeBreak::isGraphemeBreak(advances + (start - layoutStart), buf, start, count, 55 | i)) { 56 | numGraphemeClusters++; 57 | if (isAfter) { 58 | numGraphemeClustersAfter++; 59 | } 60 | } 61 | } 62 | if (numGraphemeClusters > 0) { 63 | advance -= clusterWidth * numGraphemeClustersAfter / numGraphemeClusters; 64 | } 65 | } 66 | return advance; 67 | } 68 | 69 | float getRunAdvance(const float* advances, const uint16_t* buf, size_t start, size_t count, 70 | size_t offset) { 71 | return getRunAdvance(advances, buf, start, start, count, offset); 72 | } 73 | 74 | /** 75 | * Essentially the inverse of getRunAdvance. Compute the value of offset for which the 76 | * measured caret comes closest to the provided advance param, and which is on a grapheme 77 | * cluster boundary. 78 | * 79 | * The actual implementation fast-forwards through clusters to get "close", then does a finer-grain 80 | * search within the cluster and grapheme breaks. 81 | */ 82 | size_t getOffsetForAdvance(const float* advances, const uint16_t* buf, size_t start, size_t count, 83 | float advance) { 84 | float x = 0.0f, xLastClusterStart = 0.0f, xSearchStart = 0.0f; 85 | size_t lastClusterStart = start, searchStart = start; 86 | for (size_t i = start; i < start + count; i++) { 87 | if (GraphemeBreak::isGraphemeBreak(advances, buf, start, count, i)) { 88 | searchStart = lastClusterStart; 89 | xSearchStart = xLastClusterStart; 90 | } 91 | float width = advances[i - start]; 92 | if (width != 0.0f) { 93 | lastClusterStart = i; 94 | xLastClusterStart = x; 95 | x += width; 96 | if (x > advance) { 97 | break; 98 | } 99 | } 100 | } 101 | size_t best = searchStart; 102 | float bestDist = FLT_MAX; 103 | for (size_t i = searchStart; i <= start + count; i++) { 104 | if (GraphemeBreak::isGraphemeBreak(advances, buf, start, count, i)) { 105 | // "getRunAdvance(layout, buf, start, count, i) - advance" but more efficient 106 | float delta = getRunAdvance(advances, buf, start, searchStart, count - searchStart, i) 107 | 108 | + xSearchStart - advance; 109 | if (std::abs(delta) < bestDist) { 110 | bestDist = std::abs(delta); 111 | best = i; 112 | } 113 | if (delta >= 0.0f) { 114 | break; 115 | } 116 | } 117 | } 118 | return best; 119 | } 120 | 121 | } // namespace minikin 122 | -------------------------------------------------------------------------------- /libs/minikin/HyphenatorMap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "HyphenatorMap.h" 18 | 19 | #include "LocaleListCache.h" 20 | #include "MinikinInternal.h" 21 | 22 | namespace minikin { 23 | 24 | namespace { 25 | constexpr SubtagBits LANGUAGE = SubtagBits::LANGUAGE; 26 | constexpr SubtagBits SCRIPT = SubtagBits::SCRIPT; 27 | constexpr SubtagBits REGION = SubtagBits::REGION; 28 | constexpr SubtagBits VARIANT = SubtagBits::VARIANT; 29 | 30 | constexpr int DEFAULT_MIN_PREFIX = 2; 31 | constexpr int DEFAULT_MAX_PREFIX = 2; 32 | } // namespace 33 | 34 | // Following two function's implementations are here since Hyphenator.cpp can't include 35 | // HyphenatorMap.h due to harfbuzz dependency on the host binary. 36 | void addHyphenator(const std::string& localeStr, const Hyphenator* hyphenator) { 37 | HyphenatorMap::add(localeStr, hyphenator); 38 | } 39 | 40 | void addHyphenatorAlias(const std::string& fromLocaleStr, const std::string& toLocaleStr) { 41 | HyphenatorMap::addAlias(fromLocaleStr, toLocaleStr); 42 | } 43 | 44 | HyphenatorMap::HyphenatorMap() 45 | : mSoftHyphenOnlyHyphenator( 46 | Hyphenator::loadBinary(nullptr, DEFAULT_MIN_PREFIX, DEFAULT_MAX_PREFIX, "")) {} 47 | 48 | void HyphenatorMap::addInternal(const std::string& localeStr, const Hyphenator* hyphenator) { 49 | const Locale locale(localeStr); 50 | std::lock_guard lock(mMutex); 51 | // Overwrite even if there is already a fallback entry. 52 | mMap[locale.getIdentifier()] = hyphenator; 53 | } 54 | 55 | void HyphenatorMap::clearInternal() { 56 | std::lock_guard lock(mMutex); 57 | mMap.clear(); 58 | } 59 | void HyphenatorMap::addAliasInternal(const std::string& fromLocaleStr, 60 | const std::string& toLocaleStr) { 61 | const Locale fromLocale(fromLocaleStr); 62 | const Locale toLocale(toLocaleStr); 63 | std::lock_guard lock(mMutex); 64 | auto it = mMap.find(toLocale.getIdentifier()); 65 | if (it == mMap.end()) { 66 | ALOGE("Target Hyphenator not found."); 67 | return; 68 | } 69 | // Overwrite even if there is already a fallback entry. 70 | mMap[fromLocale.getIdentifier()] = it->second; 71 | } 72 | 73 | const Hyphenator* HyphenatorMap::lookupInternal(const Locale& locale) { 74 | const uint64_t id = locale.getIdentifier(); 75 | std::lock_guard lock(mMutex); 76 | const Hyphenator* result = lookupByIdentifier(id); 77 | if (result != nullptr) { 78 | return result; // Found with exact match. 79 | } 80 | 81 | // First, try with dropping emoji extensions. 82 | result = lookupBySubtag(locale, LANGUAGE | REGION | SCRIPT | VARIANT); 83 | if (result != nullptr) { 84 | goto insert_result_and_return; 85 | } 86 | // If not found, try with dropping script. 87 | result = lookupBySubtag(locale, LANGUAGE | REGION | VARIANT); 88 | if (result != nullptr) { 89 | goto insert_result_and_return; 90 | } 91 | // If not found, try with dropping script and region code. 92 | result = lookupBySubtag(locale, LANGUAGE | VARIANT); 93 | if (result != nullptr) { 94 | goto insert_result_and_return; 95 | } 96 | // If not found, try only with language code. 97 | result = lookupBySubtag(locale, LANGUAGE); 98 | if (result != nullptr) { 99 | goto insert_result_and_return; 100 | } 101 | // Still not found, try only with script. 102 | result = lookupBySubtag(locale, SCRIPT); 103 | if (result != nullptr) { 104 | goto insert_result_and_return; 105 | } 106 | 107 | // If not found, use soft hyphen only hyphenator. 108 | result = mSoftHyphenOnlyHyphenator; 109 | 110 | insert_result_and_return: 111 | mMap.insert(std::make_pair(id, result)); 112 | return result; 113 | } 114 | 115 | const Hyphenator* HyphenatorMap::lookupByIdentifier(uint64_t id) const { 116 | auto it = mMap.find(id); 117 | return it == mMap.end() ? nullptr : it->second; 118 | } 119 | 120 | const Hyphenator* HyphenatorMap::lookupBySubtag(const Locale& locale, SubtagBits bits) const { 121 | const Locale partialLocale = locale.getPartialLocale(bits); 122 | if (!partialLocale.isSupported() || partialLocale == locale) { 123 | return nullptr; // Skip the partial locale result in the same locale or not supported. 124 | } 125 | return lookupByIdentifier(partialLocale.getIdentifier()); 126 | } 127 | 128 | } // namespace minikin 129 | --------------------------------------------------------------------------------