summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/jni/android/graphics/TextLayoutCache.cpp84
-rw-r--r--core/jni/android/graphics/TextLayoutCache.h18
2 files changed, 94 insertions, 8 deletions
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 81bf4d5de603..fac367929a1e 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -19,6 +19,8 @@
#include "TextLayoutCache.h"
#include "TextLayout.h"
#include "SkFontHost.h"
+#include <unicode/unistr.h>
+#include <unicode/normlzr.h>
extern "C" {
#include "harfbuzz-unicode.h"
@@ -503,7 +505,8 @@ void TextLayoutEngine::computeValues(SkPaint* paint, const UChar* chars,
static void logGlyphs(HB_ShaperItem shaperItem) {
LOGD(" -- glyphs count=%d", shaperItem.num_glyphs);
for (size_t i = 0; i < shaperItem.num_glyphs; i++) {
- LOGD(" -- glyph[%d] = %d, offset.x = %f, offset.y = %f", i, shaperItem.glyphs[i],
+ LOGD(" -- glyph[%d] = %d, offset.x = %0.2f, offset.y = %0.2f", i,
+ shaperItem.glyphs[i],
HBFixedToFloat(shaperItem.offsets[i].x),
HBFixedToFloat(shaperItem.offsets[i].y));
}
@@ -519,8 +522,73 @@ void TextLayoutEngine::computeRunValues(SkPaint* paint, const UChar* chars,
return;
}
+ UErrorCode error = U_ZERO_ERROR;
+ bool useNormalizedString = false;
+ for (ssize_t i = count - 1; i >= 0; --i) {
+ UChar ch1 = chars[i];
+ if (::ublock_getCode(ch1) == UBLOCK_COMBINING_DIACRITICAL_MARKS) {
+ // So we have found a diacritic, let's get now the main code point which is paired
+ // with it. As we can have several diacritics in a row, we need to iterate back again
+#if DEBUG_GLYPHS
+ LOGD("The BiDi run '%s' is containing a Diacritic at position %d",
+ String8(chars, count).string(), int(i));
+#endif
+ ssize_t j = i - 1;
+ for (; j >= 0; --j) {
+ UChar ch2 = chars[j];
+ if (::ublock_getCode(ch2) != UBLOCK_COMBINING_DIACRITICAL_MARKS) {
+ break;
+ }
+ }
+
+ // We could not found the main code point, so we will just use the initial chars
+ if (j < 0) {
+ break;
+ }
+
+#if DEBUG_GLYPHS
+ LOGD("Found main code point at index %d", int(j));
+#endif
+ // We found the main code point, so we can normalize the "chunck" and fill
+ // the remaining with ZWSP so that the Paint.getTextWidth() APIs will still be able
+ // to get one advance per char
+ mBuffer.remove();
+ Normalizer::normalize(UnicodeString(chars + j, i - j + 1),
+ UNORM_NFC, 0 /* no options */, mBuffer, error);
+ if (U_SUCCESS(error)) {
+ if (!useNormalizedString) {
+ useNormalizedString = true;
+ mNormalizedString.setTo(false /* not terminated*/, chars, count);
+ }
+ // Set the normalized chars
+ for (ssize_t k = j; k < j + mBuffer.length(); ++k) {
+ mNormalizedString.setCharAt(k, mBuffer.charAt(k - j));
+ }
+ // Fill the remain part with ZWSP (ZWNJ and ZWJ would lead to weird results
+ // because some fonts are missing those glyphs)
+ for (ssize_t k = j + mBuffer.length(); k <= i; ++k) {
+ mNormalizedString.setCharAt(k, UNICODE_ZWSP);
+ }
+ }
+ i = j - 1;
+ }
+ }
+
+#if DEBUG_GLYPHS
+ if (useNormalizedString) {
+ LOGD("Will use normalized string '%s', length = %d",
+ String8(mNormalizedString.getTerminatedBuffer(),
+ mNormalizedString.length()).string(),
+ mNormalizedString.length());
+ } else {
+ LOGD("Normalization cannot be done, using initial string");
+ }
+#endif
+
+ assert(mNormalizedString.length() == count);
+
// Set the string properties
- mShaperItem.string = chars;
+ mShaperItem.string = useNormalizedString ? mNormalizedString.getTerminatedBuffer() : chars;
mShaperItem.stringLength = count;
// Define shaping paint properties
@@ -532,14 +600,14 @@ void TextLayoutEngine::computeRunValues(SkPaint* paint, const UChar* chars,
// Split the BiDi run into Script runs. Harfbuzz will populate the pos, length and script
// into the shaperItem
- ssize_t indexFontRun = isRTL ? count - 1 : 0;
+ ssize_t indexFontRun = isRTL ? mShaperItem.stringLength - 1 : 0;
unsigned numCodePoints = 0;
jfloat totalAdvance = 0;
while ((isRTL) ?
- hb_utf16_script_run_prev(&numCodePoints, &mShaperItem.item, chars,
- count, &indexFontRun):
- hb_utf16_script_run_next(&numCodePoints, &mShaperItem.item, chars,
- count, &indexFontRun)) {
+ hb_utf16_script_run_prev(&numCodePoints, &mShaperItem.item, mShaperItem.string,
+ mShaperItem.stringLength, &indexFontRun):
+ hb_utf16_script_run_next(&numCodePoints, &mShaperItem.item, mShaperItem.string,
+ mShaperItem.stringLength, &indexFontRun)) {
ssize_t startScriptRun = mShaperItem.item.pos;
size_t countScriptRun = mShaperItem.item.length;
@@ -611,7 +679,7 @@ void TextLayoutEngine::computeRunValues(SkPaint* paint, const UChar* chars,
#if DEBUG_ADVANCES
LOGD("Returned advances");
for (size_t i = 0; i < countScriptRun; i++) {
- LOGD(" -- hb-adv[%d] = %f, log_clusters = %d, total = %f", i,
+ LOGD(" -- hb-adv[%d] = %0.2f, log_clusters = %d, total = %0.2f", i,
(*outAdvances)[i], mShaperItem.log_clusters[i], totalFontRunAdvance);
}
#endif
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index fd9ccb100010..c0ae31d6eee3 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -35,6 +35,8 @@
#include <unicode/ubidi.h>
#include <unicode/ushape.h>
+#include <unicode/unistr.h>
+
#include "HarfbuzzSkia.h"
#include "harfbuzz-shaper.h"
@@ -249,10 +251,26 @@ private:
SkTypeface* mHebrewRegularTypeface;
SkTypeface* mHebrewBoldTypeface;
+ /**
+ * Cache of Harfbuzz faces
+ */
KeyedVector<SkFontID, HB_Face> mCachedHBFaces;
+ /**
+ * Cache of glyph array size
+ */
size_t mShaperItemGlyphArraySize;
+ /**
+ * Buffer for containing the ICU normalized form of a run
+ */
+ UnicodeString mNormalizedString;
+
+ /**
+ * Buffer for normalizing a piece of a run with ICU
+ */
+ UnicodeString mBuffer;
+
size_t shapeFontRun(SkPaint* paint, bool isRTL);
void computeValues(SkPaint* paint, const UChar* chars,