Loading core/java/android/text/TextLine.java +58 −45 Original line number Diff line number Diff line Loading @@ -72,8 +72,8 @@ class TextLine { private final SpanSet<ReplacementSpan> mReplacementSpanSpanSet = new SpanSet<ReplacementSpan>(ReplacementSpan.class); private final UnderlineInfo mUnderlineInfo = new UnderlineInfo(); private final ArrayList<UnderlineInfo> mUnderlines = new ArrayList(); private final DecorationInfo mDecorationInfo = new DecorationInfo(); private final ArrayList<DecorationInfo> mDecorations = new ArrayList(); private static final TextLine[] sCached = new TextLine[3]; Loading Loading @@ -704,9 +704,9 @@ class TextLine { fmi.leading = Math.max(fmi.leading, previousLeading); } private static void drawUnderline(TextPaint wp, Canvas c, int color, float thickness, float xleft, float xright, float baseline) { final float underlineTop = baseline + wp.baselineShift + wp.getUnderlinePosition(); private static void drawStroke(TextPaint wp, Canvas c, int color, float position, float thickness, float xleft, float xright, float baseline) { final float strokeTop = baseline + wp.baselineShift + position; final int previousColor = wp.getColor(); final Paint.Style previousStyle = wp.getStyle(); Loading @@ -716,7 +716,7 @@ class TextLine { wp.setAntiAlias(true); wp.setColor(color); c.drawRect(xleft, underlineTop, xright, underlineTop + thickness, wp); c.drawRect(xleft, strokeTop, xright, strokeTop + thickness, wp); wp.setStyle(previousStyle); wp.setColor(previousColor); Loading Loading @@ -750,7 +750,7 @@ class TextLine { * @param fmi receives metrics information, can be null * @param needWidth true if the width of the run is needed * @param offset the offset for the purpose of measuring * @param underlines the list of locations and paremeters for drawing underlines * @param decorations the list of locations and paremeters for drawing decorations * @return the signed width of the run based on the run direction; only * valid if needWidth is true */ Loading @@ -758,7 +758,7 @@ class TextLine { int contextStart, int contextEnd, boolean runIsRtl, Canvas c, float x, int top, int y, int bottom, FontMetricsInt fmi, boolean needWidth, int offset, @Nullable ArrayList<UnderlineInfo> underlines) { @Nullable ArrayList<DecorationInfo> decorations) { wp.setWordSpacing(mAddedWidth); // Get metrics first (even for empty strings or "0" width runs) Loading @@ -773,8 +773,8 @@ class TextLine { float totalWidth = 0; final int numUnderlines = underlines == null ? 0 : underlines.size(); if (needWidth || (c != null && (wp.bgColor != 0 || numUnderlines != 0 || runIsRtl))) { final int numDecorations = decorations == null ? 0 : decorations.size(); if (needWidth || (c != null && (wp.bgColor != 0 || numDecorations != 0 || runIsRtl))) { totalWidth = getRunAdvance(wp, start, end, contextStart, contextEnd, runIsRtl, offset); } Loading @@ -800,37 +800,44 @@ class TextLine { wp.setColor(previousColor); } if (numUnderlines != 0) { for (int i = 0; i < numUnderlines; i++) { final UnderlineInfo info = underlines.get(i); if (numDecorations != 0) { for (int i = 0; i < numDecorations; i++) { final DecorationInfo info = decorations.get(i); final int underlineStart = Math.max(info.start, start); final int underlineEnd = Math.min(info.end, offset); float underlineStartAdvance = getRunAdvance( wp, start, end, contextStart, contextEnd, runIsRtl, underlineStart); float underlineEndAdvance = getRunAdvance( wp, start, end, contextStart, contextEnd, runIsRtl, underlineEnd); final float underlineXLeft, underlineXRight; final int decorationStart = Math.max(info.start, start); final int decorationEnd = Math.min(info.end, offset); float decorationStartAdvance = getRunAdvance( wp, start, end, contextStart, contextEnd, runIsRtl, decorationStart); float decorationEndAdvance = getRunAdvance( wp, start, end, contextStart, contextEnd, runIsRtl, decorationEnd); final float decorationXLeft, decorationXRight; if (runIsRtl) { underlineXLeft = rightX - underlineEndAdvance; underlineXRight = rightX - underlineStartAdvance; decorationXLeft = rightX - decorationEndAdvance; decorationXRight = rightX - decorationStartAdvance; } else { underlineXLeft = leftX + underlineStartAdvance; underlineXRight = leftX + underlineEndAdvance; decorationXLeft = leftX + decorationStartAdvance; decorationXRight = leftX + decorationEndAdvance; } // Theoretically, there could be cases where both Paint's and TextPaint's // setUnderLineText() are called. For backward compatibility, we need to draw // both underlines, the one with custom color first. if (info.underlineColor != 0) { drawUnderline(wp, c, info.underlineColor, info.underlineThickness, underlineXLeft, underlineXRight, y); drawStroke(wp, c, info.underlineColor, wp.getUnderlinePosition(), info.underlineThickness, decorationXLeft, decorationXRight, y); } if (info.isUnderlineText) { final float thickness = Math.max(((Paint) wp).getUnderlineThickness(), 1.0f); drawUnderline(wp, c, wp.getColor(), thickness, underlineXLeft, underlineXRight, y); drawStroke(wp, c, wp.getColor(), wp.getUnderlinePosition(), thickness, decorationXLeft, decorationXRight, y); } if (info.isStrikeThruText) { final float thickness = Math.max(((Paint) wp).getStrikeThruThickness(), 1.0f); drawStroke(wp, c, wp.getColor(), wp.getStrikeThruPosition(), thickness, decorationXLeft, decorationXRight, y); } } } Loading Loading @@ -919,20 +926,22 @@ class TextLine { return result; } private static final class UnderlineInfo { private static final class DecorationInfo { public boolean isStrikeThruText; public boolean isUnderlineText; public int underlineColor; public float underlineThickness; public int start = -1; public int end = -1; public boolean hasUnderline() { return isUnderlineText || underlineColor != 0; public boolean hasDecoration() { return isStrikeThruText || isUnderlineText || underlineColor != 0; } // Copies the info, but not the start and end range. public UnderlineInfo copyInfo() { final UnderlineInfo copy = new UnderlineInfo(); public DecorationInfo copyInfo() { final DecorationInfo copy = new DecorationInfo(); copy.isStrikeThruText = isStrikeThruText; copy.isUnderlineText = isUnderlineText; copy.underlineColor = underlineColor; copy.underlineThickness = underlineThickness; Loading @@ -940,7 +949,11 @@ class TextLine { } } private void extractUnderlineInfo(@NonNull TextPaint paint, @NonNull UnderlineInfo info) { private void extractDecorationInfo(@NonNull TextPaint paint, @NonNull DecorationInfo info) { info.isStrikeThruText = paint.isStrikeThruText(); if (info.isStrikeThruText) { paint.setStrikeThruText(false); } info.isUnderlineText = paint.isUnderlineText(); if (info.isUnderlineText) { paint.setUnderlineText(false); Loading Loading @@ -1047,8 +1060,8 @@ class TextLine { activePaint.set(mPaint); int activeStart = i; int activeEnd = mlimit; final UnderlineInfo underlineInfo = mUnderlineInfo; mUnderlines.clear(); final DecorationInfo decorationInfo = mDecorationInfo; mDecorations.clear(); for (int j = i, jnext; j < mlimit; j = jnext) { jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + inext) - mStart; Loading @@ -1064,7 +1077,7 @@ class TextLine { span.updateDrawState(wp); } extractUnderlineInfo(wp, underlineInfo); extractDecorationInfo(wp, decorationInfo); if (j == i) { // First chunk of text. We can't handle it yet, since we may need to merge it Loading @@ -1079,24 +1092,24 @@ class TextLine { activeStart, activeEnd, mPaint.getHyphenEdit())); x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, x, top, y, bottom, fmi, needWidth || activeEnd < measureLimit, Math.min(activeEnd, mlimit), mUnderlines); Math.min(activeEnd, mlimit), mDecorations); activeStart = j; activePaint.set(wp); mUnderlines.clear(); mDecorations.clear(); } else { // The present TextPaint is substantially equal to the last TextPaint except // perhaps for underlines. We just need to expand the active piece of text to // perhaps for decorations. We just need to expand the active piece of text to // include the present chunk, which we always do anyway. We don't need to save // wp to activePaint, since they are already equal. } activeEnd = jnext; if (underlineInfo.hasUnderline()) { final UnderlineInfo copy = underlineInfo.copyInfo(); if (decorationInfo.hasDecoration()) { final DecorationInfo copy = decorationInfo.copyInfo(); copy.start = j; copy.end = jnext; mUnderlines.add(copy); mDecorations.add(copy); } } // Handle the final piece of text. Loading @@ -1104,7 +1117,7 @@ class TextLine { activeStart, activeEnd, mPaint.getHyphenEdit())); x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, x, top, y, bottom, fmi, needWidth || activeEnd < measureLimit, Math.min(activeEnd, mlimit), mUnderlines); Math.min(activeEnd, mlimit), mDecorations); } return x - originalX; Loading core/jni/android/graphics/Paint.cpp +12 −0 Original line number Diff line number Diff line Loading @@ -985,6 +985,16 @@ namespace PaintGlue { } } static jfloat getStrikeThruPosition(jlong paintHandle, jlong typefaceHandle) { const SkScalar textSize = reinterpret_cast<Paint*>(paintHandle)->getTextSize(); return SkScalarToFloat(Paint::kStdStrikeThru_Top * textSize); } static jfloat getStrikeThruThickness(jlong paintHandle, jlong typefaceHandle) { const SkScalar textSize = reinterpret_cast<Paint*>(paintHandle)->getTextSize(); return SkScalarToFloat(Paint::kStdStrikeThru_Thickness * textSize); } static void setShadowLayer(jlong paintHandle, jfloat radius, jfloat dx, jfloat dy, jint color) { Paint* paint = reinterpret_cast<Paint*>(paintHandle); Loading Loading @@ -1098,6 +1108,8 @@ static const JNINativeMethod methods[] = { {"nDescent","(JJ)F", (void*) PaintGlue::descent}, {"nGetUnderlinePosition","(JJ)F", (void*) PaintGlue::getUnderlinePosition}, {"nGetUnderlineThickness","(JJ)F", (void*) PaintGlue::getUnderlineThickness}, {"nGetStrikeThruPosition","(JJ)F", (void*) PaintGlue::getStrikeThruPosition}, {"nGetStrikeThruThickness","(JJ)F", (void*) PaintGlue::getStrikeThruThickness}, {"nSetShadowLayer", "(JFFFI)V", (void*)PaintGlue::setShadowLayer}, {"nHasShadowLayer", "(J)Z", (void*)PaintGlue::hasShadowLayer} }; Loading graphics/java/android/graphics/Paint.java +21 −0 Original line number Diff line number Diff line Loading @@ -851,6 +851,23 @@ public class Paint { return (getFlags() & STRIKE_THRU_TEXT_FLAG) != 0; } /** * Distance from top of the strike-through line to the baseline. Negative values mean above the * baseline. This method returns where the strike-through line should be drawn independent of if * the strikeThruText bit is set at the moment. * @hide */ public float getStrikeThruPosition() { return nGetStrikeThruPosition(mNativePaint, mNativeTypeface); } /** * @hide */ public float getStrikeThruThickness() { return nGetStrikeThruThickness(mNativePaint, mNativeTypeface); } /** * Helper for setFlags(), setting or clearing the STRIKE_THRU_TEXT_FLAG bit * Loading Loading @@ -2997,5 +3014,9 @@ public class Paint { @CriticalNative private static native float nGetUnderlineThickness(long paintPtr, long typefacePtr); @CriticalNative private static native float nGetStrikeThruPosition(long paintPtr, long typefacePtr); @CriticalNative private static native float nGetStrikeThruThickness(long paintPtr, long typefacePtr); @CriticalNative private static native void nSetTextSize(long paintPtr, float textSize); } libs/hwui/hwui/Canvas.cpp +12 −9 Original line number Diff line number Diff line Loading @@ -35,6 +35,13 @@ Canvas* Canvas::create_recording_canvas(int width, int height, uirenderer::Rende return new uirenderer::RecordingCanvas(width, height); } static inline void drawStroke(SkScalar left, SkScalar right, SkScalar top, SkScalar thickness, const SkPaint& paint, Canvas* canvas) { const SkScalar strokeWidth = fmax(thickness, 1.0f); const SkScalar bottom = top + strokeWidth; canvas->drawRect(left, top, right, bottom, paint); } void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& paint) { uint32_t flags; SkDrawFilter* drawFilter = getDrawFilter(); Loading @@ -46,7 +53,6 @@ void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& flags = paint.getFlags(); } if (flags & (SkPaint::kUnderlineText_ReserveFlag | SkPaint::kStrikeThruText_ReserveFlag)) { const SkScalar left = x; const SkScalar right = x + length; if (flags & SkPaint::kUnderlineText_ReserveFlag) { Loading @@ -60,18 +66,15 @@ void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& if (!metrics.hasUnderlineThickness(&thickness)) { thickness = paint.getTextSize() * Paint::kStdUnderline_Thickness; } const float strokeWidth = fmax(thickness, 1.0f); const SkScalar top = y + position; const SkScalar bottom = top + strokeWidth; drawRect(left, top, right, bottom, paint); drawStroke(left, right, top, thickness, paint, this); } if (flags & SkPaint::kStrikeThruText_ReserveFlag) { const float textSize = paint.getTextSize(); const float position = textSize * Paint::kStdStrikeThru_Offset; const float strokeWidth = fmax(textSize * Paint::kStdUnderline_Thickness, 1.0f); const SkScalar top = y + position - 0.5f * strokeWidth; const SkScalar bottom = y + position + 0.5f * strokeWidth; drawRect(left, top, right, bottom, paint); const float position = textSize * Paint::kStdStrikeThru_Top; const SkScalar thickness = textSize * Paint::kStdStrikeThru_Thickness; const SkScalar top = y + position; drawStroke(left, right, top, thickness, paint, this); } } } Loading libs/hwui/hwui/Paint.h +4 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,10 @@ public: constexpr static float kStdUnderline_Top = kStdUnderline_Offset - 0.5f * kStdUnderline_Thickness; constexpr static float kStdStrikeThru_Thickness = kStdUnderline_Thickness; constexpr static float kStdStrikeThru_Top = kStdStrikeThru_Offset - 0.5f * kStdStrikeThru_Thickness; Paint(); Paint(const Paint& paint); Paint(const SkPaint& paint); // NOLINT(implicit) Loading Loading
core/java/android/text/TextLine.java +58 −45 Original line number Diff line number Diff line Loading @@ -72,8 +72,8 @@ class TextLine { private final SpanSet<ReplacementSpan> mReplacementSpanSpanSet = new SpanSet<ReplacementSpan>(ReplacementSpan.class); private final UnderlineInfo mUnderlineInfo = new UnderlineInfo(); private final ArrayList<UnderlineInfo> mUnderlines = new ArrayList(); private final DecorationInfo mDecorationInfo = new DecorationInfo(); private final ArrayList<DecorationInfo> mDecorations = new ArrayList(); private static final TextLine[] sCached = new TextLine[3]; Loading Loading @@ -704,9 +704,9 @@ class TextLine { fmi.leading = Math.max(fmi.leading, previousLeading); } private static void drawUnderline(TextPaint wp, Canvas c, int color, float thickness, float xleft, float xright, float baseline) { final float underlineTop = baseline + wp.baselineShift + wp.getUnderlinePosition(); private static void drawStroke(TextPaint wp, Canvas c, int color, float position, float thickness, float xleft, float xright, float baseline) { final float strokeTop = baseline + wp.baselineShift + position; final int previousColor = wp.getColor(); final Paint.Style previousStyle = wp.getStyle(); Loading @@ -716,7 +716,7 @@ class TextLine { wp.setAntiAlias(true); wp.setColor(color); c.drawRect(xleft, underlineTop, xright, underlineTop + thickness, wp); c.drawRect(xleft, strokeTop, xright, strokeTop + thickness, wp); wp.setStyle(previousStyle); wp.setColor(previousColor); Loading Loading @@ -750,7 +750,7 @@ class TextLine { * @param fmi receives metrics information, can be null * @param needWidth true if the width of the run is needed * @param offset the offset for the purpose of measuring * @param underlines the list of locations and paremeters for drawing underlines * @param decorations the list of locations and paremeters for drawing decorations * @return the signed width of the run based on the run direction; only * valid if needWidth is true */ Loading @@ -758,7 +758,7 @@ class TextLine { int contextStart, int contextEnd, boolean runIsRtl, Canvas c, float x, int top, int y, int bottom, FontMetricsInt fmi, boolean needWidth, int offset, @Nullable ArrayList<UnderlineInfo> underlines) { @Nullable ArrayList<DecorationInfo> decorations) { wp.setWordSpacing(mAddedWidth); // Get metrics first (even for empty strings or "0" width runs) Loading @@ -773,8 +773,8 @@ class TextLine { float totalWidth = 0; final int numUnderlines = underlines == null ? 0 : underlines.size(); if (needWidth || (c != null && (wp.bgColor != 0 || numUnderlines != 0 || runIsRtl))) { final int numDecorations = decorations == null ? 0 : decorations.size(); if (needWidth || (c != null && (wp.bgColor != 0 || numDecorations != 0 || runIsRtl))) { totalWidth = getRunAdvance(wp, start, end, contextStart, contextEnd, runIsRtl, offset); } Loading @@ -800,37 +800,44 @@ class TextLine { wp.setColor(previousColor); } if (numUnderlines != 0) { for (int i = 0; i < numUnderlines; i++) { final UnderlineInfo info = underlines.get(i); if (numDecorations != 0) { for (int i = 0; i < numDecorations; i++) { final DecorationInfo info = decorations.get(i); final int underlineStart = Math.max(info.start, start); final int underlineEnd = Math.min(info.end, offset); float underlineStartAdvance = getRunAdvance( wp, start, end, contextStart, contextEnd, runIsRtl, underlineStart); float underlineEndAdvance = getRunAdvance( wp, start, end, contextStart, contextEnd, runIsRtl, underlineEnd); final float underlineXLeft, underlineXRight; final int decorationStart = Math.max(info.start, start); final int decorationEnd = Math.min(info.end, offset); float decorationStartAdvance = getRunAdvance( wp, start, end, contextStart, contextEnd, runIsRtl, decorationStart); float decorationEndAdvance = getRunAdvance( wp, start, end, contextStart, contextEnd, runIsRtl, decorationEnd); final float decorationXLeft, decorationXRight; if (runIsRtl) { underlineXLeft = rightX - underlineEndAdvance; underlineXRight = rightX - underlineStartAdvance; decorationXLeft = rightX - decorationEndAdvance; decorationXRight = rightX - decorationStartAdvance; } else { underlineXLeft = leftX + underlineStartAdvance; underlineXRight = leftX + underlineEndAdvance; decorationXLeft = leftX + decorationStartAdvance; decorationXRight = leftX + decorationEndAdvance; } // Theoretically, there could be cases where both Paint's and TextPaint's // setUnderLineText() are called. For backward compatibility, we need to draw // both underlines, the one with custom color first. if (info.underlineColor != 0) { drawUnderline(wp, c, info.underlineColor, info.underlineThickness, underlineXLeft, underlineXRight, y); drawStroke(wp, c, info.underlineColor, wp.getUnderlinePosition(), info.underlineThickness, decorationXLeft, decorationXRight, y); } if (info.isUnderlineText) { final float thickness = Math.max(((Paint) wp).getUnderlineThickness(), 1.0f); drawUnderline(wp, c, wp.getColor(), thickness, underlineXLeft, underlineXRight, y); drawStroke(wp, c, wp.getColor(), wp.getUnderlinePosition(), thickness, decorationXLeft, decorationXRight, y); } if (info.isStrikeThruText) { final float thickness = Math.max(((Paint) wp).getStrikeThruThickness(), 1.0f); drawStroke(wp, c, wp.getColor(), wp.getStrikeThruPosition(), thickness, decorationXLeft, decorationXRight, y); } } } Loading Loading @@ -919,20 +926,22 @@ class TextLine { return result; } private static final class UnderlineInfo { private static final class DecorationInfo { public boolean isStrikeThruText; public boolean isUnderlineText; public int underlineColor; public float underlineThickness; public int start = -1; public int end = -1; public boolean hasUnderline() { return isUnderlineText || underlineColor != 0; public boolean hasDecoration() { return isStrikeThruText || isUnderlineText || underlineColor != 0; } // Copies the info, but not the start and end range. public UnderlineInfo copyInfo() { final UnderlineInfo copy = new UnderlineInfo(); public DecorationInfo copyInfo() { final DecorationInfo copy = new DecorationInfo(); copy.isStrikeThruText = isStrikeThruText; copy.isUnderlineText = isUnderlineText; copy.underlineColor = underlineColor; copy.underlineThickness = underlineThickness; Loading @@ -940,7 +949,11 @@ class TextLine { } } private void extractUnderlineInfo(@NonNull TextPaint paint, @NonNull UnderlineInfo info) { private void extractDecorationInfo(@NonNull TextPaint paint, @NonNull DecorationInfo info) { info.isStrikeThruText = paint.isStrikeThruText(); if (info.isStrikeThruText) { paint.setStrikeThruText(false); } info.isUnderlineText = paint.isUnderlineText(); if (info.isUnderlineText) { paint.setUnderlineText(false); Loading Loading @@ -1047,8 +1060,8 @@ class TextLine { activePaint.set(mPaint); int activeStart = i; int activeEnd = mlimit; final UnderlineInfo underlineInfo = mUnderlineInfo; mUnderlines.clear(); final DecorationInfo decorationInfo = mDecorationInfo; mDecorations.clear(); for (int j = i, jnext; j < mlimit; j = jnext) { jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + inext) - mStart; Loading @@ -1064,7 +1077,7 @@ class TextLine { span.updateDrawState(wp); } extractUnderlineInfo(wp, underlineInfo); extractDecorationInfo(wp, decorationInfo); if (j == i) { // First chunk of text. We can't handle it yet, since we may need to merge it Loading @@ -1079,24 +1092,24 @@ class TextLine { activeStart, activeEnd, mPaint.getHyphenEdit())); x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, x, top, y, bottom, fmi, needWidth || activeEnd < measureLimit, Math.min(activeEnd, mlimit), mUnderlines); Math.min(activeEnd, mlimit), mDecorations); activeStart = j; activePaint.set(wp); mUnderlines.clear(); mDecorations.clear(); } else { // The present TextPaint is substantially equal to the last TextPaint except // perhaps for underlines. We just need to expand the active piece of text to // perhaps for decorations. We just need to expand the active piece of text to // include the present chunk, which we always do anyway. We don't need to save // wp to activePaint, since they are already equal. } activeEnd = jnext; if (underlineInfo.hasUnderline()) { final UnderlineInfo copy = underlineInfo.copyInfo(); if (decorationInfo.hasDecoration()) { final DecorationInfo copy = decorationInfo.copyInfo(); copy.start = j; copy.end = jnext; mUnderlines.add(copy); mDecorations.add(copy); } } // Handle the final piece of text. Loading @@ -1104,7 +1117,7 @@ class TextLine { activeStart, activeEnd, mPaint.getHyphenEdit())); x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, x, top, y, bottom, fmi, needWidth || activeEnd < measureLimit, Math.min(activeEnd, mlimit), mUnderlines); Math.min(activeEnd, mlimit), mDecorations); } return x - originalX; Loading
core/jni/android/graphics/Paint.cpp +12 −0 Original line number Diff line number Diff line Loading @@ -985,6 +985,16 @@ namespace PaintGlue { } } static jfloat getStrikeThruPosition(jlong paintHandle, jlong typefaceHandle) { const SkScalar textSize = reinterpret_cast<Paint*>(paintHandle)->getTextSize(); return SkScalarToFloat(Paint::kStdStrikeThru_Top * textSize); } static jfloat getStrikeThruThickness(jlong paintHandle, jlong typefaceHandle) { const SkScalar textSize = reinterpret_cast<Paint*>(paintHandle)->getTextSize(); return SkScalarToFloat(Paint::kStdStrikeThru_Thickness * textSize); } static void setShadowLayer(jlong paintHandle, jfloat radius, jfloat dx, jfloat dy, jint color) { Paint* paint = reinterpret_cast<Paint*>(paintHandle); Loading Loading @@ -1098,6 +1108,8 @@ static const JNINativeMethod methods[] = { {"nDescent","(JJ)F", (void*) PaintGlue::descent}, {"nGetUnderlinePosition","(JJ)F", (void*) PaintGlue::getUnderlinePosition}, {"nGetUnderlineThickness","(JJ)F", (void*) PaintGlue::getUnderlineThickness}, {"nGetStrikeThruPosition","(JJ)F", (void*) PaintGlue::getStrikeThruPosition}, {"nGetStrikeThruThickness","(JJ)F", (void*) PaintGlue::getStrikeThruThickness}, {"nSetShadowLayer", "(JFFFI)V", (void*)PaintGlue::setShadowLayer}, {"nHasShadowLayer", "(J)Z", (void*)PaintGlue::hasShadowLayer} }; Loading
graphics/java/android/graphics/Paint.java +21 −0 Original line number Diff line number Diff line Loading @@ -851,6 +851,23 @@ public class Paint { return (getFlags() & STRIKE_THRU_TEXT_FLAG) != 0; } /** * Distance from top of the strike-through line to the baseline. Negative values mean above the * baseline. This method returns where the strike-through line should be drawn independent of if * the strikeThruText bit is set at the moment. * @hide */ public float getStrikeThruPosition() { return nGetStrikeThruPosition(mNativePaint, mNativeTypeface); } /** * @hide */ public float getStrikeThruThickness() { return nGetStrikeThruThickness(mNativePaint, mNativeTypeface); } /** * Helper for setFlags(), setting or clearing the STRIKE_THRU_TEXT_FLAG bit * Loading Loading @@ -2997,5 +3014,9 @@ public class Paint { @CriticalNative private static native float nGetUnderlineThickness(long paintPtr, long typefacePtr); @CriticalNative private static native float nGetStrikeThruPosition(long paintPtr, long typefacePtr); @CriticalNative private static native float nGetStrikeThruThickness(long paintPtr, long typefacePtr); @CriticalNative private static native void nSetTextSize(long paintPtr, float textSize); }
libs/hwui/hwui/Canvas.cpp +12 −9 Original line number Diff line number Diff line Loading @@ -35,6 +35,13 @@ Canvas* Canvas::create_recording_canvas(int width, int height, uirenderer::Rende return new uirenderer::RecordingCanvas(width, height); } static inline void drawStroke(SkScalar left, SkScalar right, SkScalar top, SkScalar thickness, const SkPaint& paint, Canvas* canvas) { const SkScalar strokeWidth = fmax(thickness, 1.0f); const SkScalar bottom = top + strokeWidth; canvas->drawRect(left, top, right, bottom, paint); } void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& paint) { uint32_t flags; SkDrawFilter* drawFilter = getDrawFilter(); Loading @@ -46,7 +53,6 @@ void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& flags = paint.getFlags(); } if (flags & (SkPaint::kUnderlineText_ReserveFlag | SkPaint::kStrikeThruText_ReserveFlag)) { const SkScalar left = x; const SkScalar right = x + length; if (flags & SkPaint::kUnderlineText_ReserveFlag) { Loading @@ -60,18 +66,15 @@ void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& if (!metrics.hasUnderlineThickness(&thickness)) { thickness = paint.getTextSize() * Paint::kStdUnderline_Thickness; } const float strokeWidth = fmax(thickness, 1.0f); const SkScalar top = y + position; const SkScalar bottom = top + strokeWidth; drawRect(left, top, right, bottom, paint); drawStroke(left, right, top, thickness, paint, this); } if (flags & SkPaint::kStrikeThruText_ReserveFlag) { const float textSize = paint.getTextSize(); const float position = textSize * Paint::kStdStrikeThru_Offset; const float strokeWidth = fmax(textSize * Paint::kStdUnderline_Thickness, 1.0f); const SkScalar top = y + position - 0.5f * strokeWidth; const SkScalar bottom = y + position + 0.5f * strokeWidth; drawRect(left, top, right, bottom, paint); const float position = textSize * Paint::kStdStrikeThru_Top; const SkScalar thickness = textSize * Paint::kStdStrikeThru_Thickness; const SkScalar top = y + position; drawStroke(left, right, top, thickness, paint, this); } } } Loading
libs/hwui/hwui/Paint.h +4 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,10 @@ public: constexpr static float kStdUnderline_Top = kStdUnderline_Offset - 0.5f * kStdUnderline_Thickness; constexpr static float kStdStrikeThru_Thickness = kStdUnderline_Thickness; constexpr static float kStdStrikeThru_Top = kStdStrikeThru_Offset - 0.5f * kStdStrikeThru_Thickness; Paint(); Paint(const Paint& paint); Paint(const SkPaint& paint); // NOLINT(implicit) Loading