Support font resource in TextAppearanceSpan
To be able to parcel/unparcel Typeface, keep it in static context. Bug: 62850669 Test: Manually done Test: bit CtsTextTestCases:android.text.style.cts.TextAppearanceSpanTest Change-Id: I408cd33b98d8bb13776560231d1eeaac0a7c6bf8
This commit is contained in:
@@ -19,6 +19,7 @@ package android.text.style;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.LeakyTypefaceStorage;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Parcel;
|
||||
import android.text.ParcelableSpan;
|
||||
@@ -30,11 +31,12 @@ import android.text.TextUtils;
|
||||
* resource.
|
||||
*/
|
||||
public class TextAppearanceSpan extends MetricAffectingSpan implements ParcelableSpan {
|
||||
private final String mTypeface;
|
||||
private final String mFamilyName;
|
||||
private final int mStyle;
|
||||
private final int mTextSize;
|
||||
private final ColorStateList mTextColor;
|
||||
private final ColorStateList mTextColorLink;
|
||||
private final Typeface mTypeface;
|
||||
|
||||
/**
|
||||
* Uses the specified TextAppearance resource to determine the
|
||||
@@ -55,7 +57,7 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
|
||||
*/
|
||||
public TextAppearanceSpan(Context context, int appearance, int colorList) {
|
||||
ColorStateList textColor;
|
||||
|
||||
|
||||
TypedArray a =
|
||||
context.obtainStyledAttributes(appearance,
|
||||
com.android.internal.R.styleable.TextAppearance);
|
||||
@@ -68,28 +70,33 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
|
||||
TextAppearance_textSize, -1);
|
||||
|
||||
mStyle = a.getInt(com.android.internal.R.styleable.TextAppearance_textStyle, 0);
|
||||
String family = a.getString(com.android.internal.R.styleable.TextAppearance_fontFamily);
|
||||
if (family != null) {
|
||||
mTypeface = family;
|
||||
mTypeface = a.getFont(com.android.internal.R.styleable.TextAppearance_fontFamily);
|
||||
if (mTypeface != null) {
|
||||
mFamilyName = null;
|
||||
} else {
|
||||
int tf = a.getInt(com.android.internal.R.styleable.TextAppearance_typeface, 0);
|
||||
String family = a.getString(com.android.internal.R.styleable.TextAppearance_fontFamily);
|
||||
if (family != null) {
|
||||
mFamilyName = family;
|
||||
} else {
|
||||
int tf = a.getInt(com.android.internal.R.styleable.TextAppearance_typeface, 0);
|
||||
|
||||
switch (tf) {
|
||||
case 1:
|
||||
mTypeface = "sans";
|
||||
break;
|
||||
switch (tf) {
|
||||
case 1:
|
||||
mFamilyName = "sans";
|
||||
break;
|
||||
|
||||
case 2:
|
||||
mTypeface = "serif";
|
||||
break;
|
||||
case 2:
|
||||
mFamilyName = "serif";
|
||||
break;
|
||||
|
||||
case 3:
|
||||
mTypeface = "monospace";
|
||||
break;
|
||||
case 3:
|
||||
mFamilyName = "monospace";
|
||||
break;
|
||||
|
||||
default:
|
||||
mTypeface = null;
|
||||
break;
|
||||
default:
|
||||
mFamilyName = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +109,7 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
|
||||
textColor = a.getColorStateList(colorList);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
|
||||
mTextColor = textColor;
|
||||
}
|
||||
|
||||
@@ -112,15 +119,16 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
|
||||
*/
|
||||
public TextAppearanceSpan(String family, int style, int size,
|
||||
ColorStateList color, ColorStateList linkColor) {
|
||||
mTypeface = family;
|
||||
mFamilyName = family;
|
||||
mStyle = style;
|
||||
mTextSize = size;
|
||||
mTextColor = color;
|
||||
mTextColorLink = linkColor;
|
||||
mTypeface = null;
|
||||
}
|
||||
|
||||
public TextAppearanceSpan(Parcel src) {
|
||||
mTypeface = src.readString();
|
||||
mFamilyName = src.readString();
|
||||
mStyle = src.readInt();
|
||||
mTextSize = src.readInt();
|
||||
if (src.readInt() != 0) {
|
||||
@@ -133,8 +141,9 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
|
||||
} else {
|
||||
mTextColorLink = null;
|
||||
}
|
||||
mTypeface = LeakyTypefaceStorage.readTypefaceFromParcel(src);
|
||||
}
|
||||
|
||||
|
||||
public int getSpanTypeId() {
|
||||
return getSpanTypeIdInternal();
|
||||
}
|
||||
@@ -143,7 +152,7 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
|
||||
public int getSpanTypeIdInternal() {
|
||||
return TextUtils.TEXT_APPEARANCE_SPAN;
|
||||
}
|
||||
|
||||
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
@@ -154,7 +163,7 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
|
||||
|
||||
/** @hide */
|
||||
public void writeToParcelInternal(Parcel dest, int flags) {
|
||||
dest.writeString(mTypeface);
|
||||
dest.writeString(mFamilyName);
|
||||
dest.writeInt(mStyle);
|
||||
dest.writeInt(mTextSize);
|
||||
if (mTextColor != null) {
|
||||
@@ -169,6 +178,7 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
LeakyTypefaceStorage.writeTypefaceToParcel(mTypeface, dest);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,7 +186,7 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
|
||||
* if it does not specify one.
|
||||
*/
|
||||
public String getFamily() {
|
||||
return mTypeface;
|
||||
return mFamilyName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -226,9 +236,14 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
|
||||
|
||||
@Override
|
||||
public void updateMeasureState(TextPaint ds) {
|
||||
if (mTypeface != null || mStyle != 0) {
|
||||
final Typeface styledTypeface;
|
||||
int style = 0;
|
||||
|
||||
if (mTypeface != null) {
|
||||
style = mStyle;
|
||||
styledTypeface = Typeface.create(mTypeface, style);
|
||||
} else if (mFamilyName != null || mStyle != 0) {
|
||||
Typeface tf = ds.getTypeface();
|
||||
int style = 0;
|
||||
|
||||
if (tf != null) {
|
||||
style = tf.getStyle();
|
||||
@@ -236,15 +251,19 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
|
||||
|
||||
style |= mStyle;
|
||||
|
||||
if (mTypeface != null) {
|
||||
tf = Typeface.create(mTypeface, style);
|
||||
if (mFamilyName != null) {
|
||||
styledTypeface = Typeface.create(mFamilyName, style);
|
||||
} else if (tf == null) {
|
||||
tf = Typeface.defaultFromStyle(style);
|
||||
styledTypeface = Typeface.defaultFromStyle(style);
|
||||
} else {
|
||||
tf = Typeface.create(tf, style);
|
||||
styledTypeface = Typeface.create(tf, style);
|
||||
}
|
||||
} else {
|
||||
styledTypeface = null;
|
||||
}
|
||||
|
||||
int fake = style & ~tf.getStyle();
|
||||
if (styledTypeface != null) {
|
||||
int fake = style & ~styledTypeface.getStyle();
|
||||
|
||||
if ((fake & Typeface.BOLD) != 0) {
|
||||
ds.setFakeBoldText(true);
|
||||
@@ -254,7 +273,7 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
|
||||
ds.setTextSkewX(-0.25f);
|
||||
}
|
||||
|
||||
ds.setTypeface(tf);
|
||||
ds.setTypeface(styledTypeface);
|
||||
}
|
||||
|
||||
if (mTextSize > 0) {
|
||||
|
||||
86
graphics/java/android/graphics/LeakyTypefaceStorage.java
Normal file
86
graphics/java/android/graphics/LeakyTypefaceStorage.java
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.graphics;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Process;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* This class is used for Parceling Typeface object.
|
||||
* Note: Typeface object can not be passed over the process boundary.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class LeakyTypefaceStorage {
|
||||
private static final Object sLock = new Object();
|
||||
|
||||
@GuardedBy("sLock")
|
||||
private static final ArrayList<Typeface> sStorage = new ArrayList<>();
|
||||
@GuardedBy("sLock")
|
||||
private static final ArrayMap<Typeface, Integer> sTypefaceMap = new ArrayMap<>();
|
||||
|
||||
/**
|
||||
* Write typeface to parcel.
|
||||
*
|
||||
* You can't transfer Typeface to a different process. {@link readTypefaceFromParcel} will
|
||||
* return {@code null} if the {@link readTypefaceFromParcel} is called in a different process.
|
||||
*
|
||||
* @param typeface A {@link Typeface} to be written.
|
||||
* @param parcel A {@link Parcel} object.
|
||||
*/
|
||||
public static void writeTypefaceToParcel(@Nullable Typeface typeface, @NonNull Parcel parcel) {
|
||||
parcel.writeInt(Process.myPid());
|
||||
synchronized (sLock) {
|
||||
final int id;
|
||||
final Integer i = sTypefaceMap.get(typeface);
|
||||
if (i != null) {
|
||||
id = i.intValue();
|
||||
} else {
|
||||
id = sStorage.size();
|
||||
sStorage.add(typeface);
|
||||
sTypefaceMap.put(typeface, id);
|
||||
}
|
||||
parcel.writeInt(id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read typeface from parcel.
|
||||
*
|
||||
* If the {@link Typeface} was created in another process, this method returns null.
|
||||
*
|
||||
* @param parcel A {@link Parcel} object
|
||||
* @return A {@link Typeface} object.
|
||||
*/
|
||||
public static @Nullable Typeface readTypefaceFromParcel(@NonNull Parcel parcel) {
|
||||
final int pid = parcel.readInt();
|
||||
final int typefaceId = parcel.readInt();
|
||||
if (pid != Process.myPid()) {
|
||||
return null; // The Typeface was created and written in another process.
|
||||
}
|
||||
synchronized (sLock) {
|
||||
return sStorage.get(typefaceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user