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.graphics.Paint;
21 import android.graphics.Typeface;
22 import android.os.Parcel;
23 import android.text.ParcelableSpan;
24 import android.text.TextPaint;
25 import android.text.TextUtils;
26 
27 /**
28  * Span that allows setting the style of the text it's attached to.
29  * Possible styles are: {@link Typeface#NORMAL}, {@link Typeface#BOLD}, {@link Typeface#ITALIC} and
30  * {@link Typeface#BOLD_ITALIC}.
31  * <p>
32  * Note that styles are cumulative -- if both bold and italic are set in
33  * separate spans, or if the base style is bold and a span calls for italic,
34  * you get bold italic.  You can't turn off a style from the base style.
35  * <p>
36  * For example, the <code>StyleSpan</code> can be used like this:
37  * <pre>
38  * SpannableString string = new SpannableString("Bold and italic text");
39  * string.setSpan(new StyleSpan(Typeface.BOLD), 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
40  * string.setSpan(new StyleSpan(Typeface.ITALIC), 9, 15, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
41  * </pre>
42  * <img src="{@docRoot}reference/android/images/text/style/stylespan.png" />
43  * <figcaption>Text styled bold and italic with the <code>StyleSpan</code>.</figcaption>
44  */
45 public class StyleSpan extends MetricAffectingSpan implements ParcelableSpan {
46 
47     private final int mStyle;
48 
49     /**
50      * Creates a {@link StyleSpan} from a style.
51      *
52      * @param style An integer constant describing the style for this span. Examples
53      *              include bold, italic, and normal. Values are constants defined
54      *              in {@link Typeface}.
55      */
StyleSpan(int style)56     public StyleSpan(int style) {
57         mStyle = style;
58     }
59 
60     /**
61      * Creates a {@link StyleSpan} from a parcel.
62      *
63      * @param src the parcel
64      */
StyleSpan(@onNull Parcel src)65     public StyleSpan(@NonNull Parcel src) {
66         mStyle = src.readInt();
67     }
68 
69     @Override
getSpanTypeId()70     public int getSpanTypeId() {
71         return getSpanTypeIdInternal();
72     }
73 
74     /** @hide */
75     @Override
getSpanTypeIdInternal()76     public int getSpanTypeIdInternal() {
77         return TextUtils.STYLE_SPAN;
78     }
79 
80     @Override
describeContents()81     public int describeContents() {
82         return 0;
83     }
84 
85     @Override
writeToParcel(Parcel dest, int flags)86     public void writeToParcel(Parcel dest, int flags) {
87         writeToParcelInternal(dest, flags);
88     }
89 
90     /** @hide */
91     @Override
writeToParcelInternal(@onNull Parcel dest, int flags)92     public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
93         dest.writeInt(mStyle);
94     }
95 
96     /**
97      * Returns the style constant defined in {@link Typeface}.
98      */
getStyle()99     public int getStyle() {
100         return mStyle;
101     }
102 
103     @Override
updateDrawState(TextPaint ds)104     public void updateDrawState(TextPaint ds) {
105         apply(ds, mStyle);
106     }
107 
108     @Override
updateMeasureState(TextPaint paint)109     public void updateMeasureState(TextPaint paint) {
110         apply(paint, mStyle);
111     }
112 
apply(Paint paint, int style)113     private static void apply(Paint paint, int style) {
114         int oldStyle;
115 
116         Typeface old = paint.getTypeface();
117         if (old == null) {
118             oldStyle = 0;
119         } else {
120             oldStyle = old.getStyle();
121         }
122 
123         int want = oldStyle | style;
124 
125         Typeface tf;
126         if (old == null) {
127             tf = Typeface.defaultFromStyle(want);
128         } else {
129             tf = Typeface.create(old, want);
130         }
131 
132         int fake = want & ~tf.getStyle();
133 
134         if ((fake & Typeface.BOLD) != 0) {
135             paint.setFakeBoldText(true);
136         }
137 
138         if ((fake & Typeface.ITALIC) != 0) {
139             paint.setTextSkewX(-0.25f);
140         }
141 
142         paint.setTypeface(tf);
143     }
144 }
145