Styled.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
1/* 2 * Copyright (C) 2006 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 17package android.text; 18 19import android.graphics.Paint; 20import android.graphics.Canvas; 21import android.graphics.Path; 22import android.graphics.RectF; 23import android.graphics.Typeface; 24import android.graphics.MaskFilter; 25import android.graphics.Rasterizer; 26import android.graphics.LayerRasterizer; 27import android.text.style.*; 28 29/* package */ class Styled 30{ 31 private static float each(Canvas canvas, 32 Spanned text, int start, int end, 33 int dir, boolean reverse, 34 float x, int top, int y, int bottom, 35 Paint.FontMetricsInt fm, 36 TextPaint realPaint, 37 TextPaint paint, 38 boolean needwid) { 39 40 boolean havewid = false; 41 float ret = 0; 42 CharacterStyle[] spans = text.getSpans(start, end, CharacterStyle.class); 43 44 ReplacementSpan replacement = null; 45 46 realPaint.bgColor = 0; 47 realPaint.baselineShift = 0; 48 paint.set(realPaint); 49 50 if (spans.length > 0) { 51 for (int i = 0; i < spans.length; i++) { 52 CharacterStyle span = spans[i]; 53 54 if (span instanceof ReplacementSpan) { 55 replacement = (ReplacementSpan)span; 56 } 57 else { 58 span.updateDrawState(paint); 59 } 60 } 61 } 62 63 if (replacement == null) { 64 CharSequence tmp; 65 int tmpstart, tmpend; 66 67 if (reverse) { 68 tmp = TextUtils.getReverse(text, start, end); 69 tmpstart = 0; 70 tmpend = end - start; 71 } else { 72 tmp = text; 73 tmpstart = start; 74 tmpend = end; 75 } 76 77 if (fm != null) { 78 paint.getFontMetricsInt(fm); 79 } 80 81 if (canvas != null) { 82 if (paint.bgColor != 0) { 83 int c = paint.getColor(); 84 Paint.Style s = paint.getStyle(); 85 paint.setColor(paint.bgColor); 86 paint.setStyle(Paint.Style.FILL); 87 88 if (!havewid) { 89 ret = paint.measureText(tmp, tmpstart, tmpend); 90 havewid = true; 91 } 92 93 if (dir == Layout.DIR_RIGHT_TO_LEFT) 94 canvas.drawRect(x - ret, top, x, bottom, paint); 95 else 96 canvas.drawRect(x, top, x + ret, bottom, paint); 97 98 paint.setStyle(s); 99 paint.setColor(c); 100 } 101 102 if (dir == Layout.DIR_RIGHT_TO_LEFT) { 103 if (!havewid) { 104 ret = paint.measureText(tmp, tmpstart, tmpend); 105 havewid = true; 106 } 107 108 canvas.drawText(tmp, tmpstart, tmpend, 109 x - ret, y + paint.baselineShift, paint); 110 } else { 111 if (needwid) { 112 if (!havewid) { 113 ret = paint.measureText(tmp, tmpstart, tmpend); 114 havewid = true; 115 } 116 } 117 118 canvas.drawText(tmp, tmpstart, tmpend, 119 x, y + paint.baselineShift, paint); 120 } 121 } else { 122 if (needwid && !havewid) { 123 ret = paint.measureText(tmp, tmpstart, tmpend); 124 havewid = true; 125 } 126 } 127 } else { 128 ret = replacement.getSize(paint, text, start, end, fm); 129 130 if (canvas != null) { 131 if (dir == Layout.DIR_RIGHT_TO_LEFT) 132 replacement.draw(canvas, text, start, end, 133 x - ret, top, y, bottom, paint); 134 else 135 replacement.draw(canvas, text, start, end, 136 x, top, y, bottom, paint); 137 } 138 } 139 140 if (dir == Layout.DIR_RIGHT_TO_LEFT) 141 return -ret; 142 else 143 return ret; 144 } 145 146 public static int getTextWidths(TextPaint realPaint, 147 TextPaint paint, 148 Spanned text, int start, int end, 149 float[] widths, Paint.FontMetricsInt fm) { 150 151 MetricAffectingSpan[] spans = text.getSpans(start, end, MetricAffectingSpan.class); 152 153 ReplacementSpan replacement = null; 154 paint.set(realPaint); 155 156 for (int i = 0; i < spans.length; i++) { 157 MetricAffectingSpan span = spans[i]; 158 if (span instanceof ReplacementSpan) { 159 replacement = (ReplacementSpan)span; 160 } 161 else { 162 span.updateMeasureState(paint); 163 } 164 } 165 166 if (replacement == null) { 167 paint.getFontMetricsInt(fm); 168 paint.getTextWidths(text, start, end, widths); 169 } else { 170 int wid = replacement.getSize(paint, text, start, end, fm); 171 172 if (end > start) { 173 widths[0] = wid; 174 175 for (int i = start + 1; i < end; i++) 176 widths[i - start] = 0; 177 } 178 } 179 return end - start; 180 } 181 182 private static float foreach(Canvas canvas, 183 CharSequence text, int start, int end, 184 int dir, boolean reverse, 185 float x, int top, int y, int bottom, 186 Paint.FontMetricsInt fm, 187 TextPaint paint, 188 TextPaint workPaint, 189 boolean needwid) { 190 if (! (text instanceof Spanned)) { 191 float ret = 0; 192 193 if (reverse) { 194 CharSequence tmp = TextUtils.getReverse(text, start, end); 195 int tmpend = end - start; 196 197 if (canvas != null || needwid) 198 ret = paint.measureText(tmp, 0, tmpend); 199 200 if (canvas != null) 201 canvas.drawText(tmp, 0, tmpend, 202 x - ret, y, paint); 203 } else { 204 if (needwid) 205 ret = paint.measureText(text, start, end); 206 207 if (canvas != null) 208 canvas.drawText(text, start, end, x, y, paint); 209 } 210 211 if (fm != null) { 212 paint.getFontMetricsInt(fm); 213 } 214 215 return ret * dir; //Layout.DIR_RIGHT_TO_LEFT == -1 216 } 217 218 float ox = x; 219 int asc = 0, desc = 0; 220 int ftop = 0, fbot = 0; 221 222 Spanned sp = (Spanned) text; 223 Class division; 224 225 if (canvas == null) 226 division = MetricAffectingSpan.class; 227 else 228 division = CharacterStyle.class; 229 230 int next; 231 for (int i = start; i < end; i = next) { 232 next = sp.nextSpanTransition(i, end, division); 233 234 x += each(canvas, sp, i, next, dir, reverse, 235 x, top, y, bottom, fm, paint, workPaint, 236 needwid || next != end); 237 238 if (fm != null) { 239 if (fm.ascent < asc) 240 asc = fm.ascent; 241 if (fm.descent > desc) 242 desc = fm.descent; 243 244 if (fm.top < ftop) 245 ftop = fm.top; 246 if (fm.bottom > fbot) 247 fbot = fm.bottom; 248 } 249 } 250 251 if (fm != null) { 252 if (start == end) { 253 paint.getFontMetricsInt(fm); 254 } else { 255 fm.ascent = asc; 256 fm.descent = desc; 257 fm.top = ftop; 258 fm.bottom = fbot; 259 } 260 } 261 262 return x - ox; 263 } 264 265 public static float drawText(Canvas canvas, 266 CharSequence text, int start, int end, 267 int dir, boolean reverse, 268 float x, int top, int y, int bottom, 269 TextPaint paint, 270 TextPaint workPaint, 271 boolean needwid) { 272 if ((dir == Layout.DIR_RIGHT_TO_LEFT && !reverse)||(reverse && dir == Layout.DIR_LEFT_TO_RIGHT)) { 273 float ch = foreach(null, text, start, end, Layout.DIR_LEFT_TO_RIGHT, 274 false, 0, 0, 0, 0, null, paint, workPaint, 275 true); 276 277 ch *= dir; // DIR_RIGHT_TO_LEFT == -1 278 foreach(canvas, text, start, end, -dir, 279 reverse, x + ch, top, y, bottom, null, paint, 280 workPaint, true); 281 282 return ch; 283 } 284 285 return foreach(canvas, text, start, end, dir, reverse, 286 x, top, y, bottom, null, paint, workPaint, 287 needwid); 288 } 289 290 public static float measureText(TextPaint paint, 291 TextPaint workPaint, 292 CharSequence text, int start, int end, 293 Paint.FontMetricsInt fm) { 294 return foreach(null, text, start, end, 295 Layout.DIR_LEFT_TO_RIGHT, false, 296 0, 0, 0, 0, fm, paint, workPaint, true); 297 } 298} 299