1 7 package javax.swing.text; 8 9 import java.util.*; 10 import java.awt.*; 11 import java.text.AttributedCharacterIterator ; 12 import java.text.BreakIterator ; 13 import java.awt.font.*; 14 import java.awt.geom.AffineTransform ; 15 import javax.swing.event.DocumentEvent ; 16 import sun.font.BidiUtils; 17 18 28 class TextLayoutStrategy extends FlowView.FlowStrategy { 29 30 34 public TextLayoutStrategy() { 35 text = new AttributedSegment(); 36 } 37 38 40 51 public void insertUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) { 52 sync(fv); 53 super.insertUpdate(fv, e, alloc); 54 } 55 56 64 public void removeUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) { 65 sync(fv); 66 super.removeUpdate(fv, e, alloc); 67 } 68 69 78 public void changedUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) { 79 sync(fv); 80 super.changedUpdate(fv, e, alloc); 81 } 82 83 91 public void layout(FlowView fv) { 92 super.layout(fv); 93 } 94 95 108 protected int layoutRow(FlowView fv, int rowIndex, int p0) { 109 int p1 = super.layoutRow(fv, rowIndex, p0); 110 View row = fv.getView(rowIndex); 111 Document doc = fv.getDocument(); 112 Object i18nFlag = doc.getProperty(AbstractDocument.I18NProperty); 113 if ((i18nFlag != null) && i18nFlag.equals(Boolean.TRUE)) { 114 int n = row.getViewCount(); 115 if (n > 1) { 116 AbstractDocument d = (AbstractDocument )fv.getDocument(); 117 Element bidiRoot = d.getBidiRootElement(); 118 byte[] levels = new byte[n]; 119 View [] reorder = new View [n]; 120 121 for( int i=0; i<n; i++ ) { 122 View v = row.getView(i); 123 int bidiIndex =bidiRoot.getElementIndex(v.getStartOffset()); 124 Element bidiElem = bidiRoot.getElement( bidiIndex ); 125 levels[i] = (byte)StyleConstants.getBidiLevel(bidiElem.getAttributes()); 126 reorder[i] = v; 127 } 128 129 BidiUtils.reorderVisually( levels, reorder ); 130 row.replace(0, n, reorder); 131 } 132 } 133 return p1; 134 } 135 136 147 protected void adjustRow(FlowView fv, int rowIndex, int desiredSpan, int x) { 148 } 149 150 160 protected View createView(FlowView fv, int startOffset, int spanLeft, int rowIndex) { 161 View lv = getLogicalView(fv); 163 View row = fv.getView(rowIndex); 164 boolean requireNextWord = (row.getViewCount() == 0) ? false : true; 165 int childIndex = lv.getViewIndex(startOffset, Position.Bias.Forward); 166 View v = lv.getView(childIndex); 167 168 int endOffset = getLimitingOffset(v, startOffset, spanLeft, requireNextWord); 169 if (endOffset == startOffset) { 170 return null; 171 } 172 173 View frag; 174 if ((startOffset==v.getStartOffset()) && (endOffset == v.getEndOffset())) { 175 frag = v; 177 } else { 178 frag = v.createFragment(startOffset, endOffset); 180 } 181 182 if ((frag instanceof GlyphView ) && (measurer != null)) { 183 boolean isTab = false; 187 int p0 = frag.getStartOffset(); 188 int p1 = frag.getEndOffset(); 189 if ((p1 - p0) == 1) { 190 Segment s = ((GlyphView )frag).getText(p0, p1); 192 char ch = s.first(); 193 if (ch == '\t') { 194 isTab = true; 195 } 196 } 197 TextLayout tl = (isTab) ? null : 198 measurer.nextLayout(spanLeft, text.toIteratorIndex(endOffset), 199 requireNextWord); 200 if (tl != null) { 201 ((GlyphView )frag).setGlyphPainter(new GlyphPainter2 (tl)); 202 } 203 } 204 return frag; 205 } 206 207 219 int getLimitingOffset(View v, int startOffset, int spanLeft, boolean requireNextWord) { 220 int endOffset = v.getEndOffset(); 221 222 Document doc = v.getDocument(); 224 if (doc instanceof AbstractDocument ) { 225 AbstractDocument d = (AbstractDocument ) doc; 226 Element bidiRoot = d.getBidiRootElement(); 227 if( bidiRoot.getElementCount() > 1 ) { 228 int bidiIndex = bidiRoot.getElementIndex( startOffset ); 229 Element bidiElem = bidiRoot.getElement( bidiIndex ); 230 endOffset = Math.min( bidiElem.getEndOffset(), endOffset ); 231 } 232 } 233 234 if (v instanceof GlyphView ) { 236 Segment s = ((GlyphView )v).getText(startOffset, endOffset); 237 char ch = s.first(); 238 if (ch == '\t') { 239 endOffset = startOffset + 1; 242 } else { 243 for (ch = s.next(); ch != Segment.DONE; ch = s.next()) { 244 if (ch == '\t') { 245 endOffset = startOffset + s.getIndex() - s.getBeginIndex(); 247 break; 248 } 249 } 250 } 251 } 252 253 int limitIndex = text.toIteratorIndex(endOffset); 255 if (measurer != null) { 256 int index = text.toIteratorIndex(startOffset); 257 if (measurer.getPosition() != index) { 258 measurer.setPosition(index); 259 } 260 limitIndex = measurer.nextOffset(spanLeft, limitIndex, requireNextWord); 261 } 262 int pos = text.toModelPosition(limitIndex); 263 return pos; 264 } 265 266 272 void sync(FlowView fv) { 273 View lv = getLogicalView(fv); 274 text.setView(lv); 275 276 Container container = fv.getContainer(); 277 FontRenderContext frc = com.sun.java.swing.SwingUtilities2. 278 getFontRenderContext(container); 279 BreakIterator iter; 280 Container c = fv.getContainer(); 281 if (c != null) { 282 iter = BreakIterator.getLineInstance(c.getLocale()); 283 } else { 284 iter = BreakIterator.getLineInstance(); 285 } 286 287 measurer = new LineBreakMeasurer(text, iter, frc); 288 289 int n = lv.getViewCount(); 292 for( int i=0; i<n; i++ ) { 293 View child = lv.getView(i); 294 if( child instanceof GlyphView ) { 295 int p0 = child.getStartOffset(); 296 int p1 = child.getEndOffset(); 297 measurer.setPosition(text.toIteratorIndex(p0)); 298 TextLayout layout 299 = measurer.nextLayout( Float.MAX_VALUE, 300 text.toIteratorIndex(p1), false ); 301 ((GlyphView )child).setGlyphPainter(new GlyphPainter2 (layout)); 302 } 303 } 304 305 measurer.setPosition(text.getBeginIndex()); 307 308 } 309 310 312 private LineBreakMeasurer measurer; 313 private AttributedSegment text; 314 315 320 static class AttributedSegment extends Segment implements AttributedCharacterIterator { 321 322 AttributedSegment() { 323 } 324 325 View getView() { 326 return v; 327 } 328 329 void setView(View v) { 330 this.v = v; 331 Document doc = v.getDocument(); 332 int p0 = v.getStartOffset(); 333 int p1 = v.getEndOffset(); 334 try { 335 doc.getText(p0, p1 - p0, this); 336 } catch (BadLocationException bl) { 337 throw new IllegalArgumentException ("Invalid view"); 338 } 339 first(); 340 } 341 342 351 int getFontBoundary(int childIndex, int dir) { 352 View child = v.getView(childIndex); 353 Font f = getFont(childIndex); 354 for (childIndex += dir; (childIndex >= 0) && (childIndex < v.getViewCount()); 355 childIndex += dir) { 356 Font next = getFont(childIndex); 357 if (next != f) { 358 break; 360 } 361 child = v.getView(childIndex); 362 } 363 return (dir < 0) ? child.getStartOffset() : child.getEndOffset(); 364 } 365 366 369 Font getFont(int childIndex) { 370 View child = v.getView(childIndex); 371 if (child instanceof GlyphView ) { 372 return ((GlyphView )child).getFont(); 373 } 374 return null; 375 } 376 377 int toModelPosition(int index) { 378 return v.getStartOffset() + (index - getBeginIndex()); 379 } 380 381 int toIteratorIndex(int pos) { 382 return pos - v.getStartOffset() + getBeginIndex(); 383 } 384 385 387 391 public int getRunStart() { 392 int pos = toModelPosition(getIndex()); 393 int i = v.getViewIndex(pos, Position.Bias.Forward); 394 View child = v.getView(i); 395 return toIteratorIndex(child.getStartOffset()); 396 } 397 398 402 public int getRunStart(AttributedCharacterIterator.Attribute attribute) { 403 if (attribute instanceof TextAttribute) { 404 int pos = toModelPosition(getIndex()); 405 int i = v.getViewIndex(pos, Position.Bias.Forward); 406 if (attribute == TextAttribute.FONT) { 407 return toIteratorIndex(getFontBoundary(i, -1)); 408 } 409 } 410 return getBeginIndex(); 411 } 412 413 417 public int getRunStart(Set<? extends Attribute> attributes) { 418 int index = getBeginIndex(); 419 Object [] a = attributes.toArray(); 420 for (int i = 0; i < a.length; i++) { 421 TextAttribute attr = (TextAttribute) a[i]; 422 index = Math.max(getRunStart(attr), index); 423 } 424 return Math.min(getIndex(), index); 425 } 426 427 431 public int getRunLimit() { 432 int pos = toModelPosition(getIndex()); 433 int i = v.getViewIndex(pos, Position.Bias.Forward); 434 View child = v.getView(i); 435 return toIteratorIndex(child.getEndOffset()); 436 } 437 438 442 public int getRunLimit(AttributedCharacterIterator.Attribute attribute) { 443 if (attribute instanceof TextAttribute) { 444 int pos = toModelPosition(getIndex()); 445 int i = v.getViewIndex(pos, Position.Bias.Forward); 446 if (attribute == TextAttribute.FONT) { 447 return toIteratorIndex(getFontBoundary(i, 1)); 448 } 449 } 450 return getEndIndex(); 451 } 452 453 457 public int getRunLimit(Set<? extends Attribute> attributes) { 458 int index = getEndIndex(); 459 Object [] a = attributes.toArray(); 460 for (int i = 0; i < a.length; i++) { 461 TextAttribute attr = (TextAttribute) a[i]; 462 index = Math.min(getRunLimit(attr), index); 463 } 464 return Math.max(getIndex(), index); 465 } 466 467 471 public Map getAttributes() { 472 Object [] ka = keys.toArray(); 473 Hashtable h = new Hashtable(); 474 for (int i = 0; i < ka.length; i++) { 475 TextAttribute a = (TextAttribute) ka[i]; 476 Object value = getAttribute(a); 477 if (value != null) { 478 h.put(a, value); 479 } 480 } 481 return h; 482 } 483 484 489 public Object getAttribute(AttributedCharacterIterator.Attribute attribute) { 490 int pos = toModelPosition(getIndex()); 491 int childIndex = v.getViewIndex(pos, Position.Bias.Forward); 492 if (attribute == TextAttribute.FONT) { 493 return getFont(childIndex); 494 } else if( attribute == TextAttribute.RUN_DIRECTION ) { 495 return 496 v.getDocument().getProperty(TextAttribute.RUN_DIRECTION); 497 } 498 return null; 499 } 500 501 506 public Set getAllAttributeKeys() { 507 return keys; 508 } 509 510 View v; 511 512 static Set keys; 513 514 static { 515 keys = new HashSet(); 516 keys.add(TextAttribute.FONT); 517 keys.add(TextAttribute.RUN_DIRECTION); 518 } 519 520 } 521 522 } 523 | Popular Tags |