提交 dae9b7ce 编写于 作者: A Adam Barth

Add BUILD.gn and make the library build

Change-Id: Ie2c3d6f97987e8a9938af8f02b093bb74dd22a18
上级 4d06fe21
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
group("txt") {
deps = [
"libs/minikin",
]
}
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
......@@ -3,7 +3,6 @@
#include <string.h>
#include "unicode/locid.h"
#include "utils/Log.h"
#include <vector>
#include <minikin/Hyphenator.h>
......
# Copyright 2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
config("minikin_config") {
include_dirs = [ "../../include" ]
}
static_library("minikin") {
sources = [
"CmapCoverage.cpp",
"Emoji.cpp",
"FontCollection.cpp",
"FontFamily.cpp",
"FontLanguage.cpp",
"FontLanguage.h",
"FontLanguageListCache.cpp",
"FontLanguageListCache.h",
"FontUtils.cpp",
"FontUtils.h",
"GraphemeBreak.cpp",
"HbFontCache.cpp",
"HbFontCache.h",
"Hyphenator.cpp",
"Layout.cpp",
"LayoutUtils.cpp",
"LayoutUtils.h",
"LineBreaker.cpp",
"Measurement.cpp",
"MinikinFont.cpp",
"MinikinInternal.cpp",
"MinikinInternal.h",
"SparseBitSet.cpp",
"WordBreaker.cpp",
]
public_configs = [ ":minikin_config" ]
public_deps = [
"//third_party/freetype2",
"//third_party/harfbuzz",
"//third_party/icu:icuuc",
]
deps = [
"//third_party/zlib",
"//lib/txt/shims",
]
}
......@@ -56,7 +56,7 @@ FontCollection::FontCollection(const vector<std::shared_ptr<FontFamily>>& typefa
}
void FontCollection::init(const vector<std::shared_ptr<FontFamily>>& typefaces) {
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
mId = sNextId++;
vector<uint32_t> lastChar;
size_t nTypefaces = typefaces.size();
......@@ -333,7 +333,7 @@ bool FontCollection::hasVariationSelector(uint32_t baseCodepoint,
return false;
}
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
// Currently mRanges can not be used here since it isn't aware of the variation sequence.
for (size_t i = 0; i < mVSFamilyVec.size(); i++) {
......
......@@ -56,7 +56,7 @@ android::hash_t FontStyle::hash() const {
// static
uint32_t FontStyle::registerLanguageList(const std::string& languages) {
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
return FontLanguageListCache::getId(languages);
}
......@@ -111,7 +111,7 @@ FontFamily::FontFamily(uint32_t langId, int variant, std::vector<Font>&& fonts)
bool FontFamily::analyzeStyle(const std::shared_ptr<MinikinFont>& typeface, int* weight,
bool* italic) {
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
const uint32_t os2Tag = MinikinFont::MakeTag('O', 'S', '/', '2');
HbBlob os2Table(getFontTable(typeface.get(), os2Tag));
if (os2Table.get() == nullptr) return false;
......@@ -166,7 +166,7 @@ bool FontFamily::isColorEmojiFamily() const {
}
void FontFamily::computeCoverage() {
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
const FontStyle defaultStyle;
const MinikinFont* typeface = getClosestMatch(defaultStyle).font;
const uint32_t cmapTag = MinikinFont::MakeTag('c', 'm', 'a', 'p');
......@@ -220,7 +220,7 @@ std::shared_ptr<FontFamily> FontFamily::createFamilyWithVariation(
std::vector<Font> fonts;
for (const Font& font : mFonts) {
bool supportedVariations = false;
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
std::unordered_set<AxisTag> supportedAxes = font.getSupportedAxesLocked();
if (!supportedAxes.empty()) {
for (const FontVariation& variation : variations) {
......
......@@ -104,7 +104,8 @@ bool GraphemeBreak::isGraphemeBreak(const float* advances, const uint16_t* buf,
return false;
}
// Rule GB9, x (Extend | ZWJ); Rule GB9a, x SpacingMark; Rule GB9b, Prepend x
if (p2 == U_GCB_EXTEND || p2 == U_GCB_ZWJ || p2 == U_GCB_SPACING_MARK || p1 == U_GCB_PREPEND) {
// TODO(abarth): Add U_GCB_ZWJ once we update ICU.
if (p2 == U_GCB_EXTEND || /* p2 == U_GCB_ZWJ || */ p2 == U_GCB_SPACING_MARK || p1 == U_GCB_PREPEND) {
return false;
}
......@@ -142,25 +143,28 @@ bool GraphemeBreak::isGraphemeBreak(const float* advances, const uint16_t* buf,
return false;
}
}
// TODO(abarth): Enablet his code once we update ICU.
// Tailored version of Rule GB11, ZWJ × (Glue_After_Zwj | EBG)
// We try to make emoji sequences with ZWJ a single grapheme cluster, but only if they actually
// merge to one cluster. So we are more relaxed than the UAX #29 rules in accepting any emoji
// character after the ZWJ, but are tighter in that we only treat it as one cluster if a
// ligature is actually formed and we also require the character before the ZWJ to also be an
// emoji.
if (p1 == U_GCB_ZWJ && isEmoji(c2) && offset_back > start) {
// look at character before ZWJ to see that both can participate in an emoji zwj sequence
uint32_t c0 = 0;
size_t offset_backback = offset_back;
U16_PREV(buf, start, offset_backback, c0);
if (c0 == 0xFE0F && offset_backback > start) {
// skip over emoji variation selector
U16_PREV(buf, start, offset_backback, c0);
}
if (isEmoji(c0)) {
return false;
}
}
// if (p1 == U_GCB_ZWJ && isEmoji(c2) && offset_back > start) {
// // look at character before ZWJ to see that both can participate in an emoji zwj sequence
// uint32_t c0 = 0;
// size_t offset_backback = offset_back;
// U16_PREV(buf, start, offset_backback, c0);
// if (c0 == 0xFE0F && offset_backback > start) {
// // skip over emoji variation selector
// U16_PREV(buf, start, offset_backback, c0);
// }
// if (isEmoji(c0)) {
// return false;
// }
// }
// Tailored version of Rule GB12 and Rule GB13 that look at even-odd cases.
// sot (RI RI)* RI x RI
// [^RI] (RI RI)* RI x RI
......
......@@ -117,11 +117,12 @@ hb_font_t* getHbFontLocked(const MinikinFont* minikinFont) {
hb_font_set_scale(parent_font, upem, upem);
font = hb_font_create_sub_font(parent_font);
std::vector<hb_variation_t> variations;
for (const FontVariation& variation : minikinFont->GetAxes()) {
variations.push_back({variation.axisTag, variation.value});
}
hb_font_set_variations(font, variations.data(), variations.size());
// TODO(abarth): Enable this code once we update harfbuzz.
// std::vector<hb_variation_t> variations;
// for (const FontVariation& variation : minikinFont->GetAxes()) {
// variations.push_back({variation.axisTag, variation.value});
// }
// hb_font_set_variations(font, variations.data(), variations.size());
hb_font_destroy(parent_font);
hb_face_destroy(face);
fontCache->put(fontId, font);
......
......@@ -25,7 +25,6 @@
#include <fcntl.h>
#define LOG_TAG "Minikin"
#include "utils/Log.h"
#include "minikin/Hyphenator.h"
......
......@@ -28,8 +28,6 @@
#include <log/log.h>
#include <utils/JenkinsHash.h>
#include <utils/LruCache.h>
#include <utils/Singleton.h>
#include <utils/String16.h>
#include <hb-icu.h>
#include <hb-ot.h>
......@@ -164,7 +162,7 @@ static unsigned int disabledDecomposeCompatibility(hb_unicode_funcs_t*, hb_codep
return 0;
}
class LayoutEngine : public ::android::Singleton<LayoutEngine> {
class LayoutEngine {
public:
LayoutEngine() {
unicodeFunctions = hb_unicode_funcs_create(hb_icu_get_unicode_funcs());
......@@ -178,6 +176,11 @@ public:
hb_buffer_t* hbBuffer;
hb_unicode_funcs_t* unicodeFunctions;
LayoutCache layoutCache;
static LayoutEngine& getInstance() {
static LayoutEngine* instance = new LayoutEngine();
return *instance;
}
};
bool LayoutCacheKey::operator==(const LayoutCacheKey& other) const {
......@@ -556,7 +559,7 @@ BidiText::BidiText(const uint16_t* buf, size_t start, size_t count, size_t bufSi
void Layout::doLayout(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
int bidiFlags, const FontStyle &style, const MinikinPaint &paint,
const std::shared_ptr<FontCollection>& collection) {
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
LayoutContext ctx;
ctx.style = style;
......@@ -575,7 +578,7 @@ void Layout::doLayout(const uint16_t* buf, size_t start, size_t count, size_t bu
float Layout::measureText(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
int bidiFlags, const FontStyle &style, const MinikinPaint &paint,
const std::shared_ptr<FontCollection>& collection, float* advances) {
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
LayoutContext ctx;
ctx.style = style;
......@@ -1102,17 +1105,10 @@ void Layout::getBounds(MinikinRect* bounds) const {
}
void Layout::purgeCaches() {
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
LayoutCache& layoutCache = LayoutEngine::getInstance().layoutCache;
layoutCache.clear();
purgeHbFontCacheLocked();
}
} // namespace minikin
// Unable to define the static data member outside of android.
// TODO: introduce our own Singleton to drop android namespace.
namespace android {
ANDROID_SINGLETON_STATIC_INSTANCE(minikin::LayoutEngine);
} // namespace android
......@@ -17,6 +17,7 @@
#ifndef MINIKIN_LAYOUT_UTILS_H
#define MINIKIN_LAYOUT_UTILS_H
#include <stddef.h>
#include <stdint.h>
namespace minikin {
......
......@@ -19,7 +19,7 @@
#include <cmath>
#include <unicode/uchar.h>
#include <android/log.h>
#include <log/log.h>
#include <minikin/GraphemeBreak.h>
#include <minikin/Measurement.h>
......
......@@ -21,7 +21,7 @@
namespace minikin {
MinikinFont::~MinikinFont() {
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
purgeHbFontLocked(this);
}
......
......@@ -24,7 +24,7 @@
namespace minikin {
android::Mutex gMinikinLock;
std::mutex gMinikinLock;
void assertMinikinLocked() {
#ifdef ENABLE_RACE_DETECTION
......
......@@ -19,9 +19,9 @@
#ifndef MINIKIN_INTERNAL_H
#define MINIKIN_INTERNAL_H
#include <hb.h>
#include <mutex>
#include <utils/Mutex.h>
#include <hb.h>
#include <minikin/MinikinFont.h>
......@@ -31,7 +31,7 @@ namespace minikin {
// Presently, that's implemented by through a global lock, and having
// all external interfaces take that lock.
extern android::Mutex gMinikinLock;
extern std::mutex gMinikinLock;
// Aborts if gMinikinLock is not acquired. Do nothing on the release build.
void assertMinikinLocked();
......
......@@ -16,7 +16,7 @@
#define LOG_TAG "Minikin"
#include <android/log.h>
#include <log/log.h>
#include <minikin/Emoji.h>
#include <minikin/Hyphenator.h>
......
# Copyright 2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
config("shims_config") {
include_dirs = [ "." ]
}
source_set("shims") {
sources = [
"log/log.h",
"log/log.cc",
"utils/JenkinsHash.h",
"utils/LruCache.h",
"utils/TypeHelpers.h",
]
public_configs = [ ":shims_config" ]
public_deps = [
"//lib/ftl",
]
}
/*
* Copyright 2017 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <log/log.h>
int __android_log_error_write(int tag,
const char* subTag,
int32_t uid,
const char* data,
uint32_t dataLen) {
return 0;
}
/*
* Copyright 2017 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <stdint.h>
#include "lib/ftl/logging.h"
#ifndef LOG_ALWAYS_FATAL_IF
#define LOG_ALWAYS_FATAL_IF(cond, ...) \
((cond) ? (FTL_LOG(FATAL) << #cond) : (void)0)
#endif
#ifndef LOG_ALWAYS_FATAL
#define LOG_ALWAYS_FATAL(...) FTL_LOG(FATAL)
#endif
#ifndef LOG_ASSERT
#define LOG_ASSERT(cond, ...) FTL_CHECK(cond)
#define ALOG_ASSERT LOG_ASSERT
#endif
#ifndef ALOGD
#define ALOGD(message, ...) FTL_DLOG(INFO) << (message)
#endif
#ifndef ALOGW
#define ALOGW(message, ...) FTL_LOG(WARNING) << (message)
#endif
#ifndef ALOGE
#define ALOGE(message, ...) FTL_LOG(ERROR) << (message)
#endif
#define android_errorWriteLog(tag, subTag) \
__android_log_error_write(tag, subTag, -1, NULL, 0)
#define android_errorWriteWithInfoLog(tag, subTag, uid, data, dataLen) \
__android_log_error_write(tag, subTag, uid, data, dataLen)
int __android_log_error_write(int tag,
const char* subTag,
int32_t uid,
const char* data,
uint32_t dataLen);
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* Implementation of Jenkins one-at-a-time hash function. These choices are
* optimized for code size and portability, rather than raw speed. But speed
* should still be quite good.
**/
#ifndef ANDROID_JENKINS_HASH_H
#define ANDROID_JENKINS_HASH_H
#include <utils/TypeHelpers.h>
namespace android {
/* The Jenkins hash of a sequence of 32 bit words A, B, C is:
* Whiten(Mix(Mix(Mix(0, A), B), C)) */
#ifdef __clang__
__attribute__((no_sanitize("integer")))
#endif
inline uint32_t JenkinsHashMix(uint32_t hash, uint32_t data) {
hash += data;
hash += (hash << 10);
hash ^= (hash >> 6);
return hash;
}
hash_t JenkinsHashWhiten(uint32_t hash);
/* Helpful utility functions for hashing data in 32 bit chunks */
uint32_t JenkinsHashMixBytes(uint32_t hash, const uint8_t* bytes, size_t size);
uint32_t JenkinsHashMixShorts(uint32_t hash, const uint16_t* shorts, size_t size);
}
#endif // ANDROID_JENKINS_HASH_H
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_UTILS_LRU_CACHE_H
#define ANDROID_UTILS_LRU_CACHE_H
#include <memory>
#include <unordered_set>
#include "utils/TypeHelpers.h" // hash_t
namespace android {
/**
* GenerationCache callback used when an item is removed
*/
template<typename EntryKey, typename EntryValue>
class OnEntryRemoved {
public:
virtual ~OnEntryRemoved() { };
virtual void operator()(EntryKey& key, EntryValue& value) = 0;
}; // class OnEntryRemoved
template <typename TKey, typename TValue>
class LruCache {
public:
explicit LruCache(uint32_t maxCapacity);
virtual ~LruCache();
enum Capacity {
kUnlimitedCapacity,
};
void setOnEntryRemovedListener(OnEntryRemoved<TKey, TValue>* listener);
size_t size() const;
const TValue& get(const TKey& key);
bool put(const TKey& key, const TValue& value);
bool remove(const TKey& key);
bool removeOldest();
void clear();
const TValue& peekOldestValue();
private:
LruCache(const LruCache& that); // disallow copy constructor
// Super class so that we can have entries having only a key reference, for searches.
class KeyedEntry {
public:
virtual const TKey& getKey() const = 0;
// Make sure the right destructor is executed so that keys and values are deleted.
virtual ~KeyedEntry() {}
};
class Entry final : public KeyedEntry {
public:
TKey key;
TValue value;
Entry* parent;
Entry* child;
Entry(TKey _key, TValue _value) : key(_key), value(_value), parent(NULL), child(NULL) {
}
const TKey& getKey() const final { return key; }
};
class EntryForSearch : public KeyedEntry {
public:
const TKey& key;
EntryForSearch(const TKey& key_) : key(key_) {
}
const TKey& getKey() const final { return key; }
};
struct HashForEntry : public std::unary_function<KeyedEntry*, hash_t> {
size_t operator() (const KeyedEntry* entry) const {
return hash_type(entry->getKey());
};
};
struct EqualityForHashedEntries : public std::unary_function<KeyedEntry*, hash_t> {
bool operator() (const KeyedEntry* lhs, const KeyedEntry* rhs) const {
return lhs->getKey() == rhs->getKey();
};
};
// All entries in the set will be Entry*. Using the weaker KeyedEntry as to allow entries
// that have only a key reference, for searching.
typedef std::unordered_set<KeyedEntry*, HashForEntry, EqualityForHashedEntries> LruCacheSet;
void attachToCache(Entry& entry);
void detachFromCache(Entry& entry);
typename LruCacheSet::iterator findByKey(const TKey& key) {
EntryForSearch entryForSearch(key);
typename LruCacheSet::iterator result = mSet->find(&entryForSearch);
return result;
}
std::unique_ptr<LruCacheSet> mSet;
OnEntryRemoved<TKey, TValue>* mListener;
Entry* mOldest;
Entry* mYoungest;
uint32_t mMaxCapacity;
TValue mNullValue;
public:
// To be used like:
// while (it.next()) {
// it.value(); it.key();
// }
class Iterator {
public:
Iterator(const LruCache<TKey, TValue>& cache):
mCache(cache), mIterator(mCache.mSet->begin()), mBeginReturned(false) {
}
bool next() {
if (mIterator == mCache.mSet->end()) {
return false;
}
if (!mBeginReturned) {
// mIterator has been initialized to the beginning and
// hasn't been returned. Do not advance:
mBeginReturned = true;
} else {
std::advance(mIterator, 1);
}
bool ret = (mIterator != mCache.mSet->end());
return ret;
}
const TValue& value() const {
// All the elements in the set are of type Entry. See comment in the definition
// of LruCacheSet above.
return reinterpret_cast<Entry *>(*mIterator)->value;
}
const TKey& key() const {
return (*mIterator)->getKey();
}
private:
const LruCache<TKey, TValue>& mCache;
typename LruCacheSet::iterator mIterator;
bool mBeginReturned;
};
};
// Implementation is here, because it's fully templated
template <typename TKey, typename TValue>
LruCache<TKey, TValue>::LruCache(uint32_t maxCapacity)
: mSet(new LruCacheSet())
, mListener(NULL)
, mOldest(NULL)
, mYoungest(NULL)
, mMaxCapacity(maxCapacity)
, mNullValue(0) {
mSet->max_load_factor(1.0);
};
template <typename TKey, typename TValue>
LruCache<TKey, TValue>::~LruCache() {
// Need to delete created entries.
clear();
};
template<typename K, typename V>
void LruCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener) {
mListener = listener;
}
template <typename TKey, typename TValue>
size_t LruCache<TKey, TValue>::size() const {
return mSet->size();
}
template <typename TKey, typename TValue>
const TValue& LruCache<TKey, TValue>::get(const TKey& key) {
typename LruCacheSet::const_iterator find_result = findByKey(key);
if (find_result == mSet->end()) {
return mNullValue;
}
// All the elements in the set are of type Entry. See comment in the definition
// of LruCacheSet above.
Entry *entry = reinterpret_cast<Entry*>(*find_result);
detachFromCache(*entry);
attachToCache(*entry);
return entry->value;
}
template <typename TKey, typename TValue>
bool LruCache<TKey, TValue>::put(const TKey& key, const TValue& value) {
if (mMaxCapacity != kUnlimitedCapacity && size() >= mMaxCapacity) {
removeOldest();
}
if (findByKey(key) != mSet->end()) {
return false;
}
Entry* newEntry = new Entry(key, value);
mSet->insert(newEntry);
attachToCache(*newEntry);
return true;
}
template <typename TKey, typename TValue>
bool LruCache<TKey, TValue>::remove(const TKey& key) {
typename LruCacheSet::const_iterator find_result = findByKey(key);
if (find_result == mSet->end()) {
return false;
}
// All the elements in the set are of type Entry. See comment in the definition
// of LruCacheSet above.
Entry* entry = reinterpret_cast<Entry*>(*find_result);
mSet->erase(entry);
if (mListener) {
(*mListener)(entry->key, entry->value);
}
detachFromCache(*entry);
delete entry;
return true;
}
template <typename TKey, typename TValue>
bool LruCache<TKey, TValue>::removeOldest() {
if (mOldest != NULL) {
return remove(mOldest->key);
// TODO: should probably abort if false
}
return false;
}
template <typename TKey, typename TValue>
const TValue& LruCache<TKey, TValue>::peekOldestValue() {
if (mOldest) {
return mOldest->value;
}
return mNullValue;
}
template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::clear() {
if (mListener) {
for (Entry* p = mOldest; p != NULL; p = p->child) {
(*mListener)(p->key, p->value);
}
}
mYoungest = NULL;
mOldest = NULL;
for (auto entry : *mSet.get()) {
delete entry;
}
mSet->clear();
}
template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::attachToCache(Entry& entry) {
if (mYoungest == NULL) {
mYoungest = mOldest = &entry;
} else {
entry.parent = mYoungest;
mYoungest->child = &entry;
mYoungest = &entry;
}
}
template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::detachFromCache(Entry& entry) {
if (entry.parent != NULL) {
entry.parent->child = entry.child;
} else {
mOldest = entry.child;
}
if (entry.child != NULL) {
entry.child->parent = entry.parent;
} else {
mYoungest = entry.parent;
}
entry.parent = NULL;
entry.child = NULL;
}
}
#endif // ANDROID_UTILS_LRU_CACHE_H
/*
* Copyright (C) 2005 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_TYPE_HELPERS_H
#define ANDROID_TYPE_HELPERS_H
#include <new>
#include <type_traits>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
// ---------------------------------------------------------------------------
namespace android {
/*
* Types traits
*/
template <typename T> struct trait_trivial_ctor { enum { value = false }; };
template <typename T> struct trait_trivial_dtor { enum { value = false }; };
template <typename T> struct trait_trivial_copy { enum { value = false }; };
template <typename T> struct trait_trivial_move { enum { value = false }; };
template <typename T> struct trait_pointer { enum { value = false }; };
template <typename T> struct trait_pointer<T*> { enum { value = true }; };
template <typename TYPE>
struct traits {
enum {
// whether this type is a pointer
is_pointer = trait_pointer<TYPE>::value,
// whether this type's constructor is a no-op
has_trivial_ctor = is_pointer || trait_trivial_ctor<TYPE>::value,
// whether this type's destructor is a no-op
has_trivial_dtor = is_pointer || trait_trivial_dtor<TYPE>::value,
// whether this type type can be copy-constructed with memcpy
has_trivial_copy = is_pointer || trait_trivial_copy<TYPE>::value,
// whether this type can be moved with memmove
has_trivial_move = is_pointer || trait_trivial_move<TYPE>::value
};
};
template <typename T, typename U>
struct aggregate_traits {
enum {
is_pointer = false,
has_trivial_ctor =
traits<T>::has_trivial_ctor && traits<U>::has_trivial_ctor,
has_trivial_dtor =
traits<T>::has_trivial_dtor && traits<U>::has_trivial_dtor,
has_trivial_copy =
traits<T>::has_trivial_copy && traits<U>::has_trivial_copy,
has_trivial_move =
traits<T>::has_trivial_move && traits<U>::has_trivial_move
};
};
#define ANDROID_TRIVIAL_CTOR_TRAIT( T ) \
template<> struct trait_trivial_ctor< T > { enum { value = true }; };
#define ANDROID_TRIVIAL_DTOR_TRAIT( T ) \
template<> struct trait_trivial_dtor< T > { enum { value = true }; };
#define ANDROID_TRIVIAL_COPY_TRAIT( T ) \
template<> struct trait_trivial_copy< T > { enum { value = true }; };
#define ANDROID_TRIVIAL_MOVE_TRAIT( T ) \
template<> struct trait_trivial_move< T > { enum { value = true }; };
#define ANDROID_BASIC_TYPES_TRAITS( T ) \
ANDROID_TRIVIAL_CTOR_TRAIT( T ) \
ANDROID_TRIVIAL_DTOR_TRAIT( T ) \
ANDROID_TRIVIAL_COPY_TRAIT( T ) \
ANDROID_TRIVIAL_MOVE_TRAIT( T )
// ---------------------------------------------------------------------------
/*
* basic types traits
*/
ANDROID_BASIC_TYPES_TRAITS( void )
ANDROID_BASIC_TYPES_TRAITS( bool )
ANDROID_BASIC_TYPES_TRAITS( char )
ANDROID_BASIC_TYPES_TRAITS( unsigned char )
ANDROID_BASIC_TYPES_TRAITS( short )
ANDROID_BASIC_TYPES_TRAITS( unsigned short )
ANDROID_BASIC_TYPES_TRAITS( int )
ANDROID_BASIC_TYPES_TRAITS( unsigned int )
ANDROID_BASIC_TYPES_TRAITS( long )
ANDROID_BASIC_TYPES_TRAITS( unsigned long )
ANDROID_BASIC_TYPES_TRAITS( long long )
ANDROID_BASIC_TYPES_TRAITS( unsigned long long )
ANDROID_BASIC_TYPES_TRAITS( float )
ANDROID_BASIC_TYPES_TRAITS( double )
// ---------------------------------------------------------------------------
/*
* compare and order types
*/
template<typename TYPE> inline
int strictly_order_type(const TYPE& lhs, const TYPE& rhs) {
return (lhs < rhs) ? 1 : 0;
}
template<typename TYPE> inline
int compare_type(const TYPE& lhs, const TYPE& rhs) {
return strictly_order_type(rhs, lhs) - strictly_order_type(lhs, rhs);
}
/*
* create, destroy, copy and move types...
*/
template<typename TYPE> inline
void construct_type(TYPE* p, size_t n) {
if (!traits<TYPE>::has_trivial_ctor) {
while (n > 0) {
n--;
new(p++) TYPE;
}
}
}
template<typename TYPE> inline
void destroy_type(TYPE* p, size_t n) {
if (!traits<TYPE>::has_trivial_dtor) {
while (n > 0) {
n--;
p->~TYPE();
p++;
}
}
}
template<typename TYPE>
typename std::enable_if<traits<TYPE>::has_trivial_copy>::type
inline
copy_type(TYPE* d, const TYPE* s, size_t n) {
memcpy(d,s,n*sizeof(TYPE));
}
template<typename TYPE>
typename std::enable_if<!traits<TYPE>::has_trivial_copy>::type
inline
copy_type(TYPE* d, const TYPE* s, size_t n) {
while (n > 0) {
n--;
new(d) TYPE(*s);
d++, s++;
}
}
template<typename TYPE> inline
void splat_type(TYPE* where, const TYPE* what, size_t n) {
if (!traits<TYPE>::has_trivial_copy) {
while (n > 0) {
n--;
new(where) TYPE(*what);
where++;
}
} else {
while (n > 0) {
n--;
*where++ = *what;
}
}
}
template<typename TYPE>
struct use_trivial_move : public std::integral_constant<bool,
(traits<TYPE>::has_trivial_dtor && traits<TYPE>::has_trivial_copy)
|| traits<TYPE>::has_trivial_move
> {};
template<typename TYPE>
typename std::enable_if<use_trivial_move<TYPE>::value>::type
inline
move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
memmove(d, s, n*sizeof(TYPE));
}
template<typename TYPE>
typename std::enable_if<!use_trivial_move<TYPE>::value>::type
inline
move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
d += n;
s += n;
while (n > 0) {
n--;
--d, --s;
if (!traits<TYPE>::has_trivial_copy) {
new(d) TYPE(*s);
} else {
*d = *s;
}
if (!traits<TYPE>::has_trivial_dtor) {
s->~TYPE();
}
}
}
template<typename TYPE>
typename std::enable_if<use_trivial_move<TYPE>::value>::type
inline
move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
memmove(d, s, n*sizeof(TYPE));
}
template<typename TYPE>
typename std::enable_if<!use_trivial_move<TYPE>::value>::type
inline
move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
while (n > 0) {
n--;
if (!traits<TYPE>::has_trivial_copy) {
new(d) TYPE(*s);
} else {
*d = *s;
}
if (!traits<TYPE>::has_trivial_dtor) {
s->~TYPE();
}
d++, s++;
}
}
// ---------------------------------------------------------------------------
/*
* a key/value pair
*/
template <typename KEY, typename VALUE>
struct key_value_pair_t {
typedef KEY key_t;
typedef VALUE value_t;
KEY key;
VALUE value;
key_value_pair_t() { }
key_value_pair_t(const key_value_pair_t& o) : key(o.key), value(o.value) { }
key_value_pair_t& operator=(const key_value_pair_t& o) {
key = o.key;
value = o.value;
return *this;
}
key_value_pair_t(const KEY& k, const VALUE& v) : key(k), value(v) { }
explicit key_value_pair_t(const KEY& k) : key(k) { }
inline bool operator < (const key_value_pair_t& o) const {
return strictly_order_type(key, o.key);
}
inline const KEY& getKey() const {
return key;
}
inline const VALUE& getValue() const {
return value;
}
};
template <typename K, typename V>
struct trait_trivial_ctor< key_value_pair_t<K, V> >
{ enum { value = aggregate_traits<K,V>::has_trivial_ctor }; };
template <typename K, typename V>
struct trait_trivial_dtor< key_value_pair_t<K, V> >
{ enum { value = aggregate_traits<K,V>::has_trivial_dtor }; };
template <typename K, typename V>
struct trait_trivial_copy< key_value_pair_t<K, V> >
{ enum { value = aggregate_traits<K,V>::has_trivial_copy }; };
template <typename K, typename V>
struct trait_trivial_move< key_value_pair_t<K, V> >
{ enum { value = aggregate_traits<K,V>::has_trivial_move }; };
// ---------------------------------------------------------------------------
/*
* Hash codes.
*/
typedef uint32_t hash_t;
template <typename TKey>
hash_t hash_type(const TKey& key);
/* Built-in hash code specializations */
#define ANDROID_INT32_HASH(T) \
template <> inline hash_t hash_type(const T& value) { return hash_t(value); }
#define ANDROID_INT64_HASH(T) \
template <> inline hash_t hash_type(const T& value) { \
return hash_t((value >> 32) ^ value); }
#define ANDROID_REINTERPRET_HASH(T, R) \
template <> inline hash_t hash_type(const T& value) { \
R newValue; \
static_assert(sizeof(newValue) == sizeof(value), "size mismatch"); \
memcpy(&newValue, &value, sizeof(newValue)); \
return hash_type(newValue); \
}
ANDROID_INT32_HASH(bool)
ANDROID_INT32_HASH(int8_t)
ANDROID_INT32_HASH(uint8_t)
ANDROID_INT32_HASH(int16_t)
ANDROID_INT32_HASH(uint16_t)
ANDROID_INT32_HASH(int32_t)
ANDROID_INT32_HASH(uint32_t)
ANDROID_INT64_HASH(int64_t)
ANDROID_INT64_HASH(uint64_t)
ANDROID_REINTERPRET_HASH(float, uint32_t)
ANDROID_REINTERPRET_HASH(double, uint64_t)
template <typename T> inline hash_t hash_type(T* const & value) {
return hash_type(uintptr_t(value));
}
}; // namespace android
// ---------------------------------------------------------------------------
#endif // ANDROID_TYPE_HELPERS_H
......@@ -87,7 +87,7 @@ static void BM_FontCollection_itemize(benchmark::State& state) {
std::vector<FontCollection::Run> result;
FontStyle style(FontStyle::registerLanguageList(ITEMIZE_TEST_CASES[testIndex].languageTag));
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
while (state.KeepRunning()) {
result.clear();
collection->itemize(buffer, utf16_length, style, &result);
......
......@@ -60,7 +60,7 @@ void itemize(const std::shared_ptr<FontCollection>& collection, const char* str,
result->clear();
ParseUnicode(buf, BUF_SIZE, str, &len, NULL);
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
collection->itemize(buf, len, style, result);
}
......@@ -72,7 +72,7 @@ const std::string& getFontPath(const FontCollection::Run& run) {
// Utility function to obtain FontLanguages from string.
const FontLanguages& registerAndGetFontLanguages(const std::string& lang_string) {
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
return FontLanguageListCache::getById(FontLanguageListCache::getId(lang_string));
}
......
......@@ -16,7 +16,7 @@
#include <minikin/FontFamily.h>
#include <android/log.h>
#include <log/log.h>
#include <gtest/gtest.h>
#include "FontLanguageListCache.h"
......@@ -30,13 +30,13 @@ typedef ICUTestBase FontLanguagesTest;
typedef ICUTestBase FontLanguageTest;
static const FontLanguages& createFontLanguages(const std::string& input) {
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
uint32_t langId = FontLanguageListCache::getId(input);
return FontLanguageListCache::getById(langId);
}
static FontLanguage createFontLanguage(const std::string& input) {
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
uint32_t langId = FontLanguageListCache::getId(input);
return FontLanguageListCache::getById(langId)[0];
}
......@@ -539,7 +539,7 @@ TEST_F(FontFamilyTest, hasVariationSelectorTest) {
std::shared_ptr<FontFamily> family(
new FontFamily(std::vector<Font>{ Font(minikinFont, FontStyle()) }));
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
const uint32_t kVS1 = 0xFE00;
const uint32_t kVS2 = 0xFE01;
......@@ -592,7 +592,7 @@ TEST_F(FontFamilyTest, hasVSTableTest) {
new MinikinFontForTest(testCase.fontPath));
std::shared_ptr<FontFamily> family(new FontFamily(
std::vector<Font>{ Font(minikinFont, FontStyle()) }));
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
EXPECT_EQ(testCase.hasVSTable, family->hasVSTable());
}
}
......@@ -673,7 +673,7 @@ TEST_F(FontFamilyTest, coverageTableSelectionTest) {
std::shared_ptr<FontFamily> unicodeEnc3Font = makeFamily(kUnicodeEncoding3Font);
std::shared_ptr<FontFamily> unicodeEnc4Font = makeFamily(kUnicodeEncoding4Font);
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
EXPECT_TRUE(unicodeEnc1Font->hasGlyph(0x0061, 0));
EXPECT_TRUE(unicodeEnc3Font->hasGlyph(0x0061, 0));
......
......@@ -31,7 +31,7 @@ TEST_F(FontLanguageListCacheTest, getId) {
EXPECT_NE(0UL, FontStyle::registerLanguageList("jp"));
EXPECT_NE(0UL, FontStyle::registerLanguageList("en,zh-Hans"));
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
EXPECT_EQ(0UL, FontLanguageListCache::getId(""));
EXPECT_EQ(FontLanguageListCache::getId("en"), FontLanguageListCache::getId("en"));
......@@ -50,7 +50,7 @@ TEST_F(FontLanguageListCacheTest, getId) {
}
TEST_F(FontLanguageListCacheTest, getById) {
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
uint32_t enLangId = FontLanguageListCache::getId("en");
uint32_t jpLangId = FontLanguageListCache::getId("jp");
FontLanguage english = FontLanguageListCache::getById(enLangId)[0];
......
......@@ -16,10 +16,10 @@
#include "HbFontCache.h"
#include <android/log.h>
#include <log/log.h>
#include <gtest/gtest.h>
#include <utils/Mutex.h>
#include <mutex>
#include <memory>
#include <hb.h>
......@@ -33,7 +33,7 @@ namespace minikin {
class HbFontCacheTest : public testing::Test {
public:
virtual void TearDown() {
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
purgeHbFontCacheLocked();
}
};
......@@ -48,7 +48,7 @@ TEST_F(HbFontCacheTest, getHbFontLockedTest) {
std::shared_ptr<MinikinFontForTest> fontC(
new MinikinFontForTest(kTestFontDir "BoldItalic.ttf"));
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
// Never return NULL.
EXPECT_NE(nullptr, getHbFontLocked(fontA.get()));
EXPECT_NE(nullptr, getHbFontLocked(fontB.get()));
......@@ -70,7 +70,7 @@ TEST_F(HbFontCacheTest, purgeCacheTest) {
std::shared_ptr<MinikinFontForTest> minikinFont(
new MinikinFontForTest(kTestFontDir "Regular.ttf"));
android::AutoMutex _l(gMinikinLock);
std::lock_guard<std::mutex> _l(gMinikinLock);
hb_font_t* font = getHbFontLocked(minikinFont.get());
ASSERT_NE(nullptr, font);
......
......@@ -16,7 +16,7 @@
#define LOG_TAG "Minikin"
#include <android/log.h>
#include <log/log.h>
#include <gtest/gtest.h>
#include "ICUTestBase.h"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册