• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.text.style;
18 
19 import android.annotation.NonNull;
20 import android.content.res.Configuration;
21 import android.graphics.Paint;
22 import android.graphics.Typeface;
23 import android.graphics.fonts.FontStyle;
24 import android.os.Parcel;
25 import android.text.ParcelableSpan;
26 import android.text.TextPaint;
27 import android.text.TextUtils;
28 
29 /**
30  * Span that allows setting the style of the text it's attached to.
31  * Possible styles are: {@link Typeface#NORMAL}, {@link Typeface#BOLD}, {@link Typeface#ITALIC} and
32  * {@link Typeface#BOLD_ITALIC}.
33  * <p>
34  * Note that styles are cumulative -- if both bold and italic are set in
35  * separate spans, or if the base style is bold and a span calls for italic,
36  * you get bold italic.  You can't turn off a style from the base style.
37  * <p>
38  * For example, the <code>StyleSpan</code> can be used like this:
39  * <pre>
40  * SpannableString string = new SpannableString("Bold and italic text");
41  * string.setSpan(new StyleSpan(Typeface.BOLD), 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
42  * string.setSpan(new StyleSpan(Typeface.ITALIC), 9, 15, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
43  * </pre>
44  * <img src="{@docRoot}reference/android/images/text/style/stylespan.png" />
45  * <figcaption>Text styled bold and italic with the <code>StyleSpan</code>.</figcaption>
46  */
47 @android.ravenwood.annotation.RavenwoodKeepWholeClass
48 public class StyleSpan extends MetricAffectingSpan implements ParcelableSpan {
49 
50     private final int mStyle;
51     private final int mFontWeightAdjustment;
52 
53     /**
54      * Creates a {@link StyleSpan} from a style.
55      *
56      * @param style An integer constant describing the style for this span. Examples
57      *              include bold, italic, and normal. Values are constants defined
58      *              in {@link Typeface}.
59      */
StyleSpan(int style)60     public StyleSpan(int style) {
61         this(style, Configuration.FONT_WEIGHT_ADJUSTMENT_UNDEFINED);
62     }
63 
64     /**
65      * Creates a {@link StyleSpan} from a style and font weight adjustment.
66      *
67      * @param style An integer constant describing the style for this span. Examples
68      *              include bold, italic, and normal. Values are constants defined
69      *              in {@link Typeface}.
70      * @param fontWeightAdjustment An integer describing the adjustment to be made to the font
71      *              weight. This is added to the value of the current weight returned by
72      *              {@link Typeface#getWeight()}.
73      * @see Configuration#fontWeightAdjustment This is the adjustment in text font weight
74      * that is used to reflect the current user's preference for increasing font weight.
75      */
StyleSpan(@ypeface.Style int style, int fontWeightAdjustment)76     public StyleSpan(@Typeface.Style int style, int fontWeightAdjustment) {
77         mStyle = style;
78         mFontWeightAdjustment = fontWeightAdjustment;
79     }
80 
81     /**
82      * Creates a {@link StyleSpan} from a parcel.
83      *
84      * @param src the parcel
85      */
StyleSpan(@onNull Parcel src)86     public StyleSpan(@NonNull Parcel src) {
87         mStyle = src.readInt();
88         mFontWeightAdjustment = src.readInt();
89     }
90 
91     @Override
getSpanTypeId()92     public int getSpanTypeId() {
93         return getSpanTypeIdInternal();
94     }
95 
96     /** @hide */
97     @Override
getSpanTypeIdInternal()98     public int getSpanTypeIdInternal() {
99         return TextUtils.STYLE_SPAN;
100     }
101 
102     @Override
describeContents()103     public int describeContents() {
104         return 0;
105     }
106 
107     @Override
writeToParcel(Parcel dest, int flags)108     public void writeToParcel(Parcel dest, int flags) {
109         writeToParcelInternal(dest, flags);
110     }
111 
112     /** @hide */
113     @Override
writeToParcelInternal(@onNull Parcel dest, int flags)114     public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
115         dest.writeInt(mStyle);
116         dest.writeInt(mFontWeightAdjustment);
117     }
118 
119     /**
120      * Returns the style constant defined in {@link Typeface}.
121      */
getStyle()122     public int getStyle() {
123         return mStyle;
124     }
125 
126     /**
127      * Returns the font weight adjustment specified by this span.
128      * <p>
129      * This can be {@link Configuration#FONT_WEIGHT_ADJUSTMENT_UNDEFINED}. This is added to the
130      * value of the current weight returned by {@link Typeface#getWeight()}.
131      */
getFontWeightAdjustment()132     public int getFontWeightAdjustment() {
133         return mFontWeightAdjustment;
134     }
135 
136     @Override
updateDrawState(TextPaint ds)137     public void updateDrawState(TextPaint ds) {
138         apply(ds, mStyle, mFontWeightAdjustment);
139     }
140 
141     @Override
updateMeasureState(TextPaint paint)142     public void updateMeasureState(TextPaint paint) {
143         apply(paint, mStyle, mFontWeightAdjustment);
144     }
145 
apply(Paint paint, int style, int fontWeightAdjustment)146     private static void apply(Paint paint, int style, int fontWeightAdjustment) {
147         int oldStyle;
148 
149         Typeface old = paint.getTypeface();
150         if (old == null) {
151             oldStyle = 0;
152         } else {
153             oldStyle = old.getStyle();
154         }
155 
156         int want = oldStyle | style;
157 
158         Typeface tf;
159         if (old == null) {
160             tf = Typeface.defaultFromStyle(want);
161         } else {
162             tf = Typeface.create(old, want);
163         }
164 
165         // Base typeface may already be bolded by auto bold. Bold further.
166         if ((style & Typeface.BOLD) != 0) {
167             if (fontWeightAdjustment != 0
168                     && fontWeightAdjustment != Configuration.FONT_WEIGHT_ADJUSTMENT_UNDEFINED) {
169                 int newWeight = Math.min(
170                         Math.max(tf.getWeight() + fontWeightAdjustment, FontStyle.FONT_WEIGHT_MIN),
171                         FontStyle.FONT_WEIGHT_MAX);
172                 boolean italic = (want & Typeface.ITALIC) != 0;
173                 tf = Typeface.create(tf, newWeight, italic);
174             }
175         }
176 
177         int fake = want & ~tf.getStyle();
178 
179         if ((fake & Typeface.BOLD) != 0) {
180             paint.setFakeBoldText(true);
181         }
182 
183         if ((fake & Typeface.ITALIC) != 0) {
184             paint.setTextSkewX(-0.25f);
185         }
186 
187         paint.setTypeface(tf);
188     }
189 
190     @Override
toString()191     public String toString() {
192         return "StyleSpan{"
193                 + "style=" + getStyle()
194                 + ", fontWeightAdjustment=" + getFontWeightAdjustment()
195                 + '}';
196     }
197 }
198