1 /*
2  * Copyright (C) 2013 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 com.android.inputmethod.latin.utils;
18 
19 import android.graphics.Paint;
20 import android.graphics.Rect;
21 import android.graphics.Typeface;
22 import android.util.SparseArray;
23 
24 public final class TypefaceUtils {
25     private static final char[] KEY_LABEL_REFERENCE_CHAR = { 'M' };
26     private static final char[] KEY_NUMERIC_HINT_LABEL_REFERENCE_CHAR = { '8' };
27 
TypefaceUtils()28     private TypefaceUtils() {
29         // This utility class is not publicly instantiable.
30     }
31 
32     // This sparse array caches key label text height in pixel indexed by key label text size.
33     private static final SparseArray<Float> sTextHeightCache = new SparseArray<>();
34     // Working variable for the following method.
35     private static final Rect sTextHeightBounds = new Rect();
36 
getCharHeight(final char[] referenceChar, final Paint paint)37     private static float getCharHeight(final char[] referenceChar, final Paint paint) {
38         final int key = getCharGeometryCacheKey(referenceChar[0], paint);
39         synchronized (sTextHeightCache) {
40             final Float cachedValue = sTextHeightCache.get(key);
41             if (cachedValue != null) {
42                 return cachedValue;
43             }
44 
45             paint.getTextBounds(referenceChar, 0, 1, sTextHeightBounds);
46             final float height = sTextHeightBounds.height();
47             sTextHeightCache.put(key, height);
48             return height;
49         }
50     }
51 
52     // This sparse array caches key label text width in pixel indexed by key label text size.
53     private static final SparseArray<Float> sTextWidthCache = new SparseArray<>();
54     // Working variable for the following method.
55     private static final Rect sTextWidthBounds = new Rect();
56 
getCharWidth(final char[] referenceChar, final Paint paint)57     private static float getCharWidth(final char[] referenceChar, final Paint paint) {
58         final int key = getCharGeometryCacheKey(referenceChar[0], paint);
59         synchronized (sTextWidthCache) {
60             final Float cachedValue = sTextWidthCache.get(key);
61             if (cachedValue != null) {
62                 return cachedValue;
63             }
64 
65             paint.getTextBounds(referenceChar, 0, 1, sTextWidthBounds);
66             final float width = sTextWidthBounds.width();
67             sTextWidthCache.put(key, width);
68             return width;
69         }
70     }
71 
getCharGeometryCacheKey(final char referenceChar, final Paint paint)72     private static int getCharGeometryCacheKey(final char referenceChar, final Paint paint) {
73         final int labelSize = (int)paint.getTextSize();
74         final Typeface face = paint.getTypeface();
75         final int codePointOffset = referenceChar << 15;
76         if (face == Typeface.DEFAULT) {
77             return codePointOffset + labelSize;
78         } else if (face == Typeface.DEFAULT_BOLD) {
79             return codePointOffset + labelSize + 0x1000;
80         } else if (face == Typeface.MONOSPACE) {
81             return codePointOffset + labelSize + 0x2000;
82         } else {
83             return codePointOffset + labelSize;
84         }
85     }
86 
getReferenceCharHeight(final Paint paint)87     public static float getReferenceCharHeight(final Paint paint) {
88         return getCharHeight(KEY_LABEL_REFERENCE_CHAR, paint);
89     }
90 
getReferenceCharWidth(final Paint paint)91     public static float getReferenceCharWidth(final Paint paint) {
92         return getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint);
93     }
94 
getReferenceDigitWidth(final Paint paint)95     public static float getReferenceDigitWidth(final Paint paint) {
96         return getCharWidth(KEY_NUMERIC_HINT_LABEL_REFERENCE_CHAR, paint);
97     }
98 
99     // Working variable for the following method.
100     private static final Rect sStringWidthBounds = new Rect();
101 
getStringWidth(final String string, final Paint paint)102     public static float getStringWidth(final String string, final Paint paint) {
103         synchronized (sStringWidthBounds) {
104             paint.getTextBounds(string, 0, string.length(), sStringWidthBounds);
105             return sStringWidthBounds.width();
106         }
107     }
108 }
109