Make <font size> and <font height> in string resources respect density.
This unfortunately requires API changes because the existing text markup classes had no access to the screen density. TextPaint gains a "density" field so that TextView can pass the density along. AbsoluteSizeSpan gains a new flag to indicate that its argument is in dip instead of in physical pixels. LineHeightSpan gains an inner interface whose chooseHeight() method includes a TextPaint argument so it can get at the density. And when StringBlock creates the markup objects, it now uses the density-aware versions. Bug 1976971, Bug 2031746
This commit is contained in:
@@ -130128,6 +130128,16 @@
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="density"
|
||||
type="float"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="drawableState"
|
||||
type="int[]"
|
||||
transient="false"
|
||||
@@ -135126,6 +135136,18 @@
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="size" type="int">
|
||||
</parameter>
|
||||
<parameter name="dip" type="boolean">
|
||||
</parameter>
|
||||
</constructor>
|
||||
<constructor name="AbsoluteSizeSpan"
|
||||
type="android.text.style.AbsoluteSizeSpan"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="src" type="android.os.Parcel">
|
||||
</parameter>
|
||||
</constructor>
|
||||
@@ -135140,6 +135162,17 @@
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getDip"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getSize"
|
||||
return="int"
|
||||
abstract="false"
|
||||
@@ -136530,6 +136563,41 @@
|
||||
</parameter>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="LineHeightSpan.WithDensity"
|
||||
abstract="true"
|
||||
static="true"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<implements name="android.text.style.LineHeightSpan">
|
||||
</implements>
|
||||
<method name="chooseHeight"
|
||||
return="void"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="text" type="java.lang.CharSequence">
|
||||
</parameter>
|
||||
<parameter name="start" type="int">
|
||||
</parameter>
|
||||
<parameter name="end" type="int">
|
||||
</parameter>
|
||||
<parameter name="spanstartv" type="int">
|
||||
</parameter>
|
||||
<parameter name="v" type="int">
|
||||
</parameter>
|
||||
<parameter name="fm" type="android.graphics.Paint.FontMetricsInt">
|
||||
</parameter>
|
||||
<parameter name="paint" type="android.text.TextPaint">
|
||||
</parameter>
|
||||
</method>
|
||||
</interface>
|
||||
<class name="MaskFilterSpan"
|
||||
extends="android.text.style.CharacterStyle"
|
||||
abstract="false"
|
||||
|
||||
@@ -202,7 +202,7 @@ final class StringBlock {
|
||||
sub = subtag(tag, ";size=");
|
||||
if (sub != null) {
|
||||
int size = Integer.parseInt(sub);
|
||||
buffer.setSpan(new AbsoluteSizeSpan(size),
|
||||
buffer.setSpan(new AbsoluteSizeSpan(size, true),
|
||||
style[i+1], style[i+2]+1,
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
@@ -310,7 +310,7 @@ final class StringBlock {
|
||||
* the ascent if possible, or the descent if shrinking the ascent further
|
||||
* will make the text unreadable.
|
||||
*/
|
||||
private static class Height implements LineHeightSpan {
|
||||
private static class Height implements LineHeightSpan.WithDensity {
|
||||
private int mSize;
|
||||
private static float sProportion = 0;
|
||||
|
||||
@@ -321,9 +321,21 @@ final class StringBlock {
|
||||
public void chooseHeight(CharSequence text, int start, int end,
|
||||
int spanstartv, int v,
|
||||
Paint.FontMetricsInt fm) {
|
||||
if (fm.bottom - fm.top < mSize) {
|
||||
fm.top = fm.bottom - mSize;
|
||||
fm.ascent = fm.ascent - mSize;
|
||||
// Should not get called, at least not by StaticLayout.
|
||||
chooseHeight(text, start, end, spanstartv, v, fm, null);
|
||||
}
|
||||
|
||||
public void chooseHeight(CharSequence text, int start, int end,
|
||||
int spanstartv, int v,
|
||||
Paint.FontMetricsInt fm, TextPaint paint) {
|
||||
int size = mSize;
|
||||
if (paint != null) {
|
||||
size *= paint.density;
|
||||
}
|
||||
|
||||
if (fm.bottom - fm.top < size) {
|
||||
fm.top = fm.bottom - size;
|
||||
fm.ascent = fm.ascent - size;
|
||||
} else {
|
||||
if (sProportion == 0) {
|
||||
/*
|
||||
@@ -343,27 +355,27 @@ final class StringBlock {
|
||||
|
||||
int need = (int) Math.ceil(-fm.top * sProportion);
|
||||
|
||||
if (mSize - fm.descent >= need) {
|
||||
if (size - fm.descent >= need) {
|
||||
/*
|
||||
* It is safe to shrink the ascent this much.
|
||||
*/
|
||||
|
||||
fm.top = fm.bottom - mSize;
|
||||
fm.ascent = fm.descent - mSize;
|
||||
} else if (mSize >= need) {
|
||||
fm.top = fm.bottom - size;
|
||||
fm.ascent = fm.descent - size;
|
||||
} else if (size >= need) {
|
||||
/*
|
||||
* We can't show all the descent, but we can at least
|
||||
* show all the ascent.
|
||||
*/
|
||||
|
||||
fm.top = fm.ascent = -need;
|
||||
fm.bottom = fm.descent = fm.top + mSize;
|
||||
fm.bottom = fm.descent = fm.top + size;
|
||||
} else {
|
||||
/*
|
||||
* Show as much of the ascent as we can, and no descent.
|
||||
*/
|
||||
|
||||
fm.top = fm.ascent = -mSize;
|
||||
fm.top = fm.ascent = -size;
|
||||
fm.bottom = fm.descent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -968,7 +968,13 @@ extends Layout
|
||||
fm.bottom = bottom;
|
||||
|
||||
for (int i = 0; i < chooseht.length; i++) {
|
||||
chooseht[i].chooseHeight(text, start, end, choosehtv[i], v, fm);
|
||||
if (chooseht[i] instanceof LineHeightSpan.WithDensity) {
|
||||
((LineHeightSpan.WithDensity) chooseht[i]).
|
||||
chooseHeight(text, start, end, choosehtv[i], v, fm, paint);
|
||||
|
||||
} else {
|
||||
chooseht[i].chooseHeight(text, start, end, choosehtv[i], v, fm);
|
||||
}
|
||||
}
|
||||
|
||||
above = fm.ascent;
|
||||
|
||||
@@ -27,6 +27,7 @@ public class TextPaint extends Paint {
|
||||
public int baselineShift;
|
||||
public int linkColor;
|
||||
public int[] drawableState;
|
||||
public float density = 1.0f;
|
||||
|
||||
public TextPaint() {
|
||||
super();
|
||||
@@ -51,5 +52,6 @@ public class TextPaint extends Paint {
|
||||
baselineShift = tp.baselineShift;
|
||||
linkColor = tp.linkColor;
|
||||
drawableState = tp.drawableState;
|
||||
density = tp.density;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,13 +24,28 @@ import android.text.TextUtils;
|
||||
public class AbsoluteSizeSpan extends MetricAffectingSpan implements ParcelableSpan {
|
||||
|
||||
private final int mSize;
|
||||
private boolean mDip;
|
||||
|
||||
/**
|
||||
* Set the text size to <code>size</code> physical pixels.
|
||||
*/
|
||||
public AbsoluteSizeSpan(int size) {
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the text size to <code>size</code> physical pixels,
|
||||
* or to <code>size</code> device-independent pixels if
|
||||
* <code>dip</code> is true.
|
||||
*/
|
||||
public AbsoluteSizeSpan(int size, boolean dip) {
|
||||
mSize = size;
|
||||
mDip = dip;
|
||||
}
|
||||
|
||||
public AbsoluteSizeSpan(Parcel src) {
|
||||
mSize = src.readInt();
|
||||
mDip = src.readInt() != 0;
|
||||
}
|
||||
|
||||
public int getSpanTypeId() {
|
||||
@@ -43,19 +58,32 @@ public class AbsoluteSizeSpan extends MetricAffectingSpan implements ParcelableS
|
||||
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(mSize);
|
||||
dest.writeInt(mDip ? 1 : 0);
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
public boolean getDip() {
|
||||
return mDip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(TextPaint ds) {
|
||||
ds.setTextSize(mSize);
|
||||
if (mDip) {
|
||||
ds.setTextSize(mSize * ds.density);
|
||||
} else {
|
||||
ds.setTextSize(mSize);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMeasureState(TextPaint ds) {
|
||||
ds.setTextSize(mSize);
|
||||
if (mDip) {
|
||||
ds.setTextSize(mSize * ds.density);
|
||||
} else {
|
||||
ds.setTextSize(mSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.text.style;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Canvas;
|
||||
import android.text.Layout;
|
||||
import android.text.TextPaint;
|
||||
|
||||
public interface LineHeightSpan
|
||||
extends ParagraphStyle, WrapTogetherSpan
|
||||
@@ -26,4 +27,10 @@ extends ParagraphStyle, WrapTogetherSpan
|
||||
public void chooseHeight(CharSequence text, int start, int end,
|
||||
int spanstartv, int v,
|
||||
Paint.FontMetricsInt fm);
|
||||
|
||||
public interface WithDensity extends LineHeightSpan {
|
||||
public void chooseHeight(CharSequence text, int start, int end,
|
||||
int spanstartv, int v,
|
||||
Paint.FontMetricsInt fm, TextPaint paint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,6 +327,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
mText = "";
|
||||
|
||||
mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
|
||||
mTextPaint.density = getResources().getDisplayMetrics().density;
|
||||
// If we get the paint from the skin, we should set it to left, since
|
||||
// the layout always wants it to be left.
|
||||
// mTextPaint.setTextAlign(Paint.Align.LEFT);
|
||||
|
||||
Reference in New Issue
Block a user