Clean up the underline investigations
This commit is contained in:
parent
a135e07f16
commit
5451a2722e
@ -1,20 +0,0 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
|
||||
compileSdkVersion config['compile-sdk']
|
||||
buildToolsVersion config['build-tools']
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion config['min-sdk']
|
||||
targetSdkVersion config['target-sdk']
|
||||
versionCode 1
|
||||
versionName version
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(':markwon-core')
|
||||
}
|
||||
|
||||
registerArtifact(this)
|
@ -1,4 +0,0 @@
|
||||
POM_NAME=Spans Better
|
||||
POM_ARTIFACT_ID=spans-better
|
||||
POM_DESCRIPTION=Better spans
|
||||
POM_PACKAGING=aar
|
@ -1 +0,0 @@
|
||||
<manifest package="io.noties.markwon.spans.better" />
|
@ -1,183 +0,0 @@
|
||||
package io.noties.markwon.spans.better;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.os.Build;
|
||||
import android.text.Layout;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.LineBackgroundSpan;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import io.noties.markwon.core.spans.TextViewSpan;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.Math.min;
|
||||
|
||||
/**
|
||||
* Credit goes to [Romain Guy](https://github.com/romainguy/elegant-underline)
|
||||
*
|
||||
* @since $nap;
|
||||
*/
|
||||
public class BetterUnderlineSpan implements LineBackgroundSpan {
|
||||
|
||||
public enum Type {
|
||||
@RequiresApi(Build.VERSION_CODES.KITKAT)
|
||||
PATH,
|
||||
REGION
|
||||
}
|
||||
|
||||
private static final float UNDERLINE_CLEAR_GAP = 5.5F;
|
||||
|
||||
private final Path underline = new Path();
|
||||
private final Path outline = new Path();
|
||||
private final Paint stroke = new Paint();
|
||||
private final Path strokedOutline = new Path();
|
||||
private char[] chars;
|
||||
|
||||
BetterUnderlineSpan() {
|
||||
stroke.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||
stroke.setStrokeCap(Paint.Cap.BUTT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawBackground(
|
||||
Canvas c,
|
||||
Paint p,
|
||||
int left,
|
||||
int right,
|
||||
int top,
|
||||
int baseline,
|
||||
int bottom,
|
||||
CharSequence text,
|
||||
int start,
|
||||
int end,
|
||||
int lnum
|
||||
) {
|
||||
final Spanned spanned = (Spanned) text;
|
||||
final TextView textView = TextViewSpan.textViewOf(spanned);
|
||||
|
||||
if (textView == null) {
|
||||
// no, cannot do it, the whole text will be changed
|
||||
// p.setUnderlineText(true);
|
||||
return;
|
||||
}
|
||||
|
||||
final Layout layout = textView.getLayout();
|
||||
|
||||
final int selfStart = spanned.getSpanStart(this);
|
||||
final int selfEnd = spanned.getSpanEnd(this);
|
||||
|
||||
// TODO: also doesn't mean that it is last line, imagine text after span is ended
|
||||
final boolean isLastLine = end == selfEnd || (selfEnd == (end - 1));
|
||||
|
||||
final int s = max(selfStart, start);
|
||||
|
||||
// e - 1, but only if not last?
|
||||
// oh... layout line count != span lines..
|
||||
final int e = min(selfEnd, end) - (isLastLine ? 0 : 1);
|
||||
|
||||
final int l = (int) (layout.getPrimaryHorizontal(s) + .5F);
|
||||
final int r = (int) (layout.getPrimaryHorizontal(e) + .5F);
|
||||
final int b = getLineBottom(layout, lnum, isLastLine);
|
||||
|
||||
final float density = textView.getResources().getDisplayMetrics().density;
|
||||
|
||||
underline.rewind();
|
||||
// TODO: proper baseline
|
||||
// underline.addRect(
|
||||
// l, b - (1.8F * density),
|
||||
// r, b,
|
||||
// Path.Direction.CW
|
||||
//
|
||||
// );
|
||||
|
||||
// TODO: this must be configured somehow...
|
||||
final int diff = (int) (p.descent() / 2F + .5F);
|
||||
|
||||
underline.addRect(
|
||||
l, baseline + diff,
|
||||
r, baseline + diff + (density * 0.8F),
|
||||
Path.Direction.CW
|
||||
);
|
||||
|
||||
|
||||
outline.rewind();
|
||||
|
||||
// reallocate only if less, otherwise re-use and then send actual indexes
|
||||
// TODO: would this return proper array for the last line?!
|
||||
chars = new char[e - s];
|
||||
TextUtils.getChars(spanned, s, e, chars, 0);
|
||||
p.getTextPath(
|
||||
chars,
|
||||
0, (e - s),
|
||||
l, baseline,
|
||||
outline
|
||||
);
|
||||
|
||||
final Paint paint = new Paint();
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setColor(Color.GREEN);
|
||||
c.drawPath(outline, paint);
|
||||
|
||||
outline.op(underline, Path.Op.INTERSECT);
|
||||
|
||||
strokedOutline.rewind();
|
||||
stroke.setStrokeWidth(UNDERLINE_CLEAR_GAP * density);
|
||||
stroke.getFillPath(outline, strokedOutline);
|
||||
|
||||
underline.op(strokedOutline, Path.Op.DIFFERENCE);
|
||||
|
||||
c.drawPath(underline, p);
|
||||
}
|
||||
|
||||
private static final float DEFAULT_EXTRA = 0F;
|
||||
private static final float DEFAULT_MULTIPLIER = 1F;
|
||||
|
||||
private static int getLineBottom(@NonNull Layout layout, int line, boolean isLastLine) {
|
||||
|
||||
final int bottom = layout.getLineBottom(line);
|
||||
final boolean lastLineSpacingNotAdded = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
|
||||
|
||||
// TODO: layout line count != span occupied lines
|
||||
// final boolean isLastLine = line == layout.getLineCount() - 1;
|
||||
|
||||
final int lineBottom;
|
||||
final float lineSpacingExtra = layout.getSpacingAdd();
|
||||
final float lineSpacingMultiplier = layout.getSpacingMultiplier();
|
||||
|
||||
// simplified check
|
||||
final boolean hasLineSpacing = lineSpacingExtra != DEFAULT_EXTRA
|
||||
|| lineSpacingMultiplier != DEFAULT_MULTIPLIER;
|
||||
|
||||
if (!hasLineSpacing
|
||||
|| (isLastLine && lastLineSpacingNotAdded)) {
|
||||
lineBottom = bottom;
|
||||
} else {
|
||||
final float extra;
|
||||
if (Float.compare(DEFAULT_MULTIPLIER, lineSpacingMultiplier) != 0) {
|
||||
final int lineHeight = getLineHeight(layout, line);
|
||||
extra = lineHeight -
|
||||
((lineHeight - lineSpacingExtra) / lineSpacingMultiplier);
|
||||
} else {
|
||||
extra = lineSpacingExtra;
|
||||
}
|
||||
lineBottom = (int) (bottom - extra + .5F);
|
||||
}
|
||||
|
||||
if (isLastLine) {
|
||||
return lineBottom - layout.getBottomPadding();
|
||||
}
|
||||
|
||||
return lineBottom;
|
||||
}
|
||||
|
||||
private static int getLineHeight(@NonNull Layout layout, int line) {
|
||||
return layout.getLineTop(line + 1) - layout.getLineTop(line);
|
||||
}
|
||||
}
|
@ -16,6 +16,5 @@ include ':app', ':sample',
|
||||
':markwon-recycler',
|
||||
':markwon-recycler-table',
|
||||
':markwon-simple-ext',
|
||||
':markwon-spans-better',
|
||||
':markwon-syntax-highlight',
|
||||
':markwon-test-span'
|
||||
|
Loading…
x
Reference in New Issue
Block a user