summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Kondik <steve@cyngn.com>2016-03-10 18:17:18 -0800
committerSteve Kondik <steve@cyngn.com>2016-03-10 18:17:18 -0800
commitd5ee256d27808e12c16b5eaf288758b2a551b02a (patch)
treebf1664de89132ced2a334006b9f7ba4d48cfd6a5
parentbf5465acad899336a775c781412fdd65b47ca60b (diff)
parent97d7265862a9df05b3521ac4954de9cc82ec989d (diff)
downloadandroid_frameworks_minikin-d5ee256d27808e12c16b5eaf288758b2a551b02a.tar.gz
android_frameworks_minikin-d5ee256d27808e12c16b5eaf288758b2a551b02a.tar.bz2
android_frameworks_minikin-d5ee256d27808e12c16b5eaf288758b2a551b02a.zip
Merge tag 'android-6.0.1_r22' of https://android.googlesource.com/platform/frameworks/minikin into cm-13.0staging/cm-13.0+r22
Android 6.0.1 release 22
-rw-r--r--libs/minikin/CmapCoverage.cpp41
-rw-r--r--libs/minikin/GraphemeBreak.cpp26
-rw-r--r--libs/minikin/SparseBitSet.cpp2
3 files changed, 53 insertions, 16 deletions
diff --git a/libs/minikin/CmapCoverage.cpp b/libs/minikin/CmapCoverage.cpp
index 6431000..9f3447e 100644
--- a/libs/minikin/CmapCoverage.cpp
+++ b/libs/minikin/CmapCoverage.cpp
@@ -49,7 +49,7 @@ static void addRange(vector<uint32_t> &coverage, uint32_t start, uint32_t end) {
}
}
-// Get the coverage information out of a Format 12 subtable, storing it in the coverage vector
+// Get the coverage information out of a Format 4 subtable, storing it in the coverage vector
static bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data, size_t size) {
const size_t kSegCountOffset = 6;
const size_t kEndCountOffset = 14;
@@ -63,29 +63,33 @@ static bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data,
return false;
}
for (size_t i = 0; i < segCount; i++) {
- int end = readU16(data, kEndCountOffset + 2 * i);
- int start = readU16(data, kHeaderSize + 2 * (segCount + i));
- int rangeOffset = readU16(data, kHeaderSize + 2 * (3 * segCount + i));
+ uint32_t end = readU16(data, kEndCountOffset + 2 * i);
+ uint32_t start = readU16(data, kHeaderSize + 2 * (segCount + i));
+ if (end < start) {
+ // invalid segment range: size must be positive
+ return false;
+ }
+ uint32_t rangeOffset = readU16(data, kHeaderSize + 2 * (3 * segCount + i));
if (rangeOffset == 0) {
- int delta = readU16(data, kHeaderSize + 2 * (2 * segCount + i));
+ uint32_t delta = readU16(data, kHeaderSize + 2 * (2 * segCount + i));
if (((end + delta) & 0xffff) > end - start) {
addRange(coverage, start, end + 1);
} else {
- for (int j = start; j < end + 1; j++) {
+ for (uint32_t j = start; j < end + 1; j++) {
if (((j + delta) & 0xffff) != 0) {
addRange(coverage, j, j + 1);
}
}
}
} else {
- for (int j = start; j < end + 1; j++) {
+ for (uint32_t j = start; j < end + 1; j++) {
uint32_t actualRangeOffset = kHeaderSize + 6 * segCount + rangeOffset +
(i + j - start) * 2;
if (actualRangeOffset + 2 > size) {
// invalid rangeOffset is considered a "warning" by OpenType Sanitizer
continue;
}
- int glyphId = readU16(data, actualRangeOffset);
+ uint32_t glyphId = readU16(data, actualRangeOffset);
if (glyphId != 0) {
addRange(coverage, j, j + 1);
}
@@ -115,6 +119,10 @@ static bool getCoverageFormat12(vector<uint32_t>& coverage, const uint8_t* data,
uint32_t groupOffset = kFirstGroupOffset + i * kGroupSize;
uint32_t start = readU32(data, groupOffset + kStartCharCodeOffset);
uint32_t end = readU32(data, groupOffset + kEndCharCodeOffset);
+ if (end < start) {
+ // invalid group range: size must be positive
+ return false;
+ }
addRange(coverage, start, end + 1); // file is inclusive, vector is exclusive
}
return true;
@@ -128,18 +136,19 @@ bool CmapCoverage::getCoverage(SparseBitSet& coverage, const uint8_t* cmap_data,
const size_t kPlatformIdOffset = 0;
const size_t kEncodingIdOffset = 2;
const size_t kOffsetOffset = 4;
- const int kMicrosoftPlatformId = 3;
- const int kUnicodeBmpEncodingId = 1;
- const int kUnicodeUcs4EncodingId = 10;
+ const uint16_t kMicrosoftPlatformId = 3;
+ const uint16_t kUnicodeBmpEncodingId = 1;
+ const uint16_t kUnicodeUcs4EncodingId = 10;
+ const uint32_t kNoTable = UINT32_MAX;
if (kHeaderSize > cmap_size) {
return false;
}
- int numTables = readU16(cmap_data, kNumTablesOffset);
+ uint32_t numTables = readU16(cmap_data, kNumTablesOffset);
if (kHeaderSize + numTables * kTableSize > cmap_size) {
return false;
}
- int bestTable = -1;
- for (int i = 0; i < numTables; i++) {
+ uint32_t bestTable = kNoTable;
+ for (uint32_t i = 0; i < numTables; i++) {
uint16_t platformId = readU16(cmap_data, kHeaderSize + i * kTableSize + kPlatformIdOffset);
uint16_t encodingId = readU16(cmap_data, kHeaderSize + i * kTableSize + kEncodingIdOffset);
if (platformId == kMicrosoftPlatformId && encodingId == kUnicodeUcs4EncodingId) {
@@ -152,11 +161,11 @@ bool CmapCoverage::getCoverage(SparseBitSet& coverage, const uint8_t* cmap_data,
#ifdef VERBOSE_DEBUG
ALOGD("best table = %d\n", bestTable);
#endif
- if (bestTable < 0) {
+ if (bestTable == kNoTable) {
return false;
}
uint32_t offset = readU32(cmap_data, kHeaderSize + bestTable * kTableSize + kOffsetOffset);
- if (offset + 2 > cmap_size) {
+ if (offset > cmap_size - 2) {
return false;
}
uint16_t format = readU16(cmap_data, offset);
diff --git a/libs/minikin/GraphemeBreak.cpp b/libs/minikin/GraphemeBreak.cpp
index f8f386c..56d5b23 100644
--- a/libs/minikin/GraphemeBreak.cpp
+++ b/libs/minikin/GraphemeBreak.cpp
@@ -22,6 +22,19 @@
namespace android {
+// Returns true if the character appears before or after zwj in a zwj emoji sequence. See
+// http://www.unicode.org/emoji/charts/emoji-zwj-sequences.html
+bool isZwjEmoji(uint32_t c) {
+ return (c == 0x2764 // HEAVY BLACK HEART
+ || c == 0x1F468 // MAN
+ || c == 0x1F469 // WOMAN
+ || c == 0x1F48B // KISS MARK
+ || c == 0x1F466 // BOY
+ || c == 0x1F467 // GIRL
+ || c == 0x1F441 // EYE
+ || c == 0x1F5E8); // LEFT SPEECH BUBBLE
+}
+
bool GraphemeBreak::isGraphemeBreak(const uint16_t* buf, size_t start, size_t count,
size_t offset) {
// This implementation closely follows Unicode Standard Annex #29 on
@@ -93,6 +106,19 @@ bool GraphemeBreak::isGraphemeBreak(const uint16_t* buf, size_t start, size_t co
&& u_getIntPropertyValue(c2, UCHAR_GENERAL_CATEGORY) == U_OTHER_LETTER) {
return false;
}
+ // Tailoring: make emoji sequences with ZWJ a single grapheme cluster
+ if (c1 == 0x200D && isZwjEmoji(c2) && offset_back > start) {
+ // look at character before ZWJ to see that both can participate in an emoji zwj sequence
+ uint32_t c0 = 0;
+ U16_PREV(buf, start, offset_back, c0);
+ if (c0 == 0xFE0F && offset_back > start) {
+ // skip over emoji variation selector
+ U16_PREV(buf, start, offset_back, c0);
+ }
+ if (isZwjEmoji(c0)) {
+ return false;
+ }
+ }
// Rule GB10, Any / Any
return true;
}
diff --git a/libs/minikin/SparseBitSet.cpp b/libs/minikin/SparseBitSet.cpp
index 7acb7ba..2265ff2 100644
--- a/libs/minikin/SparseBitSet.cpp
+++ b/libs/minikin/SparseBitSet.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <cutils/log.h>
#include <stddef.h>
#include <string.h>
#include <minikin/SparseBitSet.h>
@@ -71,6 +72,7 @@ void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) {
for (size_t i = 0; i < nRanges; i++) {
uint32_t start = ranges[i * 2];
uint32_t end = ranges[i * 2 + 1];
+ LOG_ALWAYS_FATAL_IF(end < start); // make sure range size is nonnegative
uint32_t startPage = start >> kLogValuesPerPage;
uint32_t endPage = (end - 1) >> kLogValuesPerPage;
if (startPage >= nonzeroPageEnd) {