1 5 package java.awt.font; 6 7 import java.awt.Font ; 8 import java.awt.Toolkit ; 9 import java.awt.im.InputMethodHighlight ; 10 import java.text.Annotation ; 11 import java.text.AttributedCharacterIterator ; 12 import java.util.Vector ; 13 import java.util.Hashtable ; 14 import java.util.Map ; 15 import sun.font.Decoration; 16 import sun.font.FontResolver; 17 import sun.text.CodePointIterator; 18 19 26 final class StyledParagraph { 27 28 private int length; 30 31 34 private Decoration decoration; 35 36 private Object font; 39 40 private Vector decorations; 44 int[] decorationStarts; 49 50 private Vector fonts; 55 int[] fontStarts; 60 61 private static int INITIAL_SIZE = 8; 62 63 68 public StyledParagraph(AttributedCharacterIterator aci, 69 char[] chars) { 70 71 int start = aci.getBeginIndex(); 72 int end = aci.getEndIndex(); 73 length = end - start; 74 75 int index = start; 76 aci.first(); 77 78 do { 79 final int nextRunStart = aci.getRunLimit(); 80 final int localIndex = index-start; 81 82 Map attributes = aci.getAttributes(); 83 attributes = addInputMethodAttrs(attributes); 84 Decoration d = Decoration.getDecoration(attributes); 85 addDecoration(d, localIndex); 86 87 Object f = getGraphicOrFont(attributes); 88 if (f == null) { 89 addFonts(chars, attributes, localIndex, nextRunStart-start); 90 } 91 else { 92 addFont(f, localIndex); 93 } 94 95 aci.setIndex(nextRunStart); 96 index = nextRunStart; 97 98 } while (index < end); 99 100 if (decorations != null) { 104 decorationStarts = addToVector(this, length, decorations, decorationStarts); 105 } 106 if (fonts != null) { 107 fontStarts = addToVector(this, length, fonts, fontStarts); 108 } 109 } 110 111 115 private static void insertInto(int pos, int[] starts, int numStarts) { 116 117 while (starts[--numStarts] > pos) { 118 starts[numStarts] += 1; 119 } 120 } 121 122 134 public static StyledParagraph insertChar(AttributedCharacterIterator aci, 135 char[] chars, 136 int insertPos, 137 StyledParagraph oldParagraph) { 138 139 143 char ch = aci.setIndex(insertPos); 144 int relativePos = Math.max(insertPos - aci.getBeginIndex() - 1, 0); 145 146 Map attributes = addInputMethodAttrs(aci.getAttributes()); 147 Decoration d = Decoration.getDecoration(attributes); 148 if (!oldParagraph.getDecorationAt(relativePos).equals(d)) { 149 return new StyledParagraph (aci, chars); 150 } 151 Object f = getGraphicOrFont(attributes); 152 if (f == null) { 153 FontResolver resolver = FontResolver.getInstance(); 154 int fontIndex = resolver.getFontIndex(ch); 155 f = resolver.getFont(fontIndex, attributes); 156 } 157 if (!oldParagraph.getFontOrGraphicAt(relativePos).equals(f)) { 158 return new StyledParagraph (aci, chars); 159 } 160 161 oldParagraph.length += 1; 163 if (oldParagraph.decorations != null) { 164 insertInto(relativePos, 165 oldParagraph.decorationStarts, 166 oldParagraph.decorations.size()); 167 } 168 if (oldParagraph.fonts != null) { 169 insertInto(relativePos, 170 oldParagraph.fontStarts, 171 oldParagraph.fonts.size()); 172 } 173 return oldParagraph; 174 } 175 176 182 private static void deleteFrom(int deleteAt, int[] starts, int numStarts) { 183 184 while (starts[--numStarts] > deleteAt) { 185 starts[numStarts] -= 1; 186 } 187 } 188 189 201 public static StyledParagraph deleteChar(AttributedCharacterIterator aci, 202 char[] chars, 203 int deletePos, 204 StyledParagraph oldParagraph) { 205 206 deletePos -= aci.getBeginIndex(); 210 211 if (oldParagraph.decorations == null && oldParagraph.fonts == null) { 212 oldParagraph.length -= 1; 213 return oldParagraph; 214 } 215 216 if (oldParagraph.getRunLimit(deletePos) == deletePos+1) { 217 if (deletePos == 0 || oldParagraph.getRunLimit(deletePos-1) == deletePos) { 218 return new StyledParagraph (aci, chars); 219 } 220 } 221 222 oldParagraph.length -= 1; 223 if (oldParagraph.decorations != null) { 224 deleteFrom(deletePos, 225 oldParagraph.decorationStarts, 226 oldParagraph.decorations.size()); 227 } 228 if (oldParagraph.fonts != null) { 229 deleteFrom(deletePos, 230 oldParagraph.fontStarts, 231 oldParagraph.fonts.size()); 232 } 233 return oldParagraph; 234 } 235 236 243 public int getRunLimit(int index) { 244 245 if (index < 0 || index >= length) { 246 throw new IllegalArgumentException ("index out of range"); 247 } 248 int limit1 = length; 249 if (decorations != null) { 250 int run = findRunContaining(index, decorationStarts); 251 limit1 = decorationStarts[run+1]; 252 } 253 int limit2 = length; 254 if (fonts != null) { 255 int run = findRunContaining(index, fontStarts); 256 limit2 = fontStarts[run+1]; 257 } 258 return Math.min(limit1, limit2); 259 } 260 261 266 public Decoration getDecorationAt(int index) { 267 268 if (index < 0 || index >= length) { 269 throw new IllegalArgumentException ("index out of range"); 270 } 271 if (decorations == null) { 272 return decoration; 273 } 274 int run = findRunContaining(index, decorationStarts); 275 return (Decoration) decorations.elementAt(run); 276 } 277 278 285 public Object getFontOrGraphicAt(int index) { 286 287 if (index < 0 || index >= length) { 288 throw new IllegalArgumentException ("index out of range"); 289 } 290 if (fonts == null) { 291 return font; 292 } 293 int run = findRunContaining(index, fontStarts); 294 return fonts.elementAt(run); 295 } 296 297 302 private static int findRunContaining(int index, int[] starts) { 303 304 for (int i=1; true; i++) { 305 if (starts[i] > index) { 306 return i-1; 307 } 308 } 309 } 310 311 317 private static int[] addToVector(Object obj, 318 int index, 319 Vector v, 320 int[] starts) { 321 322 if (!v.lastElement().equals(obj)) { 323 v.addElement(obj); 324 int count = v.size(); 325 if (starts.length == count) { 326 int[] temp = new int[starts.length*2]; 327 System.arraycopy(starts, 0, temp, 0, starts.length); 328 starts = temp; 329 } 330 starts[count-1] = index; 331 } 332 return starts; 333 } 334 335 339 private void addDecoration(Decoration d, int index) { 340 341 if (decorations != null) { 342 decorationStarts = addToVector(d, 343 index, 344 decorations, 345 decorationStarts); 346 } 347 else if (decoration == null) { 348 decoration = d; 349 } 350 else { 351 if (!decoration.equals(d)) { 352 decorations = new Vector (INITIAL_SIZE); 353 decorations.addElement(decoration); 354 decorations.addElement(d); 355 decorationStarts = new int[INITIAL_SIZE]; 356 decorationStarts[0] = 0; 357 decorationStarts[1] = index; 358 } 359 } 360 } 361 362 366 private void addFont(Object f, int index) { 367 368 if (fonts != null) { 369 fontStarts = addToVector(f, index, fonts, fontStarts); 370 } 371 else if (font == null) { 372 font = f; 373 } 374 else { 375 if (!font.equals(f)) { 376 fonts = new Vector (INITIAL_SIZE); 377 fonts.addElement(font); 378 fonts.addElement(f); 379 fontStarts = new int[INITIAL_SIZE]; 380 fontStarts[0] = 0; 381 fontStarts[1] = index; 382 } 383 } 384 } 385 386 390 private void addFonts(char[] chars, Map attributes, int start, int limit) { 391 392 FontResolver resolver = FontResolver.getInstance(); 393 CodePointIterator iter = CodePointIterator.create(chars, start, limit); 394 for (int runStart = iter.charIndex(); runStart < limit; runStart = iter.charIndex()) { 395 int fontIndex = resolver.nextFontRunIndex(iter); 396 addFont(resolver.getFont(fontIndex, attributes), runStart); 397 } 398 } 399 400 404 static Map addInputMethodAttrs(Map oldStyles) { 405 406 Object value = oldStyles.get(TextAttribute.INPUT_METHOD_HIGHLIGHT); 407 408 try { 409 if (value != null) { 410 if (value instanceof Annotation ) { 411 value = ((Annotation )value).getValue(); 412 } 413 414 InputMethodHighlight hl; 415 hl = (InputMethodHighlight ) value; 416 417 Map imStyles = null; 418 try { 419 imStyles = hl.getStyle(); 420 } catch (NoSuchMethodError e) { 421 } 422 423 if (imStyles == null) { 424 Toolkit tk = Toolkit.getDefaultToolkit(); 425 imStyles = tk.mapInputMethodHighlight(hl); 426 } 427 428 if (imStyles != null) { 429 Hashtable newStyles = new Hashtable (5, (float)0.9); 430 newStyles.putAll(oldStyles); 431 432 newStyles.putAll(imStyles); 433 434 return newStyles; 435 } 436 } 437 } 438 catch(ClassCastException e) { 439 } 440 441 return oldStyles; 442 } 443 444 449 private static Object getGraphicOrFont(Map attributes) { 450 451 Object value = attributes.get(TextAttribute.CHAR_REPLACEMENT); 452 if (value != null) { 453 return value; 454 } 455 value = attributes.get(TextAttribute.FONT); 456 if (value != null) { 457 return value; 458 } 459 460 if (attributes.get(TextAttribute.FAMILY) != null) { 461 return Font.getFont(attributes); 462 } 463 else { 464 return null; 465 } 466 } 467 } 468 | Popular Tags |