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