Add TypefaceUtils

Change-Id: I2d939bc1e3279253902b28ff12bbf7861716b64d
main
Tadashi G. Takaoka 2013-04-11 12:08:36 +09:00
parent cdaee868a3
commit 08ae0d5ca0
8 changed files with 178 additions and 128 deletions

View File

@ -26,10 +26,8 @@ import android.graphics.Paint.Align;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.Region; import android.graphics.Region;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.View; import android.view.View;
import com.android.inputmethod.keyboard.internal.KeyDrawParams; import com.android.inputmethod.keyboard.internal.KeyDrawParams;
@ -73,15 +71,15 @@ import java.util.HashSet;
*/ */
public class KeyboardView extends View { public class KeyboardView extends View {
// XML attributes // XML attributes
protected final KeyVisualAttributes mKeyVisualAttributes; private final KeyVisualAttributes mKeyVisualAttributes;
private final int mKeyLabelHorizontalPadding; private final int mKeyLabelHorizontalPadding;
private final float mKeyHintLetterPadding; private final float mKeyHintLetterPadding;
private final float mKeyPopupHintLetterPadding; private final float mKeyPopupHintLetterPadding;
private final float mKeyShiftedLetterHintPadding; private final float mKeyShiftedLetterHintPadding;
private final float mKeyTextShadowRadius; private final float mKeyTextShadowRadius;
protected final float mVerticalCorrection; private final float mVerticalCorrection;
protected final Drawable mKeyBackground; private final Drawable mKeyBackground;
protected final Rect mKeyBackgroundPadding = new Rect(); private final Rect mKeyBackgroundPadding = new Rect();
// HORIZONTAL ELLIPSIS "...", character for popup hint. // HORIZONTAL ELLIPSIS "...", character for popup hint.
private static final String POPUP_HINT_CHAR = "\u2026"; private static final String POPUP_HINT_CHAR = "\u2026";
@ -113,10 +111,6 @@ public class KeyboardView extends View {
private final Canvas mOffscreenCanvas = new Canvas(); private final Canvas mOffscreenCanvas = new Canvas();
private final Paint mPaint = new Paint(); private final Paint mPaint = new Paint();
private final Paint.FontMetrics mFontMetrics = new Paint.FontMetrics(); private final Paint.FontMetrics mFontMetrics = new Paint.FontMetrics();
// This sparse array caches key label text height in pixel indexed by key label text size.
private static final SparseArray<Float> sTextHeightCache = CollectionUtils.newSparseArray();
// This sparse array caches key label text width in pixel indexed by key label text size.
private static final SparseArray<Float> sTextWidthCache = CollectionUtils.newSparseArray();
private static final char[] KEY_LABEL_REFERENCE_CHAR = { 'M' }; private static final char[] KEY_LABEL_REFERENCE_CHAR = { 'M' };
private static final char[] KEY_NUMERIC_HINT_LABEL_REFERENCE_CHAR = { '8' }; private static final char[] KEY_NUMERIC_HINT_LABEL_REFERENCE_CHAR = { '8' };
@ -134,15 +128,15 @@ public class KeyboardView extends View {
mKeyLabelHorizontalPadding = keyboardViewAttr.getDimensionPixelOffset( mKeyLabelHorizontalPadding = keyboardViewAttr.getDimensionPixelOffset(
R.styleable.KeyboardView_keyLabelHorizontalPadding, 0); R.styleable.KeyboardView_keyLabelHorizontalPadding, 0);
mKeyHintLetterPadding = keyboardViewAttr.getDimension( mKeyHintLetterPadding = keyboardViewAttr.getDimension(
R.styleable.KeyboardView_keyHintLetterPadding, 0); R.styleable.KeyboardView_keyHintLetterPadding, 0.0f);
mKeyPopupHintLetterPadding = keyboardViewAttr.getDimension( mKeyPopupHintLetterPadding = keyboardViewAttr.getDimension(
R.styleable.KeyboardView_keyPopupHintLetterPadding, 0); R.styleable.KeyboardView_keyPopupHintLetterPadding, 0.0f);
mKeyShiftedLetterHintPadding = keyboardViewAttr.getDimension( mKeyShiftedLetterHintPadding = keyboardViewAttr.getDimension(
R.styleable.KeyboardView_keyShiftedLetterHintPadding, 0); R.styleable.KeyboardView_keyShiftedLetterHintPadding, 0.0f);
mKeyTextShadowRadius = keyboardViewAttr.getFloat( mKeyTextShadowRadius = keyboardViewAttr.getFloat(
R.styleable.KeyboardView_keyTextShadowRadius, 0.0f); R.styleable.KeyboardView_keyTextShadowRadius, 0.0f);
mVerticalCorrection = keyboardViewAttr.getDimension( mVerticalCorrection = keyboardViewAttr.getDimension(
R.styleable.KeyboardView_verticalCorrection, 0); R.styleable.KeyboardView_verticalCorrection, 0.0f);
keyboardViewAttr.recycle(); keyboardViewAttr.recycle();
final TypedArray keyAttr = context.obtainStyledAttributes(attrs, final TypedArray keyAttr = context.obtainStyledAttributes(attrs,
@ -185,6 +179,14 @@ public class KeyboardView extends View {
return mKeyboard; return mKeyboard;
} }
protected float getVerticalCorrection() {
return mVerticalCorrection;
}
protected void updateKeyDrawParams(final int keyHeight) {
mKeyDrawParams.updateParams(keyHeight, mKeyVisualAttributes);
}
@Override @Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
if (mKeyboard != null) { if (mKeyboard != null) {
@ -213,7 +215,7 @@ public class KeyboardView extends View {
} }
onDrawKeyboard(mOffscreenCanvas); onDrawKeyboard(mOffscreenCanvas);
} }
canvas.drawBitmap(mOffscreenBuffer, 0, 0, null); canvas.drawBitmap(mOffscreenBuffer, 0.0f, 0.0f, null);
} }
private boolean maybeAllocateOffscreenBuffer() { private boolean maybeAllocateOffscreenBuffer() {
@ -333,7 +335,7 @@ public class KeyboardView extends View {
canvas.translate(bgX, bgY); canvas.translate(bgX, bgY);
background.draw(canvas); background.draw(canvas);
if (LatinImeLogger.sVISUALDEBUG) { if (LatinImeLogger.sVISUALDEBUG) {
drawRectangle(canvas, 0, 0, bgWidth, bgHeight, 0x80c00000, new Paint()); drawRectangle(canvas, 0.0f, 0.0f, bgWidth, bgHeight, 0x80c00000, new Paint());
} }
canvas.translate(-bgX, -bgY); canvas.translate(-bgX, -bgY);
} }
@ -347,7 +349,7 @@ public class KeyboardView extends View {
final float centerY = keyHeight * 0.5f; final float centerY = keyHeight * 0.5f;
if (LatinImeLogger.sVISUALDEBUG) { if (LatinImeLogger.sVISUALDEBUG) {
drawRectangle(canvas, 0, 0, keyWidth, keyHeight, 0x800000c0, new Paint()); drawRectangle(canvas, 0.0f, 0.0f, keyWidth, keyHeight, 0x800000c0, new Paint());
} }
// Draw key label. // Draw key label.
@ -357,14 +359,16 @@ public class KeyboardView extends View {
final String label = key.mLabel; final String label = key.mLabel;
paint.setTypeface(key.selectTypeface(params)); paint.setTypeface(key.selectTypeface(params));
paint.setTextSize(key.selectTextSize(params)); paint.setTextSize(key.selectTextSize(params));
final float labelCharHeight = getCharHeight(KEY_LABEL_REFERENCE_CHAR, paint); final float labelCharHeight = TypefaceUtils.getCharHeight(
final float labelCharWidth = getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint); KEY_LABEL_REFERENCE_CHAR, paint);
final float labelCharWidth = TypefaceUtils.getCharWidth(
KEY_LABEL_REFERENCE_CHAR, paint);
// Vertical label text alignment. // Vertical label text alignment.
final float baseline = centerY + labelCharHeight / 2; final float baseline = centerY + labelCharHeight / 2.0f;
// Horizontal label text alignment // Horizontal label text alignment
float labelWidth = 0; float labelWidth = 0.0f;
if (key.isAlignLeft()) { if (key.isAlignLeft()) {
positionX = mKeyLabelHorizontalPadding; positionX = mKeyLabelHorizontalPadding;
paint.setTextAlign(Align.LEFT); paint.setTextAlign(Align.LEFT);
@ -373,31 +377,31 @@ public class KeyboardView extends View {
paint.setTextAlign(Align.RIGHT); paint.setTextAlign(Align.RIGHT);
} else if (key.isAlignLeftOfCenter()) { } else if (key.isAlignLeftOfCenter()) {
// TODO: Parameterise this? // TODO: Parameterise this?
positionX = centerX - labelCharWidth * 7 / 4; positionX = centerX - labelCharWidth * 7.0f / 4.0f;
paint.setTextAlign(Align.LEFT); paint.setTextAlign(Align.LEFT);
} else if (key.hasLabelWithIconLeft() && icon != null) { } else if (key.hasLabelWithIconLeft() && icon != null) {
labelWidth = getLabelWidth(label, paint) + icon.getIntrinsicWidth() labelWidth = TypefaceUtils.getLabelWidth(label, paint) + icon.getIntrinsicWidth()
+ LABEL_ICON_MARGIN * keyWidth; + LABEL_ICON_MARGIN * keyWidth;
positionX = centerX + labelWidth / 2; positionX = centerX + labelWidth / 2.0f;
paint.setTextAlign(Align.RIGHT); paint.setTextAlign(Align.RIGHT);
} else if (key.hasLabelWithIconRight() && icon != null) { } else if (key.hasLabelWithIconRight() && icon != null) {
labelWidth = getLabelWidth(label, paint) + icon.getIntrinsicWidth() labelWidth = TypefaceUtils.getLabelWidth(label, paint) + icon.getIntrinsicWidth()
+ LABEL_ICON_MARGIN * keyWidth; + LABEL_ICON_MARGIN * keyWidth;
positionX = centerX - labelWidth / 2; positionX = centerX - labelWidth / 2.0f;
paint.setTextAlign(Align.LEFT); paint.setTextAlign(Align.LEFT);
} else { } else {
positionX = centerX; positionX = centerX;
paint.setTextAlign(Align.CENTER); paint.setTextAlign(Align.CENTER);
} }
if (key.needsXScale()) { if (key.needsXScale()) {
paint.setTextScaleX( paint.setTextScaleX(Math.min(1.0f,
Math.min(1.0f, (keyWidth * MAX_LABEL_RATIO) / getLabelWidth(label, paint))); (keyWidth * MAX_LABEL_RATIO) / TypefaceUtils.getLabelWidth(label, paint)));
} }
paint.setColor(key.selectTextColor(params)); paint.setColor(key.selectTextColor(params));
if (key.isEnabled()) { if (key.isEnabled()) {
// Set a drop shadow for the text // Set a drop shadow for the text
paint.setShadowLayer(mKeyTextShadowRadius, 0, 0, params.mTextShadowColor); paint.setShadowLayer(mKeyTextShadowRadius, 0.0f, 0.0f, params.mTextShadowColor);
} else { } else {
// Make label invisible // Make label invisible
paint.setColor(Color.TRANSPARENT); paint.setColor(Color.TRANSPARENT);
@ -405,7 +409,7 @@ public class KeyboardView extends View {
blendAlpha(paint, params.mAnimAlpha); blendAlpha(paint, params.mAnimAlpha);
canvas.drawText(label, 0, label.length(), positionX, baseline, paint); canvas.drawText(label, 0, label.length(), positionX, baseline, paint);
// Turn off drop shadow and reset x-scale. // Turn off drop shadow and reset x-scale.
paint.setShadowLayer(0, 0, 0, 0); paint.setShadowLayer(0.0f, 0.0f, 0.0f, Color.TRANSPARENT);
paint.setTextScaleX(1.0f); paint.setTextScaleX(1.0f);
if (icon != null) { if (icon != null) {
@ -413,10 +417,10 @@ public class KeyboardView extends View {
final int iconHeight = icon.getIntrinsicHeight(); final int iconHeight = icon.getIntrinsicHeight();
final int iconY = (keyHeight - iconHeight) / 2; final int iconY = (keyHeight - iconHeight) / 2;
if (key.hasLabelWithIconLeft()) { if (key.hasLabelWithIconLeft()) {
final int iconX = (int)(centerX - labelWidth / 2); final int iconX = (int)(centerX - labelWidth / 2.0f);
drawIcon(canvas, icon, iconX, iconY, iconWidth, iconHeight); drawIcon(canvas, icon, iconX, iconY, iconWidth, iconHeight);
} else if (key.hasLabelWithIconRight()) { } else if (key.hasLabelWithIconRight()) {
final int iconX = (int)(centerX + labelWidth / 2 - iconWidth); final int iconX = (int)(centerX + labelWidth / 2.0f - iconWidth);
drawIcon(canvas, icon, iconX, iconY, iconWidth, iconHeight); drawIcon(canvas, icon, iconX, iconY, iconWidth, iconHeight);
} }
} }
@ -439,20 +443,23 @@ public class KeyboardView extends View {
// The hint label is placed just right of the key label. Used mainly on // The hint label is placed just right of the key label. Used mainly on
// "phone number" layout. // "phone number" layout.
// TODO: Generalize the following calculations. // TODO: Generalize the following calculations.
hintX = positionX + getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) * 2; hintX = positionX
hintY = centerY + getCharHeight(KEY_LABEL_REFERENCE_CHAR, paint) / 2; + TypefaceUtils.getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) * 2.0f;
hintY = centerY
+ TypefaceUtils.getCharHeight(KEY_LABEL_REFERENCE_CHAR, paint) / 2.0f;
paint.setTextAlign(Align.LEFT); paint.setTextAlign(Align.LEFT);
} else if (key.hasShiftedLetterHint()) { } else if (key.hasShiftedLetterHint()) {
// The hint label is placed at top-right corner of the key. Used mainly on tablet. // The hint label is placed at top-right corner of the key. Used mainly on tablet.
hintX = keyWidth - mKeyShiftedLetterHintPadding hintX = keyWidth - mKeyShiftedLetterHintPadding
- getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) / 2; - TypefaceUtils.getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) / 2.0f;
paint.getFontMetrics(mFontMetrics); paint.getFontMetrics(mFontMetrics);
hintY = -mFontMetrics.top; hintY = -mFontMetrics.top;
paint.setTextAlign(Align.CENTER); paint.setTextAlign(Align.CENTER);
} else { // key.hasHintLetter() } else { // key.hasHintLetter()
// The hint letter is placed at top-right corner of the key. Used mainly on phone. // The hint letter is placed at top-right corner of the key. Used mainly on phone.
hintX = keyWidth - mKeyHintLetterPadding hintX = keyWidth - mKeyHintLetterPadding
- getCharWidth(KEY_NUMERIC_HINT_LABEL_REFERENCE_CHAR, paint) / 2; - TypefaceUtils.getCharWidth(KEY_NUMERIC_HINT_LABEL_REFERENCE_CHAR, paint)
/ 2.0f;
hintY = -paint.ascent(); hintY = -paint.ascent();
paint.setTextAlign(Align.CENTER); paint.setTextAlign(Align.CENTER);
} }
@ -506,7 +513,7 @@ public class KeyboardView extends View {
paint.setColor(params.mHintLabelColor); paint.setColor(params.mHintLabelColor);
paint.setTextAlign(Align.CENTER); paint.setTextAlign(Align.CENTER);
final float hintX = keyWidth - mKeyHintLetterPadding final float hintX = keyWidth - mKeyHintLetterPadding
- getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) / 2; - TypefaceUtils.getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) / 2.0f;
final float hintY = keyHeight - mKeyPopupHintLetterPadding; final float hintY = keyHeight - mKeyPopupHintLetterPadding;
canvas.drawText(POPUP_HINT_CHAR, hintX, hintY, paint); canvas.drawText(POPUP_HINT_CHAR, hintX, hintY, paint);
@ -517,54 +524,6 @@ public class KeyboardView extends View {
} }
} }
private static int getCharGeometryCacheKey(final char referenceChar, final Paint paint) {
final int labelSize = (int)paint.getTextSize();
final Typeface face = paint.getTypeface();
final int codePointOffset = referenceChar << 15;
if (face == Typeface.DEFAULT) {
return codePointOffset + labelSize;
} else if (face == Typeface.DEFAULT_BOLD) {
return codePointOffset + labelSize + 0x1000;
} else if (face == Typeface.MONOSPACE) {
return codePointOffset + labelSize + 0x2000;
} else {
return codePointOffset + labelSize;
}
}
// Working variable for the following methods.
private final Rect mTextBounds = new Rect();
private float getCharHeight(final char[] referenceChar, final Paint paint) {
final int key = getCharGeometryCacheKey(referenceChar[0], paint);
final Float cachedValue = sTextHeightCache.get(key);
if (cachedValue != null)
return cachedValue;
paint.getTextBounds(referenceChar, 0, 1, mTextBounds);
final float height = mTextBounds.height();
sTextHeightCache.put(key, height);
return height;
}
private float getCharWidth(final char[] referenceChar, final Paint paint) {
final int key = getCharGeometryCacheKey(referenceChar[0], paint);
final Float cachedValue = sTextWidthCache.get(key);
if (cachedValue != null)
return cachedValue;
paint.getTextBounds(referenceChar, 0, 1, mTextBounds);
final float width = mTextBounds.width();
sTextWidthCache.put(key, width);
return width;
}
// TODO: Remove this method.
public float getLabelWidth(final String label, final Paint paint) {
paint.getTextBounds(label, 0, label.length(), mTextBounds);
return mTextBounds.width();
}
protected static void drawIcon(final Canvas canvas, final Drawable icon, final int x, protected static void drawIcon(final Canvas canvas, final Drawable icon, final int x,
final int y, final int width, final int height) { final int y, final int width, final int height) {
canvas.translate(x, y); canvas.translate(x, y);
@ -578,7 +537,7 @@ public class KeyboardView extends View {
paint.setStyle(Paint.Style.STROKE); paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(1.0f); paint.setStrokeWidth(1.0f);
paint.setColor(color); paint.setColor(color);
canvas.drawLine(0, y, w, y, paint); canvas.drawLine(0.0f, y, w, y, paint);
} }
private static void drawVerticalLine(final Canvas canvas, final float x, final float h, private static void drawVerticalLine(final Canvas canvas, final float x, final float h,
@ -586,7 +545,7 @@ public class KeyboardView extends View {
paint.setStyle(Paint.Style.STROKE); paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(1.0f); paint.setStrokeWidth(1.0f);
paint.setColor(color); paint.setColor(color);
canvas.drawLine(x, 0, x, h, paint); canvas.drawLine(x, 0.0f, x, h, paint);
} }
private static void drawRectangle(final Canvas canvas, final float x, final float y, private static void drawRectangle(final Canvas canvas, final float x, final float y,
@ -595,15 +554,20 @@ public class KeyboardView extends View {
paint.setStrokeWidth(1.0f); paint.setStrokeWidth(1.0f);
paint.setColor(color); paint.setColor(color);
canvas.translate(x, y); canvas.translate(x, y);
canvas.drawRect(0, 0, w, h, paint); canvas.drawRect(0.0f, 0.0f, w, h, paint);
canvas.translate(-x, -y); canvas.translate(-x, -y);
} }
public Paint newDefaultLabelPaint() { public Paint newLabelPaint(final Key key) {
final Paint paint = new Paint(); final Paint paint = new Paint();
paint.setAntiAlias(true); paint.setAntiAlias(true);
if (key == null) {
paint.setTypeface(mKeyDrawParams.mTypeface); paint.setTypeface(mKeyDrawParams.mTypeface);
paint.setTextSize(mKeyDrawParams.mLabelSize); paint.setTextSize(mKeyDrawParams.mLabelSize);
} else {
paint.setTypeface(key.selectTypeface(mKeyDrawParams));
paint.setTextSize(key.selectTextSize(mKeyDrawParams));
}
return paint; return paint;
} }

View File

@ -530,9 +530,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator, 0); R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator, 0);
final float keyHysteresisDistance = mainKeyboardViewAttr.getDimension( final float keyHysteresisDistance = mainKeyboardViewAttr.getDimension(
R.styleable.MainKeyboardView_keyHysteresisDistance, 0); R.styleable.MainKeyboardView_keyHysteresisDistance, 0.0f);
final float keyHysteresisDistanceForSlidingModifier = mainKeyboardViewAttr.getDimension( final float keyHysteresisDistanceForSlidingModifier = mainKeyboardViewAttr.getDimension(
R.styleable.MainKeyboardView_keyHysteresisDistanceForSlidingModifier, 0); R.styleable.MainKeyboardView_keyHysteresisDistanceForSlidingModifier, 0.0f);
mKeyDetector = new KeyDetector( mKeyDetector = new KeyDetector(
keyHysteresisDistance, keyHysteresisDistanceForSlidingModifier); keyHysteresisDistance, keyHysteresisDistanceForSlidingModifier);
mKeyTimerHandler = new KeyTimerHandler(this, mainKeyboardViewAttr); mKeyTimerHandler = new KeyTimerHandler(this, mainKeyboardViewAttr);
@ -655,7 +655,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
mKeyTimerHandler.cancelLongPressTimer(); mKeyTimerHandler.cancelLongPressTimer();
super.setKeyboard(keyboard); super.setKeyboard(keyboard);
mKeyDetector.setKeyboard( mKeyDetector.setKeyboard(
keyboard, -getPaddingLeft(), -getPaddingTop() + mVerticalCorrection); keyboard, -getPaddingLeft(), -getPaddingTop() + getVerticalCorrection());
PointerTracker.setKeyDetector(mKeyDetector); PointerTracker.setKeyDetector(mKeyDetector);
mTouchScreenRegulator.setKeyboardGeometry(keyboard.mOccupiedWidth); mTouchScreenRegulator.setKeyboardGeometry(keyboard.mOccupiedWidth);
mMoreKeysKeyboardCache.clear(); mMoreKeysKeyboardCache.clear();
@ -1329,7 +1329,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
// Overlay a dark rectangle to dim. // Overlay a dark rectangle to dim.
if (mNeedsToDimEntireKeyboard) { if (mNeedsToDimEntireKeyboard) {
canvas.drawRect(0, 0, getWidth(), getHeight(), mBackgroundDimAlphaPaint); canvas.drawRect(0.0f, 0.0f, getWidth(), getHeight(), mBackgroundDimAlphaPaint);
} }
} }
@ -1353,9 +1353,10 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
} }
} }
private boolean fitsTextIntoWidth(final int width, final String text, final Paint paint) { private static boolean fitsTextIntoWidth(final int width, final String text,
final Paint paint) {
paint.setTextScaleX(1.0f); paint.setTextScaleX(1.0f);
final float textWidth = getLabelWidth(text, paint); final float textWidth = TypefaceUtils.getLabelWidth(text, paint);
if (textWidth < width) { if (textWidth < width) {
return true; return true;
} }
@ -1366,12 +1367,12 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
} }
paint.setTextScaleX(scaleX); paint.setTextScaleX(scaleX);
return getLabelWidth(text, paint) < width; return TypefaceUtils.getLabelWidth(text, paint) < width;
} }
// Layout language name on spacebar. // Layout language name on spacebar.
private String layoutLanguageOnSpacebar(final Paint paint, final InputMethodSubtype subtype, private static String layoutLanguageOnSpacebar(final Paint paint,
final int width) { final InputMethodSubtype subtype, final int width) {
// Choose appropriate language name to fit into the width. // Choose appropriate language name to fit into the width.
final String fullText = getFullDisplayName(subtype); final String fullText = getFullDisplayName(subtype);
if (fitsTextIntoWidth(width, fullText, paint)) { if (fitsTextIntoWidth(width, fullText, paint)) {

View File

@ -17,6 +17,7 @@
package com.android.inputmethod.keyboard; package com.android.inputmethod.keyboard;
import android.content.Context; import android.content.Context;
import android.content.res.Resources;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
@ -257,7 +258,6 @@ public final class MoreKeysKeyboard extends Keyboard {
private static final float LABEL_PADDING_RATIO = 0.2f; private static final float LABEL_PADDING_RATIO = 0.2f;
private static final float DIVIDER_RATIO = 0.2f; private static final float DIVIDER_RATIO = 0.2f;
/** /**
* The builder of MoreKeysKeyboard. * The builder of MoreKeysKeyboard.
* @param context the context of {@link MoreKeysKeyboardView}. * @param context the context of {@link MoreKeysKeyboardView}.
@ -289,10 +289,10 @@ public final class MoreKeysKeyboard extends Keyboard {
// be considered because the vertical positions of both backgrounds were already // be considered because the vertical positions of both backgrounds were already
// adjusted with their bottom paddings deducted. // adjusted with their bottom paddings deducted.
width = keyPreviewDrawParams.mPreviewVisibleWidth; width = keyPreviewDrawParams.mPreviewVisibleWidth;
height = keyPreviewDrawParams.mPreviewVisibleHeight height = keyPreviewDrawParams.mPreviewVisibleHeight + mParams.mVerticalGap;
+ mParams.mVerticalGap;
} else { } else {
width = getMaxKeyWidth(parentKeyboardView, parentKey, mParams.mDefaultKeyWidth); width = getMaxKeyWidth(parentKeyboardView, parentKey, mParams.mDefaultKeyWidth,
context.getResources());
height = parentKeyboard.mMostCommonKeyHeight; height = parentKeyboard.mMostCommonKeyHeight;
} }
final int dividerWidth; final int dividerWidth;
@ -310,22 +310,18 @@ public final class MoreKeysKeyboard extends Keyboard {
} }
private static int getMaxKeyWidth(final KeyboardView view, final Key parentKey, private static int getMaxKeyWidth(final KeyboardView view, final Key parentKey,
final int minKeyWidth) { final int minKeyWidth, final Resources res) {
final int padding = (int)(view.getResources() final float padding =
.getDimension(R.dimen.more_keys_keyboard_key_horizontal_padding) res.getDimension(R.dimen.more_keys_keyboard_key_horizontal_padding)
+ (parentKey.hasLabelsInMoreKeys() ? minKeyWidth * LABEL_PADDING_RATIO : 0)); + (parentKey.hasLabelsInMoreKeys() ? minKeyWidth * LABEL_PADDING_RATIO : 0.0f);
final Paint paint = view.newDefaultLabelPaint(); final Paint paint = view.newLabelPaint(parentKey);
paint.setTypeface(parentKey.selectTypeface(view.mKeyDrawParams));
paint.setTextSize(parentKey.selectMoreKeyTextSize(view.mKeyDrawParams));
int maxWidth = minKeyWidth; int maxWidth = minKeyWidth;
for (final MoreKeySpec spec : parentKey.mMoreKeys) { for (final MoreKeySpec spec : parentKey.mMoreKeys) {
final String label = spec.mLabel; final String label = spec.mLabel;
// If the label is single letter, minKeyWidth is enough to hold the label. // If the label is single letter, minKeyWidth is enough to hold the label.
if (label != null && StringUtils.codePointCount(label) > 1) { if (label != null && StringUtils.codePointCount(label) > 1) {
final int width = (int)view.getLabelWidth(label, paint) + padding; maxWidth = Math.max(maxWidth,
if (maxWidth < width) { (int)(TypefaceUtils.getLabelWidth(label, paint) + padding));
maxWidth = width;
}
} }
} }
return maxWidth; return maxWidth;

View File

@ -71,7 +71,7 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel
public void setKeyboard(final Keyboard keyboard) { public void setKeyboard(final Keyboard keyboard) {
super.setKeyboard(keyboard); super.setKeyboard(keyboard);
mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(),
-getPaddingTop() + mVerticalCorrection); -getPaddingTop() + getVerticalCorrection());
} }
@Override @Override

View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.inputmethod.keyboard;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.SparseArray;
import com.android.inputmethod.latin.CollectionUtils;
public final class TypefaceUtils {
private TypefaceUtils() {
// This utility class is not publicly instantiable.
}
// This sparse array caches key label text height in pixel indexed by key label text size.
private static final SparseArray<Float> sTextHeightCache = CollectionUtils.newSparseArray();
// Working variable for the following method.
private static final Rect sTextHeightBounds = new Rect();
public static float getCharHeight(final char[] referenceChar, final Paint paint) {
final int key = getCharGeometryCacheKey(referenceChar[0], paint);
synchronized (sTextHeightCache) {
final Float cachedValue = sTextHeightCache.get(key);
if (cachedValue != null) {
return cachedValue;
}
paint.getTextBounds(referenceChar, 0, 1, sTextHeightBounds);
final float height = sTextHeightBounds.height();
sTextHeightCache.put(key, height);
return height;
}
}
// This sparse array caches key label text width in pixel indexed by key label text size.
private static final SparseArray<Float> sTextWidthCache = CollectionUtils.newSparseArray();
// Working variable for the following method.
private static final Rect sTextWidthBounds = new Rect();
public static float getCharWidth(final char[] referenceChar, final Paint paint) {
final int key = getCharGeometryCacheKey(referenceChar[0], paint);
synchronized (sTextWidthCache) {
final Float cachedValue = sTextWidthCache.get(key);
if (cachedValue != null) {
return cachedValue;
}
paint.getTextBounds(referenceChar, 0, 1, sTextWidthBounds);
final float width = sTextWidthBounds.width();
sTextWidthCache.put(key, width);
return width;
}
}
private static int getCharGeometryCacheKey(final char referenceChar, final Paint paint) {
final int labelSize = (int)paint.getTextSize();
final Typeface face = paint.getTypeface();
final int codePointOffset = referenceChar << 15;
if (face == Typeface.DEFAULT) {
return codePointOffset + labelSize;
} else if (face == Typeface.DEFAULT_BOLD) {
return codePointOffset + labelSize + 0x1000;
} else if (face == Typeface.MONOSPACE) {
return codePointOffset + labelSize + 0x2000;
} else {
return codePointOffset + labelSize;
}
}
public static float getLabelWidth(final String label, final Paint paint) {
final Rect textBounds = new Rect();
paint.getTextBounds(label, 0, label.length(), textBounds);
return textBounds.width();
}
}

View File

@ -16,12 +16,14 @@
package com.android.inputmethod.latin.suggestions; package com.android.inputmethod.latin.suggestions;
import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.TypefaceUtils;
import com.android.inputmethod.keyboard.internal.KeyboardBuilder; import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
import com.android.inputmethod.keyboard.internal.KeyboardParams; import com.android.inputmethod.keyboard.internal.KeyboardParams;
@ -50,16 +52,12 @@ public final class MoreSuggestions extends Keyboard {
super(); super();
} }
// TODO: Remove {@link MoreSuggestionsView} argument.
public int layout(final SuggestedWords suggestions, final int fromPos, final int maxWidth, public int layout(final SuggestedWords suggestions, final int fromPos, final int maxWidth,
final int minWidth, final int maxRow, final MoreSuggestionsView view) { final int minWidth, final int maxRow, final Paint paint, final Resources res) {
clearKeys(); clearKeys();
final Resources res = view.getResources();
mDivider = res.getDrawable(R.drawable.more_suggestions_divider); mDivider = res.getDrawable(R.drawable.more_suggestions_divider);
mDividerWidth = mDivider.getIntrinsicWidth(); mDividerWidth = mDivider.getIntrinsicWidth();
final int padding = (int) res.getDimension( final float padding = res.getDimension(R.dimen.more_suggestions_key_horizontal_padding);
R.dimen.more_suggestions_key_horizontal_padding);
final Paint paint = view.newDefaultLabelPaint();
int row = 0; int row = 0;
int pos = fromPos, rowStartPos = fromPos; int pos = fromPos, rowStartPos = fromPos;
@ -67,7 +65,7 @@ public final class MoreSuggestions extends Keyboard {
while (pos < size) { while (pos < size) {
final String word = suggestions.getWord(pos); final String word = suggestions.getWord(pos);
// TODO: Should take care of text x-scaling. // TODO: Should take care of text x-scaling.
mWidths[pos] = (int)view.getLabelWidth(word, paint) + padding; mWidths[pos] = (int)(TypefaceUtils.getLabelWidth(word, paint) + padding);
final int numColumn = pos - rowStartPos + 1; final int numColumn = pos - rowStartPos + 1;
final int columnWidth = final int columnWidth =
(maxWidth - mDividerWidth * (numColumn - 1)) / numColumn; (maxWidth - mDividerWidth * (numColumn - 1)) / numColumn;
@ -169,8 +167,8 @@ public final class MoreSuggestions extends Keyboard {
private int mFromPos; private int mFromPos;
private int mToPos; private int mToPos;
public Builder(final MoreSuggestionsView paneView) { public Builder(final Context context, final MoreSuggestionsView paneView) {
super(paneView.getContext(), new MoreSuggestionsParam()); super(context, new MoreSuggestionsParam());
mPaneView = paneView; mPaneView = paneView;
} }
@ -183,7 +181,7 @@ public final class MoreSuggestions extends Keyboard {
mPaneView.updateKeyboardGeometry(mParams.mDefaultRowHeight); mPaneView.updateKeyboardGeometry(mParams.mDefaultRowHeight);
final int count = mParams.layout(suggestions, fromPos, maxWidth, minWidth, maxRow, final int count = mParams.layout(suggestions, fromPos, maxWidth, minWidth, maxRow,
mPaneView); mPaneView.newLabelPaint(null /* key */), mResources);
mFromPos = fromPos; mFromPos = fromPos;
mToPos = fromPos + count; mToPos = fromPos + count;
mSuggestions = suggestions; mSuggestions = suggestions;

View File

@ -43,7 +43,7 @@ public final class MoreSuggestionsView extends MoreKeysKeyboardView {
} }
public void updateKeyboardGeometry(final int keyHeight) { public void updateKeyboardGeometry(final int keyHeight) {
mKeyDrawParams.updateParams(keyHeight, mKeyVisualAttributes); updateKeyDrawParams(keyHeight);
} }
@Override @Override

View File

@ -596,7 +596,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
mMoreSuggestionsContainer = inflater.inflate(R.layout.more_suggestions, null); mMoreSuggestionsContainer = inflater.inflate(R.layout.more_suggestions, null);
mMoreSuggestionsView = (MoreSuggestionsView)mMoreSuggestionsContainer mMoreSuggestionsView = (MoreSuggestionsView)mMoreSuggestionsContainer
.findViewById(R.id.more_suggestions_view); .findViewById(R.id.more_suggestions_view);
mMoreSuggestionsBuilder = new MoreSuggestions.Builder(mMoreSuggestionsView); mMoreSuggestionsBuilder = new MoreSuggestions.Builder(context, mMoreSuggestionsView);
final Resources res = context.getResources(); final Resources res = context.getResources();
mMoreSuggestionsModalTolerance = res.getDimensionPixelOffset( mMoreSuggestionsModalTolerance = res.getDimensionPixelOffset(