From fb1b47931407723a83045f649235d53982116f98 Mon Sep 17 00:00:00 2001 From: Seigo Nonaka Date: Fri, 8 Mar 2019 14:05:08 -0800 Subject: [PATCH] Hide packing structure from public API The hyphen edit is packed into 8bit integer in native library, but this should not be exposed to public API as API council suggested. This CL includes: - Removing packing structure from HyphenEdit and move constants from Hyphenator to Paint. - Replace LineBreaker's getLineHyphenEdit with two separate start/end function. - Replace Paint's getHyphenEdit with two separate start/end function. - StaticLayout still relies on this packing mechanism but no longer need to be the same packing structure as in Minikin. Bug: 124794844 Test: atest CtsGraphicsTestCases Test: atest CtsTextTestCases Change-Id: I8206061f554cf6e119b2b565162f54317eac630a --- api/current.txt | 35 ++-- core/java/android/text/DynamicLayout.java | 15 +- core/java/android/text/Hyphenator.java | 133 +------------- core/java/android/text/Layout.java | 24 ++- core/java/android/text/StaticLayout.java | 44 ++++- core/java/android/text/TextLine.java | 39 ++-- core/jni/android/graphics/Paint.cpp | 24 ++- .../src/android/text/StaticLayoutTest.java | 7 +- .../src/android/widget/TextViewTest.java | 3 +- graphics/java/android/graphics/Paint.java | 172 +++++++++++++----- .../android/graphics/text/LineBreaker.java | 30 ++- libs/hwui/hwui/MinikinUtils.cpp | 10 +- libs/hwui/hwui/Paint.h | 21 ++- 13 files changed, 306 insertions(+), 251 deletions(-) diff --git a/api/current.txt b/api/current.txt index 3489335ba471a..a9778202b38db 100644 --- a/api/current.txt +++ b/api/current.txt @@ -14428,6 +14428,7 @@ package android.graphics { method @ColorInt public int getColor(); method public android.graphics.ColorFilter getColorFilter(); method @ColorLong public long getColorLong(); + method public int getEndHyphenEdit(); method public boolean getFillPath(android.graphics.Path, android.graphics.Path); method public int getFlags(); method public String getFontFeatureSettings(); @@ -14438,7 +14439,6 @@ package android.graphics { method public float getFontSpacing(); method public String getFontVariationSettings(); method public int getHinting(); - method public int getHyphenEdit(); method public float getLetterSpacing(); method public android.graphics.MaskFilter getMaskFilter(); method public int getOffsetForAdvance(char[], int, int, int, int, boolean, float); @@ -14452,6 +14452,7 @@ package android.graphics { method public float getShadowLayerDx(); method public float getShadowLayerDy(); method public float getShadowLayerRadius(); + method public int getStartHyphenEdit(); method @Px public float getStrikeThruPosition(); method @Px public float getStrikeThruThickness(); method public android.graphics.Paint.Cap getStrokeCap(); @@ -14507,13 +14508,13 @@ package android.graphics { method public android.graphics.ColorFilter setColorFilter(android.graphics.ColorFilter); method public void setDither(boolean); method public void setElegantTextHeight(boolean); + method public void setEndHyphenEdit(int); method public void setFakeBoldText(boolean); method public void setFilterBitmap(boolean); method public void setFlags(int); method public void setFontFeatureSettings(String); method public boolean setFontVariationSettings(String); method public void setHinting(int); - method public void setHyphenEdit(int); method public void setLetterSpacing(float); method public void setLinearText(boolean); method public android.graphics.MaskFilter setMaskFilter(android.graphics.MaskFilter); @@ -14521,6 +14522,7 @@ package android.graphics { method public android.graphics.Shader setShader(android.graphics.Shader); method public void setShadowLayer(float, float, float, @ColorInt int); method public void setShadowLayer(float, float, float, @ColorLong long); + method public void setStartHyphenEdit(int); method public void setStrikeThruText(boolean); method public void setStrokeCap(android.graphics.Paint.Cap); method public void setStrokeJoin(android.graphics.Paint.Join); @@ -14547,11 +14549,21 @@ package android.graphics { field public static final int DEV_KERN_TEXT_FLAG = 256; // 0x100 field public static final int DITHER_FLAG = 4; // 0x4 field public static final int EMBEDDED_BITMAP_TEXT_FLAG = 1024; // 0x400 + field public static final int END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN = 3; // 0x3 + field public static final int END_HYPHEN_EDIT_INSERT_HYPHEN = 2; // 0x2 + field public static final int END_HYPHEN_EDIT_INSERT_MAQAF = 4; // 0x4 + field public static final int END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN = 5; // 0x5 + field public static final int END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN = 6; // 0x6 + field public static final int END_HYPHEN_EDIT_NO_EDIT = 0; // 0x0 + field public static final int END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN = 1; // 0x1 field public static final int FAKE_BOLD_TEXT_FLAG = 32; // 0x20 field public static final int FILTER_BITMAP_FLAG = 2; // 0x2 field public static final int HINTING_OFF = 0; // 0x0 field public static final int HINTING_ON = 1; // 0x1 field public static final int LINEAR_TEXT_FLAG = 64; // 0x40 + field public static final int START_HYPHEN_EDIT_INSERT_HYPHEN = 1; // 0x1 + field public static final int START_HYPHEN_EDIT_INSERT_ZWJ = 2; // 0x2 + field public static final int START_HYPHEN_EDIT_NO_EDIT = 0; // 0x0 field public static final int STRIKE_THRU_TEXT_FLAG = 16; // 0x10 field public static final int SUBPIXEL_TEXT_FLAG = 128; // 0x80 field public static final int UNDERLINE_TEXT_FLAG = 8; // 0x8 @@ -15925,12 +15937,13 @@ package android.graphics.text { } public static class LineBreaker.Result { + method public int getEndLineHyphenEdit(int); method @Px public float getLineAscent(@IntRange(from=0) int); method @IntRange(from=0) public int getLineBreakOffset(@IntRange(from=0) int); method @IntRange(from=0) public int getLineCount(); method @Px public float getLineDescent(@IntRange(from=0) int); - method public int getLineHyphenEdit(int); method @Px public float getLineWidth(@IntRange(from=0) int); + method public int getStartLineHyphenEdit(int); method public boolean hasLineTab(int); } @@ -45992,22 +46005,6 @@ package android.text { method public void handleTag(boolean, String, android.text.Editable, org.xml.sax.XMLReader); } - public class Hyphenator { - method public static int packHyphenEdit(int, int); - method public static int unpackEndHyphenEdit(int); - method public static int unpackStartHyphenEdit(int); - field public static final int END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN = 3; // 0x3 - field public static final int END_HYPHEN_EDIT_INSERT_HYPHEN = 2; // 0x2 - field public static final int END_HYPHEN_EDIT_INSERT_MAQAF = 4; // 0x4 - field public static final int END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN = 5; // 0x5 - field public static final int END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN = 6; // 0x6 - field public static final int END_HYPHEN_EDIT_NO_EDIT = 0; // 0x0 - field public static final int END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN = 1; // 0x1 - field public static final int START_HYPHEN_EDIT_INSERT_HYPHEN = 1; // 0x1 - field public static final int START_HYPHEN_EDIT_INSERT_ZWJ = 2; // 0x2 - field public static final int START_HYPHEN_EDIT_NO_EDIT = 0; // 0x0 - } - public interface InputFilter { method public CharSequence filter(CharSequence, int, int, android.text.Spanned, int, int); } diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java index c928da103557c..32982f9df15de 100644 --- a/core/java/android/text/DynamicLayout.java +++ b/core/java/android/text/DynamicLayout.java @@ -674,7 +674,8 @@ public class DynamicLayout extends Layout { objects[0] = reflowed.getLineDirections(i); final int end = (i == n - 1) ? where + after : reflowed.getLineStart(i + 1); - ints[HYPHEN] = reflowed.getHyphen(i) & HYPHEN_MASK; + ints[HYPHEN] = StaticLayout.packHyphenEdit( + reflowed.getStartHyphenEdit(i), reflowed.getEndHyphenEdit(i)); ints[MAY_PROTRUDE_FROM_TOP_OR_BOTTOM] |= contentMayProtrudeFromLineTopOrBottom(text, start, end) ? MAY_PROTRUDE_FROM_TOP_OR_BOTTOM_MASK : 0; @@ -1056,8 +1057,16 @@ public class DynamicLayout extends Layout { * @hide */ @Override - public int getHyphen(int line) { - return mInts.getValue(line, HYPHEN) & HYPHEN_MASK; + public @Paint.StartHyphenEdit int getStartHyphenEdit(int line) { + return StaticLayout.unpackStartHyphenEdit(mInts.getValue(line, HYPHEN) & HYPHEN_MASK); + } + + /** + * @hide + */ + @Override + public @Paint.EndHyphenEdit int getEndHyphenEdit(int line) { + return StaticLayout.unpackEndHyphenEdit(mInts.getValue(line, HYPHEN) & HYPHEN_MASK); } private boolean getContentMayProtrudeFromTopOrBottom(int line) { diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java index e4200ac0bc6c2..6f0628ad38e6c 100644 --- a/core/java/android/text/Hyphenator.java +++ b/core/java/android/text/Hyphenator.java @@ -16,142 +16,15 @@ package android.text; -import android.annotation.IntDef; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - /** - * Provides constants and pack/unpack methods for the HyphenEdit. + * Does the native Hyphenator initialization. * - * Hyphenator provides constant values for start of line and end of line modification. - * For example, by passing {@link #END_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010) - * character is appended at the end of line. - * - *
- * 
- *   Paint paint = new Paint();
- *   paint.setHyphenEdit(Hyphenator.packHyphenEdit(
- *       Hyphenator.START_HYPHEN_EDIT_NO_EDIT,
- *       Hyphenator.END_HYPHEN_EDIT_INSERT_HYPHEN));
- *   paint.measureText("abc", 0, 3);  // Returns the width of "abc‐"
- *   Canvas.drawText("abc", 0, 3, 0f, 0f, paint);  // Draws "abc‐"
- * 
- * 
- * - * @see android.graphics.Paint#setHyphenEdit(int) + * @hide */ public class Hyphenator { private Hyphenator() {} - /** @hide */ - @IntDef(prefix = { "START_HYPHEN_EDIT_" }, value = { - START_HYPHEN_EDIT_NO_EDIT, - START_HYPHEN_EDIT_INSERT_HYPHEN, - START_HYPHEN_EDIT_INSERT_ZWJ - }) - @Retention(RetentionPolicy.SOURCE) - public @interface StartHyphenEdit {} - - /** - * An integer representing the starting of the line has no modification for hyphenation. - */ - public static final int START_HYPHEN_EDIT_NO_EDIT = 0x00; - - /** - * An integer representing the starting of the line has normal hyphen character (U+002D). - */ - public static final int START_HYPHEN_EDIT_INSERT_HYPHEN = 0x01; - - /** - * An integer representing the starting of the line has Zero-Width-Joiner (U+200D). - */ - public static final int START_HYPHEN_EDIT_INSERT_ZWJ = 0x02; - - /** @hide */ - @IntDef(prefix = { "END_HYPHEN_EDIT_" }, value = { - END_HYPHEN_EDIT_NO_EDIT, - END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN, - END_HYPHEN_EDIT_INSERT_HYPHEN, - END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN, - END_HYPHEN_EDIT_INSERT_MAQAF, - END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN, - END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN - }) - @Retention(RetentionPolicy.SOURCE) - public @interface EndHyphenEdit {} - - /** - * An integer representing the end of the line has no modification for hyphenation. - */ - public static final int END_HYPHEN_EDIT_NO_EDIT = 0x00; - - /** - * An integer representing the character at the end of the line is replaced with hyphen - * character (U+002D). - */ - public static final int END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN = 0x01; - - /** - * An integer representing the end of the line has normal hyphen character (U+002D). - */ - public static final int END_HYPHEN_EDIT_INSERT_HYPHEN = 0x02; - - /** - * An integer representing the end of the line has Armentian hyphen (U+058A). - */ - public static final int END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN = 0x03; - - /** - * An integer representing the end of the line has maqaf (Hebrew hyphen, U+05BE). - */ - public static final int END_HYPHEN_EDIT_INSERT_MAQAF = 0x04; - - /** - * An integer representing the end of the line has Canadian Syllabics hyphen (U+1400). - */ - public static final int END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN = 0x05; - - /** - * An integer representing the end of the line has Zero-Width-Joiner (U+200D) followed by normal - * hyphen character (U+002D). - */ - public static final int END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN = 0x06; - - // Following three constants are used for packing start hyphen edit and end hyphen edit into - // single integer. Following encodings must be the same as the minikin's one. - // See frameworks/minikin/include/Hyphenator.h for more details. - private static final int END_HYPHEN_EDIT_MASK = 0x07; // 0b00111 - private static final int START_HYPHEN_EDIT_MASK = 0x18; // 0b11000 - private static final int START_HYPHEN_EDIT_SHIFT = 0x03; - - /** - * Extract start hyphen edit from packed value. - */ - public static @StartHyphenEdit int unpackStartHyphenEdit(int hyphenEdit) { - return (hyphenEdit & START_HYPHEN_EDIT_MASK) >> START_HYPHEN_EDIT_SHIFT; - } - - /** - * Extract end hyphen edit from packed value. - */ - public static @EndHyphenEdit int unpackEndHyphenEdit(int hyphenEdit) { - return hyphenEdit & END_HYPHEN_EDIT_MASK; - } - - /** - * Pack the start hyphen edit and end hyphen edit into single integer. - */ - public static int packHyphenEdit(@StartHyphenEdit int startHyphenEdit, - @EndHyphenEdit int endHyphenEdit) { - return ((startHyphenEdit << START_HYPHEN_EDIT_SHIFT) & START_HYPHEN_EDIT_MASK) - | (endHyphenEdit & END_HYPHEN_EDIT_MASK); - } - - - /** - * @hide - */ + // This method is called from Zygote. public static void init() { nInit(); } diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index 2d5f3bf8c862d..fb6dc228e786a 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -437,7 +437,8 @@ public abstract class Layout { previousLineEnd = getLineStart(lineNum + 1); final boolean justify = isJustificationRequired(lineNum); int end = getLineVisibleEnd(lineNum, start, previousLineEnd); - paint.setHyphenEdit(getHyphen(lineNum)); + paint.setStartHyphenEdit(getStartHyphenEdit(lineNum)); + paint.setEndHyphenEdit(getEndHyphenEdit(lineNum)); int ltop = previousLineBottom; int lbottom = getLineTop(lineNum + 1); @@ -910,12 +911,21 @@ public abstract class Layout { public abstract int getBottomPadding(); /** - * Returns the hyphen edit for a line. + * Returns the start hyphen edit for a line. * * @hide */ - public int getHyphen(int line) { - return 0; + public @Paint.StartHyphenEdit int getStartHyphenEdit(int line) { + return Paint.START_HYPHEN_EDIT_NO_EDIT; + } + + /** + * Returns the end hyphen edit for a line. + * + * @hide + */ + public @Paint.EndHyphenEdit int getEndHyphenEdit(int line) { + return Paint.END_HYPHEN_EDIT_NO_EDIT; } /** @@ -1418,7 +1428,8 @@ public abstract class Layout { final TextLine tl = TextLine.obtain(); final TextPaint paint = mWorkPaint; paint.set(mPaint); - paint.setHyphenEdit(getHyphen(line)); + paint.setStartHyphenEdit(getStartHyphenEdit(line)); + paint.setEndHyphenEdit(getEndHyphenEdit(line)); tl.set(paint, mText, start, end, dir, directions, hasTabs, tabStops, getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line)); if (isJustificationRequired(line)) { @@ -1447,7 +1458,8 @@ public abstract class Layout { final TextLine tl = TextLine.obtain(); final TextPaint paint = mWorkPaint; paint.set(mPaint); - paint.setHyphenEdit(getHyphen(line)); + paint.setStartHyphenEdit(getStartHyphenEdit(line)); + paint.setEndHyphenEdit(getEndHyphenEdit(line)); tl.set(paint, mText, start, end, dir, directions, hasTabs, tabStops, getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line)); if (isJustificationRequired(line)) { diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index defe2cefc1f77..9fefc83056ac4 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -779,7 +779,8 @@ public class StaticLayout extends Layout { ascents[i] = res.getLineAscent(i); descents[i] = res.getLineDescent(i); hasTabs[i] = res.hasLineTab(i); - hyphenEdits[i] = res.getLineHyphenEdit(i); + hyphenEdits[i] = + packHyphenEdit(res.getStartLineHyphenEdit(i), res.getEndLineHyphenEdit(i)); } final int remainingLineCount = mMaximumVisibleLineCount - mLineCount; @@ -1258,20 +1259,42 @@ public class StaticLayout extends Layout { return mBottomPadding; } + // To store into single int field, pack the pair of start and end hyphen edit. + static int packHyphenEdit( + @Paint.StartHyphenEdit int start, @Paint.EndHyphenEdit int end) { + return start << START_HYPHEN_BITS_SHIFT | end; + } + + static int unpackStartHyphenEdit(int packedHyphenEdit) { + return (packedHyphenEdit & START_HYPHEN_MASK) >> START_HYPHEN_BITS_SHIFT; + } + + static int unpackEndHyphenEdit(int packedHyphenEdit) { + return packedHyphenEdit & END_HYPHEN_MASK; + } + /** - * Returns the packed hyphen edit value for this line. - * - * You can extract start hyphen edit and end hyphen edit by using - * {@link Hyphenator#unpackStartHyphenEdit(int)} and - * {@link Hyphenator#unpackEndHyphenEdit(int)}. + * Returns the start hyphen edit value for this line. * * @param lineNumber a line number - * @return A packed hyphen edit value. + * @return A start hyphen edit value. * @hide */ @Override - public int getHyphen(int lineNumber) { - return mLines[mColumns * lineNumber + HYPHEN] & HYPHEN_MASK; + public @Paint.StartHyphenEdit int getStartHyphenEdit(int lineNumber) { + return unpackStartHyphenEdit(mLines[mColumns * lineNumber + HYPHEN] & HYPHEN_MASK); + } + + /** + * Returns the packed hyphen edit value for this line. + * + * @param lineNumber a line number + * @return An end hyphen edit value. + * @hide + */ + @Override + public @Paint.EndHyphenEdit int getEndHyphenEdit(int lineNumber) { + return unpackEndHyphenEdit(mLines[mColumns * lineNumber + HYPHEN] & HYPHEN_MASK); } /** @@ -1395,6 +1418,9 @@ public class StaticLayout extends Layout { private static final int DIR_SHIFT = 30; private static final int TAB_MASK = 0x20000000; private static final int HYPHEN_MASK = 0xFF; + private static final int START_HYPHEN_BITS_SHIFT = 3; + private static final int START_HYPHEN_MASK = 0x18; // 0b11000 + private static final int END_HYPHEN_MASK = 0x7; // 0b00111 private static final int TAB_INCREMENT = 20; // same as Layout, but that's private diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 915a18e59226c..86651060a3946 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -1012,19 +1012,14 @@ public class TextLine { return runIsRtl ? -ret : ret; } - private int adjustHyphenEdit(int start, int limit, int packedHyphenEdit) { - int result = packedHyphenEdit; - // Only draw hyphens on first or last run in line. Disable them otherwise. - if (start > 0) { // not the first run - result = Hyphenator.packHyphenEdit(Hyphenator.START_HYPHEN_EDIT_NO_EDIT, - Hyphenator.unpackEndHyphenEdit(packedHyphenEdit)); - } - if (limit < mLen) { // not the last run - result = Hyphenator.packHyphenEdit(Hyphenator.unpackStartHyphenEdit(packedHyphenEdit), - Hyphenator.END_HYPHEN_EDIT_NO_EDIT); - result &= ~Paint.HYPHENEDIT_MASK_END_OF_LINE; - } - return result; + private int adjustStartHyphenEdit(int start, @Paint.StartHyphenEdit int startHyphenEdit) { + // Only draw hyphens on first in line. Disable them otherwise. + return start > 0 ? Paint.START_HYPHEN_EDIT_NO_EDIT : startHyphenEdit; + } + + private int adjustEndHyphenEdit(int limit, @Paint.EndHyphenEdit int endHyphenEdit) { + // Only draw hyphens on last run in line. Disable them otherwise. + return limit < mLen ? Paint.END_HYPHEN_EDIT_NO_EDIT : endHyphenEdit; } private static final class DecorationInfo { @@ -1115,7 +1110,8 @@ public class TextLine { if (!needsSpanMeasurement) { final TextPaint wp = mWorkPaint; wp.set(mPaint); - wp.setHyphenEdit(adjustHyphenEdit(start, limit, wp.getHyphenEdit())); + wp.setStartHyphenEdit(adjustStartHyphenEdit(start, wp.getStartHyphenEdit())); + wp.setEndHyphenEdit(adjustEndHyphenEdit(limit, wp.getEndHyphenEdit())); return handleText(wp, start, limit, start, limit, runIsRtl, c, x, top, y, bottom, fmi, needWidth, measureLimit, null); } @@ -1193,8 +1189,10 @@ public class TextLine { // The style of the present chunk of text is substantially different from the // style of the previous chunk. We need to handle the active piece of text // and restart with the present chunk. - activePaint.setHyphenEdit(adjustHyphenEdit( - activeStart, activeEnd, mPaint.getHyphenEdit())); + activePaint.setStartHyphenEdit( + adjustStartHyphenEdit(activeStart, mPaint.getStartHyphenEdit())); + activePaint.setEndHyphenEdit( + adjustEndHyphenEdit(activeEnd, mPaint.getEndHyphenEdit())); x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, x, top, y, bottom, fmi, needWidth || activeEnd < measureLimit, Math.min(activeEnd, mlimit), mDecorations); @@ -1218,8 +1216,10 @@ public class TextLine { } } // Handle the final piece of text. - activePaint.setHyphenEdit(adjustHyphenEdit( - activeStart, activeEnd, mPaint.getHyphenEdit())); + activePaint.setStartHyphenEdit( + adjustStartHyphenEdit(activeStart, mPaint.getStartHyphenEdit())); + activePaint.setEndHyphenEdit( + adjustEndHyphenEdit(activeEnd, mPaint.getEndHyphenEdit())); x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, x, top, y, bottom, fmi, needWidth || activeEnd < measureLimit, Math.min(activeEnd, mlimit), mDecorations); @@ -1323,7 +1323,8 @@ public class TextLine { && lp.getTextSkewX() == rp.getTextSkewX() && lp.getLetterSpacing() == rp.getLetterSpacing() && lp.getWordSpacing() == rp.getWordSpacing() - && lp.getHyphenEdit() == rp.getHyphenEdit() + && lp.getStartHyphenEdit() == rp.getStartHyphenEdit() + && lp.getEndHyphenEdit() == rp.getEndHyphenEdit() && lp.bgColor == rp.bgColor && lp.baselineShift == rp.baselineShift && lp.linkColor == rp.linkColor diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 85f11595346fc..cd7346eb02159 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -923,14 +923,24 @@ namespace PaintGlue { paint->setWordSpacing(wordSpacing); } - static jint getHyphenEdit(jlong paintHandle, jint hyphen) { + static jint getStartHyphenEdit(jlong paintHandle, jint hyphen) { Paint* paint = reinterpret_cast(paintHandle); - return paint->getHyphenEdit(); + return static_cast(paint->getStartHyphenEdit()); } - static void setHyphenEdit(jlong paintHandle, jint hyphen) { + static jint getEndHyphenEdit(jlong paintHandle, jint hyphen) { Paint* paint = reinterpret_cast(paintHandle); - paint->setHyphenEdit((uint32_t)hyphen); + return static_cast(paint->getEndHyphenEdit()); + } + + static void setStartHyphenEdit(jlong paintHandle, jint hyphen) { + Paint* paint = reinterpret_cast(paintHandle); + paint->setStartHyphenEdit((uint32_t)hyphen); + } + + static void setEndHyphenEdit(jlong paintHandle, jint hyphen) { + Paint* paint = reinterpret_cast(paintHandle); + paint->setEndHyphenEdit((uint32_t)hyphen); } static jfloat ascent(jlong paintHandle) { @@ -1105,8 +1115,10 @@ static const JNINativeMethod methods[] = { {"nSetLetterSpacing","(JF)V", (void*) PaintGlue::setLetterSpacing}, {"nGetWordSpacing","(J)F", (void*) PaintGlue::getWordSpacing}, {"nSetWordSpacing","(JF)V", (void*) PaintGlue::setWordSpacing}, - {"nGetHyphenEdit", "(J)I", (void*) PaintGlue::getHyphenEdit}, - {"nSetHyphenEdit", "(JI)V", (void*) PaintGlue::setHyphenEdit}, + {"nGetStartHyphenEdit", "(J)I", (void*) PaintGlue::getStartHyphenEdit}, + {"nGetEndHyphenEdit", "(J)I", (void*) PaintGlue::getEndHyphenEdit}, + {"nSetStartHyphenEdit", "(JI)V", (void*) PaintGlue::setStartHyphenEdit}, + {"nSetEndHyphenEdit", "(JI)V", (void*) PaintGlue::setEndHyphenEdit}, {"nAscent","(J)F", (void*) PaintGlue::ascent}, {"nDescent","(J)F", (void*) PaintGlue::descent}, {"nGetUnderlinePosition","(J)F", (void*) PaintGlue::getUnderlinePosition}, diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java index b1c896ec2ce4e..0ebf03fab966f 100644 --- a/core/tests/coretests/src/android/text/StaticLayoutTest.java +++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.Paint.FontMetricsInt; import android.os.LocaleList; import android.platform.test.annotations.Presubmit; @@ -799,11 +800,13 @@ public class StaticLayoutTest { @Test public void testLayoutDoesntModifyPaint() { final TextPaint paint = new TextPaint(); - paint.setHyphenEdit(31); + paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_INSERT_HYPHEN); + paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN); final StaticLayout layout = StaticLayout.Builder.obtain("", 0, 0, paint, 100).build(); final Canvas canvas = new Canvas(); layout.drawText(canvas, 0, 0); - assertEquals(31, paint.getHyphenEdit()); + assertEquals(Paint.START_HYPHEN_EDIT_INSERT_HYPHEN, paint.getStartHyphenEdit()); + assertEquals(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN, paint.getEndHyphenEdit()); } @Test diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java index 585360fdd2f3e..0617caf573086 100644 --- a/core/tests/coretests/src/android/widget/TextViewTest.java +++ b/core/tests/coretests/src/android/widget/TextViewTest.java @@ -209,7 +209,8 @@ public class TextViewTest { int lineCount = layout.getLineCount(); boolean hyphenationHappend = false; for (int i = 0; i < lineCount; ++i) { - if (layout.getHyphen(i) == 0) { + if (layout.getStartHyphenEdit(i) == Paint.START_HYPHEN_EDIT_NO_EDIT + && layout.getEndHyphenEdit(i) == Paint.END_HYPHEN_EDIT_NO_EDIT) { continue; // Hyphantion does not happen. } hyphenationHappend = true; diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 9eeb43b579bc0..452f7c93f8aa4 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -364,19 +364,79 @@ public class Paint { */ private static final int CURSOR_OPT_MAX_VALUE = CURSOR_AT; - /** - * Mask for hyphen edits that happen at the end of a line. Keep in sync with the definition in - * Minikin's Hyphenator.h. - * @hide - */ - public static final int HYPHENEDIT_MASK_END_OF_LINE = 0x07; + /** @hide */ + @IntDef(prefix = { "START_HYPHEN_EDIT_" }, value = { + START_HYPHEN_EDIT_NO_EDIT, + START_HYPHEN_EDIT_INSERT_HYPHEN, + START_HYPHEN_EDIT_INSERT_ZWJ + }) + @Retention(RetentionPolicy.SOURCE) + public @interface StartHyphenEdit {} /** - * Mask for hyphen edits that happen at the start of a line. Keep in sync with the definition in - * Minikin's Hyphenator.h. - * @hide + * An integer representing the starting of the line has no modification for hyphenation. */ - public static final int HYPHENEDIT_MASK_START_OF_LINE = 0x03 << 3; + public static final int START_HYPHEN_EDIT_NO_EDIT = 0x00; + + /** + * An integer representing the starting of the line has normal hyphen character (U+002D). + */ + public static final int START_HYPHEN_EDIT_INSERT_HYPHEN = 0x01; + + /** + * An integer representing the starting of the line has Zero-Width-Joiner (U+200D). + */ + public static final int START_HYPHEN_EDIT_INSERT_ZWJ = 0x02; + + /** @hide */ + @IntDef(prefix = { "END_HYPHEN_EDIT_" }, value = { + END_HYPHEN_EDIT_NO_EDIT, + END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN, + END_HYPHEN_EDIT_INSERT_HYPHEN, + END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN, + END_HYPHEN_EDIT_INSERT_MAQAF, + END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN, + END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN + }) + @Retention(RetentionPolicy.SOURCE) + public @interface EndHyphenEdit {} + + /** + * An integer representing the end of the line has no modification for hyphenation. + */ + public static final int END_HYPHEN_EDIT_NO_EDIT = 0x00; + + /** + * An integer representing the character at the end of the line is replaced with hyphen + * character (U+002D). + */ + public static final int END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN = 0x01; + + /** + * An integer representing the end of the line has normal hyphen character (U+002D). + */ + public static final int END_HYPHEN_EDIT_INSERT_HYPHEN = 0x02; + + /** + * An integer representing the end of the line has Armentian hyphen (U+058A). + */ + public static final int END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN = 0x03; + + /** + * An integer representing the end of the line has maqaf (Hebrew hyphen, U+05BE). + */ + public static final int END_HYPHEN_EDIT_INSERT_MAQAF = 0x04; + + /** + * An integer representing the end of the line has Canadian Syllabics hyphen (U+1400). + */ + public static final int END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN = 0x05; + + /** + * An integer representing the end of the line has Zero-Width-Joiner (U+200D) followed by normal + * hyphen character (U+002D). + */ + public static final int END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN = 0x06; /** * The Style specifies if the primitive being drawn is filled, stroked, or @@ -1873,54 +1933,80 @@ public class Paint { } /** - * Get the current value of packed hyphen edit. + * Get the current value of start hyphen edit. * - * You can extract start hyphen edit and end hyphen edit by using - * {@link android.text.Hyphenator#unpackStartHyphenEdit(int)} and - * {@link android.text.Hyphenator#unpackEndHyphenEdit(int)}. + * The default value is 0 which is equivalent to {@link #START_HYPHEN_EDIT_NO_EDIT}. * - * The default value is 0 which is equivalent to packed value of - * {@link android.text.Hyphenator#START_HYPHEN_EDIT_NO_EDIT} and - * {@link android.text.Hyphenator#END_HYPHEN_EDIT_NO_EDIT}. - * - * @return the current hyphen edit value - * @see #setHyphenEdit(int) + * @return the current starting hyphen edit value + * @see #setStartHyphenEdit(int) */ - public int getHyphenEdit() { - return nGetHyphenEdit(mNativePaint); + public @StartHyphenEdit int getStartHyphenEdit() { + return nGetStartHyphenEdit(mNativePaint); } /** - * Set a packed hyphen edit on the paint. + * Get the current value of end hyphen edit. * - * By setting hyphen edit, the measurement and drawing is performed with modifying hyphenation - * at the start of line and end of line. For example, by passing - * {@link android.text.Hyphenator#END_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010) + * The default value is 0 which is equivalent to {@link #END_HYPHEN_EDIT_NO_EDIT}. + * + * @return the current starting hyphen edit value + * @see #setStartHyphenEdit(int) + */ + public @EndHyphenEdit int getEndHyphenEdit() { + return nGetEndHyphenEdit(mNativePaint); + } + + /** + * Set a start hyphen edit on the paint. + * + * By setting start hyphen edit, the measurement and drawing is performed with modifying + * hyphenation at the start of line. For example, by passing + * {@link #START_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010) + * character is appended at the start of line. + * + *
+     * 
+     *   Paint paint = new Paint();
+     *   paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_INSERT_HYPHEN);
+     *   paint.measureText("abc", 0, 3);  // Returns the width of "‐abc"
+     *   Canvas.drawText("abc", 0, 3, 0f, 0f, paint);  // Draws "‐abc"
+     * 
+     * 
+ * + * The default value is 0 which is equivalent to + * {@link #START_HYPHEN_EDIT_NO_EDIT}. + * + * @param startHyphen a start hyphen edit value. + * @see #getStartHyphenEdit() + */ + public void setStartHyphenEdit(@StartHyphenEdit int startHyphen) { + nSetStartHyphenEdit(mNativePaint, startHyphen); + } + + /** + * Set a end hyphen edit on the paint. + * + * By setting end hyphen edit, the measurement and drawing is performed with modifying + * hyphenation at the end of line. For example, by passing + * {@link #END_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010) * character is appended at the end of line. * *
      * 
      *   Paint paint = new Paint();
-     *   paint.setHyphenEdit(Hyphenator.packHyphenEdit(
-     *       Hyphenator.START_HYPHEN_EDIT_NO_EDIT,
-     *       Hyphenator.END_HYPHEN_EDIT_INSERT_HYPHEN));
+     *   paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN);
      *   paint.measureText("abc", 0, 3);  // Returns the width of "abc‐"
      *   Canvas.drawText("abc", 0, 3, 0f, 0f, paint);  // Draws "abc‐"
      * 
      * 
* - * You can pack start hyphen edit and end hyphen edit by - * {@link android.text.Hyphenator#packHyphenEdit(int,int)} + * The default value is 0 which is equivalent to {@link #END_HYPHEN_EDIT_NO_EDIT}. * - * The default value is 0 which is equivalent to packed value of - * {@link android.text.Hyphenator#START_HYPHEN_EDIT_NO_EDIT} and - * {@link android.text.Hyphenator#END_HYPHEN_EDIT_NO_EDIT}. - * - * @param hyphen a packed hyphen edit value. - * @see #getHyphenEdit() + * @param endHyphen a end hyphen edit value. + * @see #getEndHyphenEdit() */ - public void setHyphenEdit(int hyphen) { - nSetHyphenEdit(mNativePaint, hyphen); + public void setEndHyphenEdit(@EndHyphenEdit int endHyphen) { + nSetEndHyphenEdit(mNativePaint, endHyphen); } /** @@ -3063,9 +3149,13 @@ public class Paint { @CriticalNative private static native void nSetWordSpacing(long paintPtr, float wordSpacing); @CriticalNative - private static native int nGetHyphenEdit(long paintPtr); + private static native int nGetStartHyphenEdit(long paintPtr); @CriticalNative - private static native void nSetHyphenEdit(long paintPtr, int hyphen); + private static native int nGetEndHyphenEdit(long paintPtr); + @CriticalNative + private static native void nSetStartHyphenEdit(long paintPtr, int hyphen); + @CriticalNative + private static native void nSetEndHyphenEdit(long paintPtr, int hyphen); @CriticalNative private static native void nSetStrokeMiter(long paintPtr, float miter); @CriticalNative diff --git a/graphics/java/android/graphics/text/LineBreaker.java b/graphics/java/android/graphics/text/LineBreaker.java index 046bbcffb76ac..9cabf1ce185df 100644 --- a/graphics/java/android/graphics/text/LineBreaker.java +++ b/graphics/java/android/graphics/text/LineBreaker.java @@ -342,8 +342,12 @@ public class LineBreaker { */ public static class Result { // Following two contstant must be synced with minikin's line breaker. + // TODO(nona): Remove these constatns by introducing native methods. private static final int TAB_MASK = 0x20000000; private static final int HYPHEN_MASK = 0xFF; + private static final int START_HYPHEN_MASK = 0x18; // 0b11000 + private static final int END_HYPHEN_MASK = 0x7; // 0b00111 + private static final int START_HYPHEN_BITS_SHIFT = 3; private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( Result.class.getClassLoader(), nGetReleaseResultFunc(), 32); @@ -414,17 +418,29 @@ public class LineBreaker { } /** - * Returns a packed hyphen edit for the line. + * Returns a start hyphen edit for the line. * * @param lineIndex an index of the line. - * @return a packed hyphen edit for the line. + * @return a start hyphen edit for the line. * - * @see android.text.Hyphenator#unpackStartHyphenEdit(int) - * @see android.text.Hyphenator#unpackEndHyphenEdit(int) - * @see android.text.Hyphenator#packHyphenEdit(int,int) + * @see android.graphics.Paint#setStartHyphenEdit + * @see android.graphics.Paint#getStartHyphenEdit */ - public int getLineHyphenEdit(int lineIndex) { - return (nGetLineFlag(mPtr, lineIndex) & HYPHEN_MASK); + public int getStartLineHyphenEdit(int lineIndex) { + return (nGetLineFlag(mPtr, lineIndex) & START_HYPHEN_MASK) >> START_HYPHEN_BITS_SHIFT; + } + + /** + * Returns an end hyphen edit for the line. + * + * @param lineIndex an index of the line. + * @return an end hyphen edit for the line. + * + * @see android.graphics.Paint#setEndHyphenEdit + * @see android.graphics.Paint#getEndHyphenEdit + */ + public int getEndLineHyphenEdit(int lineIndex) { + return nGetLineFlag(mPtr, lineIndex) & END_HYPHEN_MASK; } } diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp index 733f8e415270d..5f6b53ac767fe 100644 --- a/libs/hwui/hwui/MinikinUtils.cpp +++ b/libs/hwui/hwui/MinikinUtils.cpp @@ -58,9 +58,8 @@ minikin::Layout MinikinUtils::doLayout(const Paint* paint, minikin::Bidi bidiFla const minikin::U16StringPiece textBuf(buf, bufSize); const minikin::Range range(start, start + count); const minikin::Range contextRange(contextStart, contextStart + contextCount); - const minikin::HyphenEdit hyphenEdit = static_cast(paint->getHyphenEdit()); - const minikin::StartHyphenEdit startHyphen = minikin::startHyphenEdit(hyphenEdit); - const minikin::EndHyphenEdit endHyphen = minikin::endHyphenEdit(hyphenEdit); + const minikin::StartHyphenEdit startHyphen = paint->getStartHyphenEdit(); + const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit(); if (mt == nullptr) { return minikin::Layout(textBuf.substr(contextRange), range - contextStart, bidiFlags, @@ -76,9 +75,8 @@ float MinikinUtils::measureText(const Paint* paint, minikin::Bidi bidiFlags, minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface); const minikin::U16StringPiece textBuf(buf, bufSize); const minikin::Range range(start, start + count); - const minikin::HyphenEdit hyphenEdit = static_cast(paint->getHyphenEdit()); - const minikin::StartHyphenEdit startHyphen = minikin::startHyphenEdit(hyphenEdit); - const minikin::EndHyphenEdit endHyphen = minikin::endHyphenEdit(hyphenEdit); + const minikin::StartHyphenEdit startHyphen = paint->getStartHyphenEdit(); + const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit(); return minikin::Layout::measureText(textBuf, range, bidiFlags, minikinPaint, startHyphen, endHyphen, advances); diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h index 601b3c23cc1f9..9b2fa9df1e8f1 100644 --- a/libs/hwui/hwui/Paint.h +++ b/libs/hwui/hwui/Paint.h @@ -27,6 +27,7 @@ #include #include +#include namespace android { @@ -89,9 +90,25 @@ public: minikin::FamilyVariant getFamilyVariant() const { return mFamilyVariant; } - void setHyphenEdit(uint32_t hyphen) { mHyphenEdit = hyphen; } + void setStartHyphenEdit(uint32_t startHyphen) { + mHyphenEdit = minikin::packHyphenEdit( + static_cast(startHyphen), + minikin::endHyphenEdit(mHyphenEdit)); + } - uint32_t getHyphenEdit() const { return mHyphenEdit; } + void setEndHyphenEdit(uint32_t endHyphen) { + mHyphenEdit = minikin::packHyphenEdit( + minikin::startHyphenEdit(mHyphenEdit), + static_cast(endHyphen)); + } + + minikin::StartHyphenEdit getStartHyphenEdit() const { + return minikin::startHyphenEdit(mHyphenEdit); + } + + minikin::EndHyphenEdit getEndHyphenEdit() const { + return minikin::endHyphenEdit(mHyphenEdit); + } void setAndroidTypeface(Typeface* typeface) { mTypeface = typeface; }