EmojiSpan.java revision 82d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439
1/* 2 * Copyright (C) 2017 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 */ 16package android.support.text.emoji; 17 18import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP; 19 20import android.graphics.Paint; 21import android.support.annotation.NonNull; 22import android.support.annotation.RestrictTo; 23import android.support.annotation.VisibleForTesting; 24import android.support.v4.util.Preconditions; 25import android.text.style.ReplacementSpan; 26 27/** 28 * Base span class for the emoji replacement. When an emoji is found and needs to be replaced in a 29 * CharSequence, an instance of this class is added to the CharSequence. 30 */ 31public abstract class EmojiSpan extends ReplacementSpan { 32 33 /** 34 * Temporary object to calculate the size of the span. 35 */ 36 private final Paint.FontMetricsInt mTmpFontMetrics = new Paint.FontMetricsInt(); 37 38 /** 39 * Information about emoji. This is not parcelled since we do not want multiple objects 40 * representing same emoji to be in memory. When unparcelled, EmojiSpan tries to set it back 41 * using the singleton EmojiCompat instance. 42 */ 43 private final EmojiMetadata mMetadata; 44 45 /** 46 * Cached width of the span. Width is calculated according to the font metrics. 47 */ 48 private short mWidth = -1; 49 50 /** 51 * Cached height of the span. Height is calculated according to the font metrics. 52 */ 53 private short mHeight = -1; 54 55 /** 56 * Cached ratio of current font height to emoji image height. 57 */ 58 private float mRatio = 1.0f; 59 60 /** 61 * Default constructor. 62 * 63 * @param metadata information about the emoji, cannot be {@code null} 64 * 65 * @hide 66 */ 67 @RestrictTo(LIBRARY_GROUP) 68 EmojiSpan(@NonNull final EmojiMetadata metadata) { 69 Preconditions.checkNotNull(metadata, "metadata cannot be null"); 70 mMetadata = metadata; 71 } 72 73 @Override 74 public int getSize(@NonNull final Paint paint, final CharSequence text, final int start, 75 final int end, final Paint.FontMetricsInt fm) { 76 paint.getFontMetricsInt(mTmpFontMetrics); 77 final int fontHeight = Math.abs(mTmpFontMetrics.descent - mTmpFontMetrics.ascent); 78 79 mRatio = fontHeight * 1.0f / mMetadata.getHeight(); 80 mHeight = (short) (mMetadata.getHeight() * mRatio); 81 mWidth = (short) (mMetadata.getWidth() * mRatio); 82 83 if (fm != null) { 84 fm.ascent = mTmpFontMetrics.ascent; 85 fm.descent = mTmpFontMetrics.descent; 86 fm.top = mTmpFontMetrics.top; 87 fm.bottom = mTmpFontMetrics.bottom; 88 } 89 90 return mWidth; 91 } 92 93 /** 94 * @hide 95 */ 96 @RestrictTo(LIBRARY_GROUP) 97 final EmojiMetadata getMetadata() { 98 return mMetadata; 99 } 100 101 /** 102 * @return width of the span 103 * 104 * @hide 105 */ 106 @RestrictTo(LIBRARY_GROUP) 107 final int getWidth() { 108 return mWidth; 109 } 110 111 /** 112 * @return height of the span 113 * 114 * @hide 115 */ 116 @RestrictTo(LIBRARY_GROUP) 117 final int getHeight() { 118 return mHeight; 119 } 120 121 /** 122 * @hide 123 */ 124 @RestrictTo(LIBRARY_GROUP) 125 final float getRatio() { 126 return mRatio; 127 } 128 129 /** 130 * @return unique id for the emoji that this EmojiSpan is used for 131 * 132 * @hide 133 */ 134 @RestrictTo(LIBRARY_GROUP) 135 @VisibleForTesting 136 public final int getId() { 137 return getMetadata().getId(); 138 } 139} 140