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