diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-04-08 16:02:15 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-04-08 16:02:15 +0000 |
commit | 344df572feecf520d16939e52b3a963e998bbc4f (patch) | |
tree | cc760592822d295652a6f09cc869fbcd02b0a04e | |
parent | 7c70575d509031ed26d3c1c46affb04a7082044c (diff) | |
parent | c3bd9a03ecb1a19393046c522f5b6c91d615f7c5 (diff) | |
download | minikin-android12-mainline-tzdata2-release.tar.gz |
Snap for 8426163 from c3bd9a03ecb1a19393046c522f5b6c91d615f7c5 to mainline-tzdata2-releaseandroid-mainline-12.0.0_r112aml_tz2_305400500aml_tz2_305400300aml_tz2_305400100aml_tz2_304500300aml_tz2_303900110aml_tz2_303900102aml_tz2_303800002aml_tz2_303800001aml_tz2_303200001android12-mainline-tzdata2-releaseaml_tz2_305400100
Change-Id: Ic88d6223a6a5e2373d196bf0c2beb159a82463e8
77 files changed, 489 insertions, 4165 deletions
@@ -1,17 +1,7 @@ -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - cc_library_headers { name: "libminikin_headers", host_supported: true, export_include_dirs: ["include"], - header_libs: [ - "libgtest_prod_headers", - ], - export_header_lib_headers: [ - "libgtest_prod_headers", - ], target: { windows: { enabled: true, diff --git a/app/Android.bp b/app/Android.bp index 9d6c28a..6c7c66b 100644 --- a/app/Android.bp +++ b/app/Android.bp @@ -14,10 +14,6 @@ // see how_to_run.txt for instructions on running these tests -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - cc_binary_host { name: "hyphtool", diff --git a/include/minikin/BoundsCache.h b/include/minikin/BoundsCache.h deleted file mode 100644 index 64f2b49..0000000 --- a/include/minikin/BoundsCache.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef MINIKIN_BOUNDS_CACHE_H -#define MINIKIN_BOUNDS_CACHE_H - -#include "minikin/LayoutCache.h" - -#include <mutex> - -#include <utils/LruCache.h> - -#include "minikin/BoundsCache.h" -#include "minikin/FontCollection.h" -#include "minikin/Hasher.h" -#include "minikin/MinikinPaint.h" - -namespace minikin { - -// Cache entry -struct BoundsValue { - MinikinRect rect; - float advance; -}; - -// Used for callback for LayoutCache. -struct ValueExtractor { - void operator()(const LayoutPiece& layoutPiece, const MinikinPaint& paint); - std::unique_ptr<BoundsValue> value; -}; - -class BoundsCache : private android::OnEntryRemoved<LayoutCacheKey, BoundsValue*> { -public: - void clear() { - std::lock_guard<std::mutex> lock(mMutex); - mCache.clear(); - } - - // Do not use BoundsCache inside the callback function, otherwise dead-lock may happen. - template <typename F> - void getOrCreate(const U16StringPiece& text, const Range& range, const MinikinPaint& paint, - bool dir, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, F& f) { - LayoutCacheKey key(text, range, paint, dir, startHyphen, endHyphen); - if (paint.skipCache() || range.getLength() >= LENGTH_LIMIT_CACHE) { - LayoutPiece piece = LayoutPiece(text, range, dir, paint, startHyphen, endHyphen); - f(getBounds(piece, paint), piece.advance()); - return; - } - { - std::lock_guard<std::mutex> lock(mMutex); - BoundsValue* value = mCache.get(key); - if (value != nullptr) { - f(value->rect, value->advance); - return; - } - } - // Doing text layout takes long time, so releases the mutex during doing layout. - // Don't care even if we do the same layout in other thread. - key.copyText(); - ValueExtractor ve; - LayoutCache::getInstance().getOrCreate(text, range, paint, dir, startHyphen, endHyphen, ve); - f(ve.value->rect, ve.value->advance); - { - std::lock_guard<std::mutex> lock(mMutex); - mCache.put(key, ve.value.release()); - } - } - - static BoundsCache& getInstance() { - static BoundsCache cache(kMaxEntries); - return cache; - } - - // Compute new bounding box for the layout piece. - static MinikinRect getBounds(const LayoutPiece& layoutPiece, const MinikinPaint& paint); - -protected: - BoundsCache(uint32_t maxEntries) : mCache(maxEntries) { - mCache.setOnEntryRemovedListener(this); - } - -private: - // callback for OnEntryRemoved - void operator()(LayoutCacheKey& key, BoundsValue*& value) { - key.freeText(); - delete value; - } - - std::mutex mMutex; - android::LruCache<LayoutCacheKey, BoundsValue*> mCache GUARDED_BY(mMutex) GUARDED_BY(mMutex); - // LRU cache capacity. Should be fine to be less than LayoutCache#kMaxEntries since bbox - // calculation happens less than layout calculation. - static const size_t kMaxEntries = 500; -}; - -} // namespace minikin -#endif // MINIKIN_BOUNDS_CACHE_H diff --git a/include/minikin/Buffer.h b/include/minikin/Buffer.h deleted file mode 100644 index 87ba3fd..0000000 --- a/include/minikin/Buffer.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef MINIKIN_BUFFER_H -#define MINIKIN_BUFFER_H - -#include <cstring> -#include <string_view> -#include <type_traits> -#include <utility> - -namespace minikin { - -// This is a helper class to read data from a memory buffer. -// This class does not copy memory, and may return pointers to parts of the memory buffer. -// Thus the memory buffer should outlive objects created using this class. -class BufferReader { -public: - BufferReader(const void* buffer) : BufferReader(buffer, 0) {} - BufferReader(const void* buffer, uint32_t pos) - : mData(reinterpret_cast<const uint8_t*>(buffer)), mPos(pos) {} - - template <typename T> - static uint32_t align(uint32_t pos) { - // This should be true for all types, unless custom alignment attributes are set. - static_assert(sizeof(T) % alignof(T) == 0, "sizeof(T) must be a multiple of alignof(T)"); - // We align to sizeof(T) instead of alignof(T), because the buffer may be shared between - // 32-bit processes and 64-bit processes. alignof(T) may change between the two. - // We assume that T is a type whose size is fixed (e.g. uint32_t). - return (pos + sizeof(T) - 1) / sizeof(T) * sizeof(T); - } - - template <typename T> - const T& read() { - static_assert(std::is_pod<T>::value, "T must be a POD"); - mPos = BufferReader::align<T>(mPos); - const T* data = reinterpret_cast<const T*>(mData + mPos); - mPos += sizeof(T); - return *data; - } - - template <typename T> - void skip() { - static_assert(std::is_pod<T>::value, "T must be a POD"); - mPos = BufferReader::align<T>(mPos); - mPos += sizeof(T); - } - - // Return a pointer to an array and its number of elements. - template <typename T> - std::pair<const T*, uint32_t> readArray() { - static_assert(std::is_pod<T>::value, "T must be a POD"); - uint32_t size = read<uint32_t>(); - mPos = BufferReader::align<T>(mPos); - const T* data = reinterpret_cast<const T*>(mData + mPos); - mPos += size * sizeof(T); - return std::make_pair(data, size); - } - - template <typename T> - void skipArray() { - static_assert(std::is_pod<T>::value, "T must be a POD"); - uint32_t size = read<uint32_t>(); - mPos = BufferReader::align<T>(mPos); - mPos += size * sizeof(T); - } - - std::string_view readString() { - auto [data, size] = readArray<char>(); - return std::string_view(data, size); - } - - void skipString() { skipArray<char>(); } - - const void* data() const { return mData; } - size_t pos() const { return mPos; } - -private: - const uint8_t* mData; - size_t mPos; -}; - -// This is a helper class to write data to a memory buffer. -class BufferWriter { -public: - // Create a buffer writer. Passing nullptr creates a fake writer, - // which can be used to measure the buffer size needed. - BufferWriter(void* buffer) : mData(reinterpret_cast<uint8_t*>(buffer)), mPos(0) {} - - BufferWriter(BufferWriter&&) = default; - BufferWriter& operator=(BufferWriter&&) = default; - - // Write a single data of type T. - // Please always specify T explicitly using <>. std::common_type_t<T> resolves to T, but - // disables template argument deduction. - // TODO: use std::type_identity_t when C++20 is available. - template <typename T> - void write(const std::common_type_t<T>& data) { - static_assert(std::is_pod<T>::value, "T must be a POD"); - mPos = BufferReader::align<T>(mPos); - if (mData != nullptr) { - memcpy(mData + mPos, &data, sizeof(T)); - } - mPos += sizeof(T); - } - - // Write an array of type T. - // Please always specify T explicitly using <>. std::common_type_t<T> resolves to T, but - // disables template argument deduction. - // TODO: use std::type_identity_t when C++20 is available. - template <typename T> - void writeArray(const std::common_type_t<T>* data, uint32_t size) { - static_assert(std::is_pod<T>::value, "T must be a POD"); - write<uint32_t>(size); - mPos = BufferReader::align<T>(mPos); - if (mData != nullptr) { - memcpy(mData + mPos, data, size * sizeof(T)); - } - mPos += size * sizeof(T); - } - - void writeString(std::string_view string) { writeArray<char>(string.data(), string.size()); } - - // Return the number of bytes written. - size_t size() const { return mPos; } - -private: - uint8_t* mData; - size_t mPos; - - // Forbid copy and assign. - BufferWriter(const BufferWriter&) = delete; - void operator=(const BufferWriter&) = delete; -}; - -} // namespace minikin - -#endif // MINIKIN_BUFFER_H diff --git a/include/minikin/Font.h b/include/minikin/Font.h index 67feecf..eeb074e 100644 --- a/include/minikin/Font.h +++ b/include/minikin/Font.h @@ -18,14 +18,11 @@ #define MINIKIN_FONT_H #include <memory> -#include <mutex> #include <unordered_set> -#include "minikin/Buffer.h" #include "minikin/FontStyle.h" #include "minikin/FontVariation.h" #include "minikin/HbUtils.h" -#include "minikin/LocaleList.h" #include "minikin/Macros.h" #include "minikin/MinikinFont.h" @@ -58,10 +55,7 @@ struct FakedFont { inline bool operator!=(const FakedFont& o) const { return !(*this == o); } // ownership is the enclosing FontCollection - // FakedFont will be stored in the LayoutCache. It is not a good idea too keep font instance - // even if the enclosing FontCollection, i.e. Typeface is GC-ed. The layout cache is only - // purged when it is overflown, thus intentionally keep only reference. - const std::shared_ptr<Font>& font; + const Font* font; FontFakery fakery; }; @@ -94,96 +88,44 @@ public: return *this; } - Builder& setLocaleListId(uint32_t id) { - mLocaleListId = id; - return *this; - } - - std::shared_ptr<Font> build(); + Font build(); private: std::shared_ptr<MinikinFont> mTypeface; uint16_t mWeight = static_cast<uint16_t>(FontStyle::Weight::NORMAL); FontStyle::Slant mSlant = FontStyle::Slant::UPRIGHT; - uint32_t mLocaleListId = kEmptyLocaleListId; bool mIsWeightSet = false; bool mIsSlantSet = false; }; - // Type for functions to load MinikinFont lazily. - using TypefaceLoader = std::shared_ptr<MinikinFont>(BufferReader reader); - // Type for functions to read MinikinFont metadata and return - // TypefaceLoader. - using TypefaceReader = TypefaceLoader*(BufferReader* reader); - // Type for functions to write MinikinFont metadata. - using TypefaceWriter = void(BufferWriter* writer, const MinikinFont* typeface); - - template <TypefaceReader typefaceReader> - static std::shared_ptr<Font> readFrom(BufferReader* reader, uint32_t localeListId) { - FontStyle style = FontStyle(reader); - BufferReader typefaceMetadataReader = *reader; - TypefaceLoader* typefaceLoader = typefaceReader(reader); - return std::shared_ptr<Font>( - new Font(style, typefaceMetadataReader, typefaceLoader, localeListId)); - } + Font(Font&& o) = default; + Font& operator=(Font&& o) = default; - template <TypefaceWriter typefaceWriter> - void writeTo(BufferWriter* writer) const { - mStyle.writeTo(writer); - typefaceWriter(writer, typeface().get()); + Font& operator=(const Font& o) { + mTypeface = o.mTypeface; + mStyle = o.mStyle; + mBaseFont = HbFontUniquePtr(hb_font_reference(o.mBaseFont.get())); + return *this; } + Font(const Font& o) { *this = o; } - // This locale list is just for API compatibility. This is not used in font selection or family - // fallback. - uint32_t getLocaleListId() const { return mLocaleListId; } - const std::shared_ptr<MinikinFont>& typeface() const; + inline const std::shared_ptr<MinikinFont>& typeface() const { return mTypeface; } inline FontStyle style() const { return mStyle; } - const HbFontUniquePtr& baseFont() const; - BufferReader typefaceMetadataReader() const { return mTypefaceMetadataReader; } + inline const HbFontUniquePtr& baseFont() const { return mBaseFont; } std::unordered_set<AxisTag> getSupportedAxes() const; private: // Use Builder instead. - Font(std::shared_ptr<MinikinFont>&& typeface, FontStyle style, HbFontUniquePtr&& baseFont, - uint32_t localeListId) - : mTypeface(std::move(typeface)), - mStyle(style), - mBaseFont(std::move(baseFont)), - mTypefaceLoader(nullptr), - mTypefaceMetadataReader(nullptr), - mLocaleListId(localeListId) {} - Font(FontStyle style, BufferReader typefaceMetadataReader, TypefaceLoader* typefaceLoader, - uint32_t localeListId) - : mStyle(style), - mTypefaceLoader(typefaceLoader), - mTypefaceMetadataReader(typefaceMetadataReader), - mLocaleListId(localeListId) {} - - void initTypefaceLocked() const EXCLUSIVE_LOCKS_REQUIRED(mTypefaceMutex); + Font(std::shared_ptr<MinikinFont>&& typeface, FontStyle style, HbFontUniquePtr&& baseFont) + : mTypeface(std::move(typeface)), mStyle(style), mBaseFont(std::move(baseFont)) {} static HbFontUniquePtr prepareFont(const std::shared_ptr<MinikinFont>& typeface); static FontStyle analyzeStyle(const HbFontUniquePtr& font); - // Lazy-initialized if created by readFrom(). - mutable std::shared_ptr<MinikinFont> mTypeface GUARDED_BY(mTypefaceMutex); + std::shared_ptr<MinikinFont> mTypeface; FontStyle mStyle; - // Lazy-initialized if created by readFrom(). - mutable HbFontUniquePtr mBaseFont GUARDED_BY(mTypefaceMutex); - - mutable std::mutex mTypefaceMutex; - // Non-null if created by readFrom(). - TypefaceLoader* mTypefaceLoader; - // Non-null if created by readFrom(). - BufferReader mTypefaceMetadataReader; - - uint32_t mLocaleListId; - - // Stop copying and moving - Font(Font&& o) = delete; - Font& operator=(Font&& o) = delete; - Font(const Font& o) = delete; - Font& operator=(const Font& o) = delete; + HbFontUniquePtr mBaseFont; }; } // namespace minikin diff --git a/include/minikin/FontCollection.h b/include/minikin/FontCollection.h index 98df571..f136384 100644 --- a/include/minikin/FontCollection.h +++ b/include/minikin/FontCollection.h @@ -18,14 +18,9 @@ #define MINIKIN_FONT_COLLECTION_H #include <memory> -#include <unordered_map> #include <unordered_set> #include <vector> -#include <gtest/gtest_prod.h> - -#include "minikin/Buffer.h" -#include "minikin/Font.h" #include "minikin/FontFamily.h" #include "minikin/MinikinFont.h" #include "minikin/U16StringPiece.h" @@ -40,134 +35,12 @@ public: explicit FontCollection(const std::vector<std::shared_ptr<FontFamily>>& typefaces); explicit FontCollection(std::shared_ptr<FontFamily>&& typeface); - template <Font::TypefaceReader typefaceReader> - static std::vector<std::shared_ptr<FontCollection>> readVector(BufferReader* reader) { - uint32_t allFontFamiliesCount = reader->read<uint32_t>(); - std::vector<std::shared_ptr<FontFamily>> allFontFamilies; - allFontFamilies.reserve(allFontFamiliesCount); - for (uint32_t i = 0; i < allFontFamiliesCount; i++) { - allFontFamilies.push_back(FontFamily::readFrom<typefaceReader>(reader)); - } - uint32_t fontCollectionsCount = reader->read<uint32_t>(); - std::vector<std::shared_ptr<FontCollection>> fontCollections; - fontCollections.reserve(fontCollectionsCount); - for (uint32_t i = 0; i < fontCollectionsCount; i++) { - fontCollections.emplace_back(new FontCollection(reader, allFontFamilies)); - } - return fontCollections; - } - - template <Font::TypefaceWriter typefaceWriter> - static void writeVector(BufferWriter* writer, - const std::vector<std::shared_ptr<FontCollection>>& fontCollections) { - std::vector<std::shared_ptr<FontFamily>> allFontFamilies; - // Note: operator== for shared_ptr compares raw pointer values. - std::unordered_map<std::shared_ptr<FontFamily>, uint32_t> fontFamilyToIndexMap; - collectAllFontFamilies(fontCollections, &allFontFamilies, &fontFamilyToIndexMap); - - writer->write<uint32_t>(allFontFamilies.size()); - for (const auto& fontFamily : allFontFamilies) { - fontFamily->writeTo<typefaceWriter>(writer); - } - writer->write<uint32_t>(fontCollections.size()); - for (const auto& fontCollection : fontCollections) { - fontCollection->writeTo(writer, fontFamilyToIndexMap); - } - } - - // Helper class for representing font family match result in packed bits. - struct FamilyMatchResult { - public: - struct Builder { - public: - Builder() : mSize(0), mBits(0) {} - - Builder& add(uint8_t x) { - if (mSize >= 7) [[unlikely]] { - return *this; - } - mBits = mBits | (static_cast<uint64_t>(x) << (8 * mSize)); - mSize++; - return *this; - } - - Builder& reset() { - mSize = 0; - mBits = 0; - return *this; - } - - uint8_t size() const { return mSize; } - - bool empty() const { return size() == 0; } - - FamilyMatchResult build() { - return FamilyMatchResult(mBits | (static_cast<uint64_t>(mSize) << 56)); - } - - private: - uint8_t mSize; - uint64_t mBits; - }; - - // Helper class for iterating FamilyMatchResult - class iterator { - public: - inline bool operator==(const iterator& o) const { - return mOffset == o.mOffset && mResult == o.mResult; - } - - inline bool operator!=(const iterator& o) const { return !(*this == o); } - inline uint8_t operator*() const { return mResult[mOffset]; } - inline iterator& operator++() { - mOffset++; - return *this; - } - - private: - friend struct FamilyMatchResult; - iterator(const FamilyMatchResult& result, uint32_t offset) - : mResult(result), mOffset(offset) {} - const FamilyMatchResult& mResult; - uint32_t mOffset; - }; - - // Create empty FamilyMatchResult. - FamilyMatchResult() : mBits(0) {} - - inline uint8_t size() const { return static_cast<uint8_t>(mBits >> 56); } - - inline uint8_t operator[](uint32_t pos) const { - return static_cast<uint8_t>(mBits >> (pos * 8)); - } - - inline bool empty() const { return size() == 0; } - - inline bool operator==(const FamilyMatchResult& o) const { return mBits == o.mBits; } - - // Returns the common family indices between l and r. - static FamilyMatchResult intersect(FamilyMatchResult l, FamilyMatchResult r); - - // Iterator - inline iterator begin() const { return iterator(*this, 0); } - inline iterator end() const { return iterator(*this, size()); } - - FamilyMatchResult(const FamilyMatchResult& o) = default; - FamilyMatchResult& operator=(const FamilyMatchResult& o) = default; - - private: - explicit FamilyMatchResult(uint64_t bits) : mBits(bits) {} - uint64_t mBits; - }; - struct Run { - FamilyMatchResult familyMatch; + FakedFont fakedFont; int start; int end; }; - FakedFont getBestFont(U16StringPiece textBuf, const Run& run, FontStyle style); - // Perform the itemization until given max runs. std::vector<Run> itemize(U16StringPiece text, FontStyle style, uint32_t localeListId, FamilyVariant familyVariant, uint32_t runMax) const; @@ -195,23 +68,7 @@ public: uint32_t getId() const; - const std::vector<std::shared_ptr<FontFamily>>& getFamilies() const { return mFamilies; } - private: - FRIEND_TEST(FontCollectionTest, bufferTest); - - FontCollection(BufferReader* reader, - const std::vector<std::shared_ptr<FontFamily>>& allFontFamilies); - // Write fields of the instance, using fontFamilyToIndexMap for finding - // indices for FontFamily. - void writeTo(BufferWriter* writer, - const std::unordered_map<std::shared_ptr<FontFamily>, uint32_t>& - fontFamilyToIndexMap) const; - static void collectAllFontFamilies( - const std::vector<std::shared_ptr<FontCollection>>& fontCollections, - std::vector<std::shared_ptr<FontFamily>>* outAllFontFamilies, - std::unordered_map<std::shared_ptr<FontFamily>, uint32_t>* outFontFamilyToIndexMap); - static const int kLogCharsPerPage = 8; static const int kPageMask = (1 << kLogCharsPerPage) - 1; @@ -228,8 +85,9 @@ private: // Initialize the FontCollection. void init(const std::vector<std::shared_ptr<FontFamily>>& typefaces); - FamilyMatchResult getFamilyForChar(uint32_t ch, uint32_t vs, uint32_t localeListId, - FamilyVariant variant) const; + const std::shared_ptr<FontFamily>& getFamilyForChar(uint32_t ch, uint32_t vs, + uint32_t localeListId, + FamilyVariant variant) const; uint32_t calcFamilyScore(uint32_t ch, uint32_t vs, FamilyVariant variant, uint32_t localeListId, const std::shared_ptr<FontFamily>& fontFamily) const; @@ -258,21 +116,14 @@ private: // mFamilyVec[mRange[0xXXYY].end] instead of whole mFamilies. // This vector contains indices into mFamilies. // This vector can't be empty. - uint32_t mRangesCount; - const Range* mRanges; - uint32_t mFamilyVecCount; - const uint8_t* mFamilyVec; + std::vector<Range> mRanges; + std::vector<uint8_t> mFamilyVec; // This vector has pointers to the font family instances which have cmap 14 subtables. std::vector<std::shared_ptr<FontFamily>> mVSFamilyVec; // Set of supported axes in this collection. std::unordered_set<AxisTag> mSupportedAxes; - - // Owns allocated memory if this class is created from font families, otherwise these are - // nullptr. - std::unique_ptr<Range[]> mOwnedRanges; - std::vector<uint8_t> mOwnedFamilyVec; }; } // namespace minikin diff --git a/include/minikin/FontFamily.h b/include/minikin/FontFamily.h index 6169193..4aafaa0 100644 --- a/include/minikin/FontFamily.h +++ b/include/minikin/FontFamily.h @@ -33,32 +33,10 @@ namespace minikin { class FontFamily { public: - explicit FontFamily(std::vector<std::shared_ptr<Font>>&& fonts); - FontFamily(FamilyVariant variant, std::vector<std::shared_ptr<Font>>&& fonts); - FontFamily(uint32_t localeListId, FamilyVariant variant, - std::vector<std::shared_ptr<Font>>&& fonts, bool isCustomFallback); - - template <Font::TypefaceReader typefaceReader> - static std::shared_ptr<FontFamily> readFrom(BufferReader* reader) { - uint32_t localeListId = readLocaleListInternal(reader); - uint32_t fontsCount = reader->read<uint32_t>(); - std::vector<std::shared_ptr<Font>> fonts; - fonts.reserve(fontsCount); - for (uint32_t i = 0; i < fontsCount; i++) { - fonts.emplace_back(Font::readFrom<typefaceReader>(reader, localeListId)); - } - return readFromInternal(reader, std::move(fonts), localeListId); - } - - template <Font::TypefaceWriter typefaceWriter> - void writeTo(BufferWriter* writer) const { - writeLocaleListInternal(writer); - writer->write<uint32_t>(mFonts.size()); - for (const std::shared_ptr<Font>& font : mFonts) { - font->writeTo<typefaceWriter>(writer); - } - writeToInternal(writer); - } + explicit FontFamily(std::vector<Font>&& fonts); + FontFamily(FamilyVariant variant, std::vector<Font>&& fonts); + FontFamily(uint32_t localeListId, FamilyVariant variant, std::vector<Font>&& fonts, + bool isCustomFallback); FakedFont getClosestMatch(FontStyle style) const; @@ -67,9 +45,8 @@ public: // API's for enumerating the fonts in a family. These don't guarantee any particular order size_t getNumFonts() const { return mFonts.size(); } - const Font* getFont(size_t index) const { return mFonts[index].get(); } - const std::shared_ptr<Font>& getFontRef(size_t index) const { return mFonts[index]; } - FontStyle getStyle(size_t index) const { return mFonts[index]->style(); } + const Font* getFont(size_t index) const { return &mFonts[index]; } + FontStyle getStyle(size_t index) const { return mFonts[index].style(); } bool isColorEmojiFamily() const { return mIsColorEmoji; } const std::unordered_set<AxisTag>& supportedAxes() const { return mSupportedAxes; } bool isCustomFallback() const { return mIsCustomFallback; } @@ -90,24 +67,11 @@ public: const std::vector<FontVariation>& variations) const; private: - FontFamily(uint32_t localeListId, FamilyVariant variant, - std::vector<std::shared_ptr<Font>>&& fonts, - std::unordered_set<AxisTag>&& supportedAxes, bool isColorEmoji, - bool isCustomFallback, SparseBitSet&& coverage, - std::vector<std::unique_ptr<SparseBitSet>>&& cmapFmt14Coverage); - - static uint32_t readLocaleListInternal(BufferReader* reader); - static std::shared_ptr<FontFamily> readFromInternal(BufferReader* reader, - std::vector<std::shared_ptr<Font>>&& fonts, - uint32_t localeListId); - void writeLocaleListInternal(BufferWriter* writer) const; - void writeToInternal(BufferWriter* writer) const; - void computeCoverage(); uint32_t mLocaleListId; FamilyVariant mVariant; - std::vector<std::shared_ptr<Font>> mFonts; + std::vector<Font> mFonts; std::unordered_set<AxisTag> mSupportedAxes; bool mIsColorEmoji; bool mIsCustomFallback; diff --git a/include/minikin/FontFileParser.h b/include/minikin/FontFileParser.h deleted file mode 100644 index 34880a3..0000000 --- a/include/minikin/FontFileParser.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef MINIKIN_FONT_FILE_PARSER_H -#define MINIKIN_FONT_FILE_PARSER_H - -#include "minikin/HbUtils.h" - -#include <optional> -#include <string> - -namespace minikin { - -// FontFileParser provides various parser logic for OpenType font file. -class FontFileParser { -public: - // This class does not take an ownership of buffer. Caller must free it. - FontFileParser(const void* buffer, size_t size, uint32_t index); - explicit FontFileParser(const HbFaceUniquePtr& face); - explicit FontFileParser(const HbFontUniquePtr& font); - - virtual ~FontFileParser(); - - std::optional<uint32_t> getFontRevision() const; - std::optional<std::string> getPostScriptName() const; - std::optional<bool> isPostScriptType1Font() const; - -protected: // protected for testing purposes. - static bool analyzeFontRevision(const uint8_t* head_data, size_t head_size, uint32_t* out); - static bool checkPSName(const std::string& psName); - -private: - HbFaceUniquePtr mFace; - - static HbFaceUniquePtr makeHbFace(const void* buffer, size_t size, uint32_t index); -}; - -} // namespace minikin - -#endif // MINIKIN_FONT_FILE_PARSER_H diff --git a/include/minikin/FontStyle.h b/include/minikin/FontStyle.h index 51e4ad8..73cf427 100644 --- a/include/minikin/FontStyle.h +++ b/include/minikin/FontStyle.h @@ -17,8 +17,6 @@ #ifndef MINIKIN_FONT_STYLE_H #define MINIKIN_FONT_STYLE_H -#include <minikin/Buffer.h> - namespace minikin { // FontStyle represents style information. @@ -48,15 +46,6 @@ public: constexpr FontStyle(Weight weight, Slant slant) : FontStyle(static_cast<uint16_t>(weight), slant) {} constexpr FontStyle(uint16_t weight, Slant slant) : mWeight(weight), mSlant(slant) {} - explicit FontStyle(BufferReader* reader) { - mWeight = reader->read<uint16_t>(); - mSlant = static_cast<Slant>(reader->read<uint8_t>()); - } - - void writeTo(BufferWriter* writer) const { - writer->write<uint16_t>(mWeight); - writer->write<uint8_t>(static_cast<uint8_t>(mSlant)); - } constexpr uint16_t weight() const { return mWeight; } constexpr Slant slant() const { return mSlant; } diff --git a/include/minikin/FontVariation.h b/include/minikin/FontVariation.h index e0567c1..0c38d6a 100644 --- a/include/minikin/FontVariation.h +++ b/include/minikin/FontVariation.h @@ -24,7 +24,6 @@ namespace minikin { typedef uint32_t AxisTag; struct FontVariation { - FontVariation() = default; FontVariation(AxisTag axisTag, float value) : axisTag(axisTag), value(value) {} AxisTag axisTag; float value; diff --git a/include/minikin/Hasher.h b/include/minikin/Hasher.h index 4a76b29..8a79b61 100644 --- a/include/minikin/Hasher.h +++ b/include/minikin/Hasher.h @@ -37,26 +37,6 @@ public: return *this; } - inline Hasher& update(int32_t data) { - update(static_cast<uint32_t>(data)); - return *this; - } - - inline Hasher& update(uint64_t data) { - update(static_cast<uint32_t>(data)); - update(static_cast<uint32_t>(data >> 32)); - return *this; - } - - inline Hasher& update(float data) { - union { - float f; - uint32_t i; - } bits; - bits.f = data; - return update(bits.i); - } - inline Hasher& updateShorts(const uint16_t* data, uint32_t length) { update(length); uint32_t i; diff --git a/include/minikin/Layout.h b/include/minikin/Layout.h index 388a7a7..19f3109 100644 --- a/include/minikin/Layout.h +++ b/include/minikin/Layout.h @@ -84,8 +84,7 @@ public: // public accessors size_t nGlyphs() const { return mGlyphs.size(); } - const Font* getFont(int i) const { return mGlyphs[i].font.font.get(); } - const std::shared_ptr<Font>& getFontRef(int i) const { return mGlyphs[i].font.font; } + const MinikinFont* getFont(int i) const { return mGlyphs[i].font.font->typeface().get(); } FontFakery getFakery(int i) const { return mGlyphs[i].font.fakery; } unsigned int getGlyphId(int i) const { return mGlyphs[i].glyph_id; } float getX(int i) const { return mGlyphs[i].x; } @@ -93,6 +92,8 @@ public: float getAdvance() const { return mAdvance; } float getCharAdvance(size_t i) const { return mAdvances[i]; } const std::vector<float>& getAdvances() const { return mAdvances; } + void getBounds(MinikinRect* rect) const { rect->set(mBounds); } + const MinikinRect& getBounds() const { return mBounds; } // Purge all caches, useful in low memory conditions static void purgeCaches(); @@ -134,6 +135,7 @@ private: std::vector<float> mAdvances; float mAdvance; + MinikinRect mBounds; }; } // namespace minikin diff --git a/include/minikin/LayoutCache.h b/include/minikin/LayoutCache.h index a1cc34a..ee51f11 100644 --- a/include/minikin/LayoutCache.h +++ b/include/minikin/LayoutCache.h @@ -83,9 +83,9 @@ public: private: const uint16_t* mChars; - uint32_t mNchars; - uint32_t mStart; - uint32_t mCount; + size_t mNchars; + size_t mStart; + size_t mCount; uint32_t mId; // for the font collection FontStyle mStyle; float mSize; diff --git a/include/minikin/LayoutCore.h b/include/minikin/LayoutCore.h index cade517..852b985 100644 --- a/include/minikin/LayoutCore.h +++ b/include/minikin/LayoutCore.h @@ -49,10 +49,11 @@ public: // Low level accessors. const std::vector<uint8_t>& fontIndices() const { return mFontIndices; } - const std::vector<uint32_t>& glyphIds() const { return mGlyphIds; } - const std::vector<Point>& points() const { return mPoints; } - const std::vector<float>& advances() const { return mAdvances; } + const std::vector<uint32_t> glyphIds() const { return mGlyphIds; } + const std::vector<Point> points() const { return mPoints; } + const std::vector<float> advances() const { return mAdvances; } float advance() const { return mAdvance; } + const MinikinRect& bounds() const { return mBounds; } const MinikinExtent& extent() const { return mExtent; } const std::vector<FakedFont>& fonts() const { return mFonts; } @@ -78,6 +79,7 @@ private: std::vector<float> mAdvances; // per code units float mAdvance; + MinikinRect mBounds; MinikinExtent mExtent; std::vector<FakedFont> mFonts; diff --git a/include/minikin/LineBreaker.h b/include/minikin/LineBreaker.h index 5d3e752..3410339 100644 --- a/include/minikin/LineBreaker.h +++ b/include/minikin/LineBreaker.h @@ -62,9 +62,6 @@ public: return mStops[i]; } } - if (mTabWidth == 0) { - return 0; - } return floor(widthSoFar / mTabWidth + 1) * mTabWidth; } diff --git a/include/minikin/LocaleList.h b/include/minikin/LocaleList.h index d173a46..bfc26c7 100644 --- a/include/minikin/LocaleList.h +++ b/include/minikin/LocaleList.h @@ -21,17 +21,11 @@ namespace minikin { -// A special ID for the empty locale list. -// This value must be 0 since the empty locale list is inserted into mLocaleLists by default. -const static uint32_t kEmptyLocaleListId = 0; - // Looks up a locale list from an internal cache and returns its ID. // If the passed locale list is not in the cache, registers it and returns newly assigned ID. // TODO: Introduce LocaleId type. uint32_t registerLocaleList(const std::string& locales); -std::string getLocaleString(uint32_t id); - } // namespace minikin #endif // MINIKIN_LOCALE_H diff --git a/include/minikin/Measurement.h b/include/minikin/Measurement.h index d0aaa51..c8b97d1 100644 --- a/include/minikin/Measurement.h +++ b/include/minikin/Measurement.h @@ -20,8 +20,6 @@ #include <cstddef> #include <cstdint> -#include <minikin/Layout.h> - namespace minikin { float getRunAdvance(const float* advances, const uint16_t* buf, size_t start, size_t count, @@ -30,10 +28,6 @@ float getRunAdvance(const float* advances, const uint16_t* buf, size_t start, si size_t getOffsetForAdvance(const float* advances, const uint16_t* buf, size_t start, size_t count, float advance); -void getBounds(const U16StringPiece& str, const Range& range, Bidi bidiFlags, - const MinikinPaint& paint, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, - MinikinRect* out); - } // namespace minikin #endif // MINIKIN_MEASUREMENT_H diff --git a/include/minikin/MinikinFont.h b/include/minikin/MinikinFont.h index 4d3ba9c..a5ba074 100644 --- a/include/minikin/MinikinFont.h +++ b/include/minikin/MinikinFont.h @@ -34,7 +34,7 @@ struct MinikinRect; // multiple actual implementations of fonts. class MinikinFont { public: - MinikinFont() {} + explicit MinikinFont(int32_t uniqueId) : mUniqueId(uniqueId) {} virtual ~MinikinFont() {} @@ -54,9 +54,6 @@ public: virtual void GetFontExtent(MinikinExtent* extent, const MinikinPaint& paint, const FontFakery& fakery) const = 0; - // Returns the font path or an empty string. - virtual const std::string& GetFontPath() const = 0; - // Override if font can provide access to raw data virtual const void* GetFontData() const { return nullptr; } @@ -67,8 +64,6 @@ public: // Returns index within OpenType collection virtual int GetFontIndex() const { return 0; } - virtual int GetSourceId() const { return 0; } - virtual const std::vector<minikin::FontVariation>& GetAxes() const = 0; virtual std::shared_ptr<MinikinFont> createFontWithVariation( @@ -79,6 +74,11 @@ public: static uint32_t MakeTag(char c1, char c2, char c3, char c4) { return ((uint32_t)c1 << 24) | ((uint32_t)c2 << 16) | ((uint32_t)c3 << 8) | (uint32_t)c4; } + + int32_t GetUniqueId() const { return mUniqueId; } + +private: + const int32_t mUniqueId; }; } // namespace minikin diff --git a/include/minikin/MinikinRect.h b/include/minikin/MinikinRect.h index 38c2180..6a3d88b 100644 --- a/include/minikin/MinikinRect.h +++ b/include/minikin/MinikinRect.h @@ -28,7 +28,6 @@ struct MinikinRect { bool operator==(const MinikinRect& o) const { return mLeft == o.mLeft && mTop == o.mTop && mRight == o.mRight && mBottom == o.mBottom; } - bool operator!=(const MinikinRect& o) const { return !(*this == o); } float mLeft; float mTop; float mRight; diff --git a/include/minikin/SparseBitSet.h b/include/minikin/SparseBitSet.h index 3034243..9ccef12 100644 --- a/include/minikin/SparseBitSet.h +++ b/include/minikin/SparseBitSet.h @@ -17,7 +17,6 @@ #ifndef MINIKIN_SPARSE_BIT_SET_H #define MINIKIN_SPARSE_BIT_SET_H -#include <minikin/Buffer.h> #include <sys/types.h> #include <cstdint> #include <memory> @@ -43,13 +42,9 @@ public: initFromRanges(ranges, nRanges); } - explicit SparseBitSet(BufferReader* reader) : SparseBitSet() { initFromBuffer(reader); } - SparseBitSet(SparseBitSet&&) = default; SparseBitSet& operator=(SparseBitSet&&) = default; - void writeTo(BufferWriter* writer) const; - // Determine whether the value is included in the set bool get(uint32_t ch) const { if (ch >= mMaxVal) return false; @@ -69,7 +64,6 @@ public: private: void initFromRanges(const uint32_t* ranges, size_t nRanges); - void initFromBuffer(BufferReader* reader); static const uint32_t kMaximumCapacity = 0xFFFFFF; static const int kLogValuesPerPage = 8; @@ -87,15 +81,10 @@ private: static int CountLeadingZeros(element x); uint32_t mMaxVal; - uint32_t mIndicesCount; - const uint16_t* mIndices; - uint32_t mBitmapsCount; - const element* mBitmaps; - uint16_t mZeroPageIndex; - // Owns allocated memory if this class is created from ranges, otherwise these are nullptr. - std::unique_ptr<uint16_t[]> mOwnedIndices; - std::unique_ptr<element[]> mOwnedBitmaps; + std::unique_ptr<uint16_t[]> mIndices; + std::unique_ptr<element[]> mBitmaps; + uint16_t mZeroPageIndex; // Forbid copy and assign. SparseBitSet(const SparseBitSet&) = delete; diff --git a/include/minikin/SystemFonts.h b/include/minikin/SystemFonts.h index cf4ab75..4108215 100644 --- a/include/minikin/SystemFonts.h +++ b/include/minikin/SystemFonts.h @@ -19,7 +19,6 @@ #include <map> #include <memory> -#include <mutex> #include <string> #include "minikin/FontCollection.h" @@ -34,78 +33,39 @@ public: return getInstance().findFontCollectionInternal(familyName); } + // Do not call this function outside Zygote process. static void registerFallback(const std::string& familyName, const std::shared_ptr<FontCollection>& fc) { return getInstance().registerFallbackInternal(familyName, fc); } + // Do not call this function outside Zygote process. static void registerDefault(const std::shared_ptr<FontCollection>& fc) { return getInstance().registerDefaultInternal(fc); } - using FontMapDeleter = std::function<void()>; - - static void addFontMap(std::shared_ptr<FontCollection>&& collections) { - return getInstance().addFontMapInternal(std::move(collections)); - } - - // This obtains a mutex inside, so do not call this method inside callback. - static void getFontMap( - std::function<void(const std::vector<std::shared_ptr<FontCollection>>&)> func) { - return getInstance().getFontMapInternal(func); - } - - static void getFontSet(std::function<void(const std::vector<std::shared_ptr<Font>>&)> func) { - return getInstance().getFontSetInternal(func); - } - protected: // Visible for testing purposes. SystemFonts() {} virtual ~SystemFonts() {} - std::shared_ptr<FontCollection> findFontCollectionInternal(const std::string& familyName); + std::shared_ptr<FontCollection> findFontCollectionInternal(const std::string& familyName) const; void registerFallbackInternal(const std::string& familyName, const std::shared_ptr<FontCollection>& fc) { - std::lock_guard<std::mutex> lock(mMutex); - mSystemFallbacks[familyName] = fc; + mSystemFallbacks.insert(std::make_pair(familyName, fc)); } void registerDefaultInternal(const std::shared_ptr<FontCollection>& fc) { - std::lock_guard<std::mutex> lock(mMutex); mDefaultFallback = fc; } - void addFontMapInternal(std::shared_ptr<FontCollection>&& collections) { - std::lock_guard<std::mutex> lock(mMutex); - mCollections.emplace_back(std::move(collections)); - } - - void getFontMapInternal( - std::function<void(const std::vector<std::shared_ptr<FontCollection>>&)> func) { - std::lock_guard<std::mutex> lock(mMutex); - func(mCollections); - } - - void getFontSetInternal(std::function<void(const std::vector<std::shared_ptr<Font>>&)> func) { - std::lock_guard<std::mutex> lock(mMutex); - if (!mFonts) { - buildFontSetLocked(); - } - func(mFonts.value()); - } - private: static SystemFonts& getInstance(); - void buildFontSetLocked() EXCLUSIVE_LOCKS_REQUIRED(mMutex); - - std::map<std::string, std::shared_ptr<FontCollection>> mSystemFallbacks GUARDED_BY(mMutex); - std::shared_ptr<FontCollection> mDefaultFallback GUARDED_BY(mMutex); - std::vector<std::shared_ptr<FontCollection>> mCollections GUARDED_BY(mMutex); - std::optional<std::vector<std::shared_ptr<Font>>> mFonts GUARDED_BY(mMutex); - - std::mutex mMutex; + // There is no mutex guard here since registerFallback is designed to be + // called only in Zygote. + std::map<std::string, std::shared_ptr<FontCollection>> mSystemFallbacks; + std::shared_ptr<FontCollection> mDefaultFallback; }; } // namespace minikin diff --git a/libs/minikin/Android.bp b/libs/minikin/Android.bp index 8356ea4..9c20758 100644 --- a/libs/minikin/Android.bp +++ b/libs/minikin/Android.bp @@ -12,10 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - cc_library_headers { name: "libminikin-headers-for-tests", export_include_dirs: ["."], @@ -28,13 +24,10 @@ cc_library { host_supported: true, srcs: [ "BidiUtils.cpp", - "BoundsCache.cpp", "CmapCoverage.cpp", "Emoji.cpp", - "Font.cpp", "FontCollection.cpp", "FontFamily.cpp", - "FontFileParser.cpp", "FontUtils.cpp", "GraphemeBreak.cpp", "GreedyLineBreaker.cpp", @@ -88,6 +81,7 @@ cc_library { "libutils_headers", ], export_header_lib_headers: ["libminikin_headers"], + whole_static_libs: ["libgtest_prod"], clang: true, diff --git a/libs/minikin/BoundsCache.cpp b/libs/minikin/BoundsCache.cpp deleted file mode 100644 index 1edc853..0000000 --- a/libs/minikin/BoundsCache.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "minikin/BoundsCache.h" - -namespace minikin { - -void ValueExtractor::operator()(const LayoutPiece& layoutPiece, const MinikinPaint& paint) { - value.reset(new BoundsValue); - value->rect = BoundsCache::getBounds(layoutPiece, paint); - value->advance = layoutPiece.advance(); -} - -// static -MinikinRect BoundsCache::getBounds(const LayoutPiece& layoutPiece, const MinikinPaint& paint) { - MinikinRect pieceBounds; - MinikinRect tmpRect; - for (uint32_t i = 0; i < layoutPiece.glyphCount(); ++i) { - const FakedFont& font = layoutPiece.fontAt(i); - const Point& point = layoutPiece.pointAt(i); - - MinikinFont* minikinFont = font.font->typeface().get(); - minikinFont->GetBounds(&tmpRect, layoutPiece.glyphIdAt(i), paint, font.fakery); - tmpRect.offset(point.x, point.y); - pieceBounds.join(tmpRect); - } - return pieceBounds; -} - -} // namespace minikin diff --git a/libs/minikin/Font.cpp b/libs/minikin/Font.cpp deleted file mode 100644 index c2e74b7..0000000 --- a/libs/minikin/Font.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "Minikin" - -#include "minikin/Font.h" - -#include <vector> - -#include <hb-ot.h> -#include <hb.h> -#include <log/log.h> - -#include "minikin/HbUtils.h" -#include "minikin/MinikinFont.h" - -#include "FontUtils.h" -#include "MinikinInternal.h" - -namespace minikin { - -std::shared_ptr<Font> Font::Builder::build() { - if (mIsWeightSet && mIsSlantSet) { - // No need to read OS/2 header of the font file. - return std::shared_ptr<Font>(new Font(std::move(mTypeface), FontStyle(mWeight, mSlant), - prepareFont(mTypeface), mLocaleListId)); - } - - HbFontUniquePtr font = prepareFont(mTypeface); - FontStyle styleFromFont = analyzeStyle(font); - if (!mIsWeightSet) { - mWeight = styleFromFont.weight(); - } - if (!mIsSlantSet) { - mSlant = styleFromFont.slant(); - } - return std::shared_ptr<Font>(new Font(std::move(mTypeface), FontStyle(mWeight, mSlant), - std::move(font), mLocaleListId)); -} - -const std::shared_ptr<MinikinFont>& Font::typeface() const { - std::lock_guard lock(mTypefaceMutex); - if (mTypeface) return mTypeface; - initTypefaceLocked(); - return mTypeface; -} - -const HbFontUniquePtr& Font::baseFont() const { - std::lock_guard lock(mTypefaceMutex); - if (mBaseFont) return mBaseFont; - initTypefaceLocked(); - mBaseFont = prepareFont(mTypeface); - return mBaseFont; -} - -void Font::initTypefaceLocked() const { - if (mTypeface) return; - MINIKIN_ASSERT(mTypefaceLoader, "mTypefaceLoader should not be empty when mTypeface is null"); - mTypeface = mTypefaceLoader(mTypefaceMetadataReader); -} - -// static -HbFontUniquePtr Font::prepareFont(const std::shared_ptr<MinikinFont>& typeface) { - const char* buf = reinterpret_cast<const char*>(typeface->GetFontData()); - size_t size = typeface->GetFontSize(); - uint32_t ttcIndex = typeface->GetFontIndex(); - - HbBlobUniquePtr blob(hb_blob_create(buf, size, HB_MEMORY_MODE_READONLY, nullptr, nullptr)); - HbFaceUniquePtr face(hb_face_create(blob.get(), ttcIndex)); - HbFontUniquePtr parent(hb_font_create(face.get())); - hb_ot_font_set_funcs(parent.get()); - - uint32_t upem = hb_face_get_upem(face.get()); - hb_font_set_scale(parent.get(), upem, upem); - - HbFontUniquePtr font(hb_font_create_sub_font(parent.get())); - std::vector<hb_variation_t> variations; - variations.reserve(typeface->GetAxes().size()); - for (const FontVariation& variation : typeface->GetAxes()) { - variations.push_back({variation.axisTag, variation.value}); - } - hb_font_set_variations(font.get(), variations.data(), variations.size()); - return font; -} - -// static -FontStyle Font::analyzeStyle(const HbFontUniquePtr& font) { - HbBlob os2Table(font, MinikinFont::MakeTag('O', 'S', '/', '2')); - if (!os2Table) { - return FontStyle(); - } - - int weight; - bool italic; - if (!::minikin::analyzeStyle(os2Table.get(), os2Table.size(), &weight, &italic)) { - return FontStyle(); - } - // TODO: Update weight/italic based on fvar value. - return FontStyle(static_cast<uint16_t>(weight), static_cast<FontStyle::Slant>(italic)); -} - -std::unordered_set<AxisTag> Font::getSupportedAxes() const { - HbBlob fvarTable(baseFont(), MinikinFont::MakeTag('f', 'v', 'a', 'r')); - if (!fvarTable) { - return std::unordered_set<AxisTag>(); - } - std::unordered_set<AxisTag> supportedAxes; - analyzeAxes(fvarTable.get(), fvarTable.size(), &supportedAxes); - return supportedAxes; -} - -} // namespace minikin diff --git a/libs/minikin/FontCollection.cpp b/libs/minikin/FontCollection.cpp index 9e4dd3b..6cbabea 100644 --- a/libs/minikin/FontCollection.cpp +++ b/libs/minikin/FontCollection.cpp @@ -24,7 +24,6 @@ #include <unicode/unorm2.h> #include "minikin/Emoji.h" -#include "minikin/FontFileParser.h" #include "Locale.h" #include "LocaleListCache.h" @@ -44,23 +43,6 @@ const uint32_t TEXT_STYLE_VS = 0xFE0E; static std::atomic<uint32_t> gNextCollectionId = {0}; -namespace { - -uint32_t getGlyphCount(U16StringPiece text, uint32_t start, uint32_t end, - const HbFontUniquePtr& font) { - HbBufferUniquePtr buffer(hb_buffer_create()); - hb_buffer_set_direction(buffer.get(), HB_DIRECTION_LTR); - hb_buffer_add_utf16(buffer.get(), text.data() + start, end - start, 0, end - start); - hb_buffer_guess_segment_properties(buffer.get()); - - unsigned int numGlyphs = -1; - hb_shape(font.get(), buffer.get(), nullptr, 0); - hb_buffer_get_glyph_infos(buffer.get(), &numGlyphs); - return numGlyphs; -} - -} // namespace - FontCollection::FontCollection(std::shared_ptr<FontFamily>&& typeface) : mMaxChar(0) { std::vector<std::shared_ptr<FontFamily>> typefaces; typefaces.push_back(typeface); @@ -101,91 +83,24 @@ void FontCollection::init(const vector<std::shared_ptr<FontFamily>>& typefaces) // A font can have a glyph for a base code point and variation selector pair but no glyph for // the base code point without variation selector. The family won't be listed in the range in // this case. - mOwnedRanges = std::make_unique<Range[]>(nPages); - mRanges = mOwnedRanges.get(); - mRangesCount = nPages; for (size_t i = 0; i < nPages; i++) { - Range* range = &mOwnedRanges[i]; - range->start = mOwnedFamilyVec.size(); + Range dummy; + mRanges.push_back(dummy); + Range* range = &mRanges.back(); + range->start = mFamilyVec.size(); for (size_t j = 0; j < nTypefaces; j++) { if (lastChar[j] < (i + 1) << kLogCharsPerPage) { const std::shared_ptr<FontFamily>& family = mFamilies[j]; - mOwnedFamilyVec.push_back(static_cast<uint8_t>(j)); + mFamilyVec.push_back(static_cast<uint8_t>(j)); uint32_t nextChar = family->getCoverage().nextSetBit((i + 1) << kLogCharsPerPage); lastChar[j] = nextChar; } } - range->end = mOwnedFamilyVec.size(); + range->end = mFamilyVec.size(); } // See the comment in Range for more details. - LOG_ALWAYS_FATAL_IF(mOwnedFamilyVec.size() >= 0xFFFF, + LOG_ALWAYS_FATAL_IF(mFamilyVec.size() >= 0xFFFF, "Exceeded the maximum indexable cmap coverage."); - mFamilyVec = mOwnedFamilyVec.data(); - mFamilyVecCount = mOwnedFamilyVec.size(); -} - -FontCollection::FontCollection(BufferReader* reader, - const std::vector<std::shared_ptr<FontFamily>>& families) { - mId = gNextCollectionId++; - mMaxChar = reader->read<uint32_t>(); - uint32_t familiesCount = reader->read<uint32_t>(); - mFamilies.reserve(familiesCount); - for (uint32_t i = 0; i < familiesCount; i++) { - uint32_t index = reader->read<uint32_t>(); - if (index >= families.size()) { - ALOGE("Invalid FontFamily index: %zu", (size_t)index); - } else { - mFamilies.push_back(families[index]); - if (families[index]->hasVSTable()) { - mVSFamilyVec.push_back(families[index]); - } - } - } - // Range is two packed uint16_t - static_assert(sizeof(Range) == 4); - std::tie(mRanges, mRangesCount) = reader->readArray<Range>(); - std::tie(mFamilyVec, mFamilyVecCount) = reader->readArray<uint8_t>(); - const auto& [axesPtr, axesCount] = reader->readArray<AxisTag>(); - mSupportedAxes.insert(axesPtr, axesPtr + axesCount); -} - -void FontCollection::writeTo(BufferWriter* writer, - const std::unordered_map<std::shared_ptr<FontFamily>, uint32_t>& - fontFamilyToIndexMap) const { - writer->write<uint32_t>(mMaxChar); - writer->write<uint32_t>(mFamilies.size()); - for (const std::shared_ptr<FontFamily>& fontFamily : mFamilies) { - auto it = fontFamilyToIndexMap.find(fontFamily); - if (it == fontFamilyToIndexMap.end()) { - ALOGE("fontFamily not found in fontFamilyToIndexMap"); - writer->write<uint32_t>(-1); - } else { - writer->write<uint32_t>(it->second); - } - } - writer->writeArray<Range>(mRanges, mRangesCount); - writer->writeArray<uint8_t>(mFamilyVec, mFamilyVecCount); - // No need to serialize mVSFamilyVec as it can be reconstructed easily from mFamilies. - std::vector<AxisTag> axes(mSupportedAxes.begin(), mSupportedAxes.end()); - // Sort axes to be deterministic. - std::sort(axes.begin(), axes.end()); - writer->writeArray<AxisTag>(axes.data(), axes.size()); -} - -// static -void FontCollection::collectAllFontFamilies( - const std::vector<std::shared_ptr<FontCollection>>& fontCollections, - std::vector<std::shared_ptr<FontFamily>>* outAllFontFamilies, - std::unordered_map<std::shared_ptr<FontFamily>, uint32_t>* outFontFamilyToIndexMap) { - for (const auto& fontCollection : fontCollections) { - for (const std::shared_ptr<FontFamily>& fontFamily : fontCollection->mFamilies) { - bool inserted = - outFontFamilyToIndexMap->emplace(fontFamily, outAllFontFamilies->size()).second; - if (inserted) { - outAllFontFamilies->push_back(fontFamily); - } - } - } } // Special scores for the font fallback. @@ -334,11 +249,11 @@ uint32_t FontCollection::calcVariantMatchingScore(FamilyVariant variant, // 2. Calculate a score for the font family. See comments in calcFamilyScore for the detail. // 3. Highest score wins, with ties resolved to the first font. // This method never returns nullptr. -FontCollection::FamilyMatchResult FontCollection::getFamilyForChar(uint32_t ch, uint32_t vs, - uint32_t localeListId, - FamilyVariant variant) const { +const std::shared_ptr<FontFamily>& FontCollection::getFamilyForChar(uint32_t ch, uint32_t vs, + uint32_t localeListId, + FamilyVariant variant) const { if (ch >= mMaxChar) { - return FamilyMatchResult::Builder().add(0).build(); + return mFamilies[0]; } Range range = mRanges[ch >> kLogCharsPerPage]; @@ -347,27 +262,23 @@ FontCollection::FamilyMatchResult FontCollection::getFamilyForChar(uint32_t ch, range = {0, static_cast<uint16_t>(mFamilies.size())}; } + int bestFamilyIndex = -1; uint32_t bestScore = kUnsupportedFontScore; - FamilyMatchResult::Builder builder; - for (size_t i = range.start; i < range.end; i++) { - const uint8_t familyIndex = vs == 0 ? mFamilyVec[i] : i; - const std::shared_ptr<FontFamily>& family = mFamilies[familyIndex]; + const std::shared_ptr<FontFamily>& family = + vs == 0 ? mFamilies[mFamilyVec[i]] : mFamilies[i]; const uint32_t score = calcFamilyScore(ch, vs, variant, localeListId, family); if (score == kFirstFontScore) { // If the first font family supports the given character or variation sequence, always // use it. - return builder.add(familyIndex).build(); + return family; } - if (score != kUnsupportedFontScore && score >= bestScore) { - if (score > bestScore) { - builder.reset(); - bestScore = score; - } - builder.add(familyIndex); + if (score > bestScore) { + bestScore = score; + bestFamilyIndex = i; } } - if (builder.empty()) { + if (bestFamilyIndex == -1) { UErrorCode errorCode = U_ZERO_ERROR; const UNormalizer2* normalizer = unorm2_getNFDInstance(&errorCode); if (U_SUCCESS(errorCode)) { @@ -379,9 +290,9 @@ FontCollection::FamilyMatchResult FontCollection::getFamilyForChar(uint32_t ch, return getFamilyForChar(ch, vs, localeListId, variant); } } - return FamilyMatchResult::Builder().add(0).build(); + return mFamilies[0]; } - return builder.build(); + return vs == 0 ? mFamilies[mFamilyVec[bestFamilyIndex]] : mFamilies[bestFamilyIndex]; } // Characters where we want to continue using existing font run for (or stick to the next run if @@ -401,7 +312,7 @@ static bool doesNotNeedFontSupport(uint32_t c) { // Characters where we want to continue using existing font run instead of // recomputing the best match in the fallback list. -static const uint32_t stickyAllowlist[] = { +static const uint32_t stickyWhitelist[] = { '!', ',', '-', '.', ':', ';', '?', 0x00A0, // NBSP 0x2010, // HYPHEN @@ -412,9 +323,9 @@ static const uint32_t stickyAllowlist[] = { 0x2695, // STAFF_OF_AESCULAPIUS }; -static bool isStickyAllowlisted(uint32_t c) { - for (size_t i = 0; i < sizeof(stickyAllowlist) / sizeof(stickyAllowlist[0]); i++) { - if (stickyAllowlist[i] == c) return true; +static bool isStickyWhitelisted(uint32_t c) { + for (size_t i = 0; i < sizeof(stickyWhitelist) / sizeof(stickyWhitelist[0]); i++) { + if (stickyWhitelist[i] == c) return true; } return false; } @@ -457,45 +368,22 @@ bool FontCollection::hasVariationSelector(uint32_t baseCodepoint, constexpr uint32_t REPLACEMENT_CHARACTER = 0xFFFD; -FontCollection::FamilyMatchResult FontCollection::FamilyMatchResult::intersect( - FontCollection::FamilyMatchResult l, FontCollection::FamilyMatchResult r) { - if (l == r) { - return l; - } - - uint32_t li = 0; - uint32_t ri = 0; - FamilyMatchResult::Builder b; - while (li < l.size() && ri < r.size()) { - if (l[li] < r[ri]) { - li++; - } else if (l[li] > r[ri]) { - ri++; - } else { // l[li] == r[ri] - b.add(l[li]); - li++; - ri++; - } - } - return b.build(); -} - -std::vector<FontCollection::Run> FontCollection::itemize(U16StringPiece text, FontStyle, +std::vector<FontCollection::Run> FontCollection::itemize(U16StringPiece text, FontStyle style, uint32_t localeListId, FamilyVariant familyVariant, uint32_t runMax) const { const uint16_t* string = text.data(); const uint32_t string_size = text.size(); + std::vector<Run> result; - FamilyMatchResult lastFamilyIndices = FamilyMatchResult(); + const FontFamily* lastFamily = nullptr; + Run* run = nullptr; if (string_size == 0) { - return std::vector<Run>(); + return result; } const uint32_t kEndOfString = 0xFFFFFFFF; - std::vector<Run> result; - Run* run = nullptr; uint32_t nextCh = 0; uint32_t prevCh = 0; @@ -523,44 +411,15 @@ std::vector<FontCollection::Run> FontCollection::itemize(U16StringPiece text, Fo if (doesNotNeedFontSupport(ch)) { // Always continue if the character is a format character not needed to be in the font. shouldContinueRun = true; - } else if (!lastFamilyIndices.empty() && (isStickyAllowlisted(ch) || isCombining(ch))) { + } else if (lastFamily != nullptr && (isStickyWhitelisted(ch) || isCombining(ch))) { // Continue using existing font as long as it has coverage and is whitelisted. - - const std::shared_ptr<FontFamily>& lastFamily = mFamilies[lastFamilyIndices[0]]; - if (lastFamily->isColorEmojiFamily()) { - // If the last family is color emoji font, find the longest family. - shouldContinueRun = false; - for (uint8_t ix : lastFamilyIndices) { - shouldContinueRun |= mFamilies[ix]->getCoverage().get(ch); - } - } else { - shouldContinueRun = lastFamily->getCoverage().get(ch); - } + shouldContinueRun = lastFamily->getCoverage().get(ch); } if (!shouldContinueRun) { - FamilyMatchResult familyIndices = getFamilyForChar( + const std::shared_ptr<FontFamily>& family = getFamilyForChar( ch, isVariationSelector(nextCh) ? nextCh : 0, localeListId, familyVariant); - bool breakRun; - if (utf16Pos == 0 || lastFamilyIndices.empty()) { - breakRun = true; - } else { - const std::shared_ptr<FontFamily>& lastFamily = mFamilies[lastFamilyIndices[0]]; - if (lastFamily->isColorEmojiFamily()) { - FamilyMatchResult intersection = - FamilyMatchResult::intersect(familyIndices, lastFamilyIndices); - if (intersection.empty()) { - breakRun = true; // None of last family can draw the given char. - } else { - lastFamilyIndices = intersection; - breakRun = false; - } - } else { - breakRun = familyIndices[0] != lastFamilyIndices[0]; - } - } - - if (breakRun) { + if (utf16Pos == 0 || family.get() != lastFamily) { size_t start = utf16Pos; // Workaround for combining marks and emoji modifiers until we implement // per-cluster font selection: if a combining mark or an emoji modifier is found in @@ -568,31 +427,27 @@ std::vector<FontCollection::Run> FontCollection::itemize(U16StringPiece text, Fo // character to the new run. U+20E3 COMBINING ENCLOSING KEYCAP, used in emoji, is // handled properly by this since it's a combining mark too. if (utf16Pos != 0 && - (isCombining(ch) || (isEmojiModifier(ch) && isEmojiBase(prevCh)))) { - for (uint8_t ix : familyIndices) { - if (mFamilies[ix]->getCoverage().get(prevCh)) { - const size_t prevChLength = U16_LENGTH(prevCh); - if (run != nullptr) { - run->end -= prevChLength; - if (run->start == run->end) { - result.pop_back(); - } - } - start -= prevChLength; - break; + (isCombining(ch) || (isEmojiModifier(ch) && isEmojiBase(prevCh))) && + family != nullptr && family->getCoverage().get(prevCh)) { + const size_t prevChLength = U16_LENGTH(prevCh); + if (run != nullptr) { + run->end -= prevChLength; + if (run->start == run->end) { + result.pop_back(); } } + start -= prevChLength; } - if (lastFamilyIndices.empty()) { + if (lastFamily == nullptr) { // This is the first family ever assigned. We are either seeing the very first // character (which means start would already be zero), or we have only seen // characters that don't need any font support (which means we need to adjust // start to be 0 to include those characters). start = 0; } - result.push_back({familyIndices, static_cast<int>(start), 0}); + result.push_back({family->getClosestMatch(style), static_cast<int>(start), 0}); run = &result.back(); - lastFamilyIndices = run->familyMatch; + lastFamily = family.get(); } } prevCh = ch; @@ -610,42 +465,19 @@ std::vector<FontCollection::Run> FontCollection::itemize(U16StringPiece text, Fo } } while (nextCh != kEndOfString); - if (lastFamilyIndices.empty()) { + if (lastFamily == nullptr) { // No character needed any font support, so it doesn't really matter which font they end up // getting displayed in. We put the whole string in one run, using the first font. - result.push_back( - {FamilyMatchResult::Builder().add(0).build(), 0, static_cast<int>(string_size)}); + result.push_back({mFamilies[0]->getClosestMatch(style), 0, static_cast<int>(string_size)}); } if (result.size() > runMax) { // The itemization has terminated since it reaches the runMax. Remove last unfinalized runs. - return std::vector<Run>(result.begin(), result.begin() + runMax); + result.resize(runMax); } - return result; } -FakedFont FontCollection::getBestFont(U16StringPiece text, const Run& run, FontStyle style) { - uint8_t bestIndex = 0; - uint32_t bestGlyphCount = 0xFFFFFFFF; - - const std::shared_ptr<FontFamily>& family = mFamilies[run.familyMatch[0]]; - if (family->isColorEmojiFamily() && run.familyMatch.size() > 1) { - for (size_t i = 0; i < run.familyMatch.size(); ++i) { - const std::shared_ptr<FontFamily>& family = mFamilies[run.familyMatch[i]]; - const HbFontUniquePtr& font = family->getFont(0)->baseFont(); - uint32_t glyphCount = getGlyphCount(text, run.start, run.end, font); - if (glyphCount < bestGlyphCount) { - bestIndex = run.familyMatch[i]; - bestGlyphCount = glyphCount; - } - } - } else { - bestIndex = run.familyMatch[0]; - } - return mFamilies[bestIndex]->getClosestMatch(style); -} - FakedFont FontCollection::baseFontFaked(FontStyle style) { return mFamilies[0]->getClosestMatch(style); } diff --git a/libs/minikin/FontFamily.cpp b/libs/minikin/FontFamily.cpp index f1fd00a..85a5142 100644 --- a/libs/minikin/FontFamily.cpp +++ b/libs/minikin/FontFamily.cpp @@ -18,9 +18,11 @@ #include "minikin/FontFamily.h" -#include <algorithm> +#include <cstdint> #include <vector> +#include <hb-ot.h> +#include <hb.h> #include <log/log.h> #include "minikin/CmapCoverage.h" @@ -35,101 +37,92 @@ namespace minikin { -FontFamily::FontFamily(std::vector<std::shared_ptr<Font>>&& fonts) - : FontFamily(FamilyVariant::DEFAULT, std::move(fonts)) {} - -FontFamily::FontFamily(FamilyVariant variant, std::vector<std::shared_ptr<Font>>&& fonts) - : FontFamily(kEmptyLocaleListId, variant, std::move(fonts), false /* isCustomFallback */) {} +Font Font::Builder::build() { + if (mIsWeightSet && mIsSlantSet) { + // No need to read OS/2 header of the font file. + return Font(std::move(mTypeface), FontStyle(mWeight, mSlant), prepareFont(mTypeface)); + } -FontFamily::FontFamily(uint32_t localeListId, FamilyVariant variant, - std::vector<std::shared_ptr<Font>>&& fonts, bool isCustomFallback) - : mLocaleListId(localeListId), - mVariant(variant), - mFonts(std::move(fonts)), - mIsColorEmoji(LocaleListCache::getById(localeListId).getEmojiStyle() == - EmojiStyle::EMOJI), - mIsCustomFallback(isCustomFallback) { - MINIKIN_ASSERT(!mFonts.empty(), "FontFamily must contain at least one font."); - computeCoverage(); + HbFontUniquePtr font = prepareFont(mTypeface); + FontStyle styleFromFont = analyzeStyle(font); + if (!mIsWeightSet) { + mWeight = styleFromFont.weight(); + } + if (!mIsSlantSet) { + mSlant = styleFromFont.slant(); + } + return Font(std::move(mTypeface), FontStyle(mWeight, mSlant), std::move(font)); } -FontFamily::FontFamily(uint32_t localeListId, FamilyVariant variant, - std::vector<std::shared_ptr<Font>>&& fonts, - std::unordered_set<AxisTag>&& supportedAxes, bool isColorEmoji, - bool isCustomFallback, SparseBitSet&& coverage, - std::vector<std::unique_ptr<SparseBitSet>>&& cmapFmt14Coverage) - : mLocaleListId(localeListId), - mVariant(variant), - mFonts(std::move(fonts)), - mSupportedAxes(std::move(supportedAxes)), - mIsColorEmoji(isColorEmoji), - mIsCustomFallback(isCustomFallback), - mCoverage(std::move(coverage)), - mCmapFmt14Coverage(std::move(cmapFmt14Coverage)) {} - -// Read fields other than mFonts, mLocaleList. // static -std::shared_ptr<FontFamily> FontFamily::readFromInternal(BufferReader* reader, - std::vector<std::shared_ptr<Font>>&& fonts, - uint32_t localeListId) { - // FamilyVariant is uint8_t - static_assert(sizeof(FamilyVariant) == 1); - FamilyVariant variant = reader->read<FamilyVariant>(); - // AxisTag is uint32_t - static_assert(sizeof(AxisTag) == 4); - const auto& [axesPtr, axesCount] = reader->readArray<AxisTag>(); - std::unordered_set<AxisTag> supportedAxes(axesPtr, axesPtr + axesCount); - bool isColorEmoji = static_cast<bool>(reader->read<uint8_t>()); - bool isCustomFallback = static_cast<bool>(reader->read<uint8_t>()); - SparseBitSet coverage(reader); - // Read mCmapFmt14Coverage. As it can have null entries, it is stored in the buffer as a sparse - // array (size, non-null entry count, array of (index, entry)). - uint32_t cmapFmt14CoverageSize = reader->read<uint32_t>(); - std::vector<std::unique_ptr<SparseBitSet>> cmapFmt14Coverage(cmapFmt14CoverageSize); - uint32_t cmapFmt14CoverageEntryCount = reader->read<uint32_t>(); - for (uint32_t i = 0; i < cmapFmt14CoverageEntryCount; i++) { - uint32_t index = reader->read<uint32_t>(); - cmapFmt14Coverage[index] = std::make_unique<SparseBitSet>(reader); - } - return std::shared_ptr<FontFamily>(new FontFamily( - localeListId, variant, std::move(fonts), std::move(supportedAxes), isColorEmoji, - isCustomFallback, std::move(coverage), std::move(cmapFmt14Coverage))); +HbFontUniquePtr Font::prepareFont(const std::shared_ptr<MinikinFont>& typeface) { + const char* buf = reinterpret_cast<const char*>(typeface->GetFontData()); + size_t size = typeface->GetFontSize(); + uint32_t ttcIndex = typeface->GetFontIndex(); + + HbBlobUniquePtr blob(hb_blob_create(buf, size, HB_MEMORY_MODE_READONLY, nullptr, nullptr)); + HbFaceUniquePtr face(hb_face_create(blob.get(), ttcIndex)); + HbFontUniquePtr parent(hb_font_create(face.get())); + hb_ot_font_set_funcs(parent.get()); + + uint32_t upem = hb_face_get_upem(face.get()); + hb_font_set_scale(parent.get(), upem, upem); + + HbFontUniquePtr font(hb_font_create_sub_font(parent.get())); + std::vector<hb_variation_t> variations; + variations.reserve(typeface->GetAxes().size()); + for (const FontVariation& variation : typeface->GetAxes()) { + variations.push_back({variation.axisTag, variation.value}); + } + hb_font_set_variations(font.get(), variations.data(), variations.size()); + return font; } // static -uint32_t FontFamily::readLocaleListInternal(BufferReader* reader) { - return LocaleListCache::readFrom(reader); +FontStyle Font::analyzeStyle(const HbFontUniquePtr& font) { + HbBlob os2Table(font, MinikinFont::MakeTag('O', 'S', '/', '2')); + if (!os2Table) { + return FontStyle(); + } + + int weight; + bool italic; + if (!::minikin::analyzeStyle(os2Table.get(), os2Table.size(), &weight, &italic)) { + return FontStyle(); + } + // TODO: Update weight/italic based on fvar value. + return FontStyle(static_cast<uint16_t>(weight), static_cast<FontStyle::Slant>(italic)); } -// Write fields other than mFonts. -void FontFamily::writeToInternal(BufferWriter* writer) const { - writer->write<FamilyVariant>(mVariant); - std::vector<AxisTag> axes(mSupportedAxes.begin(), mSupportedAxes.end()); - // Sort axes to be deterministic. - std::sort(axes.begin(), axes.end()); - writer->writeArray<AxisTag>(axes.data(), axes.size()); - writer->write<uint8_t>(mIsColorEmoji); - writer->write<uint8_t>(mIsCustomFallback); - mCoverage.writeTo(writer); - // Write mCmapFmt14Coverage as a sparse array (size, non-null entry count, - // array of (index, entry)) - writer->write<uint32_t>(mCmapFmt14Coverage.size()); - uint32_t cmapFmt14CoverageEntryCount = 0; - for (const std::unique_ptr<SparseBitSet>& coverage : mCmapFmt14Coverage) { - if (coverage != nullptr) cmapFmt14CoverageEntryCount++; - } - writer->write<uint32_t>(cmapFmt14CoverageEntryCount); - for (size_t i = 0; i < mCmapFmt14Coverage.size(); i++) { - if (mCmapFmt14Coverage[i] != nullptr) { - writer->write<uint32_t>(i); - mCmapFmt14Coverage[i]->writeTo(writer); - } +std::unordered_set<AxisTag> Font::getSupportedAxes() const { + HbBlob fvarTable(mBaseFont, MinikinFont::MakeTag('f', 'v', 'a', 'r')); + if (!fvarTable) { + return std::unordered_set<AxisTag>(); } + std::unordered_set<AxisTag> supportedAxes; + analyzeAxes(fvarTable.get(), fvarTable.size(), &supportedAxes); + return supportedAxes; } -void FontFamily::writeLocaleListInternal(BufferWriter* writer) const { - LocaleListCache::writeTo(writer, mLocaleListId); +FontFamily::FontFamily(std::vector<Font>&& fonts) + : FontFamily(FamilyVariant::DEFAULT, std::move(fonts)) {} + +FontFamily::FontFamily(FamilyVariant variant, std::vector<Font>&& fonts) + : FontFamily(LocaleListCache::kEmptyListId, variant, std::move(fonts), + false /* isCustomFallback */) {} + +FontFamily::FontFamily(uint32_t localeListId, FamilyVariant variant, std::vector<Font>&& fonts, + bool isCustomFallback) + : mLocaleListId(localeListId), + mVariant(variant), + mFonts(std::move(fonts)), + mIsColorEmoji(LocaleListCache::getById(localeListId).getEmojiStyle() == + EmojiStyle::EMOJI), + mIsCustomFallback(isCustomFallback) { + MINIKIN_ASSERT(!mFonts.empty(), "FontFamily must contain at least one font."); + computeCoverage(); } + // Compute a matching metric between two styles - 0 is an exact match static int computeMatch(FontStyle style1, FontStyle style2) { if (style1 == style2) return 0; @@ -151,23 +144,21 @@ static FontFakery computeFakery(FontStyle wanted, FontStyle actual) { } FakedFont FontFamily::getClosestMatch(FontStyle style) const { - int bestIndex = 0; - Font* bestFont = mFonts[bestIndex].get(); + const Font* bestFont = &mFonts[0]; int bestMatch = computeMatch(bestFont->style(), style); for (size_t i = 1; i < mFonts.size(); i++) { - Font* font = mFonts[i].get(); - int match = computeMatch(font->style(), style); + const Font& font = mFonts[i]; + int match = computeMatch(font.style(), style); if (i == 0 || match < bestMatch) { - bestFont = font; - bestIndex = i; + bestFont = &font; bestMatch = match; } } - return FakedFont{mFonts[bestIndex], computeFakery(style, bestFont->style())}; + return FakedFont{bestFont, computeFakery(style, bestFont->style())}; } void FontFamily::computeCoverage() { - const std::shared_ptr<Font>& font = getClosestMatch(FontStyle()).font; + const Font* font = getClosestMatch(FontStyle()).font; HbBlob cmapTable(font->baseFont(), MinikinFont::MakeTag('c', 'm', 'a', 'p')); if (cmapTable.get() == nullptr) { ALOGE("Could not get cmap table size!\n"); @@ -177,7 +168,7 @@ void FontFamily::computeCoverage() { mCoverage = CmapCoverage::getCoverage(cmapTable.get(), cmapTable.size(), &mCmapFmt14Coverage); for (size_t i = 0; i < mFonts.size(); ++i) { - std::unordered_set<AxisTag> supportedAxes = mFonts[i]->getSupportedAxes(); + std::unordered_set<AxisTag> supportedAxes = mFonts[i].getSupportedAxes(); mSupportedAxes.insert(supportedAxes.begin(), supportedAxes.end()); } } @@ -225,10 +216,10 @@ std::shared_ptr<FontFamily> FontFamily::createFamilyWithVariation( return nullptr; } - std::vector<std::shared_ptr<Font>> fonts; - for (const auto& font : mFonts) { + std::vector<Font> fonts; + for (const Font& font : mFonts) { bool supportedVariations = false; - std::unordered_set<AxisTag> supportedAxes = font->getSupportedAxes(); + std::unordered_set<AxisTag> supportedAxes = font.getSupportedAxes(); if (!supportedAxes.empty()) { for (const FontVariation& variation : variations) { if (supportedAxes.find(variation.axisTag) != supportedAxes.end()) { @@ -239,13 +230,12 @@ std::shared_ptr<FontFamily> FontFamily::createFamilyWithVariation( } std::shared_ptr<MinikinFont> minikinFont; if (supportedVariations) { - minikinFont = font->typeface()->createFontWithVariation(variations); + minikinFont = font.typeface()->createFontWithVariation(variations); } if (minikinFont == nullptr) { - fonts.push_back(font); - } else { - fonts.push_back(Font::Builder(minikinFont).setStyle(font->style()).build()); + minikinFont = font.typeface(); } + fonts.push_back(Font::Builder(minikinFont).setStyle(font.style()).build()); } return std::shared_ptr<FontFamily>( diff --git a/libs/minikin/FontFileParser.cpp b/libs/minikin/FontFileParser.cpp deleted file mode 100644 index 1bcb711..0000000 --- a/libs/minikin/FontFileParser.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "minikin/FontFileParser.h" - -#define LOG_TAG "Minikin" - -#include <cstdint> -#include <optional> -#include <string> -#include <vector> - -#include <hb-ot.h> -#include <hb.h> - -#include "MinikinInternal.h" -#include "minikin/MinikinFont.h" - -namespace minikin { - -namespace { - -class SafeFontBufferReader { -public: - SafeFontBufferReader(const void* buffer, size_t size) - : mBuffer(reinterpret_cast<const uint8_t*>(buffer)), - mSize(size), - mPos(0), - mError(false) {} - - template <typename T> - T readBE() { - if (mError) return T(); - - if ((mSize - mPos) < sizeof(T)) { - mError = true; - return T(); - } - const T* data = reinterpret_cast<const T*>(mBuffer + mPos); - mPos += sizeof(T); - return *data; - } - - uint16_t readU16() { - if (mError) return 0; - - if ((mSize - mPos) < 2) { - mError = true; - return 0; - } - uint16_t out = ((uint32_t)mBuffer[mPos]) << 8 | ((uint32_t)mBuffer[mPos + 1]); - mPos += 2; - return out; - }; - - uint32_t readU32() { - if (mError) return 0; - - if ((mSize - mPos) < 4) { - mError = true; - return 0; - } - - uint32_t out = ((uint32_t)mBuffer[mPos]) << 24 | ((uint32_t)mBuffer[mPos + 1]) << 16 | - ((uint32_t)mBuffer[mPos + 2]) << 8 | ((uint32_t)mBuffer[mPos + 3]); - mPos += 4; - return out; - }; - - void seek(size_t pos) { - if (mError) return; - - if (pos > mSize) { - mError = true; - } else { - mPos = pos; - } - } - - size_t remaining() const { - if (mError) return 0; - return mSize - mPos; - } - - bool error() const { return mError; } - -private: - const uint8_t* mBuffer; - size_t mSize; - size_t mPos; - bool mError; -}; - -bool isPostScriptNameAllowedChar(char c) { - // OpenType spec says only ASCII codes 33 to 126, ecept for the '[', ']', '(', ')', '{', '}', - // '<', '>', '/', '%'. - if (!(33 <= c && c <= 126)) { - return false; - } - if (c == '[' || c == ']' || c == '(' || c == ')' || c == '{' || c == '}' || c == '<' || - c == '>' || c == '/' || c == '%') { - return false; - } - - return true; -} - -} // namespace - -// static -bool FontFileParser::analyzeFontRevision(const uint8_t* head_data, size_t head_size, - uint32_t* out) { - SafeFontBufferReader reader(head_data, head_size); - - if (reader.remaining() < 8) { - return false; // At least head table has 8 bytes, for version and fontRevision - } - - uint32_t majorVersion = reader.readU16(); - if (reader.error()) return false; - uint32_t minorVersion = reader.readU16(); - if (reader.error()) return false; - - // Invalid head table header. - if (majorVersion != 1 && minorVersion != 0) return false; - - *out = reader.readU32(); - if (reader.error()) return false; - return true; -} - -// static -bool FontFileParser::checkPSName(const std::string& psName) { - if (psName.size() > 63) return false; - - for (auto c : psName) { - if (!isPostScriptNameAllowedChar(c)) { - return false; - } - } - return true; -} - -FontFileParser::FontFileParser(const void* buffer, size_t size, uint32_t index) - : mFace(makeHbFace(buffer, size, index)) {} - -FontFileParser::FontFileParser(const HbFaceUniquePtr& face) - : mFace(hb_face_reference(face.get())) {} - -FontFileParser::FontFileParser(const HbFontUniquePtr& font) - : mFace(hb_face_reference(hb_font_get_face(font.get()))) {} - -FontFileParser::~FontFileParser() {} - -// static -HbFaceUniquePtr FontFileParser::makeHbFace(const void* buffer, size_t size, uint32_t index) { - HbBlobUniquePtr blob(hb_blob_create(reinterpret_cast<const char*>(buffer), size, - HB_MEMORY_MODE_READONLY, nullptr, nullptr)); - return HbFaceUniquePtr(hb_face_create(blob.get(), index)); -} - -std::optional<uint32_t> FontFileParser::getFontRevision() const { - if (!mFace) return std::optional<uint32_t>(); - - HbBlob headTable(mFace, MinikinFont::MakeTag('h', 'e', 'a', 'd')); - if (!headTable) return std::optional<uint32_t>(); - - uint32_t out = 0; - if (!analyzeFontRevision(headTable.get(), headTable.size(), &out)) { - return std::optional<uint32_t>(); - } - - return out; -} - -std::optional<std::string> FontFileParser::getPostScriptName() const { - if (!mFace) return std::optional<std::string>(); - - unsigned int size = 64; // PostScript name is up to 63 characters. - char buf[64] = {}; - - uint32_t result = hb_ot_name_get_utf8(mFace.get(), HB_OT_NAME_ID_POSTSCRIPT_NAME, - HB_LANGUAGE_INVALID, &size, buf); - - if (result == 0) { // not found. - return std::optional<std::string>(); - } - - std::string out(buf, size); - - if (!checkPSName(out)) { // Contains invalid characters. - return std::optional<std::string>(); - } - - return out; -} - -std::optional<bool> FontFileParser::isPostScriptType1Font() const { - if (!mFace) return std::optional<bool>(); - - HbBlob cffTable(mFace, MinikinFont::MakeTag('C', 'F', 'F', ' ')); - HbBlob cff2Table(mFace, MinikinFont::MakeTag('C', 'F', 'F', '2')); - return cffTable || cff2Table; -} - -} // namespace minikin diff --git a/libs/minikin/GreedyLineBreaker.cpp b/libs/minikin/GreedyLineBreaker.cpp index 9bcb22d..f6952a9 100644 --- a/libs/minikin/GreedyLineBreaker.cpp +++ b/libs/minikin/GreedyLineBreaker.cpp @@ -255,7 +255,7 @@ bool GreedyLineBreaker::tryLineBreakWithHyphenation(const Range& range, WordBrea // TODO: Respect trailing line end spaces. bool GreedyLineBreaker::doLineBreakWithGraphemeBounds(const Range& range) { - float width = mMeasuredText.widths[range.getStart()]; + double width = mMeasuredText.widths[range.getStart()]; // Starting from + 1 since at least one character needs to be assigned to a line. for (uint32_t i = range.getStart() + 1; i < range.getEnd(); ++i) { diff --git a/libs/minikin/Layout.cpp b/libs/minikin/Layout.cpp index e7d41c8..b902648 100644 --- a/libs/minikin/Layout.cpp +++ b/libs/minikin/Layout.cpp @@ -158,6 +158,9 @@ void Layout::appendLayout(const LayoutPiece& src, size_t start, float extraAdvan mAdvances[start] += extraAdvance; } } + MinikinRect srcBounds(src.bounds()); + srcBounds.offset(mAdvance, 0); + mBounds.join(srcBounds); mAdvance += src.advance() + extraAdvance; } diff --git a/libs/minikin/LayoutCore.cpp b/libs/minikin/LayoutCore.cpp index f1d0de8..6087646 100644 --- a/libs/minikin/LayoutCore.cpp +++ b/libs/minikin/LayoutCore.cpp @@ -355,9 +355,8 @@ LayoutPiece::LayoutPiece(const U16StringPiece& textBuf, const Range& range, bool mPoints.reserve(count); HbBufferUniquePtr buffer(hb_buffer_create()); - U16StringPiece substr = textBuf.substr(range); - std::vector<FontCollection::Run> items = - paint.font->itemize(substr, paint.fontStyle, paint.localeListId, paint.familyVariant); + std::vector<FontCollection::Run> items = paint.font->itemize( + textBuf.substr(range), paint.fontStyle, paint.localeListId, paint.familyVariant); std::vector<hb_feature_t> features; // Disable default-on non-required ligature features if letter-spacing @@ -385,14 +384,14 @@ LayoutPiece::LayoutPiece(const U16StringPiece& textBuf, const Range& range, bool isRtl ? run_ix >= 0 : run_ix < static_cast<int>(items.size()); isRtl ? --run_ix : ++run_ix) { FontCollection::Run& run = items[run_ix]; - FakedFont fakedFont = paint.font->getBestFont(substr, run, paint.fontStyle); - auto it = fontMap.find(fakedFont.font.get()); + const FakedFont& fakedFont = run.fakedFont; + auto it = fontMap.find(fakedFont.font); uint8_t font_ix; if (it == fontMap.end()) { // First time to see this font. font_ix = mFonts.size(); mFonts.push_back(fakedFont); - fontMap.insert(std::make_pair(fakedFont.font.get(), font_ix)); + fontMap.insert(std::make_pair(fakedFont.font, font_ix)); // We override some functions which are not thread safe. HbFontUniquePtr font(hb_font_create_sub_font(fakedFont.font->baseFont().get())); @@ -422,6 +421,8 @@ LayoutPiece::LayoutPiece(const U16StringPiece& textBuf, const Range& range, bool hb_font_set_ppem(hbFont.get(), size * scaleX, size); hb_font_set_scale(hbFont.get(), HBFloatToFixed(size * scaleX), HBFloatToFixed(size)); + const bool is_color_bitmap_font = isColorBitmapFont(hbFont); + // TODO: if there are multiple scripts within a font in an RTL run, // we need to reorder those runs. This is unlikely with our current // font stack, but should be done for correctness. @@ -501,6 +502,23 @@ LayoutPiece::LayoutPiece(const U16StringPiece& textBuf, const Range& range, bool mGlyphIds.push_back(glyph_ix); mPoints.emplace_back(x + xoff, y + yoff); float xAdvance = HBFixedToFloat(positions[i].x_advance); + MinikinRect glyphBounds; + hb_glyph_extents_t extents = {}; + if (is_color_bitmap_font && + hb_font_get_glyph_extents(hbFont.get(), glyph_ix, &extents)) { + // Note that it is technically possible for a TrueType font to have outline and + // embedded bitmap at the same time. We ignore modified bbox of hinted outline + // glyphs in that case. + glyphBounds.mLeft = roundf(HBFixedToFloat(extents.x_bearing)); + glyphBounds.mTop = roundf(HBFixedToFloat(-extents.y_bearing)); + glyphBounds.mRight = roundf(HBFixedToFloat(extents.x_bearing + extents.width)); + glyphBounds.mBottom = + roundf(HBFixedToFloat(-extents.y_bearing - extents.height)); + } else { + fakedFont.font->typeface()->GetBounds(&glyphBounds, glyph_ix, paint, + fakedFont.fakery); + } + glyphBounds.offset(xoff, yoff); if (clusterBaseIndex < count) { mAdvances[clusterBaseIndex] += xAdvance; @@ -508,6 +526,8 @@ LayoutPiece::LayoutPiece(const U16StringPiece& textBuf, const Range& range, bool ALOGE("cluster %zu (start %zu) out of bounds of count %zu", clusterBaseIndex, start, count); } + glyphBounds.offset(x, y); + mBounds.join(glyphBounds); x += xAdvance; } if (numGlyphs) { diff --git a/libs/minikin/LineBreakerUtil.h b/libs/minikin/LineBreakerUtil.h index 8b383a4..eb058cc 100644 --- a/libs/minikin/LineBreakerUtil.h +++ b/libs/minikin/LineBreakerUtil.h @@ -36,7 +36,7 @@ namespace minikin { // paragraphs, accuracy could degrade using only 32-bit float. Note however that float is used // extensively on the Java side for this. This is a typedef so that we can easily change it based // on performance/accuracy tradeoff. -typedef float ParaWidth; +typedef double ParaWidth; // Hyphenates a string potentially containing non-breaking spaces. std::vector<HyphenationType> hyphenate(const U16StringPiece& string, const Hyphenator& hypenator); diff --git a/libs/minikin/Locale.cpp b/libs/minikin/Locale.cpp index 553f61a..c1ec389 100644 --- a/libs/minikin/Locale.cpp +++ b/libs/minikin/Locale.cpp @@ -34,18 +34,6 @@ uint32_t registerLocaleList(const std::string& locales) { return LocaleListCache::getId(locales); } -std::string getLocaleString(uint32_t localeId) { - const LocaleList& localeList = LocaleListCache::getById(localeId); - std::string out; - for (size_t i = 0; i < localeList.size(); ++i) { - if (i != 0) { - out += ","; - } - out += localeList[i].getString(); - } - return out; -} - // Check if a language code supports extension such as emoji and line break etc. according to its // subtag static bool isSubtag(const char* buf, size_t bufLen, const char* subtag, size_t subtagLen) { diff --git a/libs/minikin/Locale.h b/libs/minikin/Locale.h index 7557301..8052d6c 100644 --- a/libs/minikin/Locale.h +++ b/libs/minikin/Locale.h @@ -95,17 +95,7 @@ public: // Parse from string Locale(const StringPiece& buf); - // Parse from identifier. See getIdentifier() for the identifier format. - explicit Locale(uint64_t identifier) - : mScript(extractBits(identifier, 29, 20)), - mLanguage(extractBits(identifier, 49, 15)), - mRegion(extractBits(identifier, 14, 15)), - mSubScriptBits(scriptToSubScriptBits(mScript)), - mVariant(static_cast<Variant>(extractBits(identifier, 0, 2))), - mEmojiStyle(static_cast<EmojiStyle>(extractBits(identifier, 12, 2))), - mLBStyle(static_cast<LineBreakStyle>(extractBits(identifier, 10, 2))) {} - - bool operator==(const Locale& other) const { + bool operator==(const Locale other) const { return !isUnsupported() && isEqualScript(other) && mLanguage == other.mLanguage && mRegion == other.mRegion && mVariant == other.mVariant && mLBStyle == other.mLBStyle && mEmojiStyle == other.mEmojiStyle; @@ -144,13 +134,13 @@ public: // Identifier pattern: // |-------|-------|-------|-------|-------|-------|-------|-------| - // lllllllllllllll Language Code (15 bits) - // ssssssssssssssssssss Script Code (20 bits) - // rrrrrrrrrrrrrrr Region Code (15 bits) - // ee Emoji Style (2 bits) - // bb Line Break Style (2 bits) - // XXXXXXXX Free (8 bits) - // vv German Variant (2 bits) + // lllllllllllllll Language Code + // ssssssssssssssssssss Script Code + // rrrrrrrrrrrrrrr Region Code + // ee Emoji Style + // bb Line Break Style + // XXXXXXXX Free + // vv German Variant uint64_t getIdentifier() const { return ((uint64_t)mLanguage << 49) | ((uint64_t)mScript << 29) | ((uint64_t)mRegion << 14) | ((uint64_t)mEmojiStyle << 12) | ((uint64_t)mLBStyle << 10) | (uint64_t)mVariant; @@ -191,10 +181,6 @@ private: void resolveUnicodeExtension(const char* buf, size_t length); - inline static uint64_t extractBits(uint64_t value, uint8_t shift, uint8_t nBits) { - return (value >> shift) & ((1 << nBits) - 1); - } - static uint8_t scriptToSubScriptBits(uint32_t rawScript); static LineBreakStyle resolveLineBreakStyle(const char* buf, size_t length); diff --git a/libs/minikin/LocaleListCache.cpp b/libs/minikin/LocaleListCache.cpp index 38800f7..15156cd 100644 --- a/libs/minikin/LocaleListCache.cpp +++ b/libs/minikin/LocaleListCache.cpp @@ -21,16 +21,15 @@ #include <unordered_set> #include <log/log.h> -#include <minikin/Hasher.h> -#include <minikin/LocaleList.h> #include <unicode/uloc.h> -#include <unicode/umachine.h> #include "Locale.h" #include "MinikinInternal.h" namespace minikin { +const uint32_t LocaleListCache::kEmptyListId; + // Returns the text length of output. static size_t toLanguageTag(char* output, size_t outSize, const StringPiece& locale) { output[0] = '\0'; @@ -71,7 +70,7 @@ static size_t toLanguageTag(char* output, size_t outSize, const StringPiece& loc } uErr = U_ZERO_ERROR; - outLength = uloc_toLanguageTag(likelyChars, output, outSize, false, &uErr); + outLength = uloc_toLanguageTag(likelyChars, output, outSize, FALSE, &uErr); if (U_FAILURE(uErr)) { // unable to build a proper locale identifier ALOGD("uloc_toLanguageTag(\"%s\") failed: %s", likelyChars, u_errorName(uErr)); @@ -107,39 +106,15 @@ static std::vector<Locale> parseLocaleList(const std::string& input) { return result; } -size_t LocaleListCache::LocaleVectorHash::operator()(const std::vector<Locale>& locales) const { - Hasher hasher; - for (const auto& locale : locales) { - uint64_t id = locale.getIdentifier(); - hasher.update(static_cast<uint32_t>((id >> 32) & 0xFFFFFFFF)); - hasher.update(static_cast<uint32_t>(id & 0xFFFFFFFF)); - } - return hasher.hash(); -} - LocaleListCache::LocaleListCache() { - // Insert an empty locale list for mapping default locale list to kEmptyLocaleListId. + // Insert an empty locale list for mapping default locale list to kEmptyListId. // The default locale list has only one Locale and it is the unsupported locale. mLocaleLists.emplace_back(); - mLocaleListLookupTable.emplace(std::vector<Locale>(), kEmptyLocaleListId); - mLocaleListStringCache.emplace("", kEmptyLocaleListId); + mLocaleListLookupTable.insert(std::make_pair("", kEmptyListId)); } uint32_t LocaleListCache::getIdInternal(const std::string& locales) { std::lock_guard<std::mutex> lock(mMutex); - const auto& it = mLocaleListStringCache.find(locales); - if (it != mLocaleListStringCache.end()) { - return it->second; - } - uint32_t id = getIdInternal(parseLocaleList(locales)); - mLocaleListStringCache.emplace(locales, id); - return id; -} - -uint32_t LocaleListCache::getIdInternal(std::vector<Locale>&& locales) { - if (locales.empty()) { - return kEmptyLocaleListId; - } const auto& it = mLocaleListLookupTable.find(locales); if (it != mLocaleListLookupTable.end()) { return it->second; @@ -147,31 +122,15 @@ uint32_t LocaleListCache::getIdInternal(std::vector<Locale>&& locales) { // Given locale list is not in cache. Insert it and return newly assigned ID. const uint32_t nextId = mLocaleLists.size(); - mLocaleListLookupTable.emplace(locales, nextId); - LocaleList fontLocales(std::move(locales)); + LocaleList fontLocales(parseLocaleList(locales)); + if (fontLocales.empty()) { + return kEmptyListId; + } mLocaleLists.push_back(std::move(fontLocales)); + mLocaleListLookupTable.insert(std::make_pair(locales, nextId)); return nextId; } -uint32_t LocaleListCache::readFromInternal(BufferReader* reader) { - uint32_t size = reader->read<uint32_t>(); - std::vector<Locale> locales; - locales.reserve(size); - for (uint32_t i = 0; i < size; i++) { - locales.emplace_back(reader->read<uint64_t>()); - } - std::lock_guard<std::mutex> lock(mMutex); - return getIdInternal(std::move(locales)); -} - -void LocaleListCache::writeToInternal(BufferWriter* writer, uint32_t id) { - const LocaleList& localeList = getByIdInternal(id); - writer->write<uint32_t>(localeList.size()); - for (size_t i = 0; i < localeList.size(); i++) { - writer->write<uint64_t>(localeList[i].getIdentifier()); - } -} - const LocaleList& LocaleListCache::getByIdInternal(uint32_t id) { std::lock_guard<std::mutex> lock(mMutex); MINIKIN_ASSERT(id < mLocaleLists.size(), "Lookup by unknown locale list ID."); diff --git a/libs/minikin/LocaleListCache.h b/libs/minikin/LocaleListCache.h index a83b1c8..61e3f81 100644 --- a/libs/minikin/LocaleListCache.h +++ b/libs/minikin/LocaleListCache.h @@ -20,7 +20,6 @@ #include <mutex> #include <unordered_map> -#include "minikin/Buffer.h" #include "minikin/Macros.h" #include "Locale.h" @@ -29,39 +28,30 @@ namespace minikin { class LocaleListCache { public: + // A special ID for the empty locale list. + // This value must be 0 since the empty locale list is inserted into mLocaleLists by + // default. + const static uint32_t kEmptyListId = 0; + // A special ID for the invalid locale list. const static uint32_t kInvalidListId = (uint32_t)(-1); // Returns the locale list ID for the given string representation of LocaleList. + // Caller should acquire a lock before calling the method. static inline uint32_t getId(const std::string& locales) { return getInstance().getIdInternal(locales); } - // Returns the locale list ID for the LocaleList serialized in the buffer. - static inline uint32_t readFrom(BufferReader* reader) { - return getInstance().readFromInternal(reader); - } - - static inline void writeTo(BufferWriter* writer, uint32_t id) { - return getInstance().writeToInternal(writer, id); - } - + // Caller should acquire a lock before calling the method. static inline const LocaleList& getById(uint32_t id) { return getInstance().getByIdInternal(id); } private: - struct LocaleVectorHash { - size_t operator()(const std::vector<Locale>& locales) const; - }; - LocaleListCache(); // Singleton ~LocaleListCache() {} uint32_t getIdInternal(const std::string& locales); - uint32_t getIdInternal(std::vector<Locale>&& locales) EXCLUSIVE_LOCKS_REQUIRED(mMutex); - uint32_t readFromInternal(BufferReader* reader); - void writeToInternal(BufferWriter* writer, uint32_t id); const LocaleList& getByIdInternal(uint32_t id); // Caller should acquire a lock before calling the method. @@ -72,18 +62,8 @@ private: std::vector<LocaleList> mLocaleLists GUARDED_BY(mMutex); - // A map from the list of locale identifier to the ID. - // - // Locale's operator==() doesn't have reflexivity for unsupported locales, - // but it won't cause problems because we never store unsupported locales in - // LocaleListCache. See parseLocaleList() in LocaleListCache.cpp. - std::unordered_map<std::vector<Locale>, uint32_t, LocaleVectorHash> mLocaleListLookupTable - GUARDED_BY(mMutex); - - // A cache map from the string representation of the font locale list to the ID. - // This is a mere cache over mLocaleListLookupTable. Some LocaleList objects may be in - // mLocaleListLookupTable even if they are not in mLocaleListStringCache. - std::unordered_map<std::string, uint32_t> mLocaleListStringCache GUARDED_BY(mMutex); + // A map from the string representation of the font locale list to the ID. + std::unordered_map<std::string, uint32_t> mLocaleListLookupTable GUARDED_BY(mMutex); std::mutex mMutex; }; diff --git a/libs/minikin/MeasuredText.cpp b/libs/minikin/MeasuredText.cpp index 1bf3942..af0d0ee 100644 --- a/libs/minikin/MeasuredText.cpp +++ b/libs/minikin/MeasuredText.cpp @@ -213,20 +213,10 @@ class BoundsCompositor { public: BoundsCompositor() : mAdvance(0) {} - void operator()(const LayoutPiece& layoutPiece, const MinikinPaint& paint) { - MinikinRect pieceBounds; - MinikinRect tmpRect; - for (uint32_t i = 0; i < layoutPiece.glyphCount(); ++i) { - const FakedFont& font = layoutPiece.fontAt(i); - const Point& point = layoutPiece.pointAt(i); - - MinikinFont* minikinFont = font.font->typeface().get(); - minikinFont->GetBounds(&tmpRect, layoutPiece.glyphIdAt(i), paint, font.fakery); - tmpRect.offset(point.x, point.y); - pieceBounds.join(tmpRect); - } - pieceBounds.offset(mAdvance, 0); - mBounds.join(pieceBounds); + void operator()(const LayoutPiece& layoutPiece, const MinikinPaint& /* paint */) { + MinikinRect tmpBounds = layoutPiece.bounds(); + tmpBounds.offset(mAdvance, 0); + mBounds.join(tmpBounds); mAdvance += layoutPiece.advance(); } diff --git a/libs/minikin/Measurement.cpp b/libs/minikin/Measurement.cpp index 66886da..5d110c4 100644 --- a/libs/minikin/Measurement.cpp +++ b/libs/minikin/Measurement.cpp @@ -19,9 +19,6 @@ #include <cfloat> #include <cmath> -#include "BidiUtils.h" -#include "LayoutSplitter.h" -#include "minikin/BoundsCache.h" #include "minikin/GraphemeBreak.h" namespace minikin { @@ -121,40 +118,4 @@ size_t getOffsetForAdvance(const float* advances, const uint16_t* buf, size_t st return best; } -struct BoundsComposer { - BoundsComposer() : mAdvance(0) {} - - void operator()(const MinikinRect& rect, float advance) { - MinikinRect tmp = rect; - tmp.offset(mAdvance, 0); - mBounds.join(tmp); - mAdvance += advance; - } - - float mAdvance; - MinikinRect mBounds; -}; - -void getBounds(const U16StringPiece& str, const Range& range, Bidi bidiFlag, - const MinikinPaint& paint, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, - MinikinRect* out) { - BoundsComposer bc; - for (const BidiText::RunInfo info : BidiText(str, range, bidiFlag)) { - for (const auto [context, piece] : LayoutSplitter(str, info.range, info.isRtl)) { - const StartHyphenEdit pieceStartHyphen = - (piece.getStart() == range.getStart()) ? startHyphen : StartHyphenEdit::NO_EDIT; - const EndHyphenEdit pieceEndHyphen = - (piece.getEnd() == range.getEnd()) ? endHyphen : EndHyphenEdit::NO_EDIT; - BoundsCache::getInstance().getOrCreate(str.substr(context), piece - context.getStart(), - paint, info.isRtl, pieceStartHyphen, - pieceEndHyphen, bc); - // Increment word spacing for spacer - if (piece.getLength() == 1 && isWordSpace(str[piece.getStart()])) { - bc.mAdvance += paint.wordSpacing; - } - } - } - *out = bc.mBounds; -} - } // namespace minikin diff --git a/libs/minikin/SparseBitSet.cpp b/libs/minikin/SparseBitSet.cpp index 41151f1..66d6c02 100644 --- a/libs/minikin/SparseBitSet.cpp +++ b/libs/minikin/SparseBitSet.cpp @@ -55,14 +55,9 @@ void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) { return; } mMaxVal = maxVal; - mIndicesCount = (mMaxVal + kPageMask) >> kLogValuesPerPage; - // Avoid zero-filling mOwnedIndices. - mOwnedIndices.reset(new uint16_t[mIndicesCount]); - mIndices = mOwnedIndices.get(); + mIndices.reset(new uint16_t[(mMaxVal + kPageMask) >> kLogValuesPerPage]); uint32_t nPages = calcNumPages(ranges, nRanges); - mBitmapsCount = nPages << (kLogValuesPerPage - kLogBitsPerEl); - mOwnedBitmaps = std::make_unique<element[]>(mBitmapsCount); - mBitmaps = mOwnedBitmaps.get(); + mBitmaps.reset(new element[nPages << (kLogValuesPerPage - kLogBitsPerEl)]()); mZeroPageIndex = noZeroPage; uint32_t nonzeroPageEnd = 0; uint32_t currentPage = 0; @@ -78,52 +73,32 @@ void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) { mZeroPageIndex = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl); } for (uint32_t j = nonzeroPageEnd; j < startPage; j++) { - mOwnedIndices[j] = mZeroPageIndex; + mIndices[j] = mZeroPageIndex; } } - mOwnedIndices[startPage] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl); + mIndices[startPage] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl); } size_t index = ((currentPage - 1) << (kLogValuesPerPage - kLogBitsPerEl)) + ((start & kPageMask) >> kLogBitsPerEl); size_t nElements = (end - (start & ~kElMask) + kElMask) >> kLogBitsPerEl; if (nElements == 1) { - mOwnedBitmaps[index] |= + mBitmaps[index] |= (kElAllOnes >> (start & kElMask)) & (kElAllOnes << ((~end + 1) & kElMask)); } else { - mOwnedBitmaps[index] |= kElAllOnes >> (start & kElMask); + mBitmaps[index] |= kElAllOnes >> (start & kElMask); for (size_t j = 1; j < nElements - 1; j++) { - mOwnedBitmaps[index + j] = kElAllOnes; + mBitmaps[index + j] = kElAllOnes; } - mOwnedBitmaps[index + nElements - 1] |= kElAllOnes << ((~end + 1) & kElMask); + mBitmaps[index + nElements - 1] |= kElAllOnes << ((~end + 1) & kElMask); } for (size_t j = startPage + 1; j < endPage + 1; j++) { - mOwnedIndices[j] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl); + mIndices[j] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl); } nonzeroPageEnd = endPage + 1; } } -void SparseBitSet::initFromBuffer(BufferReader* reader) { - mMaxVal = reader->read<uint32_t>(); - // mIndices and mBitmaps are not initialized when mMaxVal == 0 - if (mMaxVal == 0) return; - std::tie(mIndices, mIndicesCount) = reader->readArray<uint16_t>(); - // element is uint32_t - static_assert(sizeof(element) == 4); - std::tie(mBitmaps, mBitmapsCount) = reader->readArray<element>(); - mZeroPageIndex = reader->read<uint16_t>(); -} - -void SparseBitSet::writeTo(BufferWriter* writer) const { - writer->write<uint32_t>(mMaxVal); - // mIndices and mBitmaps are not initialized when mMaxVal == 0 - if (mMaxVal == 0) return; - writer->writeArray<uint16_t>(mIndices, mIndicesCount); - writer->writeArray<element>(mBitmaps, mBitmapsCount); - writer->write<uint16_t>(mZeroPageIndex); -} - int SparseBitSet::CountLeadingZeros(element x) { // Note: GCC / clang builtin return sizeof(element) <= sizeof(int) ? __builtin_clz(x) : __builtin_clzl(x); diff --git a/libs/minikin/SystemFonts.cpp b/libs/minikin/SystemFonts.cpp index 9c8fa66..287fc61 100644 --- a/libs/minikin/SystemFonts.cpp +++ b/libs/minikin/SystemFonts.cpp @@ -26,8 +26,7 @@ SystemFonts& SystemFonts::getInstance() { } std::shared_ptr<FontCollection> SystemFonts::findFontCollectionInternal( - const std::string& familyName) { - std::lock_guard<std::mutex> lock(mMutex); + const std::string& familyName) const { auto it = mSystemFallbacks.find(familyName); if (it != mSystemFallbacks.end()) { return it->second; @@ -36,22 +35,4 @@ std::shared_ptr<FontCollection> SystemFonts::findFontCollectionInternal( return mDefaultFallback; } -void SystemFonts::buildFontSetLocked() { - std::unordered_set<FontFamily*> uniqueFamilies; - - for (const auto& collection : mCollections) { - for (const auto& family : collection->getFamilies()) { - uniqueFamilies.insert(family.get()); - } - } - - std::vector<std::shared_ptr<Font>> result; - for (const auto family : uniqueFamilies) { - for (size_t i = 0; i < family->getNumFonts(); ++i) { - result.push_back(family->getFontRef(i)); - } - } - mFonts = std::move(result); -} - } // namespace minikin diff --git a/tests/Android.bp b/tests/Android.bp index 3088ca4..1d8c019 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -1,13 +1,8 @@ -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - filegroup { name: "minikin-test-data", srcs: [ "data/Arabic.ttf", "data/Ascii.ttf", - "data/Bbox.ttf", "data/Bold.ttf", "data/BoldItalic.ttf", "data/Cherokee.ttf", @@ -15,7 +10,6 @@ filegroup { "data/ColorTextMixedEmojiFont.ttf", "data/CustomExtent.ttf", "data/Emoji.ttf", - "data/EmojiBase.ttf", "data/Hiragana.ttf", "data/Italic.ttf", "data/Ja.ttf", @@ -25,7 +19,6 @@ filegroup { "data/MultiAxis.ttf", "data/NoCmapFormat14.ttf", "data/NoGlyphFont.ttf", - "data/OverrideEmoji.ttf", "data/Regular.ttf", "data/TextEmojiFont.ttf", "data/UnicodeBMPOnly.ttf", @@ -35,7 +28,6 @@ filegroup { "data/ZhHans.ttf", "data/ZhHant.ttf", "data/emoji.xml", - "data/emoji_itemization.xml", "data/itemize.xml", ], } diff --git a/tests/data/Ascii.ttf b/tests/data/Ascii.ttf Binary files differindex 2e6835b..be6d5fe 100644 --- a/tests/data/Ascii.ttf +++ b/tests/data/Ascii.ttf diff --git a/tests/data/Ascii.ttx b/tests/data/Ascii.ttx index c0a2ef6..74eba96 100644 --- a/tests/data/Ascii.ttx +++ b/tests/data/Ascii.ttx @@ -18,7 +18,6 @@ <GlyphOrder> <GlyphID id="0" name=".notdef"/> <GlyphID id="1" name="1em"/> - <GlyphID id="2" name="2em"/> </GlyphOrder> <head> @@ -118,7 +117,6 @@ <hmtx> <mtx name=".notdef" width="50" lsb="0"/> <mtx name="1em" width="100" lsb="0"/> - <mtx name="2em" width="200" lsb="0"/> </hmtx> <cmap> @@ -219,12 +217,6 @@ <map code="0x007C" name="1em" /> <!-- '|' --> <map code="0x007D" name="1em" /> <!-- '}' --> <map code="0x007E" name="1em" /> <!-- '~' --> - <map code="0x02B1" name="2em" /> <!-- 'α' --> - <map code="0x02B2" name="2em" /> <!-- 'β' --> - <map code="0x02B3" name="2em" /> <!-- 'γ' --> - <map code="0x02B4" name="2em" /> <!-- 'δ' --> - <map code="0x02B5" name="2em" /> <!-- 'ε' --> - <map code="0x02B6" name="2em" /> <!-- 'ζ' --> </cmap_format_12> </cmap> @@ -243,15 +235,6 @@ </contour> <instructions><assembly></assembly></instructions> </TTGlyph> - <TTGlyph name="2em" xMin="0" yMin="0" xMax="200" yMax="200"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="200" y="0" on="1" /> - <pt x="200" y="200" on="1" /> - <pt x="0" y="200" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> </glyf> <name> diff --git a/tests/data/Bbox.ttf b/tests/data/Bbox.ttf Binary files differdeleted file mode 100644 index c89c59c..0000000 --- a/tests/data/Bbox.ttf +++ /dev/null diff --git a/tests/data/Bbox.ttx b/tests/data/Bbox.ttx deleted file mode 100644 index e7d34bd..0000000 --- a/tests/data/Bbox.ttx +++ /dev/null @@ -1,265 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Copyright (C) 2020 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0"> - - <GlyphOrder> - <GlyphID id="0" name=".notdef"/> - <GlyphID id="1" name="1emx1em"/> - <GlyphID id="2" name="2emx2em"/> - <GlyphID id="3" name="3emx3em"/> - <GlyphID id="4" name="2emx2em_lsb_1em"/> - <GlyphID id="5" name="1emx1em_y1em_origin"/> - </GlyphOrder> - - <head> - <tableVersion value="1.0"/> - <fontRevision value="1.0"/> - <checkSumAdjustment value="0x640cdb2f"/> - <magicNumber value="0x5f0f3cf5"/> - <flags value="00000000 00000011"/> - <unitsPerEm value="1000"/> - <created value="Fri Mar 17 07:26:00 2017"/> - <macStyle value="00000000 00000000"/> - <lowestRecPPEM value="7"/> - <fontDirectionHint value="2"/> - <glyphDataFormat value="0"/> - </head> - - <hhea> - <tableVersion value="1.0"/> - <ascent value="1000"/> - <descent value="-200"/> - <lineGap value="0"/> - <caretSlopeRise value="1"/> - <caretSlopeRun value="0"/> - <caretOffset value="0"/> - <reserved0 value="0"/> - <reserved1 value="0"/> - <reserved2 value="0"/> - <reserved3 value="0"/> - <metricDataFormat value="0"/> - </hhea> - - <maxp> - <tableVersion value="0x10000"/> - <maxZones value="0"/> - <maxTwilightPoints value="0"/> - <maxStorage value="0"/> - <maxFunctionDefs value="0"/> - <maxInstructionDefs value="0"/> - <maxStackElements value="0"/> - <maxSizeOfInstructions value="0"/> - <maxComponentElements value="0"/> - </maxp> - - <OS_2> - <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' - will be recalculated by the compiler --> - <version value="3"/> - <xAvgCharWidth value="594"/> - <usWeightClass value="400"/> - <usWidthClass value="5"/> - <fsType value="00000000 00001000"/> - <ySubscriptXSize value="650"/> - <ySubscriptYSize value="600"/> - <ySubscriptXOffset value="0"/> - <ySubscriptYOffset value="75"/> - <ySuperscriptXSize value="650"/> - <ySuperscriptYSize value="600"/> - <ySuperscriptXOffset value="0"/> - <ySuperscriptYOffset value="350"/> - <yStrikeoutSize value="50"/> - <yStrikeoutPosition value="300"/> - <sFamilyClass value="0"/> - <panose> - <bFamilyType value="0"/> - <bSerifStyle value="0"/> - <bWeight value="5"/> - <bProportion value="0"/> - <bContrast value="0"/> - <bStrokeVariation value="0"/> - <bArmStyle value="0"/> - <bLetterForm value="0"/> - <bMidline value="0"/> - <bXHeight value="0"/> - </panose> - <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/> - <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> - <achVendID value="UKWN"/> - <fsSelection value="00000000 01000000"/> - <usFirstCharIndex value="32"/> - <usLastCharIndex value="122"/> - <sTypoAscender value="800"/> - <sTypoDescender value="-200"/> - <sTypoLineGap value="200"/> - <usWinAscent value="1000"/> - <usWinDescent value="200"/> - <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/> - <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> - <sxHeight value="500"/> - <sCapHeight value="700"/> - <usDefaultChar value="0"/> - <usBreakChar value="32"/> - <usMaxContext value="0"/> - </OS_2> - - <hmtx> - <mtx name=".notdef" width="500" lsb="93"/> - <mtx name="1emx1em" width="1000" lsb="0"/> - <mtx name="2emx2em" width="2000" lsb="0"/> - <mtx name="3emx3em" width="3000" lsb="0"/> - <mtx name="2emx2em_lsb_1em" width="2000" lsb="1000"/> - <mtx name="1emx1em_y1em_origin" width="1000" lsb="0"/> - </hmtx> - - <cmap> - <tableVersion version="0"/> - <cmap_format_12 format="12" reserved="0" length="3" nGroups="6" platformID="3" platEncID="1" language="0"> - <map code="0x0028" name="1emx1em" /> - <map code="0x0061" name="1emx1em" /> - <map code="0x0062" name="2emx2em" /> - <map code="0x0063" name="3emx3em" /> - <map code="0x0064" name="2emx2em_lsb_1em" /> - <map code="0x0065" name="1emx1em_y1em_origin" /> - </cmap_format_12> - </cmap> - - <loca> - <!-- The 'loca' table will be calculated by the compiler --> - </loca> - - <glyf> - <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" /> - <TTGlyph name="1emx1em" xMin="0" yMin="0" xMax="1000" yMax="1000"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="500" y="1000" on="1" /> - <pt x="1000" y="0" on="1" /> - </contour> - <instructions /> - </TTGlyph> - <TTGlyph name="2emx2em" xMin="0" yMin="0" xMax="2000" yMax="2000"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="1000" y="2000" on="1" /> - <pt x="2000" y="0" on="1" /> - </contour> - <instructions /> - </TTGlyph> - <TTGlyph name="3emx3em" xMin="0" yMin="0" xMax="3000" yMax="3000"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="1500" y="3000" on="1" /> - <pt x="3000" y="0" on="1" /> - </contour> - <instructions /> - </TTGlyph> - <TTGlyph name="2emx2em_lsb_1em" xMin="0" yMin="0" xMax="2000" yMax="2000"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="1000" y="2000" on="1" /> - <pt x="2000" y="0" on="1" /> - </contour> - <instructions /> - </TTGlyph> - <TTGlyph name="1emx1em_y1em_origin" xMin="0" yMin="1000" xMax="1000" yMax="2000"> - <contour> - <pt x="0" y="1000" on="1" /> - <pt x="500" y="2000" on="1" /> - <pt x="1000" y="1000" on="1" /> - </contour> - <instructions /> - </TTGlyph> - </glyf> - - <GSUB> - <Version value="0x00010000"/> - <ScriptList> - <ScriptRecord index="0"> - <ScriptTag value="latn"/> - <Script> - <DefaultLangSys> - <ReqFeatureIndex value="65535"/> - <FeatureIndex index="0" value="0"/> - </DefaultLangSys> - </Script> - </ScriptRecord> - </ScriptList> - <FeatureList> - <FeatureRecord index="0"> - <FeatureTag value="rtlm"/> - <Feature> - <LookupListIndex index="0" value="0"/> - </Feature> - </FeatureRecord> - </FeatureList> - <LookupList> - <Lookup index="0"> - <LookupType value="1"/> - <LookupFlag value="0"/> - <SingleSubst index="0" Format="2"> - <Substitution in="1emx1em" out="3emx3em" /> - </SingleSubst> - </Lookup> - </LookupList> - - </GSUB> - - <name> - <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409"> - Copyright (C) 2017 The Android Open Source Project - </namerecord> - <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> - Sample Font - </namerecord> - <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> - Regular - </namerecord> - <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409"> - Sample Font - </namerecord> - <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409"> - SampleFont-Regular - </namerecord> - <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409"> - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - </namerecord> - <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409"> - http://www.apache.org/licenses/LICENSE-2.0 - </namerecord> - </name> - - <post> - <formatType value="3.0"/> - <italicAngle value="0.0"/> - <underlinePosition value="-75"/> - <underlineThickness value="50"/> - <isFixedPitch value="0"/> - <minMemType42 value="0"/> - <maxMemType42 value="0"/> - <minMemType1 value="0"/> - <maxMemType1 value="0"/> - </post> - -</ttFont> diff --git a/tests/data/EmojiBase.ttf b/tests/data/EmojiBase.ttf Binary files differdeleted file mode 100644 index 659226d..0000000 --- a/tests/data/EmojiBase.ttf +++ /dev/null diff --git a/tests/data/EmojiBase.ttx b/tests/data/EmojiBase.ttx deleted file mode 100644 index e6e3da8..0000000 --- a/tests/data/EmojiBase.ttx +++ /dev/null @@ -1,537 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Copyright (C) 2021 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.9"> - - <GlyphOrder> - <!-- The 'id' attribute is only for humans; it is ignored when parsed. --> - <GlyphID id="0" name=".notdef"/> - - <!-- Compbining characters for Emoji --> - <GlyphID id="1" name="U+200D"/> - <GlyphID id="2" name="U+1F3FB"/> - <GlyphID id="3" name="U+1F3FC"/> - - <!-- Random Emoji --> - <GlyphID id="4" name="U+1F9B0"/> - <GlyphID id="5" name="U+1F9B1"/> - <GlyphID id="6" name="U+1F9B2"/> - <GlyphID id="7" name="U+1F9B3"/> - <GlyphID id="8" name="U+1F9B4"/> - <GlyphID id="9" name="U+1F9B5"/> - <GlyphID id="10" name="U+1F9B6"/> - <GlyphID id="11" name="U+1F9B7"/> - <GlyphID id="12" name="U+1F9B8"/> - <GlyphID id="13" name="U+1F9B9"/> - - <!-- Unassigned Code Points --> - <GlyphID id="14" name="U+E0000"/> - <GlyphID id="15" name="U+E0001"/> - - <!-- Ligature Form. Not in cmap --> - <GlyphID id="16" name="LigaForm1"/> - <GlyphID id="17" name="LigaForm2"/> - <GlyphID id="18" name="LigaForm3"/> - <GlyphID id="19" name="LigaForm4"/> - <GlyphID id="20" name="LigaForm5"/> - <GlyphID id="21" name="LigaForm6"/> - <GlyphID id="22" name="LigaForm7"/> - - <!-- Regional Indicators --> - <GlyphID id="23" name="U+1F1E6"/> - <GlyphID id="24" name="U+1F1E7"/> - - </GlyphOrder> - - <head> - <!-- Most of this table will be recalculated by the compiler --> - <tableVersion value="1.0"/> - <fontRevision value="1.0"/> - <checkSumAdjustment value="0x640cdb2f"/> - <magicNumber value="0x5f0f3cf5"/> - <flags value="00000000 00000011"/> - <unitsPerEm value="1000"/> - <created value="Wed Sep 9 08:01:17 2015"/> - <modified value="Wed Sep 9 08:48:07 2015"/> - <xMin value="0"/> - <yMin value="0"/> - <xMax value="0"/> - <yMax value="0"/> - <macStyle value="00000000 00000000"/> - <lowestRecPPEM value="7"/> - <fontDirectionHint value="2"/> - <indexToLocFormat value="0"/> - <glyphDataFormat value="0"/> - </head> - - <hhea> - <tableVersion value="0x00010000"/> - <ascent value="1000"/> - <descent value="-200"/> - <lineGap value="0"/> - <advanceWidthMax value="500"/> - <minLeftSideBearing value="0"/> - <minRightSideBearing value="0"/> - <xMaxExtent value="0"/> - <caretSlopeRise value="1"/> - <caretSlopeRun value="0"/> - <caretOffset value="0"/> - <reserved0 value="0"/> - <reserved1 value="0"/> - <reserved2 value="0"/> - <reserved3 value="0"/> - <metricDataFormat value="0"/> - <numberOfHMetrics value="1"/> - </hhea> - - <maxp> - <!-- Most of this table will be recalculated by the compiler --> - <tableVersion value="0x10000"/> - <numGlyphs value="8"/> - <maxPoints value="0"/> - <maxContours value="0"/> - <maxCompositePoints value="0"/> - <maxCompositeContours value="0"/> - <maxZones value="2"/> - <maxTwilightPoints value="12"/> - <maxStorage value="28"/> - <maxFunctionDefs value="119"/> - <maxInstructionDefs value="0"/> - <maxStackElements value="61"/> - <maxSizeOfInstructions value="2967"/> - <maxComponentElements value="0"/> - <maxComponentDepth value="0"/> - </maxp> - - <OS_2> - <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' - will be recalculated by the compiler --> - <version value="3"/> - <xAvgCharWidth value="594"/> - <usWeightClass value="400"/> - <usWidthClass value="5"/> - <fsType value="00000000 00001000"/> - <ySubscriptXSize value="650"/> - <ySubscriptYSize value="600"/> - <ySubscriptXOffset value="0"/> - <ySubscriptYOffset value="75"/> - <ySuperscriptXSize value="650"/> - <ySuperscriptYSize value="600"/> - <ySuperscriptXOffset value="0"/> - <ySuperscriptYOffset value="350"/> - <yStrikeoutSize value="50"/> - <yStrikeoutPosition value="300"/> - <sFamilyClass value="0"/> - <panose> - <bFamilyType value="0"/> - <bSerifStyle value="0"/> - <bWeight value="5"/> - <bProportion value="0"/> - <bContrast value="0"/> - <bStrokeVariation value="0"/> - <bArmStyle value="0"/> - <bLetterForm value="0"/> - <bMidline value="0"/> - <bXHeight value="0"/> - </panose> - <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/> - <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> - <achVendID value="UKWN"/> - <fsSelection value="00000000 01000000"/> - <usFirstCharIndex value="48"/> - <usLastCharIndex value="65535"/> - <sTypoAscender value="800"/> - <sTypoDescender value="-200"/> - <sTypoLineGap value="200"/> - <usWinAscent value="1000"/> - <usWinDescent value="200"/> - <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/> - <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> - <sxHeight value="500"/> - <sCapHeight value="700"/> - <usDefaultChar value="0"/> - <usBreakChar value="32"/> - <usMaxContext value="0"/> - </OS_2> - - <hmtx> - <mtx name=".notdef" width="500" lsb="93"/> - <mtx name="U+200D" width="500" lsb="93"/> - <mtx name="U+1F1E6" width="500" lsb="93"/> - <mtx name="U+1F1E7" width="500" lsb="93"/> - <mtx name="U+1F3FB" width="500" lsb="93"/> - <mtx name="U+1F3FC" width="500" lsb="93"/> - <mtx name="U+1F9B0" width="500" lsb="93"/> - <mtx name="U+1F9B1" width="500" lsb="93"/> - <mtx name="U+1F9B2" width="500" lsb="93"/> - <mtx name="U+1F9B3" width="500" lsb="93"/> - <mtx name="U+1F9B4" width="500" lsb="93"/> - <mtx name="U+1F9B5" width="500" lsb="93"/> - <mtx name="U+1F9B6" width="500" lsb="93"/> - <mtx name="U+1F9B7" width="500" lsb="93"/> - <mtx name="U+1F9B8" width="500" lsb="93"/> - <mtx name="U+1F9B9" width="500" lsb="93"/> - <mtx name="U+E0000" width="500" lsb="93"/> - <mtx name="U+E0001" width="500" lsb="93"/> - <mtx name="LigaForm1" width="500" lsb="93"/> - <mtx name="LigaForm2" width="500" lsb="93"/> - <mtx name="LigaForm3" width="500" lsb="93"/> - <mtx name="LigaForm4" width="500" lsb="93"/> - <mtx name="LigaForm5" width="500" lsb="93"/> - <mtx name="LigaForm6" width="500" lsb="93"/> - <mtx name="LigaForm7" width="500" lsb="93"/> - </hmtx> - - <cmap> - <tableVersion version="0"/> - <cmap_format_12 format="12" reserved="0" length="3" nGroups="6" platformID="3" platEncID="1" language="0"> - <map code="0x200D" name="U+200D" /> - <map code="0x1F1E6" name="U+1F1E6" /> - <map code="0x1F1E7" name="U+1F1E7" /> - <map code="0x1F3FB" name="U+1F3FB" /> - <map code="0x1F3FC" name="U+1F3FC" /> - <map code="0x1F9B0" name="U+1F9B0" /> - <map code="0x1F9B1" name="U+1F9B1" /> - <map code="0x1F9B2" name="U+1F9B2" /> - <map code="0x1F9B3" name="U+1F9B3" /> - <map code="0x1F9B4" name="U+1F9B4" /> - <map code="0x1F9B5" name="U+1F9B5" /> - <map code="0x1F9B6" name="U+1F9B6" /> - <map code="0x1F9B7" name="U+1F9B7" /> - <map code="0x1F9B8" name="U+1F9B8" /> - <map code="0x1F9B9" name="U+1F9B9" /> - <map code="0xE0000" name="U+E0000" /> - <map code="0xE0001" name="U+E0001" /> - </cmap_format_12> - </cmap> - - <loca> - <!-- The 'loca' table will be calculated by the compiler --> - </loca> - - <glyf> - - <!-- The xMin, yMin, xMax and yMax values - will be recalculated by the compiler. --> - - <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+200D" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F1E6" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F1E7" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F3FB" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F3FC" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F9B0" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F9B1" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F9B2" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F9B3" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F9B4" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F9B5" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F9B6" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F9B7" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F9B8" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F9B9" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+E0000" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+E0001" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="LigaForm1" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="LigaForm2" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="LigaForm3" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="LigaForm4" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="LigaForm5" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="LigaForm6" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="LigaForm7" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - </glyf> - - <name> - <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> - EmojiBaseFont - </namerecord> - <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> - Regular - </namerecord> - <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409"> - EmojiBaseFont - </namerecord> - <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409"> - EmojiBaseFont - </namerecord> - </name> - - <post> - <formatType value="3.0"/> - <italicAngle value="0.0"/> - <underlinePosition value="-75"/> - <underlineThickness value="50"/> - <isFixedPitch value="0"/> - <minMemType42 value="0"/> - <maxMemType42 value="0"/> - <minMemType1 value="0"/> - <maxMemType1 value="0"/> - </post> - - <GSUB> - <Version value="0x00010000"/> - <ScriptList> - <ScriptRecord index="0"> - <ScriptTag value="DFLT"/> - <Script> - <DefaultLangSys> - <ReqFeatureIndex value="65535"/> - <FeatureIndex index="0" value="0"/> - </DefaultLangSys> - </Script> - </ScriptRecord> - </ScriptList> - <FeatureList> - <FeatureRecord index="0"> - <FeatureTag value="ccmp"/> - <Feature> - <LookupListIndex index="0" value="0"/> - </Feature> - </FeatureRecord> - </FeatureList> - <LookupList> - <Lookup index="0"> - <LookupType value="4"/> - <LookupFlag value="0"/> - <LigatureSubst index="0" Format="1"> - <LigatureSet glyph="U+1F9B0"> - <!-- U+1F9B0 U+1F3FB -> LigaForm1 --> - <Ligature components="U+1F3FB" glyph="LigaForm1"/> - - <!-- U+1F9B0 U+1F3FC -> LigaForm2 --> - <Ligature components="U+1F3FC" glyph="LigaForm2"/> - </LigatureSet> - <LigatureSet glyph="U+1F9B1"> - <!-- U+1F9B1 U+1F3FB -> LigaForm3 --> - <Ligature components="U+1F3FB" glyph="LigaForm3"/> - </LigatureSet> - <LigatureSet glyph="U+1F9B2"> - <Ligature components="U+200D,U+1F9B3,U+200D,U+1F9B4" glyph="LigaForm4"/> - </LigatureSet> - <LigatureSet glyph="U+1F9B6"> - <!-- U+1F9B6 U+1F3FB -> LigaForm3 --> - <Ligature components="U+1F3FB" glyph="LigaForm3"/> - </LigatureSet> - <LigatureSet glyph="U+1F1E6"> - <Ligature components="U+1F1E6" glyph="LigaForm6"/> - <Ligature components="U+1F1E7" glyph="LigaForm7"/> - </LigatureSet> - </LigatureSubst> - </Lookup> - </LookupList> - </GSUB> -</ttFont> diff --git a/tests/data/OverrideEmoji.ttf b/tests/data/OverrideEmoji.ttf Binary files differdeleted file mode 100644 index 890796b..0000000 --- a/tests/data/OverrideEmoji.ttf +++ /dev/null diff --git a/tests/data/OverrideEmoji.ttx b/tests/data/OverrideEmoji.ttx deleted file mode 100644 index d5d4091..0000000 --- a/tests/data/OverrideEmoji.ttx +++ /dev/null @@ -1,521 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Copyright (C) 2021 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.9"> - - <GlyphOrder> - <!-- The 'id' attribute is only for humans; it is ignored when parsed. --> - <GlyphID id="0" name=".notdef"/> - - <!-- Compbining characters for Emoji --> - <GlyphID id="1" name="U+200D"/> - <GlyphID id="2" name="U+1F3FB"/> - <GlyphID id="3" name="U+1F3FC"/> - - <!-- Random Emoji --> - <GlyphID id="4" name="U+1F9B0"/> - <GlyphID id="5" name="U+1F9B1"/> - <GlyphID id="6" name="U+1F9B2"/> - <GlyphID id="7" name="U+1F9B3"/> - <GlyphID id="8" name="U+1F9B4"/> - <GlyphID id="9" name="U+1F9B5"/> - <!-- - Following four glyphs are removed from EmojiBase.ttf for verifying fallback. - <GlyphID id="10" name="U+1F9B6"/> - <GlyphID id="11" name="U+1F9B7"/> - <GlyphID id="12" name="U+1F9B8"/> - <GlyphID id="13" name="U+1F9B9"/> - --> - - <!-- Unassigned Code Points --> - <GlyphID id="14" name="U+E0000"/> - <!-- - Following glyph is removed from EmojiBase.ttf for verifying fallback. - <GlyphID id="15" name="U+E0001"/> - --> - - <!-- Ligature Form. Not in cmap --> - <GlyphID id="16" name="LigaForm1"/> - <GlyphID id="17" name="LigaForm2"/> - <GlyphID id="18" name="LigaForm3"/> - <!-- - Following glyphs are removed from EmojiBase.ttf for verifying fallback. - <GlyphID id="19" name="LigaForm4"/> - <GlyphID id="20" name="LigaForm5"/> - --> - <GlyphID id="21" name="LigaForm6"/> - <!-- - Following glyph is removed from EmojiBase.ttf for verifying fallback. - <GlyphID id="22" name="LigaForm7"/> - --> - - <GlyphID id="23" name="U+1F1E6"/> - <GlyphID id="24" name="U+1F1E7"/> - </GlyphOrder> - - <head> - <!-- Most of this table will be recalculated by the compiler --> - <tableVersion value="1.0"/> - <fontRevision value="1.0"/> - <checkSumAdjustment value="0x640cdb2f"/> - <magicNumber value="0x5f0f3cf5"/> - <flags value="00000000 00000011"/> - <unitsPerEm value="1000"/> - <created value="Wed Sep 9 08:01:17 2015"/> - <modified value="Wed Sep 9 08:48:07 2015"/> - <xMin value="0"/> - <yMin value="0"/> - <xMax value="0"/> - <yMax value="0"/> - <macStyle value="00000000 00000000"/> - <lowestRecPPEM value="7"/> - <fontDirectionHint value="2"/> - <indexToLocFormat value="0"/> - <glyphDataFormat value="0"/> - </head> - - <hhea> - <tableVersion value="0x00010000"/> - <ascent value="1000"/> - <descent value="-200"/> - <lineGap value="0"/> - <advanceWidthMax value="500"/> - <minLeftSideBearing value="0"/> - <minRightSideBearing value="0"/> - <xMaxExtent value="0"/> - <caretSlopeRise value="1"/> - <caretSlopeRun value="0"/> - <caretOffset value="0"/> - <reserved0 value="0"/> - <reserved1 value="0"/> - <reserved2 value="0"/> - <reserved3 value="0"/> - <metricDataFormat value="0"/> - <numberOfHMetrics value="1"/> - </hhea> - - <maxp> - <!-- Most of this table will be recalculated by the compiler --> - <tableVersion value="0x10000"/> - <numGlyphs value="8"/> - <maxPoints value="0"/> - <maxContours value="0"/> - <maxCompositePoints value="0"/> - <maxCompositeContours value="0"/> - <maxZones value="2"/> - <maxTwilightPoints value="12"/> - <maxStorage value="28"/> - <maxFunctionDefs value="119"/> - <maxInstructionDefs value="0"/> - <maxStackElements value="61"/> - <maxSizeOfInstructions value="2967"/> - <maxComponentElements value="0"/> - <maxComponentDepth value="0"/> - </maxp> - - <OS_2> - <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' - will be recalculated by the compiler --> - <version value="3"/> - <xAvgCharWidth value="594"/> - <usWeightClass value="400"/> - <usWidthClass value="5"/> - <fsType value="00000000 00001000"/> - <ySubscriptXSize value="650"/> - <ySubscriptYSize value="600"/> - <ySubscriptXOffset value="0"/> - <ySubscriptYOffset value="75"/> - <ySuperscriptXSize value="650"/> - <ySuperscriptYSize value="600"/> - <ySuperscriptXOffset value="0"/> - <ySuperscriptYOffset value="350"/> - <yStrikeoutSize value="50"/> - <yStrikeoutPosition value="300"/> - <sFamilyClass value="0"/> - <panose> - <bFamilyType value="0"/> - <bSerifStyle value="0"/> - <bWeight value="5"/> - <bProportion value="0"/> - <bContrast value="0"/> - <bStrokeVariation value="0"/> - <bArmStyle value="0"/> - <bLetterForm value="0"/> - <bMidline value="0"/> - <bXHeight value="0"/> - </panose> - <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/> - <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> - <achVendID value="UKWN"/> - <fsSelection value="00000000 01000000"/> - <usFirstCharIndex value="48"/> - <usLastCharIndex value="65535"/> - <sTypoAscender value="800"/> - <sTypoDescender value="-200"/> - <sTypoLineGap value="200"/> - <usWinAscent value="1000"/> - <usWinDescent value="200"/> - <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/> - <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> - <sxHeight value="500"/> - <sCapHeight value="700"/> - <usDefaultChar value="0"/> - <usBreakChar value="32"/> - <usMaxContext value="0"/> - </OS_2> - - <hmtx> - <mtx name=".notdef" width="500" lsb="93"/> - <mtx name="U+200D" width="500" lsb="93"/> - <mtx name="U+1F1E6" width="500" lsb="93"/> - <mtx name="U+1F1E7" width="500" lsb="93"/> - <mtx name="U+1F3FB" width="500" lsb="93"/> - <mtx name="U+1F3FC" width="500" lsb="93"/> - <mtx name="U+1F9B0" width="500" lsb="93"/> - <mtx name="U+1F9B1" width="500" lsb="93"/> - <mtx name="U+1F9B2" width="500" lsb="93"/> - <mtx name="U+1F9B3" width="500" lsb="93"/> - <mtx name="U+1F9B4" width="500" lsb="93"/> - <mtx name="U+1F9B5" width="500" lsb="93"/> - <!-- - Following four glyphs are removed from EmojiBase.ttf for verifying fallback. - <mtx name="U+1F9B6" width="500" lsb="93"/> - <mtx name="U+1F9B7" width="500" lsb="93"/> - <mtx name="U+1F9B8" width="500" lsb="93"/> - <mtx name="U+1F9B9" width="500" lsb="93"/> - --> - <mtx name="U+E0000" width="500" lsb="93"/> - <!-- - Following glyph is removed from EmojiBase.ttf for verifying fallback. - <mtx name="U+1F9B6" width="500" lsb="93"/> - --> - <mtx name="U+E0001" width="500" lsb="93"/> - <mtx name="LigaForm1" width="500" lsb="93"/> - <mtx name="LigaForm2" width="500" lsb="93"/> - <mtx name="LigaForm3" width="500" lsb="93"/> - <!-- - Following two glyphs are removed from EmojiBase.ttf for verifying fallback. - <mtx name="LigaForm4" width="500" lsb="93"/> - <mtx name="LigaForm5" width="500" lsb="93"/> - --> - <mtx name="LigaForm6" width="500" lsb="93"/> - <!-- - Following glyph is removed from EmojiBase.ttf for verifying fallback. - <mtx name="LigaForm7" width="500" lsb="93"/> - --> - </hmtx> - - <cmap> - <tableVersion version="0"/> - <cmap_format_12 format="12" reserved="0" length="3" nGroups="6" platformID="3" platEncID="1" language="0"> - <map code="0x200D" name="U+200D" /> - <map code="0x1F1E6" name="U+1F1E6" /> - <map code="0x1F1E7" name="U+1F1E7" /> - <map code="0x1F3FB" name="U+1F3FB" /> - <map code="0x1F3FC" name="U+1F3FC" /> - <map code="0x1F9B0" name="U+1F9B0" /> - <map code="0x1F9B1" name="U+1F9B1" /> - <map code="0x1F9B2" name="U+1F9B2" /> - <map code="0x1F9B3" name="U+1F9B3" /> - <map code="0x1F9B4" name="U+1F9B4" /> - <map code="0x1F9B5" name="U+1F9B5" /> - <!-- - Following four glyphs are removed from EmojiBase.ttf for verifying fallback. - <map code="0x1F9B6" name="U+1F9B6" /> - <map code="0x1F9B7" name="U+1F9B7" /> - <map code="0x1F9B8" name="U+1F9B8" /> - <map code="0x1F9B9" name="U+1F9B9" /> - --> - <map code="0xE0000" name="U+E0000" /> - <!-- - Following glyph is removed from EmojiBase.ttf for verifying fallback. - <map code="0xE0001" name="U+E0001" /> - --> - </cmap_format_12> - </cmap> - - <loca> - <!-- The 'loca' table will be calculated by the compiler --> - </loca> - - <glyf> - - <!-- The xMin, yMin, xMax and yMax values - will be recalculated by the compiler. --> - - <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+200D" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F1E6" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F1E7" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F3FB" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F3FC" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F9B0" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F9B1" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F9B2" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F9B3" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F9B4" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="U+1F9B5" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <!-- - Following four glyphs are removed from EmojiBase.ttf for verifying fallback. - <TTGlyph name="U+1F9B6"> - <TTGlyph name="U+1F9B7"> - <TTGlyph name="U+1F9B8"> - <TTGlyph name="U+1F9B9"> - --> - <TTGlyph name="U+E0000" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <!-- - Following glyph is removed from EmojiBase.ttf for verifying fallback. - <TTGlyph name="U+E0001"/> - --> - <TTGlyph name="LigaForm1" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="LigaForm2" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <TTGlyph name="LigaForm3" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <!-- - Following two glyphs are removed from EmojiBase.ttf for verifying fallback. - <TTGlyph name="LigaForm4"> - <TTGlyph name="LigaForm5"> - --> - <TTGlyph name="LigaForm6" xMin="0" yMin="0" xMax="100" yMax="100"> - <contour> - <pt x="0" y="0" on="1" /> - <pt x="100" y="0" on="1" /> - <pt x="100" y="100" on="1" /> - <pt x="0" y="100" on="1" /> - </contour> - <instructions><assembly></assembly></instructions> - </TTGlyph> - <!-- - Following glyph is removed from EmojiBase.ttf for verifying fallback. - <TTGlyph name="LigaForm7"> - --> - </glyf> - - <name> - <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> - OverrideEmojiFont - </namerecord> - <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> - Regular - </namerecord> - <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409"> - OverrideEmojiFont - </namerecord> - <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409"> - OverrideEmojiFont - </namerecord> - </name> - - <post> - <formatType value="3.0"/> - <italicAngle value="0.0"/> - <underlinePosition value="-75"/> - <underlineThickness value="50"/> - <isFixedPitch value="0"/> - <minMemType42 value="0"/> - <maxMemType42 value="0"/> - <minMemType1 value="0"/> - <maxMemType1 value="0"/> - </post> - - <GSUB> - <Version value="0x00010000"/> - <ScriptList> - <ScriptRecord index="0"> - <ScriptTag value="DFLT"/> - <Script> - <DefaultLangSys> - <ReqFeatureIndex value="65535"/> - <FeatureIndex index="0" value="0"/> - </DefaultLangSys> - </Script> - </ScriptRecord> - </ScriptList> - <FeatureList> - <FeatureRecord index="0"> - <FeatureTag value="ccmp"/> - <Feature> - <LookupListIndex index="0" value="0"/> - </Feature> - </FeatureRecord> - </FeatureList> - <LookupList> - <Lookup index="0"> - <LookupType value="4"/> - <LookupFlag value="0"/> - <LigatureSubst index="0" Format="1"> - <LigatureSet glyph="U+1F9B0"> - <!-- U+1F9B0 U+1F3FB -> LigaForm0 --> - <Ligature components="U+1F3FB" glyph="LigaForm1"/> - - <!-- U+1F9B0 U+1F3FC -> LigaForm1 --> - <!-- - Following ligature is removed from the EmojiBase.ttf for verifying fallback - <Ligature components="U+1F3FC" glyph="LigaForm2"/> - --> - </LigatureSet> - <!-- - Following ligature is removed from the EmojiBase.ttf for verifying fallback - <LigatureSet glyph="U+1F9B1"> - <Ligature components="U+1F3FB" glyph="LigaForm3"/> - </LigatureSet> - --> - <LigatureSet glyph="U+1F9B2"> - <Ligature components="U+200D,U+1F9B3" glyph="LigaForm3"/> - </LigatureSet> - <!-- - Following ligature is removed from the EmojIBase.ttf for verifying fallback. - <LigatureSet glyph="U+1F9B6"> - <Ligature components="U+1F3FB" glyph="LigaForm3"/> - </LigatureSet> - --> - <LigatureSet glyph="U+1F1E6"> - <Ligature components="U+1F1E6" glyph="LigaForm6"/> - <Ligature components="U+1F1E7" glyph=".notdef"/> - </LigatureSet> - </LigatureSubst> - </Lookup> - </LookupList> - </GSUB> -</ttFont> diff --git a/tests/data/emoji_itemization.xml b/tests/data/emoji_itemization.xml deleted file mode 100644 index d4213f9..0000000 --- a/tests/data/emoji_itemization.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2015 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<familyset version="22"> - <!-- Place NoGlyphFont here since the first font can be chosen if no font is - available for the code point. --> - <family> - <font weight="400" style="normal">Ascii.ttf</font> - </family> - <family lang="und-Zsye"> - <font weight="400" style="normal">EmojiSubset.ttf</font> - </family> - <family lang="und-Zsye"> - <font weight="400" style="normal">EmojiBase.ttf</font> - </family> -</familyset> diff --git a/tests/perftests/Android.bp b/tests/perftests/Android.bp index 19ed8eb..83db1c5 100644 --- a/tests/perftests/Android.bp +++ b/tests/perftests/Android.bp @@ -14,10 +14,6 @@ // limitations under the License. // -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - cc_benchmark { name: "minikin_perftests", test_suites: ["device-tests"], diff --git a/tests/perftests/main.cpp b/tests/perftests/main.cpp index 88e1900..11904e9 100644 --- a/tests/perftests/main.cpp +++ b/tests/perftests/main.cpp @@ -13,12 +13,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> #include <benchmark/benchmark.h> +#include <cutils/log.h> +#include <unicode/uclean.h> +#include <unicode/udata.h> int main(int argc, char** argv) { + const char* fn = "/apex/com.android.i18n/etc/icu/" U_ICUDATA_NAME ".dat"; + int fd = open(fn, O_RDONLY); + LOG_ALWAYS_FATAL_IF(fd == -1); + struct stat st; + LOG_ALWAYS_FATAL_IF(fstat(fd, &st) != 0); + void* data = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + + UErrorCode errorCode = U_ZERO_ERROR; + udata_setCommonData(data, &errorCode); + LOG_ALWAYS_FATAL_IF(U_FAILURE(errorCode)); + u_init(&errorCode); + LOG_ALWAYS_FATAL_IF(U_FAILURE(errorCode)); + benchmark::Initialize(&argc, argv); benchmark::RunSpecifiedBenchmarks(); + u_cleanup(); return 0; } diff --git a/tests/stresstest/Android.bp b/tests/stresstest/Android.bp index 784dc6a..fb73e09 100644 --- a/tests/stresstest/Android.bp +++ b/tests/stresstest/Android.bp @@ -14,10 +14,6 @@ // see how_to_run.txt for instructions on running these tests -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - cc_test { name: "minikin_stress_tests", diff --git a/tests/stresstest/FontFamilyTest.cpp b/tests/stresstest/FontFamilyTest.cpp index 7a9813e..7554314 100644 --- a/tests/stresstest/FontFamilyTest.cpp +++ b/tests/stresstest/FontFamilyTest.cpp @@ -36,7 +36,7 @@ TEST_P(FontFamilyHarfBuzzCompatibilityTest, CoverageTest) { int ttcIndex = GetParam().second; auto font = std::make_shared<FreeTypeMinikinFontForTest>(fontPath); - std::vector<std::shared_ptr<Font>> fonts; + std::vector<Font> fonts; fonts.push_back(Font::Builder(font).build()); std::shared_ptr<FontFamily> family = std::make_shared<FontFamily>(std::move(fonts)); diff --git a/tests/unittest/Android.bp b/tests/unittest/Android.bp index cae9003..0971a06 100644 --- a/tests/unittest/Android.bp +++ b/tests/unittest/Android.bp @@ -14,10 +14,6 @@ // see how_to_run.txt for instructions on running these tests -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - cc_test { name: "minikin_tests", test_suites: ["device-tests"], @@ -45,15 +41,12 @@ cc_test { srcs: [ "AndroidLineBreakerHelperTest.cpp", "BidiUtilsTest.cpp", - "BufferTest.cpp", - "BoundsCacheTest.cpp", "CmapCoverageTest.cpp", "EmojiTest.cpp", "FontTest.cpp", "FontCollectionTest.cpp", "FontCollectionItemizeTest.cpp", "FontFamilyTest.cpp", - "FontFileParserTest.cpp", "FontLanguageListCacheTest.cpp", "FontUtilsTest.cpp", "HasherTest.cpp", diff --git a/tests/unittest/BoundsCacheTest.cpp b/tests/unittest/BoundsCacheTest.cpp deleted file mode 100644 index 8c727f9..0000000 --- a/tests/unittest/BoundsCacheTest.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <gtest/gtest.h> - -#include "minikin/BoundsCache.h" - -#include "FontTestUtils.h" -#include "LocaleListCache.h" -#include "UnicodeUtils.h" - -namespace minikin { - -class TestableBoundsCache : public BoundsCache { -public: - TestableBoundsCache(uint32_t maxEntries) : BoundsCache(maxEntries) {} -}; - -class BoundsCapture { -public: - BoundsCapture() {} - - void operator()(const MinikinRect& rect, float advance) { - mRect = rect; - mAdvance = advance; - } - - const MinikinRect& rect() const { return mRect; } - float advance() const { return mAdvance; } - -private: - MinikinRect mRect; - float mAdvance; -}; - -TEST(BoundsCacheTest, cacheHitTest) { - auto text = utf8ToUtf16("android"); - Range range(0, text.size()); - MinikinPaint paint(buildFontCollection("Ascii.ttf")); - - TestableBoundsCache boundsCache(10); - - BoundsCapture bounds1; - boundsCache.getOrCreate(text, range, paint, false /* LTR */, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, bounds1); - - BoundsCapture bounds2; - boundsCache.getOrCreate(text, range, paint, false /* LTR */, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, bounds2); - - EXPECT_EQ(bounds1.rect(), bounds2.rect()); - EXPECT_EQ(bounds1.advance(), bounds2.advance()); -} - -TEST(BoundsCacheTest, cacheMissTest) { - auto text1 = utf8ToUtf16("android"); - auto text2 = utf8ToUtf16("αβγδζ"); - MinikinPaint paint(buildFontCollection("Ascii.ttf")); - - TestableBoundsCache boundsCache(10); - - BoundsCapture bounds1; - BoundsCapture bounds2; - - { - SCOPED_TRACE("Different text"); - boundsCache.getOrCreate(text1, Range(0, text1.size()), paint, false /* LTR */, - StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds1); - boundsCache.getOrCreate(text2, Range(0, text2.size()), paint, false /* LTR */, - StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2); - EXPECT_NE(bounds1.rect(), bounds2.rect()); - EXPECT_NE(bounds1.advance(), bounds2.advance()); - } - { - SCOPED_TRACE("Different range"); - boundsCache.getOrCreate(text1, Range(0, text1.size()), paint, false /* LTR */, - StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds1); - boundsCache.getOrCreate(text1, Range(1, text1.size()), paint, false /* LTR */, - StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2); - EXPECT_NE(bounds1.rect(), bounds2.rect()); - EXPECT_NE(bounds1.advance(), bounds2.advance()); - } - { - SCOPED_TRACE("Different collection"); - MinikinPaint paint1(buildFontCollection("Ascii.ttf")); - paint1.size = 10.0f; - paint1.scaleX = 1.0f; - boundsCache.getOrCreate(text1, Range(0, text1.size()), paint1, false /* LTR */, - StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds1); - MinikinPaint paint2(buildFontCollection("Emoji.ttf")); - paint2.size = 10.0f; - paint2.scaleX = 1.0f; - boundsCache.getOrCreate(text1, Range(0, text1.size()), paint2, false /* LTR */, - StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2); - EXPECT_NE(bounds1.rect(), bounds2.rect()); - EXPECT_NE(bounds1.advance(), bounds2.advance()); - } - { - SCOPED_TRACE("Different size"); - auto collection = buildFontCollection("Ascii.ttf"); - MinikinPaint paint1(collection); - paint1.size = 10.0f; - paint1.scaleX = 1.0f; - boundsCache.getOrCreate(text1, Range(0, text1.size()), paint1, false /* LTR */, - StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds1); - MinikinPaint paint2(collection); - paint2.size = 20.0f; - paint2.scaleX = 1.0f; - boundsCache.getOrCreate(text1, Range(0, text1.size()), paint2, false /* LTR */, - StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2); - EXPECT_NE(bounds1.rect(), bounds2.rect()); - EXPECT_NE(bounds1.advance(), bounds2.advance()); - } - { - SCOPED_TRACE("Different letter spacing"); - auto collection = buildFontCollection("Ascii.ttf"); - MinikinPaint paint1(collection); - paint1.letterSpacing = 0.0f; - paint1.size = 10.0f; - paint1.scaleX = 1.0f; - boundsCache.getOrCreate(text1, Range(0, text1.size()), paint1, false /* LTR */, - StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds1); - MinikinPaint paint2(collection); - paint2.letterSpacing = 1.0f; - paint2.size = 10.0f; - paint2.scaleX = 1.0f; - boundsCache.getOrCreate(text1, Range(0, text1.size()), paint2, false /* LTR */, - StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2); - EXPECT_NE(bounds1.rect(), bounds2.rect()); - EXPECT_NE(bounds1.advance(), bounds2.advance()); - } -} - -TEST(BoundsCacheTest, cacheOverflowTest) { - auto text = utf8ToUtf16("android"); - Range range(0, text.size()); - MinikinPaint paint(buildFontCollection("Ascii.ttf")); - - TestableBoundsCache boundsCache(5); - - BoundsCapture bounds1; - boundsCache.getOrCreate(text, range, paint, false /* LTR */, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, bounds1); - - for (char c = 'a'; c <= 'z'; c++) { - auto text1 = utf8ToUtf16(std::string(10, c)); - BoundsCapture bounds2; - boundsCache.getOrCreate(text1, Range(0, text1.size()), paint, false /* LTR */, - StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2); - } - - BoundsCapture bounds3; - boundsCache.getOrCreate(text, range, paint, false /* LTR */, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, bounds3); - EXPECT_EQ(bounds1.rect(), bounds3.rect()); - EXPECT_EQ(bounds1.advance(), bounds3.advance()); -} - -} // namespace minikin diff --git a/tests/unittest/BufferTest.cpp b/tests/unittest/BufferTest.cpp deleted file mode 100644 index 8b1db33..0000000 --- a/tests/unittest/BufferTest.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "minikin/Buffer.h" - -#include <gtest/gtest.h> - -namespace minikin { - -class TestObject { -public: - void writeTo(BufferWriter* writer) const { - // Total size = 20 - // uint8_t (1) - writer->write<uint8_t>(0xAB); - // padding (1), uint16_t (2) - writer->write<uint16_t>(0xCDEF); - // uint8_t(1) - writer->write<uint8_t>(0x01); - // padding (3), array size (4), uint32_t (4) * 2 - uint32_t uint32Array[] = {0x98765432, 0x98765433}; - writer->writeArray<uint32_t>(uint32Array, 2); - } -}; - -TEST(BufferTest, testMeasureWriteRead) { - TestObject testObject; - BufferWriter fakeWriter(nullptr); - testObject.writeTo(&fakeWriter); - ASSERT_EQ(fakeWriter.size(), 20u); - std::vector<uint8_t> buffer(fakeWriter.size()); - - BufferWriter writer(buffer.data()); - testObject.writeTo(&writer); - ASSERT_EQ(writer.size(), buffer.size()); - - BufferReader reader(buffer.data()); - ASSERT_EQ(reader.data(), buffer.data()); - ASSERT_EQ(reader.pos(), 0u); - ASSERT_EQ(reader.read<uint8_t>(), 0xABu); - ASSERT_EQ(reader.pos(), 1u); - ASSERT_EQ(reader.read<uint16_t>(), 0xCDEFu); - ASSERT_EQ(reader.pos(), 4u); - ASSERT_EQ(reader.read<uint8_t>(), 0x01u); - ASSERT_EQ(reader.pos(), 5u); - auto [uint32Array, size] = reader.readArray<uint32_t>(); - ASSERT_EQ(size, 2u); - ASSERT_EQ(uint32Array[0], 0x98765432u); - ASSERT_EQ(uint32Array[1], 0x98765433u); - ASSERT_EQ(reader.pos(), 20u); -} - -TEST(BufferTest, testSkip) { - TestObject testObject; - BufferWriter fakeWriter(nullptr); - testObject.writeTo(&fakeWriter); - ASSERT_EQ(fakeWriter.size(), 20u); - std::vector<uint8_t> buffer(fakeWriter.size()); - - BufferWriter writer(buffer.data()); - testObject.writeTo(&writer); - ASSERT_EQ(writer.size(), buffer.size()); - - BufferReader reader(buffer.data()); - ASSERT_EQ(reader.data(), buffer.data()); - ASSERT_EQ(reader.pos(), 0u); - reader.skip<uint8_t>(); - ASSERT_EQ(reader.pos(), 1u); - reader.read<uint16_t>(); - ASSERT_EQ(reader.pos(), 4u); - reader.skip<uint8_t>(); - ASSERT_EQ(reader.pos(), 5u); - reader.skipArray<uint32_t>(); - ASSERT_EQ(reader.pos(), 20u); -} - -} // namespace minikin diff --git a/tests/unittest/FontCollectionItemizeTest.cpp b/tests/unittest/FontCollectionItemizeTest.cpp index 6f1e194..8cd95aa 100644 --- a/tests/unittest/FontCollectionItemizeTest.cpp +++ b/tests/unittest/FontCollectionItemizeTest.cpp @@ -21,7 +21,6 @@ #include <gtest/gtest.h> #include "minikin/FontFamily.h" -#include "minikin/FontFileParser.h" #include "minikin/LocaleList.h" #include "minikin/MinikinPaint.h" @@ -56,15 +55,10 @@ const char kMixedEmojiFont[] = "ColorTextMixedEmojiFont.ttf"; const char kHasCmapFormat14Font[] = "NoCmapFormat14.ttf"; const char kNoCmapFormat14Font[] = "VariationSelectorTest-Regular.ttf"; -struct Run { - FakedFont fakedFont; - int start; - int end; -}; - // Utility functions for calling itemize function. -std::vector<Run> itemize(const std::shared_ptr<FontCollection>& collection, const char* str, - FontStyle style, const std::string& localeList) { +std::vector<FontCollection::Run> itemize(const std::shared_ptr<FontCollection>& collection, + const char* str, FontStyle style, + const std::string& localeList) { const size_t BUF_SIZE = 256; uint16_t buf[BUF_SIZE]; size_t len; @@ -82,38 +76,35 @@ std::vector<Run> itemize(const std::shared_ptr<FontCollection>& collection, cons for (uint32_t i = 0; i < runMax; ++i) { EXPECT_EQ(result[i].start, resultWithRunMax[i].start); EXPECT_EQ(result[i].end, resultWithRunMax[i].end); - EXPECT_EQ(result[i].familyMatch, resultWithRunMax[i].familyMatch); + EXPECT_EQ(result[i].fakedFont, resultWithRunMax[i].fakedFont); } } - std::vector<Run> runs; - for (const auto& r : result) { - runs.push_back( - {collection->getBestFont(U16StringPiece(buf, len), r, style), r.start, r.end}); - } - return runs; + return result; } // Overloaded version for default font style. -std::vector<Run> itemize(const std::shared_ptr<FontCollection>& collection, const char* str, - const std::string& localeList) { +std::vector<FontCollection::Run> itemize(const std::shared_ptr<FontCollection>& collection, + const char* str, const std::string& localeList) { return itemize(collection, str, FontStyle(), localeList); } // Overloaded version for empty locale list id. -std::vector<Run> itemize(const std::shared_ptr<FontCollection>& collection, const char* str, - FontStyle style) { +std::vector<FontCollection::Run> itemize(const std::shared_ptr<FontCollection>& collection, + const char* str, FontStyle style) { return itemize(collection, str, style, ""); } // Overloaded version for default font style and empty locale list id. -std::vector<Run> itemize(const std::shared_ptr<FontCollection>& collection, const char* str) { +std::vector<FontCollection::Run> itemize(const std::shared_ptr<FontCollection>& collection, + const char* str) { return itemize(collection, str, FontStyle(), ""); } // Utility function to obtain font path associated with run. -std::string getFontName(const Run& run) { - EXPECT_NE(nullptr, run.fakedFont.font.get()); - return getBasename(run.fakedFont.font.get()->typeface()->GetFontPath()); +std::string getFontName(const FontCollection::Run& run) { + EXPECT_NE(nullptr, run.fakedFont.font); + return getBasename( + ((FreeTypeMinikinFontForTest*)run.fakedFont.font->typeface().get())->fontPath()); } // Utility function to obtain LocaleList from string. @@ -524,13 +515,13 @@ TEST(FontCollectionItemizeTest, itemize_variationSelector) { ASSERT_EQ(1U, runs.size()); EXPECT_EQ(0, runs[0].start); EXPECT_EQ(1, runs[0].end); - EXPECT_TRUE(runs[0].fakedFont.font.get() == nullptr || kLatinFont == getFontName(runs[0])); + EXPECT_TRUE(runs[0].fakedFont.font == nullptr || kLatinFont == getFontName(runs[0])); runs = itemize(collection, "U+FE00", "zh-Hant"); ASSERT_EQ(1U, runs.size()); EXPECT_EQ(0, runs[0].start); EXPECT_EQ(1, runs[0].end); - EXPECT_TRUE(runs[0].fakedFont.font.get() == nullptr || kLatinFont == getFontName(runs[0])); + EXPECT_TRUE(runs[0].fakedFont.font == nullptr || kLatinFont == getFontName(runs[0])); // First font family (Regular.ttf) supports U+203C but doesn't support U+203C U+FE0F. // Emoji.ttf font supports U+203C U+FE0F. Emoji.ttf should be selected. @@ -661,13 +652,13 @@ TEST(FontCollectionItemizeTest, itemize_variationSelectorSupplement) { ASSERT_EQ(1U, runs.size()); EXPECT_EQ(0, runs[0].start); EXPECT_EQ(2, runs[0].end); - EXPECT_TRUE(runs[0].fakedFont.font.get() == nullptr || kLatinFont == getFontName(runs[0])); + EXPECT_TRUE(runs[0].fakedFont.font == nullptr || kLatinFont == getFontName(runs[0])); runs = itemize(collection, "U+E0100", "zh-Hant"); ASSERT_EQ(1U, runs.size()); EXPECT_EQ(0, runs[0].start); EXPECT_EQ(2, runs[0].end); - EXPECT_TRUE(runs[0].fakedFont.font.get() == nullptr || kLatinFont == getFontName(runs[0])); + EXPECT_TRUE(runs[0].fakedFont.font == nullptr || kLatinFont == getFontName(runs[0])); } TEST(FontCollectionItemizeTest, itemize_no_crash) { @@ -935,7 +926,7 @@ TEST(FontCollectionItemizeTest, itemize_LocaleScore) { // Prepare first font which doesn't supports U+9AA8 auto firstFamilyMinikinFont = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(kNoGlyphFont)); - std::vector<std::shared_ptr<Font>> fonts; + std::vector<Font> fonts; fonts.push_back(Font::Builder(firstFamilyMinikinFont).build()); auto firstFamily = std::make_shared<FontFamily>(registerLocaleList("und"), FamilyVariant::DEFAULT, @@ -950,7 +941,7 @@ TEST(FontCollectionItemizeTest, itemize_LocaleScore) { for (size_t i = 0; i < testCase.fontLocales.size(); ++i) { auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(kJAFont)); - std::vector<std::shared_ptr<Font>> fonts; + std::vector<Font> fonts; fonts.push_back(Font::Builder(minikinFont).build()); auto family = std::make_shared<FontFamily>(registerLocaleList(testCase.fontLocales[i]), FamilyVariant::DEFAULT, std::move(fonts), @@ -962,15 +953,14 @@ TEST(FontCollectionItemizeTest, itemize_LocaleScore) { // Do itemize auto runs = itemize(collection, "U+9AA8", testCase.userPreferredLocale); ASSERT_EQ(1U, runs.size()); - ASSERT_NE(nullptr, runs[0].fakedFont.font.get()); + ASSERT_NE(nullptr, runs[0].fakedFont.font); // First family doesn't support U+9AA8 and others support it, so the first font should not // be selected. - EXPECT_NE(firstFamilyMinikinFont.get(), runs[0].fakedFont.font.get()->typeface().get()); + EXPECT_NE(firstFamilyMinikinFont.get(), runs[0].fakedFont.font->typeface().get()); // Lookup used font family by MinikinFont*. - const int usedLocaleIndex = - fontLocaleIdxMap[runs[0].fakedFont.font.get()->typeface().get()]; + const int usedLocaleIndex = fontLocaleIdxMap[runs[0].fakedFont.font->typeface().get()]; EXPECT_EQ(testCase.selectedFontIndex, usedLocaleIndex); } } @@ -1531,10 +1521,10 @@ TEST(FontCollectionItemizeTest, itemizeShouldKeepOrderForVS) { // Both fontA/fontB support U+35A8 but don't support U+35A8 U+E0100. The first font should be // selected. auto runs = itemize(collection, "U+35A8 U+E0100"); - EXPECT_EQ(familyA->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(familyA->getFont(0), runs[0].fakedFont.font); runs = itemize(reversedCollection, "U+35A8 U+E0100"); - EXPECT_EQ(familyB->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(familyB->getFont(0), runs[0].fakedFont.font); } // For b/29585939 @@ -1554,10 +1544,10 @@ TEST(FontCollectionItemizeTest, itemizeShouldKeepOrderForVS2) { // Both hasCmapFormat14Font/noCmapFormat14Font support U+5380 but don't support U+5380 U+E0100. // The first font should be selected. auto runs = itemize(collection, "U+5380 U+E0100"); - EXPECT_EQ(hasCmapFormat14Family->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(hasCmapFormat14Family->getFont(0), runs[0].fakedFont.font); runs = itemize(reversedCollection, "U+5380 U+E0100"); - EXPECT_EQ(noCmapFormat14Family->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(noCmapFormat14Family->getFont(0), runs[0].fakedFont.font); } TEST(FontCollectionItemizeTest, colorEmojiSelectionTest) { @@ -1571,44 +1561,44 @@ TEST(FontCollectionItemizeTest, colorEmojiSelectionTest) { // Both textEmojiFamily and colorEmojiFamily supports U+203C and U+23E9. // U+203C is text default emoji, and U+23E9 is color default emoji. auto runs = itemize(collection, "U+203C", "en-US,en-Zsym"); - EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font); runs = itemize(collection, "U+23E9", "en-US,en-Zsym"); - EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font); runs = itemize(collection, "U+203C", "en-US,en-Zsye"); - EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font); runs = itemize(collection, "U+23E9", "en-US,en-Zsye"); - EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font); runs = itemize(collection, "U+203C", "ja-Zsym-JP"); - EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font); runs = itemize(collection, "U+23E9", "ja-Zsym-JP"); - EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font); runs = itemize(collection, "U+203C", "ja-Zsye-JP"); - EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font); runs = itemize(collection, "U+23E9", "ja-Zsye-JP"); - EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font); runs = itemize(collection, "U+203C", "ja-JP-u-em-text"); - EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font); runs = itemize(collection, "U+23E9", "ja-JP-u-em-text"); - EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font); runs = itemize(collection, "U+203C", "ja-JP-u-em-emoji"); - EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font); runs = itemize(collection, "U+23E9", "ja-JP-u-em-emoji"); - EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font); runs = itemize(collection, "U+203C", "ja-JP,und-Zsym"); - EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font); runs = itemize(collection, "U+23E9", "ja-JP,und-Zsym"); - EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font); runs = itemize(collection, "U+203C", "ja-JP,und-Zsye"); - EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font); runs = itemize(collection, "U+23E9", "ja-JP,und-Zsye"); - EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font); } TEST(FontCollectionItemizeTest, customFallbackTest) { @@ -1622,60 +1612,11 @@ TEST(FontCollectionItemizeTest, customFallbackTest) { auto collection = std::make_shared<FontCollection>(families); auto runs = itemize(collection, "'a'", ""); - EXPECT_EQ(customFallbackFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(customFallbackFamily->getFont(0), runs[0].fakedFont.font); runs = itemize(collection, "'a'", "en-US"); - EXPECT_EQ(customFallbackFamily->getFont(0), runs[0].fakedFont.font.get()); + EXPECT_EQ(customFallbackFamily->getFont(0), runs[0].fakedFont.font); runs = itemize(collection, "'a'", "ja-JP"); - EXPECT_EQ(customFallbackFamily->getFont(0), runs[0].fakedFont.font.get()); -} - -std::string itemizeEmojiAndFontPostScriptName(const std::string& txt) { - auto firstFamily = buildFontFamily(kAsciiFont); - auto OverrideEmojiFamily = buildFontFamily("OverrideEmoji.ttf", "und-Zsye"); - auto emojiBaseFamily = buildFontFamily("EmojiBase.ttf", "und-Zsye"); - - std::vector<std::shared_ptr<FontFamily>> families = {firstFamily, OverrideEmojiFamily, - emojiBaseFamily}; - - auto collection = std::make_shared<FontCollection>(families); - auto runs = itemize(collection, txt.c_str()); - - EXPECT_EQ(1u, runs.size()); - return FontFileParser(runs[0].fakedFont.font->baseFont()).getPostScriptName().value(); -} - -TEST(FontCollectionItemizeTest, emojiFallback) { - // OverrideEmojiFont supports U+1F9B0, U+E0000, U+1F3FB and U+1F9B0 U+1F3FB sequence. - // Use Override font. - EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F9B0")); - EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+E0000")); - EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F9B0 U+1F3FB")); - EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F9B0 U+FE0F U+1F3FB")); - - // OverrideEmojiFont doesn't suppot U+1F9B6 U+E0001 and U+1F3FC. - EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+1F9B6")); - EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+E0001")); - EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+1F9B6 U+1F3FC")); - EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+1F9B6 U+FE0F U+1F3FC")); - - // OverrideEmojiFont support U+1F9B1, U+1F3FB but doesn't support the sequence U+1F9B1 U+1F3FB. - EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F9B1")); - EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F3FB")); - EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+1F9B1 U+1F3FB")); - EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+1F9B1 U+FE0F U+1F3FB")); - - // Find the longest sequence if two sequences are supported. - EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F9B2 U+200D U+1F9B3")); - EXPECT_EQ("EmojiBaseFont", - itemizeEmojiAndFontPostScriptName("U+1F9B2 U+200D U+1F9B3 U+200D U+1F9B4")); -} - -TEST(FontCollectionItemizeTest, emojiFlagFallback) { - // If the OverrideEmojiFont supports U+1F1E6 U+1F1E6, use that font. - EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F1E6 U+1F1E6")); - - // Even if the OverrideEmojiFont directs to .notdef (i.e. Tofu glyph) for the sequence, use it. - EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F1E6 U+1F1E7")); + EXPECT_EQ(customFallbackFamily->getFont(0), runs[0].fakedFont.font); } } // namespace minikin diff --git a/tests/unittest/FontCollectionTest.cpp b/tests/unittest/FontCollectionTest.cpp index aa9d4a8..6b39508 100644 --- a/tests/unittest/FontCollectionTest.cpp +++ b/tests/unittest/FontCollectionTest.cpp @@ -19,7 +19,6 @@ #include <gtest/gtest.h> #include "FontTestUtils.h" -#include "FreeTypeMinikinFontForTest.h" #include "MinikinInternal.h" namespace minikin { @@ -57,23 +56,22 @@ void expectVSGlyphs(const FontCollection* fc, uint32_t codepoint, const std::set } } -void expectVSGlyphsForVsTestFont(const FontCollection* fc) { +TEST(FontCollectionTest, hasVariationSelectorTest) { + auto fc = buildFontCollection(kVsTestFont); + EXPECT_FALSE(fc->hasVariationSelector(0x82A6, 0)); - expectVSGlyphs(fc, 0x82A6, std::set<uint32_t>({0xFE00, 0xFE0E, 0xE0100, 0xE0101, 0xE0102})); + expectVSGlyphs(fc.get(), 0x82A6, + std::set<uint32_t>({0xFE00, 0xFE0E, 0xE0100, 0xE0101, 0xE0102})); EXPECT_FALSE(fc->hasVariationSelector(0x845B, 0)); - expectVSGlyphs(fc, 0x845B, std::set<uint32_t>({0xFE01, 0xFE0E, 0xE0101, 0xE0102, 0xE0103})); + expectVSGlyphs(fc.get(), 0x845B, + std::set<uint32_t>({0xFE01, 0xFE0E, 0xE0101, 0xE0102, 0xE0103})); EXPECT_FALSE(fc->hasVariationSelector(0x537F, 0)); - expectVSGlyphs(fc, 0x537F, std::set<uint32_t>({0xFE0E})); + expectVSGlyphs(fc.get(), 0x537F, std::set<uint32_t>({0xFE0E})); EXPECT_FALSE(fc->hasVariationSelector(0x717D, 0)); - expectVSGlyphs(fc, 0x717D, std::set<uint32_t>({0xFE02, 0xE0102, 0xE0103})); -} - -TEST(FontCollectionTest, hasVariationSelectorTest) { - auto fc = buildFontCollection(kVsTestFont); - expectVSGlyphsForVsTestFont(fc.get()); + expectVSGlyphs(fc.get(), 0x717D, std::set<uint32_t>({0xFE02, 0xE0102, 0xE0103})); } const char kEmojiXmlFile[] = "emoji.xml"; @@ -177,144 +175,4 @@ TEST(FontCollectionTest, createWithVariations) { } } -std::vector<uint8_t> writeToBuffer( - const std::vector<std::shared_ptr<FontCollection>>& collections) { - BufferWriter fakeWriter(nullptr); - FontCollection::writeVector<writeFreeTypeMinikinFontForTest>(&fakeWriter, collections); - std::vector<uint8_t> buffer(fakeWriter.size()); - BufferWriter writer(buffer.data()); - FontCollection::writeVector<writeFreeTypeMinikinFontForTest>(&writer, collections); - return buffer; -} - -TEST(FontCollectionTest, bufferTest) { - { - std::vector<std::shared_ptr<FontCollection>> original({buildFontCollection(kVsTestFont)}); - std::vector<uint8_t> buffer = writeToBuffer(original); - BufferReader reader(buffer.data()); - auto copied = FontCollection::readVector<readFreeTypeMinikinFontForTest>(&reader); - EXPECT_EQ(1u, copied.size()); - expectVSGlyphsForVsTestFont(copied[0].get()); - EXPECT_EQ(original[0]->getSupportedTags(), copied[0]->getSupportedTags()); - // Id will be different. - EXPECT_NE(original[0]->getId(), copied[0]->getId()); - std::vector<uint8_t> newBuffer = writeToBuffer(copied); - EXPECT_EQ(buffer, newBuffer); - } - { - // Test that FontFamily instances are shared. - std::vector<std::shared_ptr<FontFamily>> families = {buildFontFamily(kVsTestFont)}; - auto fc1 = std::make_shared<FontCollection>(families); - auto fc2 = std::make_shared<FontCollection>(families); - std::vector<std::shared_ptr<FontCollection>> original({fc1, fc2}); - std::vector<uint8_t> buffer = writeToBuffer(original); - BufferReader reader(buffer.data()); - auto copied = FontCollection::readVector<readFreeTypeMinikinFontForTest>(&reader); - EXPECT_EQ(2u, copied.size()); - EXPECT_EQ(copied[0]->mFamilies[0], copied[1]->mFamilies[0]); - std::vector<uint8_t> newBuffer = writeToBuffer(copied); - EXPECT_EQ(buffer, newBuffer); - } - { - // Test axes. - // This font has 'wdth' and 'wght' axes. - const char kMultiAxisFont[] = "MultiAxis.ttf"; - std::vector<std::shared_ptr<FontCollection>> original( - {buildFontCollection(kMultiAxisFont)}); - std::vector<uint8_t> buffer = writeToBuffer(original); - BufferReader reader(buffer.data()); - auto copied = FontCollection::readVector<readFreeTypeMinikinFontForTest>(&reader); - EXPECT_EQ(1u, copied.size()); - EXPECT_EQ(1u, - copied[0]->getSupportedTags().count(MinikinFont::MakeTag('w', 'd', 't', 'h'))); - EXPECT_EQ(1u, - copied[0]->getSupportedTags().count(MinikinFont::MakeTag('w', 'g', 'h', 't'))); - std::vector<uint8_t> newBuffer = writeToBuffer(copied); - EXPECT_EQ(buffer, newBuffer); - } -} - -TEST(FontCollectionTest, FamilyMatchResultBuilderTest) { - using Builder = FontCollection::FamilyMatchResult::Builder; - EXPECT_TRUE(Builder().empty()); - EXPECT_EQ(0u, Builder().size()); - EXPECT_EQ(1u, Builder().add(5).size()); - EXPECT_EQ(2u, Builder().add(5).add(4).size()); - - // Reset - EXPECT_TRUE(Builder().add(5).reset().empty()); - EXPECT_EQ(0u, Builder().add(5).reset().size()); -} - -TEST(FontCollectionTest, FamilyMatchResultTest) { - using Builder = FontCollection::FamilyMatchResult::Builder; - - auto r = Builder().build(); - EXPECT_EQ(0u, r.size()); - EXPECT_TRUE(r.empty()); - - r = Builder().add(1).build(); - EXPECT_EQ(1u, r.size()); - EXPECT_FALSE(r.empty()); - EXPECT_EQ(1u, r[0]); - - r = Builder().add(1).add(2).build(); - EXPECT_EQ(2u, r.size()); - EXPECT_FALSE(r.empty()); - EXPECT_EQ(1u, r[0]); - EXPECT_EQ(2u, r[1]); -} - -TEST(FontCollectionTest, FamilyMatchResultTest_BuilderHoldeFirst7) { - auto b = FontCollection::FamilyMatchResult::Builder(); - for (uint8_t i = 0; i < 128; ++i) { - b.add(i); - } - auto r = b.build(); - EXPECT_EQ(7u, r.size()); - EXPECT_FALSE(r.empty()); - EXPECT_EQ(0u, r[0]); - EXPECT_EQ(1u, r[1]); - EXPECT_EQ(2u, r[2]); - EXPECT_EQ(3u, r[3]); - EXPECT_EQ(4u, r[4]); - EXPECT_EQ(5u, r[5]); - EXPECT_EQ(6u, r[6]); -} - -TEST(FontCollectionTest, FamilyMatchResultTest_iterator) { - auto b = FontCollection::FamilyMatchResult::Builder(); - for (uint8_t i = 0; i < 7; ++i) { - b.add(i); - } - auto r = b.build(); - EXPECT_EQ(7u, r.size()); - EXPECT_FALSE(r.empty()); - int i = 0; - for (auto v : r) { - EXPECT_EQ(i, v); - i++; - } -} - -TEST(FontCollectionTest, FamilyMatchResultTest_intersect) { - using Builder = FontCollection::FamilyMatchResult::Builder; - - EXPECT_EQ(Builder().add(1).add(2).add(3).build(), - FontCollection::FamilyMatchResult::intersect(Builder().add(1).add(2).add(3).build(), - Builder().add(1).add(2).add(3).build())); - - EXPECT_EQ(Builder().build(), - FontCollection::FamilyMatchResult::intersect(Builder().add(1).add(2).add(3).build(), - Builder().build())); - - EXPECT_EQ(Builder().build(), - FontCollection::FamilyMatchResult::intersect(Builder().add(2).add(4).add(6).build(), - Builder().add(1).add(3).add(5).build())); - - EXPECT_EQ(Builder().add(1).add(3).build(), - FontCollection::FamilyMatchResult::intersect(Builder().add(1).add(2).add(3).build(), - Builder().add(1).add(3).add(5).build())); -} - } // namespace minikin diff --git a/tests/unittest/FontFamilyTest.cpp b/tests/unittest/FontFamilyTest.cpp index fd2fc9a..2b70faf 100644 --- a/tests/unittest/FontFamilyTest.cpp +++ b/tests/unittest/FontFamilyTest.cpp @@ -20,7 +20,6 @@ #include "minikin/LocaleList.h" -#include "BufferUtils.h" #include "FontTestUtils.h" #include "FreeTypeMinikinFontForTest.h" #include "LocaleListCache.h" @@ -157,40 +156,6 @@ TEST(LocaleTest, testReconstruction) { EXPECT_EQ("zzz-Zzzz-999", createLocaleWithoutICUSanitization("zzz-Zzzz-999").getString()); } -TEST(LocaleTest, ReconstructFromIdentifierTest) { - std::string locales[] = { - // Language - "en", - "fil", - "und", - // Script - "en-Latn", - "fil-Taga", - "und-Zsye", - // Region - "en-US", - "fil-PH", - "es-419", - // Variant - "de-Latn-DE", - "de-Latn-DE-1901", - "de-Latn-DE-1996", - // Line break style - "ja-JP-u-lb-loose", - "ja-JP-u-lb-normal", - "ja-JP-u-lb-strict", - // Emoji subtag - "es-Latn-419-u-em-emoji", - // Everything - "de-Latn-DE-1996-u-lb-loose-u-em-emoji", - }; - for (const std::string& locale : locales) { - EXPECT_EQ(createLocaleWithoutICUSanitization(locale), - Locale(createLocaleWithoutICUSanitization(locale).getIdentifier())) - << "locale = " << locale; - } -} - TEST(LocaleTest, ScriptEqualTest) { EXPECT_TRUE(createLocale("en").isEqualScript(createLocale("en"))); EXPECT_TRUE(createLocale("en-Latn").isEqualScript(createLocale("en"))); @@ -550,7 +515,9 @@ void expectVSGlyphs(FontFamily* family, uint32_t codepoint, const std::set<uint3 } } -void expectVSGlyphsForVsTestFont(FontFamily* family) { +TEST_F(FontFamilyTest, hasVariationSelectorTest) { + std::shared_ptr<FontFamily> family = buildFontFamily(kVsTestFont); + const uint32_t kVS1 = 0xFE00; const uint32_t kVS2 = 0xFE01; const uint32_t kVS3 = 0xFE02; @@ -561,28 +528,23 @@ void expectVSGlyphsForVsTestFont(FontFamily* family) { const uint32_t kSupportedChar1 = 0x82A6; EXPECT_TRUE(family->getCoverage().get(kSupportedChar1)); - expectVSGlyphs(family, kSupportedChar1, std::set<uint32_t>({kVS1, kVS17, kVS18, kVS19})); + expectVSGlyphs(family.get(), kSupportedChar1, std::set<uint32_t>({kVS1, kVS17, kVS18, kVS19})); const uint32_t kSupportedChar2 = 0x845B; EXPECT_TRUE(family->getCoverage().get(kSupportedChar2)); - expectVSGlyphs(family, kSupportedChar2, std::set<uint32_t>({kVS2, kVS18, kVS19, kVS20})); + expectVSGlyphs(family.get(), kSupportedChar2, std::set<uint32_t>({kVS2, kVS18, kVS19, kVS20})); const uint32_t kNoVsSupportedChar = 0x537F; EXPECT_TRUE(family->getCoverage().get(kNoVsSupportedChar)); - expectVSGlyphs(family, kNoVsSupportedChar, std::set<uint32_t>()); + expectVSGlyphs(family.get(), kNoVsSupportedChar, std::set<uint32_t>()); const uint32_t kVsOnlySupportedChar = 0x717D; EXPECT_FALSE(family->getCoverage().get(kVsOnlySupportedChar)); - expectVSGlyphs(family, kVsOnlySupportedChar, std::set<uint32_t>({kVS3, kVS19, kVS20})); + expectVSGlyphs(family.get(), kVsOnlySupportedChar, std::set<uint32_t>({kVS3, kVS19, kVS20})); const uint32_t kNotSupportedChar = 0x845C; EXPECT_FALSE(family->getCoverage().get(kNotSupportedChar)); - expectVSGlyphs(family, kNotSupportedChar, std::set<uint32_t>()); -} - -TEST_F(FontFamilyTest, hasVariationSelectorTest) { - std::shared_ptr<FontFamily> family = buildFontFamily(kVsTestFont); - expectVSGlyphsForVsTestFont(family.get()); + expectVSGlyphs(family.get(), kNotSupportedChar, std::set<uint32_t>()); } TEST_F(FontFamilyTest, hasVSTableTest) { @@ -766,7 +728,7 @@ TEST_F(FontFamilyTest, closestMatch) { for (const TestCase& testCase : testCases) { std::vector<std::shared_ptr<MinikinFont>> dummyFonts; - std::vector<std::shared_ptr<Font>> fonts; + std::vector<Font> fonts; for (auto familyStyle : testCase.familyStyles) { std::shared_ptr<MinikinFont> dummyFont( new FreeTypeMinikinFontForTest(getTestFontPath(kTestFont))); @@ -794,41 +756,4 @@ TEST_F(FontFamilyTest, closestMatch) { } } -TEST_F(FontFamilyTest, bufferTest) { - { - // Font with variation selectors - std::shared_ptr<FontFamily> original = buildFontFamily(kVsTestFont); - std::vector<uint8_t> buffer = - writeToBuffer<FontFamily, writeFreeTypeMinikinFontForTest>(*original); - BufferReader reader(buffer.data()); - std::shared_ptr<FontFamily> copied = - FontFamily::readFrom<readFreeTypeMinikinFontForTest>(&reader); - ASSERT_EQ(original->localeListId(), copied->localeListId()); - ASSERT_EQ(original->variant(), copied->variant()); - ASSERT_EQ(original->getNumFonts(), copied->getNumFonts()); - ASSERT_EQ(original->supportedAxes(), copied->supportedAxes()); - ASSERT_EQ(original->isColorEmojiFamily(), copied->isColorEmojiFamily()); - ASSERT_EQ(original->isCustomFallback(), copied->isCustomFallback()); - ASSERT_EQ(original->hasVSTable(), copied->hasVSTable()); - expectVSGlyphsForVsTestFont(copied.get()); - std::vector<uint8_t> newBuffer = - writeToBuffer<FontFamily, writeFreeTypeMinikinFontForTest>(*copied); - ASSERT_EQ(buffer, newBuffer); - } - { - // Font with axes - constexpr char kMultiAxisFont[] = "MultiAxis.ttf"; - std::shared_ptr<FontFamily> original = buildFontFamily(kMultiAxisFont); - std::vector<uint8_t> buffer = - writeToBuffer<FontFamily, writeFreeTypeMinikinFontForTest>(*original); - BufferReader reader(buffer.data()); - std::shared_ptr<FontFamily> copied = - FontFamily::readFrom<readFreeTypeMinikinFontForTest>(&reader); - ASSERT_EQ(original->supportedAxes(), copied->supportedAxes()); - std::vector<uint8_t> newBuffer = - writeToBuffer<FontFamily, writeFreeTypeMinikinFontForTest>(*copied); - ASSERT_EQ(buffer, newBuffer); - } -} - } // namespace minikin diff --git a/tests/unittest/FontFileParserTest.cpp b/tests/unittest/FontFileParserTest.cpp deleted file mode 100644 index d960217..0000000 --- a/tests/unittest/FontFileParserTest.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "minikin/FontFileParser.h" - -#include <gtest/gtest.h> - -#include "FontTestUtils.h" -#include "FreeTypeMinikinFontForTest.h" -#include "PathUtils.h" - -namespace minikin { -namespace { - -static size_t writeU16(uint16_t x, uint8_t* out, size_t offset) { - out[offset] = x >> 8; - out[offset + 1] = x; - return offset + 2; -} - -static size_t writeU32(uint32_t x, uint8_t* out, size_t offset) { - out[offset] = x >> 24; - out[offset + 1] = x >> 16; - out[offset + 2] = x >> 8; - out[offset + 3] = x; - return offset + 4; -} - -class TestableFontFileParser : public FontFileParser { -public: - using FontFileParser::analyzeFontRevision; - using FontFileParser::checkPSName; -}; - -// Returns valid head table contents. -static std::vector<uint8_t> buildHeadTable(uint32_t fontRevision) { - std::vector<uint8_t> out(46); - size_t head = writeU16(1, out.data(), 0); // major version - head = writeU16(0, out.data(), head); // minor version - head = writeU32(fontRevision, out.data(), head); // fontRevision - head = writeU32(0xB1B0AFBA, out.data(), head); // checksum. (random value) - head = writeU32(0x5F0F3CF5, out.data(), head); // magicNumber - head = writeU16(0, out.data(), head); // flasgs - head = writeU16(1024, out.data(), head); // unitsPerEm - head = writeU32(123457890, out.data(), head); // created (random value) - head = writeU32(123457890, out.data(), head); // modified (random value) - head = writeU16(0, out.data(), head); // xMin - head = writeU16(100, out.data(), head); // yMin - head = writeU16(1024, out.data(), head); // xMax - head = writeU16(2048, out.data(), head); // yMax - head = writeU16(0, out.data(), head); // macStyle - head = writeU16(10, out.data(), head); // lowestRecPPEM - head = writeU16(1, out.data(), head); // fontDirectionHint - head = writeU16(1, out.data(), head); // indexToLocFormat - head = writeU16(0, out.data(), head); // glyphDataFormat; - - return out; -} - -TEST(FontFileParserTest, analyzeFontRevision) { - uint32_t rev = 0x12345678; - std::vector<uint8_t> head = buildHeadTable(rev); - - uint32_t out = 0; - EXPECT_TRUE(TestableFontFileParser::analyzeFontRevision(head.data(), head.size(), &out)); - EXPECT_EQ(rev, out); -} - -TEST(FontFileParserTest, headInvalidLength) { - uint32_t rev = 0x12345678; - std::vector<uint8_t> head = buildHeadTable(rev); - - uint32_t out = 0; - EXPECT_FALSE(TestableFontFileParser::analyzeFontRevision(head.data(), 6, &out)); -} - -TEST(FontFileParserTest, parseFontForRev) { - auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath("Ascii.ttf")); - auto parser = FontFileParser(minikinFont->GetFontData(), minikinFont->GetFontSize(), 0); - - auto revision = parser.getFontRevision(); - EXPECT_TRUE(revision.has_value()); - EXPECT_EQ(0x00010000u, revision.value()); -} - -TEST(FontFileParser, checkPSName) { - EXPECT_TRUE(TestableFontFileParser::checkPSName("Roboto-Regular")); - EXPECT_TRUE(TestableFontFileParser::checkPSName("NotoColorEmoji")); - - // Space character is not allowed. - EXPECT_FALSE(TestableFontFileParser::checkPSName("Roboto Regular")); - EXPECT_FALSE(TestableFontFileParser::checkPSName("Noto Color Emoji")); - - // parens are not not allowed. - EXPECT_FALSE(TestableFontFileParser::checkPSName("Roboto (Regular)")); - EXPECT_FALSE(TestableFontFileParser::checkPSName("Noto <Color> {Emoji}")); - - // control characters are not allowed - EXPECT_FALSE(TestableFontFileParser::checkPSName("Roboto-Regular\b")); - EXPECT_FALSE(TestableFontFileParser::checkPSName("NotoColorEmoji\t")); - - // Up to 63 character is allowed. - EXPECT_FALSE(TestableFontFileParser::checkPSName(std::string(64, 'a'))); - - // Only printable ASCII is allowed. - EXPECT_FALSE(TestableFontFileParser::checkPSName("ろぼとふぉんと")); -} - -TEST(FontFileParserTest, parseFontForPSName) { - auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath("Ascii.ttf")); - auto parser = FontFileParser(minikinFont->GetFontData(), minikinFont->GetFontSize(), 0); - - auto psName = parser.getPostScriptName(); - EXPECT_TRUE(psName.has_value()); - EXPECT_EQ("SampleFont-Regular", psName.value()); -} - -} // namespace -} // namespace minikin diff --git a/tests/unittest/FontLanguageListCacheTest.cpp b/tests/unittest/FontLanguageListCacheTest.cpp index e68922d..e957cfc 100644 --- a/tests/unittest/FontLanguageListCacheTest.cpp +++ b/tests/unittest/FontLanguageListCacheTest.cpp @@ -61,25 +61,4 @@ TEST(LocaleListCacheTest, getById) { EXPECT_EQ(japanese, locales2[1]); } -TEST(LocaleListCacheTest, buffer) { - std::string locales[] = {"en", "jp", "en,zh-Hans"}; - // Measure - BufferWriter fakeWriter(nullptr); - for (const std::string& locale : locales) { - LocaleListCache::writeTo(&fakeWriter, LocaleListCache::getId(locale)); - } - // Write - std::vector<uint8_t> buffer(fakeWriter.size()); - BufferWriter writer(buffer.data()); - for (const std::string& locale : locales) { - LocaleListCache::writeTo(&writer, LocaleListCache::getId(locale)); - } - // Read - BufferReader reader(buffer.data()); - for (const std::string& locale : locales) { - EXPECT_EQ(LocaleListCache::getId(locale), LocaleListCache::readFrom(&reader)) - << "locale = " << locale; - } -} - } // namespace minikin diff --git a/tests/unittest/FontTest.cpp b/tests/unittest/FontTest.cpp index 68f5b51..ff2f9bc 100644 --- a/tests/unittest/FontTest.cpp +++ b/tests/unittest/FontTest.cpp @@ -18,25 +18,28 @@ #include <gtest/gtest.h> -#include "BufferUtils.h" #include "FontTestUtils.h" #include "FreeTypeMinikinFontForTest.h" namespace minikin { -TEST(FontTest, BufferTest) { +TEST(FontTest, CopyTest) { auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath("Ascii.ttf")); - std::shared_ptr<Font> original = Font::Builder(minikinFont).build(); - std::vector<uint8_t> buffer = writeToBuffer<Font, writeFreeTypeMinikinFontForTest>(*original); - - BufferReader reader(buffer.data()); - std::shared_ptr<Font> font = - Font::readFrom<readFreeTypeMinikinFontForTest>(&reader, kEmptyLocaleListId); - EXPECT_EQ(minikinFont->GetFontPath(), font->typeface()->GetFontPath()); - EXPECT_EQ(original->style(), font->style()); - EXPECT_NE(nullptr, font->baseFont()); - std::vector<uint8_t> newBuffer = writeToBuffer<Font, writeFreeTypeMinikinFontForTest>(*font); - EXPECT_EQ(buffer, newBuffer); + { + Font font = Font::Builder(minikinFont).build(); + { + Font copied(font); + EXPECT_EQ(font.typeface(), copied.typeface()); + EXPECT_EQ(font.style(), copied.style()); + EXPECT_EQ(font.baseFont(), copied.baseFont()); + } + { + Font copied = font; + EXPECT_EQ(font.typeface(), copied.typeface()); + EXPECT_EQ(font.style(), copied.style()); + EXPECT_EQ(font.baseFont(), copied.baseFont()); + } + } } } // namespace minikin diff --git a/tests/unittest/GreedyLineBreakerTest.cpp b/tests/unittest/GreedyLineBreakerTest.cpp index e9da1a1..13cc03c 100644 --- a/tests/unittest/GreedyLineBreakerTest.cpp +++ b/tests/unittest/GreedyLineBreakerTest.cpp @@ -93,33 +93,6 @@ private: std::vector<uint8_t> mHyphenationPattern; }; -TEST_F(GreedyLineBreakerTest, roundingError) { - MeasuredTextBuilder builder; - auto family1 = buildFontFamily("Ascii.ttf"); - std::vector<std::shared_ptr<FontFamily>> families = {family1}; - auto fc = std::make_shared<FontCollection>(families); - MinikinPaint paint(fc); - paint.size = 56.0f; // Make 1em=56px - paint.scaleX = 1; - paint.letterSpacing = -0.093f; - paint.localeListId = LocaleListCache::getId("en-US"); - const std::vector<uint16_t> textBuffer = utf8ToUtf16("8888888888888888888"); - - float measured = Layout::measureText(textBuffer, Range(0, textBuffer.size()), Bidi::LTR, paint, - StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, nullptr); - - builder.addStyleRun(0, textBuffer.size(), std::move(paint), false); - std::unique_ptr<MeasuredText> measuredText = - builder.build(textBuffer, false /* compute hyphenation */, - false /* compute full layout */, nullptr /* no hint */); - RectangleLineWidth rectangleLineWidth(measured); - TabStops tabStops(nullptr, 0, 10); - LineBreakResult r = breakLineGreedy(textBuffer, *measuredText, rectangleLineWidth, tabStops, - false /* do hyphenation */); - - EXPECT_EQ(1u, r.breakPoints.size()); -} - TEST_F(GreedyLineBreakerTest, testBreakWithoutHyphenation) { constexpr bool NO_HYPHEN = false; // No hyphenation in this test case. const std::vector<uint16_t> textBuf = utf8ToUtf16("This is an example text."); diff --git a/tests/unittest/HasherTest.cpp b/tests/unittest/HasherTest.cpp index 02cbda8..8e11cc6 100644 --- a/tests/unittest/HasherTest.cpp +++ b/tests/unittest/HasherTest.cpp @@ -35,9 +35,4 @@ TEST(HasherTest, hasherTest) { EXPECT_EQ(hasher.hash(), hasher.hash()); } -TEST(HasherTest, hasherTestFloat) { - float x = 1.1f; - EXPECT_NE(Hasher().update(x).hash(), Hasher().update(1).hash()); -} - } // namespace minikin diff --git a/tests/unittest/ICUEnvironment.h b/tests/unittest/ICUEnvironment.h new file mode 100644 index 0000000..8fd285f --- /dev/null +++ b/tests/unittest/ICUEnvironment.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINIKIN_TEST_ICU_ENVIRONMENT_H +#define MINIKIN_TEST_ICU_ENVIRONMENT_H + +// low level file access for mapping ICU data +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> + +#include <cutils/log.h> +#include <gtest/gtest.h> +#include <unicode/uclean.h> +#include <unicode/udata.h> + +namespace minikin { + +class ICUEnvironment : public testing::Environment { +public: + ICUEnvironment() : testing::Environment(), mData(nullptr), mSize(0) {} + + void* mData; + size_t mSize; + + virtual void SetUp() override { + const char* fn = "/apex/com.android.i18n/etc/icu/" U_ICUDATA_NAME ".dat"; + int fd = open(fn, O_RDONLY); + LOG_ALWAYS_FATAL_IF(fd == -1); + struct stat sb; + LOG_ALWAYS_FATAL_IF(fstat(fd, &sb) != 0); + + mSize = sb.st_size; + void* mData = mmap(nullptr, mSize, PROT_READ, MAP_SHARED, fd, 0); + close(fd); + + UErrorCode errorCode = U_ZERO_ERROR; + udata_setCommonData(mData, &errorCode); + LOG_ALWAYS_FATAL_IF(U_FAILURE(errorCode)); + + errorCode = U_ZERO_ERROR; + u_init(&errorCode); + LOG_ALWAYS_FATAL_IF(U_FAILURE(errorCode)); + } + + virtual void TearDown() override { + u_cleanup(); + munmap(mData, mSize); + } +}; + +} // namespace minikin +#endif // MINIKIN_TEST_ICU_ENVIRONMENT_H diff --git a/tests/unittest/LayoutCoreTest.cpp b/tests/unittest/LayoutCoreTest.cpp index 2ab7543..ef972a0 100644 --- a/tests/unittest/LayoutCoreTest.cpp +++ b/tests/unittest/LayoutCoreTest.cpp @@ -74,6 +74,7 @@ TEST(LayoutPieceTest, doLayoutTest) { auto layout = buildLayout("I", {"LayoutTestFont.ttf"}); EXPECT_EQ(1u, layout.glyphCount()); EXPECT_EQ(Point(0, 0), layout.pointAt(0)); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.bounds()); EXPECT_EQ(MinikinExtent(-100.0f, 20.0f), layout.extent()); EXPECT_EQ(1u, layout.fonts().size()); EXPECT_TRUE(layout.fontAt(0).font); @@ -86,6 +87,7 @@ TEST(LayoutPieceTest, doLayoutTest) { EXPECT_EQ(2u, layout.glyphCount()); EXPECT_EQ(Point(0, 0), layout.pointAt(0)); EXPECT_EQ(Point(10.0f, 0), layout.pointAt(1)); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), layout.bounds()); EXPECT_EQ(MinikinExtent(-100.0f, 20.0f), layout.extent()); EXPECT_EQ(1u, layout.fonts().size()); EXPECT_TRUE(layout.fontAt(0).font); @@ -101,6 +103,7 @@ TEST(LayoutPieceTest, doLayoutTest) { EXPECT_EQ(2u, layout.glyphCount()); EXPECT_EQ(Point(0, 0), layout.pointAt(0)); EXPECT_EQ(Point(10.0f, 0), layout.pointAt(1)); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 60.0f, 0.0f), layout.bounds()); EXPECT_EQ(MinikinExtent(-100.0f, 20.0f), layout.extent()); EXPECT_EQ(1u, layout.fonts().size()); EXPECT_TRUE(layout.fontAt(0).font); @@ -127,6 +130,7 @@ TEST(LayoutPieceTest, doLayoutTest_MultiFont) { EXPECT_EQ(2u, layout.glyphCount()); EXPECT_EQ(Point(0, 0), layout.pointAt(0)); EXPECT_EQ(Point(10.0f, 0), layout.pointAt(1)); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 30.0f, 0.0f), layout.bounds()); EXPECT_EQ(MinikinExtent(-160.0f, 40.0f), layout.extent()); EXPECT_EQ(2u, layout.fonts().size()); EXPECT_TRUE(layout.fontAt(0).font); @@ -142,6 +146,7 @@ TEST(LayoutPieceTest, doLayoutTest_MultiFont) { EXPECT_EQ(2u, layout.glyphCount()); EXPECT_EQ(Point(0, 0), layout.pointAt(0)); EXPECT_EQ(Point(20.0f, 0), layout.pointAt(1)); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 30.0f, 0.0f), layout.bounds()); EXPECT_EQ(MinikinExtent(-160.0f, 40.0f), layout.extent()); EXPECT_EQ(2u, layout.fonts().size()); EXPECT_TRUE(layout.fontAt(0).font); @@ -163,6 +168,7 @@ TEST(LayoutPieceTest, doLayoutTest_Ligature) { auto layout = buildLayout("fi", {"Ligature.ttf"}); EXPECT_EQ(1u, layout.glyphCount()); EXPECT_EQ(Point(0, 0), layout.pointAt(0)); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.bounds()); EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent()); EXPECT_EQ(1u, layout.fonts().size()); EXPECT_TRUE(layout.fontAt(0).font); @@ -175,6 +181,7 @@ TEST(LayoutPieceTest, doLayoutTest_Ligature) { auto layout = buildLayout("ff", {"Ligature.ttf"}); EXPECT_EQ(1u, layout.glyphCount()); EXPECT_EQ(Point(0, 0), layout.pointAt(0)); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.bounds()); EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent()); EXPECT_EQ(1u, layout.fonts().size()); EXPECT_TRUE(layout.fontAt(0).font); @@ -187,6 +194,7 @@ TEST(LayoutPieceTest, doLayoutTest_Ligature) { auto layout = buildLayout("fi", {"Ligature.ttf"}, "'liga' off"); EXPECT_EQ(1u, layout.glyphCount()); EXPECT_EQ(Point(0, 0), layout.pointAt(0)); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.bounds()); EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent()); EXPECT_EQ(1u, layout.fonts().size()); EXPECT_TRUE(layout.fontAt(0).font); @@ -199,6 +207,7 @@ TEST(LayoutPieceTest, doLayoutTest_Ligature) { auto layout = buildLayout("ff", {"Ligature.ttf"}, "'liga' off"); EXPECT_EQ(2u, layout.glyphCount()); EXPECT_EQ(Point(0, 0), layout.pointAt(0)); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), layout.bounds()); EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent()); EXPECT_EQ(1u, layout.fonts().size()); EXPECT_TRUE(layout.fontAt(0).font); @@ -213,6 +222,7 @@ TEST(LayoutPieceTest, doLayoutTest_Ligature) { auto layout = buildLayout("fii", {"Ligature.ttf"}); EXPECT_EQ(2u, layout.glyphCount()); EXPECT_EQ(Point(0, 0), layout.pointAt(0)); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), layout.bounds()); EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent()); EXPECT_EQ(1u, layout.fonts().size()); EXPECT_TRUE(layout.fontAt(0).font); @@ -228,6 +238,7 @@ TEST(LayoutPieceTest, doLayoutTest_Ligature) { auto layout = buildLayout("if", {"Ligature.ttf"}); EXPECT_EQ(2u, layout.glyphCount()); EXPECT_EQ(Point(0, 0), layout.pointAt(0)); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), layout.bounds()); EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), layout.extent()); EXPECT_EQ(1u, layout.fonts().size()); EXPECT_TRUE(layout.fontAt(0).font); diff --git a/tests/unittest/LayoutTest.cpp b/tests/unittest/LayoutTest.cpp index 7771051..4b97cee 100644 --- a/tests/unittest/LayoutTest.cpp +++ b/tests/unittest/LayoutTest.cpp @@ -20,7 +20,6 @@ #include "minikin/FontCollection.h" #include "minikin/LayoutPieces.h" -#include "minikin/Measurement.h" #include "FontTestUtils.h" #include "UnicodeUtils.h" @@ -36,12 +35,6 @@ static void expectAdvances(const std::vector<float>& expected, const std::vector } } -static void getBounds(const U16StringPiece& text, Bidi bidiFlags, const MinikinPaint& paint, - MinikinRect* out) { - getBounds(text, Range(0, text.size()), bidiFlags, paint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, out); -} - class LayoutTest : public testing::Test { protected: LayoutTest() : mCollection(nullptr) {} @@ -71,8 +64,7 @@ TEST_F(LayoutTest, doLayoutTest) { Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); EXPECT_EQ(70.0f, layout.getAdvance()); - - getBounds(text, Bidi::LTR, paint, &rect); + layout.getBounds(&rect); EXPECT_EQ(0.0f, rect.mLeft); EXPECT_EQ(10.0f, rect.mTop); EXPECT_EQ(70.0f, rect.mRight); @@ -90,8 +82,7 @@ TEST_F(LayoutTest, doLayoutTest) { Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); EXPECT_EQ(90.0f, layout.getAdvance()); - - getBounds(text, Bidi::LTR, paint, &rect); + layout.getBounds(&rect); EXPECT_EQ(0.0f, rect.mLeft); EXPECT_EQ(10.0f, rect.mTop); EXPECT_EQ(90.0f, rect.mRight); @@ -109,8 +100,7 @@ TEST_F(LayoutTest, doLayoutTest) { Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); EXPECT_EQ(160.0f, layout.getAdvance()); - - getBounds(text, Bidi::LTR, paint, &rect); + layout.getBounds(&rect); EXPECT_EQ(0.0f, rect.mLeft); EXPECT_EQ(10.0f, rect.mTop); EXPECT_EQ(160.0f, rect.mRight); @@ -128,8 +118,7 @@ TEST_F(LayoutTest, doLayoutTest) { Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); EXPECT_EQ(110.0f, layout.getAdvance()); - - getBounds(text, Bidi::LTR, paint, &rect); + layout.getBounds(&rect); EXPECT_EQ(0.0f, rect.mLeft); EXPECT_EQ(10.0f, rect.mTop); EXPECT_EQ(110.0f, rect.mRight); @@ -159,8 +148,7 @@ TEST_F(LayoutTest, doLayoutTest_wordSpacing) { Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); EXPECT_EQ(70.0f, layout.getAdvance()); - - getBounds(text, Bidi::LTR, paint, &rect); + layout.getBounds(&rect); EXPECT_EQ(0.0f, rect.mLeft); EXPECT_EQ(10.0f, rect.mTop); EXPECT_EQ(70.0f, rect.mRight); @@ -178,8 +166,7 @@ TEST_F(LayoutTest, doLayoutTest_wordSpacing) { Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); EXPECT_EQ(95.0f, layout.getAdvance()); - - getBounds(text, Bidi::LTR, paint, &rect); + layout.getBounds(&rect); EXPECT_EQ(0.0f, rect.mLeft); EXPECT_EQ(10.0f, rect.mTop); EXPECT_EQ(95.0f, rect.mRight); @@ -198,8 +185,7 @@ TEST_F(LayoutTest, doLayoutTest_wordSpacing) { Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); EXPECT_EQ(170.0f, layout.getAdvance()); - - getBounds(text, Bidi::LTR, paint, &rect); + layout.getBounds(&rect); EXPECT_EQ(0.0f, rect.mLeft); EXPECT_EQ(10.0f, rect.mTop); EXPECT_EQ(170.0f, rect.mRight); @@ -219,8 +205,7 @@ TEST_F(LayoutTest, doLayoutTest_wordSpacing) { Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); EXPECT_EQ(120.0f, layout.getAdvance()); - - getBounds(text, Bidi::LTR, paint, &rect); + layout.getBounds(&rect); EXPECT_EQ(0.0f, rect.mLeft); EXPECT_EQ(10.0f, rect.mTop); EXPECT_EQ(120.0f, rect.mRight); @@ -253,8 +238,7 @@ TEST_F(LayoutTest, doLayoutTest_negativeWordSpacing) { Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); EXPECT_EQ(70.0f, layout.getAdvance()); - - getBounds(text, Bidi::LTR, paint, &rect); + layout.getBounds(&rect); EXPECT_EQ(0.0f, rect.mLeft); EXPECT_EQ(10.0f, rect.mTop); EXPECT_EQ(70.0f, rect.mRight); @@ -272,8 +256,7 @@ TEST_F(LayoutTest, doLayoutTest_negativeWordSpacing) { Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); EXPECT_EQ(85.0f, layout.getAdvance()); - - getBounds(text, Bidi::LTR, paint, &rect); + layout.getBounds(&rect); EXPECT_EQ(0.0f, rect.mLeft); EXPECT_EQ(10.0f, rect.mTop); EXPECT_EQ(85.0f, rect.mRight); @@ -292,8 +275,7 @@ TEST_F(LayoutTest, doLayoutTest_negativeWordSpacing) { Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); EXPECT_EQ(140.0f, layout.getAdvance()); - - getBounds(text, Bidi::LTR, paint, &rect); + layout.getBounds(&rect); EXPECT_EQ(0.0f, rect.mLeft); EXPECT_EQ(10.0f, rect.mTop); EXPECT_EQ(140.0f, rect.mRight); @@ -313,8 +295,7 @@ TEST_F(LayoutTest, doLayoutTest_negativeWordSpacing) { Layout layout(text, range, Bidi::LTR, paint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); EXPECT_EQ(100.0f, layout.getAdvance()); - - getBounds(text, Bidi::LTR, paint, &rect); + layout.getBounds(&rect); EXPECT_EQ(0.0f, rect.mLeft); EXPECT_EQ(10.0f, rect.mTop); EXPECT_EQ(100.0f, rect.mRight); diff --git a/tests/unittest/MeasuredTextTest.cpp b/tests/unittest/MeasuredTextTest.cpp index e5766a1..1934ed8 100644 --- a/tests/unittest/MeasuredTextTest.cpp +++ b/tests/unittest/MeasuredTextTest.cpp @@ -19,7 +19,6 @@ #include <gtest/gtest.h> #include "minikin/LineBreaker.h" -#include "minikin/Measurement.h" #include "FontTestUtils.h" #include "UnicodeUtils.h" @@ -76,34 +75,6 @@ TEST(MeasuredTextTest, getBoundsTest) { EXPECT_EQ(MinikinRect(0.0f, 10.0f, 130.0f, 0.0f), mt->getBounds(text, Range(0, text.size()))); } -TEST(MeasuredTextTest, getBoundsTest_LTR) { - auto text = utf8ToUtf16("\u0028"); // U+0028 has 1em in LTR, 3em in RTL. - auto font = buildFontCollection("Bbox.ttf"); - - MeasuredTextBuilder builder; - MinikinPaint paint(font); - paint.size = 10.0f; - builder.addStyleRun(0, text.size(), std::move(paint), false /* is RTL */); - auto mt = builder.build(text, true /* hyphenation */, true /* full layout */, - nullptr /* no hint */); - - EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), mt->getBounds(text, Range(0, 1))); -} - -TEST(MeasuredTextTest, getBoundsTest_RTL) { - auto text = utf8ToUtf16("\u0028"); // U+0028 has 1em in LTR, 3em in RTL. - auto font = buildFontCollection("Bbox.ttf"); - - MeasuredTextBuilder builder; - MinikinPaint paint(font); - paint.size = 10.0f; - builder.addStyleRun(0, text.size(), std::move(paint), true /* is RTL */); - auto mt = builder.build(text, true /* hyphenation */, true /* full layout */, - nullptr /* no hint */); - - EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), mt->getBounds(text, Range(0, 2))); -} - TEST(MeasuredTextTest, getBoundsTest_multiStyle) { auto text = utf8ToUtf16("Hello, World!"); auto font = buildFontCollection("Ascii.ttf"); @@ -184,7 +155,6 @@ TEST(MeasuredTextTest, buildLayoutTest) { auto mt = builder.build(text, true /* hyphenation */, true /* full layout */, nullptr /* no hint */); - MinikinRect rect; MinikinPaint samePaint(font); samePaint.size = 10.0f; @@ -201,9 +171,7 @@ TEST(MeasuredTextTest, buildLayoutTest) { EXPECT_EQ(10.0f, layout.getAdvance()); EXPECT_EQ(10.0f, layout.getCharAdvance(0)); EXPECT_EQ(1u, layout.getAdvances().size()); - getBounds(text, Range(0, 1), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.getBounds()); layout = mt->buildLayout(text, Range(0, 2), fullContext, samePaint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); @@ -217,9 +185,7 @@ TEST(MeasuredTextTest, buildLayoutTest) { EXPECT_EQ(10.0f, layout.getCharAdvance(0)); EXPECT_EQ(10.0f, layout.getCharAdvance(1)); EXPECT_EQ(2u, layout.getAdvances().size()); - getBounds(text, Range(0, 2), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), layout.getBounds()); layout = mt->buildLayout(text, Range(1, 2), fullContext, samePaint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); @@ -230,9 +196,7 @@ TEST(MeasuredTextTest, buildLayoutTest) { EXPECT_EQ(10.0f, layout.getAdvance()); EXPECT_EQ(10.0f, layout.getCharAdvance(0)); EXPECT_EQ(1u, layout.getAdvances().size()); - getBounds(text, Range(1, 2), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.getBounds()); layout = mt->buildLayout(text, Range(0, text.size()), fullContext, samePaint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); @@ -246,9 +210,7 @@ TEST(MeasuredTextTest, buildLayoutTest) { } EXPECT_EQ(130.0f, layout.getAdvance()); EXPECT_EQ(text.size(), layout.getAdvances().size()); - getBounds(text, Range(0, text.size()), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 10.0f, 130.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 130.0f, 0.0f), layout.getBounds()); } TEST(MeasuredTextTest, buildLayoutTest_multiStyle) { @@ -267,7 +229,6 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle) { auto mt = builder.build(text, true /* hyphenation */, true /* full layout */, nullptr /* no hint */); - MinikinRect rect; MinikinPaint samePaint(font); samePaint.size = 10.0f; @@ -284,9 +245,7 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle) { EXPECT_EQ(10.0f, layout.getAdvance()); EXPECT_EQ(10.0f, layout.getCharAdvance(0)); EXPECT_EQ(1u, layout.getAdvances().size()); - getBounds(text, Range(0, 1), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.getBounds()); layout = mt->buildLayout(text, Range(0, 2), fullContext, samePaint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); @@ -300,9 +259,7 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle) { EXPECT_EQ(10.0f, layout.getCharAdvance(0)); EXPECT_EQ(10.0f, layout.getCharAdvance(1)); EXPECT_EQ(2u, layout.getAdvances().size()); - getBounds(text, Range(0, 2), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), layout.getBounds()); layout = mt->buildLayout(text, Range(1, 2), fullContext, samePaint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); @@ -313,9 +270,7 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle) { EXPECT_EQ(10.0f, layout.getAdvance()); EXPECT_EQ(10.0f, layout.getCharAdvance(0)); EXPECT_EQ(1u, layout.getAdvances().size()); - getBounds(text, Range(1, 2), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), layout.getBounds()); layout = mt->buildLayout(text, Range(7, 7), fullContext, samePaint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); @@ -332,9 +287,7 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle) { EXPECT_EQ(20.0f, layout.getAdvance()); EXPECT_EQ(20.0f, layout.getCharAdvance(0)); EXPECT_EQ(1u, layout.getAdvances().size()); - getBounds(text, Range(7, 8), Bidi::LTR, samePaint2, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), layout.getBounds()); } TEST(MeasuredTextTest, buildLayoutTest_differentPaint) { @@ -349,7 +302,6 @@ TEST(MeasuredTextTest, buildLayoutTest_differentPaint) { auto mt = builder.build(text, true /* hyphenation */, true /* full layout */, nullptr /* no hint */); - MinikinRect rect; MinikinPaint differentPaint(font); differentPaint.size = 20.0f; @@ -366,9 +318,7 @@ TEST(MeasuredTextTest, buildLayoutTest_differentPaint) { EXPECT_EQ(20.0f, layout.getAdvance()); EXPECT_EQ(20.0f, layout.getCharAdvance(0)); EXPECT_EQ(1u, layout.getAdvances().size()); - getBounds(text, Range(0, 1), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), layout.getBounds()); layout = mt->buildLayout(text, Range(0, 2), fullContext, differentPaint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); @@ -382,9 +332,7 @@ TEST(MeasuredTextTest, buildLayoutTest_differentPaint) { EXPECT_EQ(20.0f, layout.getCharAdvance(0)); EXPECT_EQ(20.0f, layout.getCharAdvance(1)); EXPECT_EQ(2u, layout.getAdvances().size()); - getBounds(text, Range(0, 2), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 20.0f, 40.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 20.0f, 40.0f, 0.0f), layout.getBounds()); layout = mt->buildLayout(text, Range(1, 2), fullContext, differentPaint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); @@ -395,9 +343,7 @@ TEST(MeasuredTextTest, buildLayoutTest_differentPaint) { EXPECT_EQ(20.0f, layout.getAdvance()); EXPECT_EQ(20.0f, layout.getCharAdvance(0)); EXPECT_EQ(1u, layout.getAdvances().size()); - getBounds(text, Range(1, 2), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), layout.getBounds()); layout = mt->buildLayout(text, Range(0, text.size()), fullContext, differentPaint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); @@ -411,9 +357,7 @@ TEST(MeasuredTextTest, buildLayoutTest_differentPaint) { } EXPECT_EQ(260.0f, layout.getAdvance()); EXPECT_EQ(text.size(), layout.getAdvances().size()); - getBounds(text, Range(0, text.size()), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 20.0f, 260.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 20.0f, 260.0f, 0.0f), layout.getBounds()); } TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) { @@ -432,7 +376,6 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) { auto mt = builder.build(text, true /* hyphenation */, true /* full layout */, nullptr /* no hint */); - MinikinRect rect; MinikinPaint differentPaint(font); differentPaint.size = 30.0f; @@ -449,9 +392,7 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) { EXPECT_EQ(30.0f, layout.getAdvance()); EXPECT_EQ(30.0f, layout.getCharAdvance(0)); EXPECT_EQ(1u, layout.getAdvances().size()); - getBounds(text, Range(0, 1), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), layout.getBounds()); layout = mt->buildLayout(text, Range(0, 2), fullContext, differentPaint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); @@ -465,9 +406,7 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) { EXPECT_EQ(30.0f, layout.getCharAdvance(0)); EXPECT_EQ(30.0f, layout.getCharAdvance(1)); EXPECT_EQ(2u, layout.getAdvances().size()); - getBounds(text, Range(0, 2), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 30.0f, 60.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 30.0f, 60.0f, 0.0f), layout.getBounds()); layout = mt->buildLayout(text, Range(1, 2), fullContext, differentPaint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); @@ -478,9 +417,7 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) { EXPECT_EQ(30.0f, layout.getAdvance()); EXPECT_EQ(30.0f, layout.getCharAdvance(0)); EXPECT_EQ(1u, layout.getAdvances().size()); - getBounds(text, Range(1, 2), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), layout.getBounds()); layout = mt->buildLayout(text, Range(7, 7), fullContext, differentPaint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); @@ -495,9 +432,7 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) { EXPECT_EQ(30.0f, layout.getAdvance()); EXPECT_EQ(30.0f, layout.getCharAdvance(0)); EXPECT_EQ(1u, layout.getAdvances().size()); - getBounds(text, Range(7, 8), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), layout.getBounds()); layout = mt->buildLayout(text, Range(6, 8), fullContext, differentPaint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); @@ -511,9 +446,7 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) { EXPECT_EQ(30.0f, layout.getCharAdvance(0)); EXPECT_EQ(30.0f, layout.getCharAdvance(1)); EXPECT_EQ(2u, layout.getAdvances().size()); - getBounds(text, Range(6, 8), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 30.0f, 60.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 30.0f, 60.0f, 0.0f), layout.getBounds()); layout = mt->buildLayout(text, Range(0, text.size()), fullContext, differentPaint, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT); @@ -527,9 +460,7 @@ TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) { } EXPECT_EQ(390.0f, layout.getAdvance()); EXPECT_EQ(text.size(), layout.getAdvances().size()); - getBounds(text, Range(0, text.size()), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT, - EndHyphenEdit::NO_EDIT, &rect); - EXPECT_EQ(MinikinRect(0.0f, 30.0f, 390.0f, 0.0f), rect); + EXPECT_EQ(MinikinRect(0.0f, 30.0f, 390.0f, 0.0f), layout.getBounds()); } } // namespace minikin diff --git a/tests/unittest/OptimalLineBreakerTest.cpp b/tests/unittest/OptimalLineBreakerTest.cpp index d6801cc..51aab60 100644 --- a/tests/unittest/OptimalLineBreakerTest.cpp +++ b/tests/unittest/OptimalLineBreakerTest.cpp @@ -2080,33 +2080,5 @@ TEST_F(OptimalLineBreakerTest, testControllCharAfterSpace) { << toString(textBuf, actual); } } - -TEST_F(OptimalLineBreakerTest, roundingError) { - MeasuredTextBuilder builder; - auto family1 = buildFontFamily("Ascii.ttf"); - std::vector<std::shared_ptr<FontFamily>> families = {family1}; - auto fc = std::make_shared<FontCollection>(families); - MinikinPaint paint(fc); - paint.size = 56.0f; // Make 1em=56px - paint.scaleX = 1; - paint.letterSpacing = -0.093f; - paint.localeListId = LocaleListCache::getId("en-US"); - const std::vector<uint16_t> textBuffer = utf8ToUtf16("8888888888888888888"); - - float measured = Layout::measureText(textBuffer, Range(0, textBuffer.size()), Bidi::LTR, paint, - StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, nullptr); - - builder.addStyleRun(0, textBuffer.size(), std::move(paint), false); - std::unique_ptr<MeasuredText> measuredText = - builder.build(textBuffer, false /* compute hyphenation */, - false /* compute full layout */, nullptr /* no hint */); - RectangleLineWidth rectangleLineWidth(measured); - TabStops tabStops(nullptr, 0, 10); - LineBreakResult r = doLineBreak(textBuffer, *measuredText, BreakStrategy::Balanced, - HyphenationFrequency::None, measured); - - EXPECT_EQ(1u, r.breakPoints.size()); -} - } // namespace } // namespace minikin diff --git a/tests/unittest/SparseBitSetTest.cpp b/tests/unittest/SparseBitSetTest.cpp index 8c67964..03a14d9 100644 --- a/tests/unittest/SparseBitSetTest.cpp +++ b/tests/unittest/SparseBitSetTest.cpp @@ -20,8 +20,6 @@ #include <gtest/gtest.h> -#include "BufferUtils.h" - namespace minikin { TEST(SparseBitSetTest, randomTest) { @@ -54,29 +52,4 @@ TEST(SparseBitSetTest, randomTest) { } } -TEST(SparseBitSetTest, bufferTest) { - std::vector<uint32_t> range({10, 20}); - SparseBitSet originalBitset(range.data(), range.size() / 2); - std::vector<uint8_t> buffer = writeToBuffer(originalBitset); - BufferReader reader(buffer.data()); - SparseBitSet bitset(&reader); - - for (size_t i = 0; i < 10; ++i) ASSERT_FALSE(bitset.get(i)) << i; - for (size_t i = 10; i < 20; ++i) ASSERT_TRUE(bitset.get(i)) << i; - for (size_t i = 20; i < 30; ++i) ASSERT_FALSE(bitset.get(i)) << i; - std::vector<uint8_t> newBuffer = writeToBuffer(bitset); - ASSERT_EQ(buffer, newBuffer); -} - -TEST(SparseBitSetTest, emptyBitSetBufferTest) { - SparseBitSet empty; - std::vector<uint8_t> buffer = writeToBuffer(empty); - BufferReader reader(buffer.data()); - SparseBitSet bitset(&reader); - - ASSERT_FALSE(bitset.get(0)); - std::vector<uint8_t> newBuffer = writeToBuffer(bitset); - ASSERT_EQ(buffer, newBuffer); -} - } // namespace minikin diff --git a/tests/unittest/SystemFontsTest.cpp b/tests/unittest/SystemFontsTest.cpp index f1b0109..fe603a9 100644 --- a/tests/unittest/SystemFontsTest.cpp +++ b/tests/unittest/SystemFontsTest.cpp @@ -21,7 +21,6 @@ #include "minikin/FontCollection.h" #include "FontTestUtils.h" -#include "PathUtils.h" namespace minikin { namespace { @@ -31,18 +30,10 @@ public: TestableSystemFonts() : SystemFonts() {} virtual ~TestableSystemFonts() {} - std::shared_ptr<FontCollection> findFontCollection(const std::string& familyName) { + std::shared_ptr<FontCollection> findFontCollection(const std::string& familyName) const { return findFontCollectionInternal(familyName); } - void addFontMap(std::shared_ptr<FontCollection>&& collections) { - addFontMapInternal(std::move(collections)); - } - - void getFontSet(std::function<void(const std::vector<std::shared_ptr<Font>>&)> func) { - getFontSetInternal(func); - } - void registerFallback(const std::string& familyName, const std::shared_ptr<FontCollection>& fc) { registerFallbackInternal(familyName, fc); @@ -75,44 +66,5 @@ TEST(SystemFontsTest, registerDefaultAndFallback) { EXPECT_EQ(fc2, systemFonts.findFontCollection("sans")); } -TEST(SystemFontsTest, updateDefaultAndFallback) { - TestableSystemFonts systemFonts; - auto fc1 = buildFontCollection("Ascii.ttf"); - auto fc2 = buildFontCollection("Bold.ttf"); - systemFonts.registerDefault(fc1); - systemFonts.registerFallback("sans", fc2); - systemFonts.registerDefault(fc2); - systemFonts.registerFallback("sans", fc1); - EXPECT_EQ(fc2, systemFonts.findFontCollection("unknown-name")); - EXPECT_EQ(fc1, systemFonts.findFontCollection("sans")); -} - -TEST(SystemFontTest, getAvailableFont_dedupFonts) { - TestableSystemFonts systemFonts; - auto asciiFamily = buildFontFamily("Ascii.ttf"); - auto boldFamily = buildFontFamily("Bold.ttf"); - auto boldItalicFamily = buildFontFamily("BoldItalic.ttf"); - - auto fc1Families = std::vector<std::shared_ptr<FontFamily>>{asciiFamily, boldItalicFamily}; - auto fc2Families = std::vector<std::shared_ptr<FontFamily>>{boldFamily, boldItalicFamily}; - auto fc1 = std::make_shared<FontCollection>(std::move(fc1Families)); - auto fc2 = std::make_shared<FontCollection>(std::move(fc2Families)); - - systemFonts.addFontMap(std::move(fc1)); - systemFonts.addFontMap(std::move(fc2)); - - systemFonts.getFontSet([](const std::vector<std::shared_ptr<Font>>& fonts) { - EXPECT_EQ(3u, fonts.size()); // Ascii, Bold and BoldItalic - std::unordered_set<std::string> fontPaths; - for (const auto& font : fonts) { - fontPaths.insert(getBasename(font->typeface()->GetFontPath())); - } - - EXPECT_TRUE(fontPaths.find("Ascii.ttf") != fontPaths.end()); - EXPECT_TRUE(fontPaths.find("Bold.ttf") != fontPaths.end()); - EXPECT_TRUE(fontPaths.find("BoldItalic.ttf") != fontPaths.end()); - }); -} - } // namespace } // namespace minikin diff --git a/tests/unittest/TestMain.cpp b/tests/unittest/TestMain.cpp index 05e3da4..6680fbd 100644 --- a/tests/unittest/TestMain.cpp +++ b/tests/unittest/TestMain.cpp @@ -14,9 +14,12 @@ * limitations under the License. */ +#include "ICUEnvironment.h" + #include <gtest/gtest.h> int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); + ::testing::AddGlobalTestEnvironment(new minikin::ICUEnvironment); return RUN_ALL_TESTS(); } diff --git a/tests/util/Android.bp b/tests/util/Android.bp index 1d3d8cf..8bf125b 100644 --- a/tests/util/Android.bp +++ b/tests/util/Android.bp @@ -1,7 +1,3 @@ -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - cc_library_static { name: "libminikin-tests-util", srcs: [ diff --git a/tests/util/BufferUtils.h b/tests/util/BufferUtils.h deleted file mode 100644 index 355e74e..0000000 --- a/tests/util/BufferUtils.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef MINIKIN_TEST_BUFFER_UTILS_H -#define MINIKIN_TEST_BUFFER_UTILS_H - -#include <minikin/Buffer.h> -#include <vector> - -namespace minikin { - -template <class T> -std::vector<uint8_t> allocateBuffer(const T& t) { - BufferWriter writer(nullptr); - t.writeTo(&writer); - // Fill with 0xFF for debugging. - return std::vector<uint8_t>(writer.size(), 0xFFu); -} - -template <class T, auto arg> -std::vector<uint8_t> allocateBuffer(const T& t) { - BufferWriter writer(nullptr); - t.template writeTo<arg>(&writer); - // Fill with 0xFF for debugging. - return std::vector<uint8_t>(writer.size(), 0xFFu); -} - -template <class T> -std::vector<uint8_t> writeToBuffer(const T& t) { - std::vector<uint8_t> buffer = allocateBuffer(t); - BufferWriter writer(buffer.data()); - t.writeTo(&writer); - return buffer; -} - -template <class T, auto arg> -std::vector<uint8_t> writeToBuffer(const T& t) { - std::vector<uint8_t> buffer = allocateBuffer<T, arg>(t); - BufferWriter writer(buffer.data()); - t.template writeTo<arg>(&writer); - return buffer; -} - -} // namespace minikin - -#endif // MINIKIN_TEST_BUFFER_UTILS_H diff --git a/tests/util/FontTestUtils.cpp b/tests/util/FontTestUtils.cpp index 5370ab6..4143c04 100644 --- a/tests/util/FontTestUtils.cpp +++ b/tests/util/FontTestUtils.cpp @@ -67,7 +67,7 @@ std::vector<std::shared_ptr<FontFamily>> getFontFamilies(const std::string& font } } - std::vector<std::shared_ptr<Font>> fonts; + std::vector<Font> fonts; for (xmlNode* fontNode = familyNode->children; fontNode; fontNode = fontNode->next) { if (xmlStrcmp(fontNode->name, (const xmlChar*)"font") != 0) { continue; @@ -124,7 +124,7 @@ std::shared_ptr<FontCollection> buildFontCollection(const std::string& filePath) std::shared_ptr<FontFamily> buildFontFamily(const std::string& filePath) { auto font = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(filePath)); - std::vector<std::shared_ptr<Font>> fonts; + std::vector<Font> fonts; fonts.push_back(Font::Builder(font).build()); return std::make_shared<FontFamily>(std::move(fonts)); } @@ -132,7 +132,7 @@ std::shared_ptr<FontFamily> buildFontFamily(const std::string& filePath) { std::shared_ptr<FontFamily> buildFontFamily(const std::string& filePath, const std::string& lang, bool isCustomFallback) { auto font = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(filePath)); - std::vector<std::shared_ptr<Font>> fonts; + std::vector<Font> fonts; fonts.push_back(Font::Builder(font).build()); return std::make_shared<FontFamily>(LocaleListCache::getId(lang), FamilyVariant::DEFAULT, std::move(fonts), isCustomFallback); diff --git a/tests/util/FreeTypeMinikinFontForTest.cpp b/tests/util/FreeTypeMinikinFontForTest.cpp index 1be466a..1ea0631 100644 --- a/tests/util/FreeTypeMinikinFontForTest.cpp +++ b/tests/util/FreeTypeMinikinFontForTest.cpp @@ -37,6 +37,8 @@ namespace minikin { namespace { +static int uniqueId = 0; + constexpr FT_Int32 LOAD_FLAG = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; @@ -60,7 +62,7 @@ void loadGlyphOrDie(uint32_t glyphId, float size, FT_Face face) { } // namespace FreeTypeMinikinFontForTest::FreeTypeMinikinFontForTest(const std::string& font_path, int index) - : mFontPath(font_path), mFontIndex(index) { + : MinikinFont(uniqueId++), mFontPath(font_path), mFontIndex(index) { int fd = open(font_path.c_str(), O_RDONLY); LOG_ALWAYS_FATAL_IF(fd == -1, "Open failed: %s", font_path.c_str()); struct stat st = {}; @@ -112,18 +114,4 @@ void FreeTypeMinikinFontForTest::GetFontExtent(MinikinExtent* extent, const Mini extent->descent = -static_cast<float>(mFtFace->descender) * paint.size / upem; } -void writeFreeTypeMinikinFontForTest(BufferWriter* writer, const MinikinFont* typeface) { - writer->writeString(typeface->GetFontPath()); -} - -std::shared_ptr<MinikinFont> loadFreeTypeMinikinFontForTest(BufferReader reader) { - std::string fontPath(reader.readString()); - return std::make_shared<FreeTypeMinikinFontForTest>(fontPath); -} - -Font::TypefaceLoader* readFreeTypeMinikinFontForTest(BufferReader* reader) { - reader->skipString(); // fontPath - return &loadFreeTypeMinikinFontForTest; -} - } // namespace minikin diff --git a/tests/util/FreeTypeMinikinFontForTest.h b/tests/util/FreeTypeMinikinFontForTest.h index 4cdb6d8..4b6ea05 100644 --- a/tests/util/FreeTypeMinikinFontForTest.h +++ b/tests/util/FreeTypeMinikinFontForTest.h @@ -19,8 +19,6 @@ #include <string> -#include "minikin/Buffer.h" -#include "minikin/Font.h" #include "minikin/MinikinFont.h" #include <ft2build.h> @@ -45,7 +43,8 @@ public: void GetFontExtent(MinikinExtent* extent, const MinikinPaint& paint, const FontFakery& fakery) const override; - const std::string& GetFontPath() const override { return mFontPath; } + const std::string& fontPath() const { return mFontPath; } + const void* GetFontData() const { return mFontData; } size_t GetFontSize() const { return mFontSize; } int GetFontIndex() const { return mFontIndex; } @@ -64,10 +63,6 @@ private: MINIKIN_PREVENT_COPY_AND_ASSIGN(FreeTypeMinikinFontForTest); }; -void writeFreeTypeMinikinFontForTest(BufferWriter* writer, const MinikinFont* typeface); - -Font::TypefaceLoader* readFreeTypeMinikinFontForTest(BufferReader* reader); - } // namespace minikin #endif // MINIKIN_TEST_FREE_TYPE_MINIKIN_FONT_FOR_TEST_H |