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