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.IntRange; 20 import android.annotation.NonNull; 21 import android.annotation.Px; 22 import android.graphics.Paint; 23 import android.os.Parcel; 24 import android.text.ParcelableSpan; 25 import android.text.TextPaint; 26 import android.text.TextUtils; 27 28 import com.android.internal.util.Preconditions; 29 30 /** 31 * The classes that affect the line height of paragraph should implement this interface. 32 */ 33 public interface LineHeightSpan extends ParagraphStyle, WrapTogetherSpan { 34 /** 35 * Classes that implement this should define how the height is being calculated. 36 * 37 * @param text the text 38 * @param start the start of the line 39 * @param end the end of the line 40 * @param spanstartv the start of the span 41 * @param lineHeight the line height 42 * @param fm font metrics of the paint, in integers 43 */ chooseHeight(CharSequence text, int start, int end, int spanstartv, int lineHeight, Paint.FontMetricsInt fm)44 public void chooseHeight(CharSequence text, int start, int end, 45 int spanstartv, int lineHeight, 46 Paint.FontMetricsInt fm); 47 48 /** 49 * The classes that affect the line height of paragraph with respect to density, 50 * should implement this interface. 51 */ 52 public interface WithDensity extends LineHeightSpan { 53 54 /** 55 * Classes that implement this should define how the height is being calculated. 56 * 57 * @param text the text 58 * @param start the start of the line 59 * @param end the end of the line 60 * @param spanstartv the start of the span 61 * @param lineHeight the line height 62 * @param paint the paint 63 */ chooseHeight(CharSequence text, int start, int end, int spanstartv, int lineHeight, Paint.FontMetricsInt fm, TextPaint paint)64 public void chooseHeight(CharSequence text, int start, int end, 65 int spanstartv, int lineHeight, 66 Paint.FontMetricsInt fm, TextPaint paint); 67 } 68 69 /** 70 * Default implementation of the {@link LineHeightSpan}, which changes the line height of the 71 * attached paragraph. 72 * <p> 73 * For example, a paragraph with its line height equal to 100px can be set like this: 74 * <pre> 75 * SpannableString string = new SpannableString("This is a multiline paragraph. This is a multiline paragraph."); 76 * string.setSpan(new LineHeightSpan.Standard(100), 0, string.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 77 * </pre> 78 * <img src="{@docRoot}reference/android/images/text/style/lineheightspan.png" /> 79 * <figcaption>Text with line height set to 100 pixels.</figcaption> 80 * <p> 81 * Notice that LineHeightSpan will change the line height of the entire paragraph, even though it 82 * covers only part of the paragraph. 83 * </p> 84 */ 85 class Standard implements LineHeightSpan, ParcelableSpan { 86 87 private final @Px int mHeight; 88 /** 89 * Set the line height of the paragraph to <code>height</code> physical pixels. 90 */ Standard(@x @ntRangefrom = 1) int height)91 public Standard(@Px @IntRange(from = 1) int height) { 92 Preconditions.checkArgument(height > 0, "Height:" + height + "must be positive"); 93 mHeight = height; 94 } 95 96 /** 97 * Constructor called from {@link TextUtils} to restore the span from a parcel 98 */ Standard(@onNull Parcel src)99 public Standard(@NonNull Parcel src) { 100 mHeight = src.readInt(); 101 } 102 103 /** 104 * Returns the line height specified by this span. 105 */ 106 @Px getHeight()107 public int getHeight() { 108 return mHeight; 109 } 110 111 @Override getSpanTypeId()112 public int getSpanTypeId() { 113 return getSpanTypeIdInternal(); 114 } 115 116 /** @hide */ 117 @Override getSpanTypeIdInternal()118 public int getSpanTypeIdInternal() { 119 return TextUtils.LINE_HEIGHT_SPAN; 120 } 121 122 @Override describeContents()123 public int describeContents() { 124 return 0; 125 } 126 127 @Override writeToParcel(Parcel dest, int flags)128 public void writeToParcel(Parcel dest, int flags) { 129 writeToParcelInternal(dest, flags); 130 } 131 132 /** @hide */ 133 @Override writeToParcelInternal(@onNull Parcel dest, int flags)134 public void writeToParcelInternal(@NonNull Parcel dest, int flags) { 135 dest.writeInt(mHeight); 136 } 137 138 @Override chooseHeight(@onNull CharSequence text, int start, int end, int spanstartv, int lineHeight, @NonNull Paint.FontMetricsInt fm)139 public void chooseHeight(@NonNull CharSequence text, int start, int end, 140 int spanstartv, int lineHeight, 141 @NonNull Paint.FontMetricsInt fm) { 142 final int originHeight = fm.descent - fm.ascent; 143 // If original height is not positive, do nothing. 144 if (originHeight <= 0) { 145 return; 146 } 147 final float ratio = mHeight * 1.0f / originHeight; 148 fm.descent = Math.round(fm.descent * ratio); 149 fm.ascent = fm.descent - mHeight; 150 } 151 } 152 } 153