1 /* 2 * Copyright (C) 2011 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.bidi; 18 19 import android.content.Context; 20 import android.graphics.Canvas; 21 import android.graphics.Color; 22 import android.graphics.Paint; 23 import android.graphics.Rect; 24 import android.text.TextPaint; 25 import android.util.AttributeSet; 26 import android.util.Log; 27 import android.view.View; 28 29 public class BiDiTestView extends View { 30 31 private static final String TAG = "BiDiTestView"; 32 33 private static final int BORDER_PADDING = 4; 34 private static final int TEXT_PADDING = 16; 35 private static final int TEXT_SIZE = 16; 36 private static final int ORIGIN = 80; 37 38 private static final float DEFAULT_ITALIC_SKEW_X = -0.25f; 39 40 private Rect rect = new Rect(); 41 42 private String NORMAL_TEXT; 43 private String NORMAL_LONG_TEXT; 44 private String NORMAL_LONG_TEXT_2; 45 private String NORMAL_LONG_TEXT_3; 46 private String ITALIC_TEXT; 47 private String BOLD_TEXT; 48 private String BOLD_ITALIC_TEXT; 49 private String ARABIC_TEXT; 50 private String CHINESE_TEXT; 51 private String MIXED_TEXT_1; 52 private String HEBREW_TEXT; 53 private String RTL_TEXT; 54 private String THAI_TEXT; 55 56 private int currentTextSize; 57 BiDiTestView(Context context)58 public BiDiTestView(Context context) { 59 super(context); 60 init(context); 61 } 62 BiDiTestView(Context context, AttributeSet attrs)63 public BiDiTestView(Context context, AttributeSet attrs) { 64 super(context, attrs); 65 init(context); 66 } 67 BiDiTestView(Context context, AttributeSet attrs, int defStyle)68 public BiDiTestView(Context context, AttributeSet attrs, int defStyle) { 69 super(context, attrs, defStyle); 70 init(context); 71 } 72 init(Context context)73 private void init(Context context) { 74 NORMAL_TEXT = context.getString(R.string.normal_text); 75 NORMAL_LONG_TEXT = context.getString(R.string.normal_long_text); 76 NORMAL_LONG_TEXT_2 = context.getString(R.string.normal_long_text_2); 77 NORMAL_LONG_TEXT_3 = context.getString(R.string.normal_long_text_3); 78 ITALIC_TEXT = context.getString(R.string.italic_text); 79 BOLD_TEXT = context.getString(R.string.bold_text); 80 BOLD_ITALIC_TEXT = context.getString(R.string.bold_italic_text); 81 ARABIC_TEXT = context.getString(R.string.arabic_text); 82 CHINESE_TEXT = context.getString(R.string.chinese_text); 83 MIXED_TEXT_1 = context.getString(R.string.mixed_text_1); 84 HEBREW_TEXT = context.getString(R.string.hebrew_text); 85 RTL_TEXT = context.getString(R.string.rtl); 86 THAI_TEXT = context.getString(R.string.pointer_location); 87 } 88 setCurrentTextSize(int size)89 public void setCurrentTextSize(int size) { 90 currentTextSize = size; 91 invalidate(); 92 } 93 94 @Override onDraw(Canvas canvas)95 public void onDraw(Canvas canvas) { 96 drawInsideRect(canvas, new Paint(), Color.BLACK); 97 98 int deltaX = 0; 99 100 deltaX = testString(canvas, NORMAL_TEXT, ORIGIN, ORIGIN, 101 false, false, Paint.DIRECTION_LTR, currentTextSize); 102 103 deltaX += testString(canvas, ITALIC_TEXT, ORIGIN + deltaX, ORIGIN, 104 true, false, Paint.DIRECTION_LTR, currentTextSize); 105 106 deltaX += testString(canvas, BOLD_TEXT, ORIGIN + deltaX, ORIGIN, 107 false, true, Paint.DIRECTION_LTR, currentTextSize); 108 109 deltaX += testString(canvas, BOLD_ITALIC_TEXT, ORIGIN + deltaX, ORIGIN, 110 true, true, Paint.DIRECTION_LTR, currentTextSize); 111 112 // Test with a long string 113 deltaX = testString(canvas, NORMAL_LONG_TEXT, ORIGIN, ORIGIN + 2 * currentTextSize, 114 false, false, Paint.DIRECTION_LTR, currentTextSize); 115 116 // Test with a long string 117 deltaX = testString(canvas, NORMAL_LONG_TEXT_2, ORIGIN, ORIGIN + 4 * currentTextSize, 118 false, false, Paint.DIRECTION_LTR, currentTextSize); 119 120 // Test with a long string 121 deltaX = testString(canvas, NORMAL_LONG_TEXT_3, ORIGIN, ORIGIN + 6 * currentTextSize, 122 false, false, Paint.DIRECTION_LTR, currentTextSize); 123 124 // Test Arabic ligature 125 deltaX = testString(canvas, ARABIC_TEXT, ORIGIN, ORIGIN + 8 * currentTextSize, 126 false, false, Paint.DIRECTION_RTL, currentTextSize); 127 128 // Test Chinese 129 deltaX = testString(canvas, CHINESE_TEXT, ORIGIN, ORIGIN + 10 * currentTextSize, 130 false, false, Paint.DIRECTION_LTR, currentTextSize); 131 132 // Test Mixed (English and Arabic) 133 deltaX = testString(canvas, MIXED_TEXT_1, ORIGIN, ORIGIN + 12 * currentTextSize, 134 false, false, Paint.DIRECTION_LTR, currentTextSize); 135 136 // Test Hebrew 137 deltaX = testString(canvas, RTL_TEXT, ORIGIN, ORIGIN + 14 * currentTextSize, 138 false, false, Paint.DIRECTION_RTL, currentTextSize); 139 140 // Test Thai 141 deltaX = testString(canvas, THAI_TEXT, ORIGIN, ORIGIN + 16 * currentTextSize, 142 false, false, Paint.DIRECTION_LTR, currentTextSize); 143 } 144 testString(Canvas canvas, String text, int x, int y, boolean isItalic, boolean isBold, int dir, int textSize)145 private int testString(Canvas canvas, String text, int x, int y, 146 boolean isItalic, boolean isBold, int dir, int textSize) { 147 148 TextPaint paint = new TextPaint(); 149 paint.setAntiAlias(true); 150 151 // Set paint properties 152 boolean oldFakeBold = paint.isFakeBoldText(); 153 paint.setFakeBoldText(isBold); 154 155 float oldTextSkewX = paint.getTextSkewX(); 156 if (isItalic) { 157 paint.setTextSkewX(DEFAULT_ITALIC_SKEW_X); 158 } 159 160 paint.setTextSize(textSize); 161 paint.setColor(Color.WHITE); 162 canvas.drawText(text, x, y, paint); 163 164 int length = text.length(); 165 float[] advances = new float[length]; 166 float textWidthHB = paint.getTextRunAdvances(text, 0, length, 0, length, dir, advances, 0); 167 setPaintDir(paint, dir); 168 float textWidthICU = paint.getTextRunAdvances(text, 0, length, 0, length, dir, advances, 0, 169 1 /* use ICU */); 170 171 logAdvances(text, textWidthHB, textWidthICU, advances); 172 drawMetricsAroundText(canvas, x, y, textWidthHB, textWidthICU, textSize, Color.RED, Color.GREEN); 173 174 // Restore old paint properties 175 paint.setFakeBoldText(oldFakeBold); 176 paint.setTextSkewX(oldTextSkewX); 177 178 return (int) Math.ceil(textWidthHB) + TEXT_PADDING; 179 } 180 setPaintDir(Paint paint, int dir)181 private void setPaintDir(Paint paint, int dir) { 182 Log.v(TAG, "Setting Paint dir=" + dir); 183 paint.setBidiFlags(dir); 184 } 185 drawInsideRect(Canvas canvas, Paint paint, int color)186 private void drawInsideRect(Canvas canvas, Paint paint, int color) { 187 paint.setColor(color); 188 int width = getWidth(); 189 int height = getHeight(); 190 rect.set(BORDER_PADDING, BORDER_PADDING, width - BORDER_PADDING, height - BORDER_PADDING); 191 canvas.drawRect(rect, paint); 192 } 193 drawMetricsAroundText(Canvas canvas, int x, int y, float textWidthHB, float textWidthICU, int textSize, int color, int colorICU)194 private void drawMetricsAroundText(Canvas canvas, int x, int y, float textWidthHB, 195 float textWidthICU, int textSize, int color, int colorICU) { 196 Paint paint = new Paint(); 197 paint.setColor(color); 198 canvas.drawLine(x, y - textSize, x, y + 8, paint); 199 canvas.drawLine(x, y + 8, x + textWidthHB, y + 8, paint); 200 canvas.drawLine(x + textWidthHB, y - textSize, x + textWidthHB, y + 8, paint); 201 paint.setColor(colorICU); 202 canvas.drawLine(x + textWidthICU, y - textSize, x + textWidthICU, y + 8, paint); 203 } 204 logAdvances(String text, float textWidth, float textWidthICU, float[] advances)205 private void logAdvances(String text, float textWidth, float textWidthICU, float[] advances) { 206 Log.v(TAG, "Advances for text: " + text + " total= " + textWidth + " - totalICU= " + textWidthICU); 207 // int length = advances.length; 208 // for(int n=0; n<length; n++){ 209 // Log.v(TAG, "adv[" + n + "]=" + advances[n]); 210 // } 211 } 212 } 213