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 58 public BiDiTestView(Context context) { 59 super(context); 60 init(context); 61 } 62 63 public BiDiTestView(Context context, AttributeSet attrs) { 64 super(context, attrs); 65 init(context); 66 } 67 68 public BiDiTestView(Context context, AttributeSet attrs, int defStyle) { 69 super(context, attrs, defStyle); 70 init(context); 71 } 72 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 89 public void setCurrentTextSize(int size) { 90 currentTextSize = size; 91 invalidate(); 92 } 93 94 @Override 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 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 181 private void setPaintDir(Paint paint, int dir) { 182 Log.v(TAG, "Setting Paint dir=" + dir); 183 paint.setBidiFlags(dir); 184 } 185 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 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 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