Reduce heap memory in minikin.
am: 97ee89d605
Change-Id: Ifb5bbba4ce7d452d844693409ac0ecad3168ed29
This commit is contained in:
@@ -68,6 +68,7 @@ public:
|
||||
private:
|
||||
void initFromRanges(const uint32_t* ranges, size_t nRanges);
|
||||
|
||||
static const uint32_t kMaximumCapacity = 0xFFFFFF;
|
||||
static const int kLogValuesPerPage = 8;
|
||||
static const int kPageMask = (1 << kLogValuesPerPage) - 1;
|
||||
static const int kLogBytesPerEl = 2;
|
||||
@@ -77,16 +78,16 @@ private:
|
||||
typedef uint32_t element;
|
||||
static const element kElAllOnes = ~((element)0);
|
||||
static const element kElFirst = ((element)1) << kElMask;
|
||||
static const uint32_t noZeroPage = ~0u;
|
||||
static const uint16_t noZeroPage = 0xFFFF;
|
||||
|
||||
static uint32_t calcNumPages(const uint32_t* ranges, size_t nRanges);
|
||||
static int CountLeadingZeros(element x);
|
||||
|
||||
uint32_t mMaxVal;
|
||||
|
||||
std::unique_ptr<uint32_t[]> mIndices;
|
||||
std::unique_ptr<uint16_t[]> mIndices;
|
||||
std::unique_ptr<element[]> mBitmaps;
|
||||
uint32_t mZeroPageIndex;
|
||||
uint16_t mZeroPageIndex;
|
||||
|
||||
// Forbid copy and assign.
|
||||
SparseBitSet(const SparseBitSet&) = delete;
|
||||
|
||||
@@ -25,6 +25,7 @@ using std::vector;
|
||||
|
||||
#include <minikin/SparseBitSet.h>
|
||||
#include <minikin/CmapCoverage.h>
|
||||
#include "MinikinInternal.h"
|
||||
|
||||
namespace minikin {
|
||||
|
||||
@@ -127,6 +128,16 @@ static bool getCoverageFormat12(vector<uint32_t>& coverage, const uint8_t* data,
|
||||
android_errorWriteLog(0x534e4554, "26413177");
|
||||
return false;
|
||||
}
|
||||
|
||||
// No need to read outside of Unicode code point range.
|
||||
if (start > MAX_UNICODE_CODE_POINT) {
|
||||
return true;
|
||||
}
|
||||
if (end > MAX_UNICODE_CODE_POINT) {
|
||||
// file is inclusive, vector is exclusive
|
||||
addRange(coverage, start, MAX_UNICODE_CODE_POINT + 1);
|
||||
return true;
|
||||
}
|
||||
addRange(coverage, start, end + 1); // file is inclusive, vector is exclusive
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -38,6 +38,8 @@ void assertMinikinLocked();
|
||||
|
||||
hb_blob_t* getFontTable(const MinikinFont* minikinFont, uint32_t tag);
|
||||
|
||||
constexpr uint32_t MAX_UNICODE_CODE_POINT = 0x10FFFF;
|
||||
|
||||
// An RAII wrapper for hb_blob_t
|
||||
class HbBlob {
|
||||
public:
|
||||
|
||||
@@ -55,8 +55,12 @@ void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) {
|
||||
if (nRanges == 0) {
|
||||
return;
|
||||
}
|
||||
mMaxVal = ranges[nRanges * 2 - 1];
|
||||
mIndices.reset(new uint32_t[(mMaxVal + kPageMask) >> kLogValuesPerPage]);
|
||||
const uint32_t maxVal = ranges[nRanges * 2 - 1];
|
||||
if (maxVal >= kMaximumCapacity) {
|
||||
return;
|
||||
}
|
||||
mMaxVal = maxVal;
|
||||
mIndices.reset(new uint16_t[(mMaxVal + kPageMask) >> kLogValuesPerPage]);
|
||||
uint32_t nPages = calcNumPages(ranges, nRanges);
|
||||
mBitmaps.reset(new element[nPages << (kLogValuesPerPage - kLogBitsPerEl)]());
|
||||
mZeroPageIndex = noZeroPage;
|
||||
@@ -124,7 +128,7 @@ uint32_t SparseBitSet::nextSetBit(uint32_t fromIndex) const {
|
||||
}
|
||||
uint32_t maxPage = (mMaxVal + kPageMask) >> kLogValuesPerPage;
|
||||
for (uint32_t page = fromPage + 1; page < maxPage; page++) {
|
||||
uint32_t index = mIndices[page];
|
||||
uint16_t index = mIndices[page];
|
||||
if (index == mZeroPageIndex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -271,6 +271,34 @@ TEST(CmapCoverageTest, SingleFormat12) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CmapCoverageTest, Format12_beyondTheUnicodeLimit) {
|
||||
bool has_cmap_format_14_subtable = false;
|
||||
{
|
||||
SCOPED_TRACE("Starting range is out of Unicode code point. Should be ignored.");
|
||||
std::vector<uint8_t> cmap = CmapBuilder::buildSingleFormat12Cmap(
|
||||
0, 0, std::vector<uint32_t>({'a', 'a', 0x110000, 0x110000}));
|
||||
|
||||
SparseBitSet coverage = CmapCoverage::getCoverage(
|
||||
cmap.data(), cmap.size(), &has_cmap_format_14_subtable);
|
||||
EXPECT_TRUE(coverage.get('a'));
|
||||
EXPECT_FALSE(coverage.get(0x110000));
|
||||
EXPECT_FALSE(has_cmap_format_14_subtable);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("Ending range is out of Unicode code point. Should be ignored.");
|
||||
std::vector<uint8_t> cmap = CmapBuilder::buildSingleFormat12Cmap(
|
||||
0, 0, std::vector<uint32_t>({'a', 'a', 0x10FF00, 0x110000}));
|
||||
|
||||
SparseBitSet coverage = CmapCoverage::getCoverage(
|
||||
cmap.data(), cmap.size(), &has_cmap_format_14_subtable);
|
||||
EXPECT_TRUE(coverage.get('a'));
|
||||
EXPECT_TRUE(coverage.get(0x10FF00));
|
||||
EXPECT_TRUE(coverage.get(0x10FFFF));
|
||||
EXPECT_FALSE(coverage.get(0x110000));
|
||||
EXPECT_FALSE(has_cmap_format_14_subtable);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CmapCoverageTest, notSupportedEncodings) {
|
||||
bool has_cmap_format_14_subtable = false;
|
||||
|
||||
@@ -398,6 +426,16 @@ TEST(CmapCoverageTest, brokenFormat12Table) {
|
||||
builder.appendTable(0, 0, table);
|
||||
std::vector<uint8_t> cmap = builder.build();
|
||||
|
||||
SparseBitSet coverage = CmapCoverage::getCoverage(
|
||||
cmap.data(), cmap.size(), &has_cmap_format_14_subtable);
|
||||
EXPECT_EQ(0U, coverage.length());
|
||||
EXPECT_FALSE(has_cmap_format_14_subtable);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("Too large code point");
|
||||
std::vector<uint8_t> cmap = CmapBuilder::buildSingleFormat12Cmap(
|
||||
0, 0, std::vector<uint32_t>({0x110000, 0x110000}));
|
||||
|
||||
SparseBitSet coverage = CmapCoverage::getCoverage(
|
||||
cmap.data(), cmap.size(), &has_cmap_format_14_subtable);
|
||||
EXPECT_EQ(0U, coverage.length());
|
||||
|
||||
Reference in New Issue
Block a user