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 BiDiTestView(Context context)57 public BiDiTestView(Context context) { 58 super(context); 59 init(context); 60 } 61 BiDiTestView(Context context, AttributeSet attrs)62 public BiDiTestView(Context context, AttributeSet attrs) { 63 super(context, attrs); 64 init(context); 65 } 66 BiDiTestView(Context context, AttributeSet attrs, int defStyle)67 public BiDiTestView(Context context, AttributeSet attrs, int defStyle) { 68 super(context, attrs, defStyle); 69 init(context); 70 } 71 init(Context context)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 setCurrentTextSize(int size)87 public void setCurrentTextSize(int size) { 88 currentTextSize = size; 89 invalidate(); 90 } 91 92 @Override onDraw(Canvas canvas)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 testString(Canvas canvas, String text, int x, int y, boolean isItalic, boolean isBold, int dir, int textSize)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 setPaintDir(Paint paint, int dir)175 private void setPaintDir(Paint paint, int dir) { 176 Log.v(TAG, "Setting Paint dir=" + dir); 177 paint.setBidiFlags(dir); 178 } 179 drawInsideRect(Canvas canvas, Paint paint, int color)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 drawMetricsAroundText(Canvas canvas, int x, int y, float textWidthHB, float textWidthICU, int textSize, int color, int colorICU)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 logAdvances(String text, float textWidth, float textWidthICU, float[] advances)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