1 11 package org.eclipse.swt.custom; 12 13 14 import org.eclipse.swt.SWT; 15 import org.eclipse.swt.graphics.*; 16 import org.eclipse.swt.widgets.*; 17 18 22 class StyledTextRenderer { 23 Device device; 24 StyledText styledText; 25 StyledTextContent content; 26 27 28 Font regularFont, boldFont, italicFont, boldItalicFont; 29 int tabWidth; 30 int ascent, descent; 31 int averageCharWidth; 32 33 34 int topIndex = -1; 35 TextLayout[] layouts; 36 int lineCount; 37 int[] lineWidth; 38 int[] lineHeight; 39 LineInfo[] lines; 40 int maxWidth; 41 int maxWidthLineIndex; 42 boolean idleRunning; 43 44 45 Bullet[] bullets; 46 int[] bulletsIndices; 47 int[] redrawLines; 48 49 50 int[] ranges; 51 int styleCount; 52 StyleRange[] styles; 53 StyleRange[] stylesSet; 54 int stylesSetCount = 0; 55 final static int BULLET_MARGIN = 8; 56 57 final static boolean COMPACT_STYLES = true; 58 final static boolean MERGE_STYLES = true; 59 60 final static int GROW = 32; 61 final static int IDLE_TIME = 50; 62 final static int CACHE_SIZE = 128; 63 64 final static int BACKGROUND = 1 << 0; 65 final static int ALIGNMENT = 1 << 1; 66 final static int INDENT = 1 << 2; 67 final static int JUSTIFY = 1 << 3; 68 final static int SEGMENTS = 1 << 5; 69 70 static class LineInfo { 71 int flags; 72 Color background; 73 int alignment; 74 int indent; 75 boolean justify; 76 int[] segments; 77 78 public LineInfo() { 79 } 80 public LineInfo(LineInfo info) { 81 if (info != null) { 82 flags = info.flags; 83 background = info.background; 84 alignment = info.alignment; 85 indent = info.indent; 86 justify = info.justify; 87 segments = info.segments; 88 } 89 } 90 } 91 92 StyledTextRenderer(Device device, StyledText styledText) { 93 this.device = device; 94 this.styledText = styledText; 95 } 96 int addMerge(int[] mergeRanges, StyleRange[] mergeStyles, int mergeCount, int modifyStart, int modifyEnd) { 97 int rangeCount = styleCount << 1; 98 StyleRange endStyle = null; 99 int endStart = 0, endLength = 0; 100 if (modifyEnd < rangeCount) { 101 endStyle = styles[modifyEnd >> 1]; 102 endStart = ranges[modifyEnd]; 103 endLength = ranges[modifyEnd + 1]; 104 } 105 int grow = mergeCount - (modifyEnd - modifyStart); 106 if (rangeCount + grow >= ranges.length) { 107 int[] tmpRanges = new int[ranges.length + grow + (GROW << 1)]; 108 System.arraycopy(ranges, 0, tmpRanges, 0, modifyStart); 109 StyleRange[] tmpStyles = new StyleRange[styles.length + (grow >> 1) + GROW]; 110 System.arraycopy(styles, 0, tmpStyles, 0, modifyStart >> 1); 111 if (rangeCount > modifyEnd) { 112 System.arraycopy(ranges, modifyEnd, tmpRanges, modifyStart + mergeCount, rangeCount - modifyEnd); 113 System.arraycopy(styles, modifyEnd >> 1, tmpStyles, (modifyStart + mergeCount) >> 1, styleCount - (modifyEnd >> 1)); 114 } 115 ranges = tmpRanges; 116 styles = tmpStyles; 117 } else { 118 if (rangeCount > modifyEnd) { 119 System.arraycopy(ranges, modifyEnd, ranges, modifyStart + mergeCount, rangeCount - modifyEnd); 120 System.arraycopy(styles, modifyEnd >> 1, styles, (modifyStart + mergeCount) >> 1, styleCount - (modifyEnd >> 1)); 121 } 122 } 123 if (MERGE_STYLES) { 124 int j = modifyStart; 125 for (int i = 0; i < mergeCount; i += 2) { 126 if (j > 0 && ranges[j - 2] + ranges[j - 1] == mergeRanges[i] && mergeStyles[i >> 1].similarTo(styles[(j - 2) >> 1])) { 127 ranges[j - 1] += mergeRanges[i + 1]; 128 } else { 129 styles[j >> 1] = mergeStyles[i >> 1]; 130 ranges[j++] = mergeRanges[i]; 131 ranges[j++] = mergeRanges[i + 1]; 132 } 133 } 134 if (endStyle != null && ranges[j - 2] + ranges[j - 1] == endStart && endStyle.similarTo(styles[(j - 2) >> 1])) { 135 ranges[j - 1] += endLength; 136 modifyEnd += 2; 137 mergeCount += 2; 138 } 139 if (rangeCount > modifyEnd) { 140 System.arraycopy(ranges, modifyStart + mergeCount, ranges, j, rangeCount - modifyEnd); 141 System.arraycopy(styles, (modifyStart + mergeCount) >> 1, styles, j >> 1, styleCount - (modifyEnd >> 1)); 142 } 143 grow = (j - modifyStart) - (modifyEnd - modifyStart); 144 } else { 145 System.arraycopy(mergeRanges, 0, ranges, modifyStart, mergeCount); 146 System.arraycopy(mergeStyles, 0, styles, modifyStart >> 1, mergeCount >> 1); 147 } 148 styleCount += grow >> 1; 149 return grow; 150 } 151 int addMerge(StyleRange[] mergeStyles, int mergeCount, int modifyStart, int modifyEnd) { 152 int grow = mergeCount - (modifyEnd - modifyStart); 153 StyleRange endStyle = null; 154 if (modifyEnd < styleCount) endStyle = styles[modifyEnd]; 155 if (styleCount + grow >= styles.length) { 156 StyleRange[] tmpStyles = new StyleRange[styles.length + grow + GROW]; 157 System.arraycopy(styles, 0, tmpStyles, 0, modifyStart); 158 if (styleCount > modifyEnd) { 159 System.arraycopy(styles, modifyEnd, tmpStyles, modifyStart + mergeCount, styleCount - modifyEnd); 160 } 161 styles = tmpStyles; 162 } else { 163 if (styleCount > modifyEnd) { 164 System.arraycopy(styles, modifyEnd, styles, modifyStart + mergeCount, styleCount - modifyEnd); 165 } 166 } 167 if (MERGE_STYLES) { 168 int j = modifyStart; 169 for (int i = 0; i < mergeCount; i++) { 170 StyleRange newStyle = mergeStyles[i], style; 171 if (j > 0 && (style = styles[j - 1]).start + style.length == newStyle.start && newStyle.similarTo(style)) { 172 style.length += newStyle.length; 173 } else { 174 styles[j++] = newStyle; 175 } 176 } 177 StyleRange style = styles[j - 1]; 178 if (endStyle != null && style.start + style.length == endStyle.start && endStyle.similarTo(style)) { 179 style.length += endStyle.length; 180 modifyEnd++; 181 mergeCount++; 182 } 183 if (styleCount > modifyEnd) { 184 System.arraycopy(styles, modifyStart + mergeCount, styles, j, styleCount - modifyEnd); 185 } 186 grow = (j - modifyStart) - (modifyEnd - modifyStart); 187 } else { 188 System.arraycopy(mergeStyles, 0, styles, modifyStart, mergeCount); 189 } 190 styleCount += grow; 191 return grow; 192 } 193 void calculate(int startLine, int lineCount) { 194 int endLine = startLine + lineCount; 195 if (startLine < 0 || endLine > lineWidth.length) { 196 return; 197 } 198 int hTrim = styledText.leftMargin + styledText.rightMargin + styledText.getCaretWidth(); 199 for (int i = startLine; i < endLine; i++) { 200 if (lineWidth[i] == -1 || lineHeight[i] == -1) { 201 TextLayout layout = getTextLayout(i); 202 Rectangle rect = layout.getBounds(); 203 lineWidth[i] = rect.width + hTrim; 204 lineHeight[i] = rect.height; 205 disposeTextLayout(layout); 206 } 207 if (lineWidth[i] > maxWidth) { 208 maxWidth = lineWidth[i]; 209 maxWidthLineIndex = i; 210 } 211 } 212 } 213 void calculateClientArea () { 214 int index = styledText.getTopIndex(); 215 int lineCount = content.getLineCount(); 216 int height = styledText.getClientArea().height; 217 int y = 0; 218 while (height > y && lineCount > index) { 219 calculate(index, 1); 220 y += lineHeight[index++]; 221 } 222 } 223 void calculateIdle () { 224 if (idleRunning) return; 225 Runnable runnable = new Runnable () { 226 public void run() { 227 if (styledText == null) return; 228 int i; 229 long start = System.currentTimeMillis(); 230 for (i = 0; i < lineCount; i++) { 231 if (lineHeight[i] == -1 || lineWidth[i] == -1) { 232 calculate(i, 1); 233 if (System.currentTimeMillis() - start > IDLE_TIME) break; 234 } 235 } 236 if (i < lineCount) { 237 Display display = styledText.getDisplay(); 238 display.asyncExec(this); 239 } else { 240 idleRunning = false; 241 styledText.setScrollBars(true); 242 ScrollBar bar = styledText.getVerticalBar(); 243 if (bar != null) { 244 bar.setSelection(styledText.getVerticalScrollOffset()); 245 } 246 } 247 } 248 }; 249 Display display = styledText.getDisplay(); 250 display.asyncExec(runnable); 251 idleRunning = true; 252 } 253 void clearLineBackground(int startLine, int count) { 254 if (lines == null) return; 255 for (int i = startLine; i < startLine + count; i++) { 256 LineInfo info = lines[i]; 257 if (info != null) { 258 info.flags &= ~BACKGROUND; 259 info.background = null; 260 if (info.flags == 0) lines[i] = null; 261 } 262 } 263 } 264 void clearLineStyle(int startLine, int count) { 265 if (lines == null) return; 266 for (int i = startLine; i < startLine + count; i++) { 267 LineInfo info = lines[i]; 268 if (info != null) { 269 info.flags &= ~(ALIGNMENT | INDENT | JUSTIFY); 270 if (info.flags == 0) lines[i] = null; 271 } 272 } 273 } 274 void copyInto(StyledTextRenderer renderer) { 275 if (ranges != null) { 276 int[] newRanges = renderer.ranges = new int[styleCount << 1]; 277 System.arraycopy(ranges, 0, newRanges, 0, newRanges.length); 278 } 279 if (styles != null) { 280 StyleRange[] newStyles = renderer.styles = new StyleRange[styleCount]; 281 for (int i = 0; i < newStyles.length; i++) { 282 newStyles[i] = (StyleRange)styles[i].clone(); 283 } 284 renderer.styleCount = styleCount; 285 } 286 if (lines != null) { 287 LineInfo[] newLines = renderer.lines = new LineInfo[lineCount]; 288 for (int i = 0; i < newLines.length; i++) { 289 newLines[i] = new LineInfo(lines[i]); 290 } 291 renderer.lineCount = lineCount; 292 } 293 } 294 void dispose() { 295 if (boldFont != null) boldFont.dispose(); 296 if (italicFont != null) italicFont.dispose(); 297 if (boldItalicFont != null) boldItalicFont.dispose(); 298 boldFont = italicFont = boldItalicFont = null; 299 reset(); 300 content = null; 301 device = null; 302 styledText = null; 303 } 304 void disposeTextLayout (TextLayout layout) { 305 if (layouts != null) { 306 for (int i = 0; i < layouts.length; i++) { 307 if (layouts[i] == layout) return; 308 } 309 } 310 layout.dispose(); 311 } 312 void drawBullet(Bullet bullet, GC gc, int paintX, int paintY, int index, int lineAscent, int lineDescent) { 313 StyleRange style = bullet.style; 314 GlyphMetrics metrics = style.metrics; 315 Color color = style.foreground; 316 if (color != null) gc.setForeground(color); 317 if ((bullet.type & ST.BULLET_DOT) != 0 && StyledText.IS_MOTIF) { 318 int size = Math.max(4, (lineAscent + lineDescent) / 4); 319 if ((size & 1) == 0) size++; 320 if (color == null) { 321 Display display = styledText.getDisplay(); 322 color = display.getSystemColor(SWT.COLOR_BLACK); 323 } 324 gc.setBackground(color); 325 int x = paintX + Math.max(0, metrics.width - size - BULLET_MARGIN); 326 gc.fillArc(x, paintY + size, size + 1, size + 1, 0, 360); 327 return; 328 } 329 Font font = style.font; 330 if (font != null) gc.setFont(font); 331 String string = ""; 332 int type = bullet.type & (ST.BULLET_DOT|ST.BULLET_NUMBER|ST.BULLET_LETTER_LOWER|ST.BULLET_LETTER_UPPER); 333 switch (type) { 334 case ST.BULLET_DOT: string = "\u2022"; break; 335 case ST.BULLET_NUMBER: string = String.valueOf(index); break; 336 case ST.BULLET_LETTER_LOWER: string = String.valueOf((char) (index % 26 + 97)); break; 337 case ST.BULLET_LETTER_UPPER: string = String.valueOf((char) (index % 26 + 65)); break; 338 } 339 if ((bullet.type & ST.BULLET_TEXT) != 0) string += bullet.text; 340 Display display = styledText.getDisplay(); 341 TextLayout layout = new TextLayout(display); 342 layout.setText(string); 343 layout.setAscent(lineAscent); 344 layout.setDescent(lineDescent); 345 style = (StyleRange)style.clone(); 346 style.metrics = null; 347 if (style.font == null) style.font = getFont(style.fontStyle); 348 layout.setStyle(style, 0, string.length()); 349 int x = paintX + Math.max(0, metrics.width - layout.getBounds().width - BULLET_MARGIN); 350 layout.draw(gc, x, paintY); 351 layout.dispose(); 352 } 353 int drawLine(int lineIndex, int paintX, int paintY, GC gc, Color widgetBackground, Color widgetForeground) { 354 TextLayout layout = getTextLayout(lineIndex); 355 String line = content.getLine(lineIndex); 356 int lineOffset = content.getOffsetAtLine(lineIndex); 357 int lineLength = line.length(); 358 Point selection = styledText.getSelection(); 359 int selectionStart = selection.x - lineOffset; 360 int selectionEnd = selection.y - lineOffset; 361 Rectangle client = styledText.getClientArea(); 362 Color lineBackground = getLineBackground(lineIndex, widgetBackground); 363 StyledTextEvent event = styledText.getLineBackgroundData(lineOffset, line); 364 if (event != null && event.lineBackground != null) lineBackground = event.lineBackground; 365 366 int height = layout.getBounds().height; 367 gc.setBackground(lineBackground); 368 styledText.drawBackground(gc, client.x, paintY, client.width, height); 369 370 gc.setForeground(widgetForeground); 371 gc.setBackground(lineBackground); 372 if (selectionStart == selectionEnd || (selectionEnd <= 0 && selectionStart > lineLength - 1)) { 373 layout.draw(gc, paintX, paintY); 374 } else { 375 int start = Math.max(0, selectionStart); 376 int end = Math.min(lineLength, selectionEnd); 377 Color selectionFg = styledText.getSelectionForeground(); 378 Color selectionBg = styledText.getSelectionBackground(); 379 int flags; 380 if ((styledText.getStyle() & SWT.FULL_SELECTION) != 0) { 381 flags = SWT.FULL_SELECTION; 382 } else { 383 flags = SWT.DELIMITER_SELECTION; 384 } 385 if (selectionStart <= lineLength && lineLength < selectionEnd ) { 386 flags |= SWT.LAST_LINE_SELECTION; 387 } 388 layout.draw(gc, paintX, paintY, start, end - 1, selectionFg, selectionBg, flags); 389 } 390 391 Bullet bullet = null; 393 int bulletIndex = -1; 394 if (bullets != null) { 395 if (bulletsIndices != null) { 396 int index = lineIndex - topIndex; 397 if (0 <= index && index < CACHE_SIZE) { 398 bullet = bullets[index]; 399 bulletIndex = bulletsIndices[index]; 400 } 401 } else { 402 for (int i = 0; i < bullets.length; i++) { 403 bullet = bullets[i]; 404 bulletIndex = bullet.indexOf(lineIndex); 405 if (bulletIndex != -1) break; 406 } 407 } 408 } 409 if (bulletIndex != -1 && bullet != null) { 410 FontMetrics metrics = layout.getLineMetrics(0); 411 int lineAscent = metrics.getAscent() + metrics.getLeading(); 412 if (bullet.type == ST.BULLET_CUSTOM) { 413 bullet.style.start = lineOffset; 414 styledText.paintObject(gc, paintX, paintY, lineAscent, metrics.getDescent(), bullet.style, bullet, bulletIndex); 415 } else { 416 drawBullet(bullet, gc, paintX, paintY, bulletIndex, lineAscent, metrics.getDescent()); 417 } 418 } 419 TextStyle[] styles = layout.getStyles(); 420 int[] ranges = null; 421 for (int i = 0; i < styles.length; i++) { 422 if (styles[i].metrics != null) { 423 if (ranges == null) ranges = layout.getRanges(); 424 int start = ranges[i << 1]; 425 int length = ranges[(i << 1) + 1] - start; 426 Point point = layout.getLocation(start, false); 427 FontMetrics metrics = layout.getLineMetrics(layout.getLineIndex(start)); 428 StyleRange style = (StyleRange)((StyleRange)styles[i]).clone(); 429 style.start = start + lineOffset; 430 style.length = length; 431 int lineAscent = metrics.getAscent() + metrics.getLeading(); 432 styledText.paintObject(gc, point.x + paintX, point.y + paintY, lineAscent, metrics.getDescent(), style, null, 0); 433 } 434 } 435 disposeTextLayout(layout); 436 return height; 437 } 438 int getBaseline() { 439 return ascent; 440 } 441 Font getFont(int style) { 442 switch (style) { 443 case SWT.BOLD: 444 if (boldFont != null) return boldFont; 445 return boldFont = new Font(device, getFontData(style)); 446 case SWT.ITALIC: 447 if (italicFont != null) return italicFont; 448 return italicFont = new Font(device, getFontData(style)); 449 case SWT.BOLD | SWT.ITALIC: 450 if (boldItalicFont != null) return boldItalicFont; 451 return boldItalicFont = new Font(device, getFontData(style)); 452 default: 453 return regularFont; 454 } 455 } 456 FontData[] getFontData(int style) { 457 FontData[] fontDatas = regularFont.getFontData(); 458 for (int i = 0; i < fontDatas.length; i++) { 459 fontDatas[i].setStyle(style); 460 } 461 return fontDatas; 462 } 463 int getHeight () { 464 int defaultLineHeight = getLineHeight(); 465 if (styledText.isFixedLineHeight()) { 466 return lineCount * defaultLineHeight; 467 } 468 int totalHeight = 0; 469 int width = styledText.getWrapWidth(); 470 for (int i = 0; i < lineCount; i++) { 471 int height = lineHeight[i]; 472 if (height == -1) { 473 if (width > 0) { 474 int length = content.getLine(i).length(); 475 height = ((length * averageCharWidth / width) + 1) * defaultLineHeight; 476 } else { 477 height = defaultLineHeight; 478 } 479 } 480 totalHeight += height; 481 } 482 return totalHeight + styledText.topMargin + styledText.bottomMargin; 483 } 484 int getLineAlignment(int index, int defaultAlignment) { 485 if (lines == null) return defaultAlignment; 486 LineInfo info = lines[index]; 487 if (info != null && (info.flags & ALIGNMENT) != 0) { 488 return info.alignment; 489 } 490 return defaultAlignment; 491 } 492 Color getLineBackground(int index, Color defaultBackground) { 493 if (lines == null) return defaultBackground; 494 LineInfo info = lines[index]; 495 if (info != null && (info.flags & BACKGROUND) != 0) { 496 return info.background; 497 } 498 return defaultBackground; 499 } 500 Bullet getLineBullet (int index, Bullet defaultBullet) { 501 if (bullets == null) return defaultBullet; 502 if (bulletsIndices != null) return defaultBullet; 503 for (int i = 0; i < bullets.length; i++) { 504 Bullet bullet = bullets[i]; 505 if (bullet.indexOf(index) != -1) return bullet; 506 } 507 return defaultBullet; 508 } 509 int getLineHeight() { 510 return ascent + descent; 511 } 512 int getLineHeight(int lineIndex) { 513 if (lineHeight[lineIndex] == -1) { 514 calculate(lineIndex, 1); 515 } 516 return lineHeight[lineIndex]; 517 } 518 int getLineIndent(int index, int defaultIndent) { 519 if (lines == null) return defaultIndent; 520 LineInfo info = lines[index]; 521 if (info != null && (info.flags & INDENT) != 0) { 522 return info.indent; 523 } 524 return defaultIndent; 525 } 526 boolean getLineJustify(int index, boolean defaultJustify) { 527 if (lines == null) return defaultJustify; 528 LineInfo info = lines[index]; 529 if (info != null && (info.flags & JUSTIFY) != 0) { 530 return info.justify; 531 } 532 return defaultJustify; 533 } 534 int[] getLineSegments(int index, int[] defaultSegments) { 535 if (lines == null) return defaultSegments; 536 LineInfo info = lines[index]; 537 if (info != null && (info.flags & SEGMENTS) != 0) { 538 return info.segments; 539 } 540 return defaultSegments; 541 } 542 int getRangeIndex(int offset, int low, int high) { 543 if (styleCount == 0) return 0; 544 if (ranges != null) { 545 while (high - low > 2) { 546 int index = ((high + low) / 2) / 2 * 2; 547 int end = ranges[index] + ranges[index + 1]; 548 if (end > offset) { 549 high = index; 550 } else { 551 low = index; 552 } 553 } 554 } else { 555 while (high - low > 1) { 556 int index = ((high + low) / 2); 557 int end = styles[index].start + styles[index].length; 558 if (end > offset) { 559 high = index; 560 } else { 561 low = index; 562 } 563 } 564 } 565 return high; 566 } 567 int[] getRanges(int start, int length) { 568 int[] newRanges; 569 int end = start + length - 1; 570 if (ranges != null) { 571 int rangeCount = styleCount << 1; 572 int rangeStart = getRangeIndex(start, -1, rangeCount); 573 if (rangeStart >= rangeCount) return null; 574 if (ranges[rangeStart] > end) return null; 575 int rangeEnd = Math.min(rangeCount - 2, getRangeIndex(end, rangeStart - 1, rangeCount) + 1); 576 newRanges = new int[rangeEnd - rangeStart + 2]; 577 System.arraycopy(ranges, rangeStart, newRanges, 0, newRanges.length); 578 } else { 579 int rangeStart = getRangeIndex(start, -1, styleCount); 580 if (rangeStart >= styleCount) return null; 581 if (styles[rangeStart].start > end) return null; 582 int rangeEnd = Math.min(styleCount - 1, getRangeIndex(end, rangeStart - 1, styleCount)); 583 newRanges = new int[(rangeEnd - rangeStart + 1) << 1]; 584 for (int i = rangeStart, j = 0; i <= rangeEnd; i++, j += 2) { 585 StyleRange style = styles[i]; 586 newRanges[j] = style.start; 587 newRanges[j + 1] = style.length; 588 } 589 } 590 if (start > newRanges[0]) { 591 newRanges[1] = newRanges[0] + newRanges[1] - start; 592 newRanges[0] = start; 593 } 594 if (end < newRanges[newRanges.length - 2] + newRanges[newRanges.length - 1] - 1) { 595 newRanges[newRanges.length - 1] = end - newRanges[newRanges.length - 2] + 1; 596 } 597 return newRanges; 598 } 599 StyleRange[] getStyleRanges(int start, int length, boolean includeRanges) { 600 StyleRange[] newStyles; 601 int end = start + length - 1; 602 if (ranges != null) { 603 int rangeCount = styleCount << 1; 604 int rangeStart = getRangeIndex(start, -1, rangeCount); 605 if (rangeStart >= rangeCount) return null; 606 if (ranges[rangeStart] > end) return null; 607 int rangeEnd = Math.min(rangeCount - 2, getRangeIndex(end, rangeStart - 1, rangeCount) + 1); 608 newStyles = new StyleRange[((rangeEnd - rangeStart) >> 1) + 1]; 609 if (includeRanges) { 610 for (int i = rangeStart, j = 0; i <= rangeEnd; i += 2, j++) { 611 newStyles[j] = (StyleRange)styles[i >> 1].clone(); 612 newStyles[j].start = ranges[i]; 613 newStyles[j].length = ranges[i + 1]; 614 } 615 } else { 616 System.arraycopy(styles, rangeStart >> 1, newStyles, 0, newStyles.length); 617 } 618 } else { 619 int rangeStart = getRangeIndex(start, -1, styleCount); 620 if (rangeStart >= styleCount) return null; 621 if (styles[rangeStart].start > end) return null; 622 int rangeEnd = Math.min(styleCount - 1, getRangeIndex(end, rangeStart - 1, styleCount)); 623 newStyles = new StyleRange[rangeEnd - rangeStart + 1]; 624 System.arraycopy(styles, rangeStart, newStyles, 0, newStyles.length); 625 } 626 StyleRange style = newStyles[0]; 627 if (start > style.start) { 628 if (!includeRanges || ranges == null) newStyles[0] = style = (StyleRange)style.clone(); 629 style.length = style.start + style.length - start; 630 style.start = start; 631 } 632 style = newStyles[newStyles.length - 1]; 633 if (end < style.start + style.length - 1) { 634 if (!includeRanges || ranges == null) newStyles[newStyles.length - 1] = style = (StyleRange)style.clone(); 635 style.length = end - style.start + 1; 636 } 637 return newStyles; 638 } 639 StyleRange getStyleRange(StyleRange style) { 640 if (style.start == 0 && style.length == 0 && style.fontStyle == SWT.NORMAL) return style; 641 StyleRange clone = (StyleRange)style.clone(); 642 clone.start = clone.length = 0; 643 clone.fontStyle = SWT.NORMAL; 644 if (clone.font == null) clone.font = getFont(style.fontStyle); 645 return clone; 646 } 647 TextLayout getTextLayout(int lineIndex) { 648 return getTextLayout(lineIndex, styledText.getOrientation(), styledText.getWrapWidth(), styledText.lineSpacing); 649 } 650 TextLayout getTextLayout(int lineIndex, int orientation, int width, int lineSpacing) { 651 TextLayout layout = null; 652 if (styledText != null) { 653 int topIndex = styledText.topIndex > 0 ? styledText.topIndex - 1 : 0; 654 if (layouts == null || topIndex != this.topIndex) { 655 TextLayout[] newLayouts = new TextLayout[CACHE_SIZE]; 656 if (layouts != null) { 657 for (int i = 0; i < layouts.length; i++) { 658 if (layouts[i] != null) { 659 int layoutIndex = (i + this.topIndex) - topIndex; 660 if (0 <= layoutIndex && layoutIndex < newLayouts.length) { 661 newLayouts[layoutIndex] = layouts[i]; 662 } else { 663 layouts[i].dispose(); 664 } 665 } 666 } 667 } 668 if (bullets != null && bulletsIndices != null && topIndex != this.topIndex) { 669 int delta = topIndex - this.topIndex; 670 if (delta > 0) { 671 if (delta < bullets.length) { 672 System.arraycopy(bullets, delta, bullets, 0, bullets.length - delta); 673 System.arraycopy(bulletsIndices, delta, bulletsIndices, 0, bulletsIndices.length - delta); 674 } 675 int startIndex = Math.max(0, bullets.length - delta); 676 for (int i = startIndex; i < bullets.length; i++) bullets[i] = null; 677 } else { 678 if (-delta < bullets.length) { 679 System.arraycopy(bullets, 0, bullets, -delta, bullets.length + delta); 680 System.arraycopy(bulletsIndices, 0, bulletsIndices, -delta, bulletsIndices.length + delta); 681 } 682 int endIndex = Math.min(bullets.length, -delta); 683 for (int i = 0; i < endIndex; i++) bullets[i] = null; 684 } 685 } 686 this.topIndex = topIndex; 687 layouts = newLayouts; 688 } 689 if (layouts != null) { 690 int layoutIndex = lineIndex - topIndex; 691 if (0 <= layoutIndex && layoutIndex < layouts.length) { 692 layout = layouts[layoutIndex]; 693 if (layout != null) { 694 if (lineWidth[lineIndex] != -1) return layout; 695 } else { 696 layout = layouts[layoutIndex] = new TextLayout(device); 697 } 698 } 699 } 700 } 701 if (layout == null) layout = new TextLayout(device); 702 String line = content.getLine(lineIndex); 703 int lineOffset = content.getOffsetAtLine(lineIndex); 704 int[] segments = null; 705 int indent = 0; 706 int alignment = SWT.LEFT; 707 boolean justify = false; 708 Bullet bullet = null; 709 int[] ranges = null; 710 StyleRange[] styles = null; 711 int rangeStart = 0, styleCount = 0; 712 StyledTextEvent event = null; 713 if (styledText != null) { 714 event = styledText.getLineStyleData(lineOffset, line); 715 segments = styledText.getBidiSegments(lineOffset, line); 716 indent = styledText.indent; 717 alignment = styledText.alignment; 718 justify = styledText.justify; 719 } 720 if (event != null) { 721 indent = event.indent; 722 alignment = event.alignment; 723 justify = event.justify; 724 bullet = event.bullet; 725 ranges = event.ranges; 726 styles = event.styles; 727 if (styles != null) { 728 styleCount = styles.length; 729 if (styledText.isFixedLineHeight()) { 730 for (int i = 0; i < styleCount; i++) { 731 if (styles[i].isVariableHeight()) { 732 styledText.verticalScrollOffset = -1; 733 styledText.setVariableLineHeight(); 734 styledText.redraw(); 735 break; 736 } 737 } 738 } 739 } 740 if (bullets == null || bulletsIndices == null) { 741 bullets = new Bullet[CACHE_SIZE]; 742 bulletsIndices = new int[CACHE_SIZE]; 743 } 744 int index = lineIndex - topIndex; 745 if (0 <= index && index < CACHE_SIZE) { 746 bullets[index] = bullet; 747 bulletsIndices[index] = event.bulletIndex; 748 } 749 } else { 750 if (lines != null) { 751 LineInfo info = lines[lineIndex]; 752 if (info != null) { 753 if ((info.flags & INDENT) != 0) indent = info.indent; 754 if ((info.flags & ALIGNMENT) != 0) alignment = info.alignment; 755 if ((info.flags & JUSTIFY) != 0) justify = info.justify; 756 if ((info.flags & SEGMENTS) != 0) segments = info.segments; 757 } 758 } 759 if (bulletsIndices != null) { 760 bullets = null; 761 bulletsIndices = null; 762 } 763 if (bullets != null) { 764 for (int i = 0; i < bullets.length; i++) { 765 if (bullets[i].indexOf(lineIndex) != -1) { 766 bullet = bullets[i]; 767 break; 768 } 769 } 770 } 771 ranges = this.ranges; 772 styles = this.styles; 773 styleCount = this.styleCount; 774 if (ranges != null) { 775 rangeStart = getRangeIndex(lineOffset, -1, styleCount << 1); 776 } else { 777 rangeStart = getRangeIndex(lineOffset, -1, styleCount); 778 } 779 } 780 if (bullet != null) { 781 StyleRange style = bullet.style; 782 GlyphMetrics metrics = style.metrics; 783 indent += metrics.width; 784 } 785 layout.setFont(regularFont); 786 layout.setAscent(ascent); 787 layout.setDescent(descent); 788 layout.setText(line); 789 layout.setOrientation(orientation); 790 layout.setSegments(segments); 791 layout.setWidth(width); 792 layout.setSpacing(lineSpacing); 793 layout.setTabs(new int[]{tabWidth}); 794 layout.setIndent(indent); 795 layout.setAlignment(alignment); 796 layout.setJustify(justify); 797 798 int lastOffset = 0; 799 int length = line.length(); 800 if (styles != null) { 801 if (ranges != null) { 802 int rangeCount = styleCount << 1; 803 for (int i = rangeStart; i < rangeCount; i += 2) { 804 int start, end; 805 if (lineOffset > ranges[i]) { 806 start = 0; 807 end = Math.min (length, ranges[i + 1] - lineOffset + ranges[i]); 808 } else { 809 start = ranges[i] - lineOffset; 810 end = Math.min(length, start + ranges[i + 1]); 811 } 812 if (start >= length) break; 813 if (lastOffset < start) { 814 layout.setStyle(null, lastOffset, start - 1); 815 } 816 layout.setStyle(getStyleRange(styles[i >> 1]), start, end); 817 lastOffset = Math.max(lastOffset, end); 818 } 819 } else { 820 for (int i = rangeStart; i < styleCount; i++) { 821 int start, end; 822 if (lineOffset > styles[i].start) { 823 start = 0; 824 end = Math.min (length, styles[i].length - lineOffset + styles[i].start); 825 } else { 826 start = styles[i].start - lineOffset; 827 end = Math.min(length, start + styles[i].length); 828 } 829 if (start >= length) break; 830 if (lastOffset < start) { 831 layout.setStyle(null, lastOffset, start - 1); 832 } 833 layout.setStyle(getStyleRange(styles[i]), start, end); 834 lastOffset = Math.max(lastOffset, end); 835 } 836 } 837 } 838 if (lastOffset < length) layout.setStyle(null, lastOffset, length); 839 if (styledText != null && styledText.isFixedLineHeight()) { 840 int index = -1; 841 int lineCount = layout.getLineCount(); 842 int height = getLineHeight(); 843 for (int i = 0; i < lineCount; i++) { 844 int lineHeight = layout.getLineBounds(i).height; 845 if (lineHeight > height) { 846 height = lineHeight; 847 index = i; 848 } 849 } 850 if (index != -1) { 851 FontMetrics metrics = layout.getLineMetrics(index); 852 ascent = metrics.getAscent() + metrics.getLeading(); 853 descent = metrics.getDescent(); 854 if (layouts != null) { 855 for (int i = 0; i < layouts.length; i++) { 856 if (layouts[i] != null && layouts[i] != layout) { 857 layouts[i].setAscent(ascent); 858 layouts[i].setDescent(descent); 859 } 860 } 861 } 862 if (styledText.verticalScrollOffset != 0) { 863 int topIndex = styledText.topIndex; 864 int topIndexY = styledText.topIndexY; 865 int lineHeight = getLineHeight(); 866 if (topIndexY >= 0) { 867 styledText.verticalScrollOffset = (topIndex - 1) * lineHeight + lineHeight - topIndexY; 868 } else { 869 styledText.verticalScrollOffset = topIndex * lineHeight - topIndexY; 870 } 871 } 872 styledText.calculateScrollBars(); 873 if (styledText.isBidiCaret()) styledText.createCaretBitmaps(); 874 styledText.caretDirection = SWT.NULL; 875 styledText.setCaretLocation(); 876 styledText.redraw(); 877 } 878 } 879 return layout; 880 } 881 int getWidth() { 882 return maxWidth; 883 } 884 void reset() { 885 if (layouts != null) { 886 for (int i = 0; i < layouts.length; i++) { 887 TextLayout layout = layouts[i]; 888 if (layout != null) layout.dispose(); 889 } 890 layouts = null; 891 } 892 topIndex = -1; 893 stylesSetCount = styleCount = lineCount = 0; 894 ranges = null; 895 styles = null; 896 stylesSet = null; 897 lines = null; 898 lineWidth = null; 899 lineHeight = null; 900 bullets = null; 901 bulletsIndices = null; 902 redrawLines = null; 903 } 904 void reset(int startLine, int lineCount) { 905 int endLine = startLine + lineCount; 906 if (startLine < 0 || endLine > lineWidth.length) return; 907 for (int i = startLine; i < endLine; i++) { 908 lineWidth[i] = -1; 909 lineHeight[i] = -1; 910 } 911 if (startLine <= maxWidthLineIndex && maxWidthLineIndex < endLine) { 912 maxWidth = 0; 913 maxWidthLineIndex = -1; 914 if (lineCount != this.lineCount) { 915 for (int i = 0; i < this.lineCount; i++) { 916 if (lineWidth[i] > maxWidth) { 917 maxWidth = lineWidth[i]; 918 maxWidthLineIndex = i; 919 } 920 } 921 } 922 } 923 } 924 void setContent(StyledTextContent content) { 925 reset(); 926 this.content = content; 927 lineCount = content.getLineCount(); 928 lineWidth = new int[lineCount]; 929 lineHeight = new int[lineCount]; 930 reset(0, lineCount); 931 } 932 void setFont(Font font, int tabs) { 933 TextLayout layout = new TextLayout(device); 934 layout.setFont(regularFont); 935 if (font != null) { 936 if (boldFont != null) boldFont.dispose(); 937 if (italicFont != null) italicFont.dispose(); 938 if (boldItalicFont != null) boldItalicFont.dispose(); 939 boldFont = italicFont = boldItalicFont = null; 940 regularFont = font; 941 layout.setText(" "); 942 layout.setFont(font); 943 layout.setStyle(new TextStyle(getFont(SWT.NORMAL), null, null), 0, 0); 944 layout.setStyle(new TextStyle(getFont(SWT.BOLD), null, null), 1, 1); 945 layout.setStyle(new TextStyle(getFont(SWT.ITALIC), null, null), 2, 2); 946 layout.setStyle(new TextStyle(getFont(SWT.BOLD | SWT.ITALIC), null, null), 3, 3); 947 FontMetrics metrics = layout.getLineMetrics(0); 948 ascent = metrics.getAscent() + metrics.getLeading(); 949 descent = metrics.getDescent(); 950 boldFont.dispose(); 951 italicFont.dispose(); 952 boldItalicFont.dispose(); 953 boldFont = italicFont = boldItalicFont = null; 954 } 955 layout.dispose(); 956 layout = new TextLayout(device); 957 layout.setFont(regularFont); 958 StringBuffer tabBuffer = new StringBuffer (tabs); 959 for (int i = 0; i < tabs; i++) { 960 tabBuffer.append(' '); 961 } 962 layout.setText(tabBuffer.toString()); 963 tabWidth = layout.getBounds().width; 964 layout.dispose(); 965 if (styledText != null) { 966 GC gc = new GC(styledText); 967 averageCharWidth = gc.getFontMetrics().getAverageCharWidth(); 968 gc.dispose(); 969 } 970 } 971 void setLineAlignment(int startLine, int count, int alignment) { 972 if (lines == null) lines = new LineInfo[lineCount]; 973 for (int i = startLine; i < startLine + count; i++) { 974 if (lines[i] == null) { 975 lines[i] = new LineInfo(); 976 } 977 lines[i].flags |= ALIGNMENT; 978 lines[i].alignment = alignment; 979 } 980 } 981 void setLineBackground(int startLine, int count, Color background) { 982 if (lines == null) lines = new LineInfo[lineCount]; 983 for (int i = startLine; i < startLine + count; i++) { 984 if (lines[i] == null) { 985 lines[i] = new LineInfo(); 986 } 987 lines[i].flags |= BACKGROUND; 988 lines[i].background = background; 989 } 990 } 991 void setLineBullet(int startLine, int count, Bullet bullet) { 992 if (bulletsIndices != null) { 993 bulletsIndices = null; 994 bullets = null; 995 } 996 if (bullets == null) { 997 if (bullet == null) return; 998 bullets = new Bullet[1]; 999 bullets[0] = bullet; 1000 } 1001 int index = 0; 1002 while (index < bullets.length) { 1003 if (bullet == bullets[index]) break; 1004 index++; 1005 } 1006 if (bullet != null) { 1007 if (index == bullets.length) { 1008 Bullet[] newBulletsList = new Bullet[bullets.length + 1]; 1009 System.arraycopy(bullets, 0, newBulletsList, 0, bullets.length); 1010 newBulletsList[index] = bullet; 1011 bullets = newBulletsList; 1012 } 1013 bullet.addIndices(startLine, count); 1014 } else { 1015 updateBullets(startLine, count, 0, false); 1016 styledText.redrawLinesBullet(redrawLines); 1017 redrawLines = null; 1018 } 1019} 1020void setLineIndent(int startLine, int count, int indent) { 1021 if (lines == null) lines = new LineInfo[lineCount]; 1022 for (int i = startLine; i < startLine + count; i++) { 1023 if (lines[i] == null) { 1024 lines[i] = new LineInfo(); 1025 } 1026 lines[i].flags |= INDENT; 1027 lines[i].indent = indent; 1028 } 1029} 1030void setLineJustify(int startLine, int count, boolean justify) { 1031 if (lines == null) lines = new LineInfo[lineCount]; 1032 for (int i = startLine; i < startLine + count; i++) { 1033 if (lines[i] == null) { 1034 lines[i] = new LineInfo(); 1035 } 1036 lines[i].flags |= JUSTIFY; 1037 lines[i].justify = justify; 1038 } 1039} 1040void setLineSegments(int startLine, int count, int[] segments) { 1041 if (lines == null) lines = new LineInfo[lineCount]; 1042 for (int i = startLine; i < startLine + count; i++) { 1043 if (lines[i] == null) { 1044 lines[i] = new LineInfo(); 1045 } 1046 lines[i].flags |= SEGMENTS; 1047 lines[i].segments = segments; 1048 } 1049} 1050void setStyleRanges (int[] newRanges, StyleRange[] newStyles) { 1051 if (newStyles == null) { 1052 stylesSetCount = styleCount = 0; 1053 ranges = null; 1054 styles = null; 1055 stylesSet = null; 1056 return; 1057 } 1058 if (newRanges == null && COMPACT_STYLES) { 1059 newRanges = new int[newStyles.length << 1]; 1060 StyleRange[] tmpStyles = new StyleRange[newStyles.length]; 1061 if (stylesSet == null) stylesSet = new StyleRange[4]; 1062 for (int i = 0, j = 0; i < newStyles.length; i++) { 1063 StyleRange newStyle = newStyles[i]; 1064 newRanges[j++] = newStyle.start; 1065 newRanges[j++] = newStyle.length; 1066 int index = 0; 1067 while (index < stylesSetCount) { 1068 if (stylesSet[index].similarTo(newStyle)) break; 1069 index++; 1070 } 1071 if (index == stylesSetCount) { 1072 if (stylesSetCount == stylesSet.length) { 1073 StyleRange[] tmpStylesSet = new StyleRange[stylesSetCount + 4]; 1074 System.arraycopy(stylesSet, 0, tmpStylesSet, 0, stylesSetCount); 1075 stylesSet = tmpStylesSet; 1076 } 1077 stylesSet[stylesSetCount++] = newStyle; 1078 } 1079 tmpStyles[i] = stylesSet[index]; 1080 } 1081 newStyles = tmpStyles; 1082 } 1083 1084 if (styleCount == 0) { 1085 if (newRanges != null) { 1086 ranges = new int[newRanges.length]; 1087 System.arraycopy(newRanges, 0, ranges, 0, ranges.length); 1088 } 1089 styles = new StyleRange[newStyles.length]; 1090 System.arraycopy(newStyles, 0, styles, 0, styles.length); 1091 styleCount = newStyles.length; 1092 return; 1093 } 1094 if (newRanges != null && ranges == null) { 1095 ranges = new int[styles.length << 1]; 1096 for (int i = 0, j = 0; i < styleCount; i++) { 1097 ranges[j++] = styles[i].start; 1098 ranges[j++] = styles[i].length; 1099 } 1100 } 1101 if (newRanges == null && ranges != null) { 1102 newRanges = new int[newStyles.length << 1]; 1103 for (int i = 0, j = 0; i < newStyles.length; i++) { 1104 newRanges[j++] = newStyles[i].start; 1105 newRanges[j++] = newStyles[i].length; 1106 } 1107 } 1108 if (ranges != null) { 1109 int rangeCount = styleCount << 1; 1110 int start = newRanges[0]; 1111 int modifyStart = getRangeIndex(start, -1, rangeCount), modifyEnd; 1112 boolean insert = modifyStart == rangeCount; 1113 if (!insert) { 1114 int end = newRanges[newRanges.length - 2] + newRanges[newRanges.length - 1]; 1115 modifyEnd = getRangeIndex(end, modifyStart - 1, rangeCount); 1116 insert = modifyStart == modifyEnd && ranges[modifyStart] >= end; 1117 } 1118 if (insert) { 1119 addMerge(newRanges, newStyles, newRanges.length, modifyStart, modifyStart); 1120 return; 1121 } 1122 modifyEnd = modifyStart; 1123 int[] mergeRanges = new int[6]; 1124 StyleRange[] mergeStyles = new StyleRange[3]; 1125 for (int i = 0; i < newRanges.length; i += 2) { 1126 int newStart = newRanges[i]; 1127 int newEnd = newStart + newRanges[i + 1]; 1128 if (newStart == newEnd) continue; 1129 int modifyLast = 0, mergeCount = 0; 1130 while (modifyEnd < rangeCount) { 1131 if (newStart >= ranges[modifyStart] + ranges[modifyStart + 1]) modifyStart += 2; 1132 if (ranges[modifyEnd] + ranges[modifyEnd + 1] > newEnd) break; 1133 modifyEnd += 2; 1134 } 1135 if (ranges[modifyStart] < newStart && newStart < ranges[modifyStart] + ranges[modifyStart + 1]) { 1136 mergeStyles[mergeCount >> 1] = styles[modifyStart >> 1]; 1137 mergeRanges[mergeCount] = ranges[modifyStart]; 1138 mergeRanges[mergeCount + 1] = newStart - ranges[modifyStart]; 1139 mergeCount += 2; 1140 } 1141 mergeStyles[mergeCount >> 1] = newStyles[i >> 1]; 1142 mergeRanges[mergeCount] = newStart; 1143 mergeRanges[mergeCount + 1] = newRanges[i + 1]; 1144 mergeCount += 2; 1145 if (modifyEnd < rangeCount && ranges[modifyEnd] < newEnd && newEnd < ranges[modifyEnd] + ranges[modifyEnd + 1]) { 1146 mergeStyles[mergeCount >> 1] = styles[modifyEnd >> 1]; 1147 mergeRanges[mergeCount] = newEnd; 1148 mergeRanges[mergeCount + 1] = ranges[modifyEnd] + ranges[modifyEnd + 1] - newEnd; 1149 mergeCount += 2; 1150 modifyLast = 2; 1151 } 1152 int grow = addMerge(mergeRanges, mergeStyles, mergeCount, modifyStart, modifyEnd + modifyLast); 1153 rangeCount += grow; 1154 modifyStart = modifyEnd += grow; 1155 } 1156 } else { 1157 int start = newStyles[0].start; 1158 int modifyStart = getRangeIndex(start, -1, styleCount), modifyEnd; 1159 boolean insert = modifyStart == styleCount; 1160 if (!insert) { 1161 int end = newStyles[newStyles.length - 1].start + newStyles[newStyles.length - 1].length; 1162 modifyEnd = getRangeIndex(end, modifyStart - 1, styleCount); 1163 insert = modifyStart == modifyEnd && styles[modifyStart].start >= end; 1164 } 1165 if (insert) { 1166 addMerge(newStyles, newStyles.length, modifyStart, modifyStart); 1167 return; 1168 } 1169 modifyEnd = modifyStart; 1170 StyleRange[] mergeStyles = new StyleRange[3]; 1171 for (int i = 0; i < newStyles.length; i++) { 1172 StyleRange newStyle = newStyles[i], style; 1173 int newStart = newStyle.start; 1174 int newEnd = newStart + newStyle.length; 1175 if (newStart == newEnd) continue; 1176 int modifyLast = 0, mergeCount = 0; 1177 while (modifyEnd < styleCount) { 1178 if (newStart >= styles[modifyStart].start + styles[modifyStart].length) modifyStart++; 1179 if (styles[modifyEnd].start + styles[modifyEnd].length > newEnd) break; 1180 modifyEnd++; 1181 } 1182 style = styles[modifyStart]; 1183 if (style.start < newStart && newStart < style.start + style.length) { 1184 style = mergeStyles[mergeCount++] = (StyleRange)style.clone(); 1185 style.length = newStart - style.start; 1186 } 1187 mergeStyles[mergeCount++] = newStyle; 1188 if (modifyEnd < styleCount) { 1189 style = styles[modifyEnd]; 1190 if (style.start < newEnd && newEnd < style.start + style.length) { 1191 style = mergeStyles[mergeCount++] = (StyleRange)style.clone(); 1192 style.length += style.start - newEnd; 1193 style.start = newEnd; 1194 modifyLast = 1; 1195 } 1196 } 1197 int grow = addMerge(mergeStyles, mergeCount, modifyStart, modifyEnd + modifyLast); 1198 modifyStart = modifyEnd += grow; 1199 } 1200 } 1201} 1202void textChanging(TextChangingEvent event) { 1203 int start = event.start; 1204 int newCharCount = event.newCharCount, replaceCharCount = event.replaceCharCount; 1205 int newLineCount = event.newLineCount, replaceLineCount = event.replaceLineCount; 1206 1207 updateRanges(start, replaceCharCount, newCharCount); 1208 1209 int startLine = content.getLineAtOffset(start); 1210 if (replaceCharCount == content.getCharCount()) lines = null; 1211 if (replaceLineCount == lineCount) { 1212 lineCount = newLineCount; 1213 lineWidth = new int[lineCount]; 1214 lineHeight = new int[lineCount]; 1215 reset(0, lineCount); 1216 } else { 1217 int delta = newLineCount - replaceLineCount; 1218 if (lineCount + delta > lineWidth.length) { 1219 int[] newWidths = new int[lineCount + delta + GROW]; 1220 System.arraycopy(lineWidth, 0, newWidths, 0, lineCount); 1221 lineWidth = newWidths; 1222 int[] newHeights = new int[lineCount + delta + GROW]; 1223 System.arraycopy(lineHeight, 0, newHeights, 0, lineCount); 1224 lineHeight = newHeights; 1225 } 1226 if (lines != null) { 1227 if (lineCount + delta > lines.length) { 1228 LineInfo[] newLines = new LineInfo[lineCount + delta + GROW]; 1229 System.arraycopy(lines, 0, newLines, 0, lineCount); 1230 lines = newLines; 1231 } 1232 } 1233 int startIndex = startLine + replaceLineCount + 1; 1234 int endIndex = startLine + newLineCount + 1; 1235 System.arraycopy(lineWidth, startIndex, lineWidth, endIndex, lineCount - startIndex); 1236 System.arraycopy(lineHeight, startIndex, lineHeight, endIndex, lineCount - startIndex); 1237 for (int i = startLine; i < endIndex; i++) { 1238 lineWidth[i] = lineHeight[i] = -1; 1239 } 1240 for (int i = lineCount + delta; i < lineCount; i++) { 1241 lineWidth[i] = lineHeight[i] = -1; 1242 } 1243 if (layouts != null) { 1244 int layoutStartLine = startLine - topIndex; 1245 int layoutEndLine = layoutStartLine + replaceLineCount + 1; 1246 for (int i = layoutStartLine; i < layoutEndLine; i++) { 1247 if (0 <= i && i < layouts.length) { 1248 if (layouts[i] != null) layouts[i].dispose(); 1249 layouts[i] = null; 1250 if (bullets != null && bulletsIndices != null) bullets[i] = null; 1251 } 1252 } 1253 if (delta > 0) { 1254 for (int i = layouts.length - 1; i >= layoutEndLine; i--) { 1255 if (0 <= i && i < layouts.length) { 1256 endIndex = i + delta; 1257 if (0 <= endIndex && endIndex < layouts.length) { 1258 layouts[endIndex] = layouts[i]; 1259 layouts[i] = null; 1260 if (bullets != null && bulletsIndices != null) { 1261 bullets[endIndex] = bullets[i]; 1262 bulletsIndices[endIndex] = bulletsIndices[i]; 1263 bullets[i] = null; 1264 } 1265 } else { 1266 if (layouts[i] != null) layouts[i].dispose(); 1267 layouts[i] = null; 1268 if (bullets != null && bulletsIndices != null) bullets[i] = null; 1269 } 1270 } 1271 } 1272 } else if (delta < 0) { 1273 for (int i = layoutEndLine; i < layouts.length; i++) { 1274 if (0 <= i && i < layouts.length) { 1275 endIndex = i + delta; 1276 if (0 <= endIndex && endIndex < layouts.length) { 1277 layouts[endIndex] = layouts[i]; 1278 layouts[i] = null; 1279 if (bullets != null && bulletsIndices != null) { 1280 bullets[endIndex] = bullets[i]; 1281 bulletsIndices[endIndex] = bulletsIndices[i]; 1282 bullets[i] = null; 1283 } 1284 } else { 1285 if (layouts[i] != null) layouts[i].dispose(); 1286 layouts[i] = null; 1287 if (bullets != null && bulletsIndices != null) bullets[i] = null; 1288 } 1289 } 1290 } 1291 } 1292 } 1293 if (replaceLineCount != 0 || newLineCount != 0) { 1294 int startLineOffset = content.getOffsetAtLine(startLine); 1295 if (startLineOffset != start) startLine++; 1296 updateBullets(startLine, replaceLineCount, newLineCount, true); 1297 if (lines != null) { 1298 startIndex = startLine + replaceLineCount; 1299 endIndex = startLine + newLineCount; 1300 System.arraycopy(lines, startIndex, lines, endIndex, lineCount - startIndex); 1301 for (int i = startLine; i < endIndex; i++) { 1302 lines[i] = null; 1303 } 1304 for (int i = lineCount + delta; i < lineCount; i++) { 1305 lines[i] = null; 1306 } 1307 } 1308 } 1309 lineCount += delta; 1310 if (maxWidthLineIndex != -1 && startLine <= maxWidthLineIndex && maxWidthLineIndex <= startLine + replaceLineCount) { 1311 maxWidth = 0; 1312 maxWidthLineIndex = -1; 1313 for (int i = 0; i < lineCount; i++) { 1314 if (lineWidth[i] > maxWidth) { 1315 maxWidth = lineWidth[i]; 1316 maxWidthLineIndex = i; 1317 } 1318 } 1319 } 1320 } 1321} 1322void updateBullets(int startLine, int replaceLineCount, int newLineCount, boolean update) { 1323 if (bullets == null) return; 1324 if (bulletsIndices != null) return; 1325 for (int i = 0; i < bullets.length; i++) { 1326 Bullet bullet = bullets[i]; 1327 int[] lines = bullet.removeIndices(startLine, replaceLineCount, newLineCount, update); 1328 if (lines != null) { 1329 if (redrawLines == null) { 1330 redrawLines = lines; 1331 } else { 1332 int[] newRedrawBullets = new int[redrawLines.length + lines.length]; 1333 System.arraycopy(redrawLines, 0, newRedrawBullets, 0, redrawLines.length); 1334 System.arraycopy(lines, 0, newRedrawBullets, redrawLines.length, lines.length); 1335 redrawLines = newRedrawBullets; 1336 } 1337 } 1338 } 1339 int removed = 0; 1340 for (int i = 0; i < bullets.length; i++) { 1341 if (bullets[i].size() == 0) removed++; 1342 } 1343 if (removed > 0) { 1344 if (removed == bullets.length) { 1345 bullets = null; 1346 } else { 1347 Bullet[] newBulletsList = new Bullet[bullets.length - removed]; 1348 for (int i = 0, j = 0; i < bullets.length; i++) { 1349 Bullet bullet = bullets[i]; 1350 if (bullet.size() > 0) newBulletsList[j++] = bullet; 1351 } 1352 bullets = newBulletsList; 1353 } 1354 } 1355} 1356void updateRanges(int start, int replaceCharCount, int newCharCount) { 1357 if (styleCount == 0 || (replaceCharCount == 0 && newCharCount == 0)) return; 1358 if (ranges != null) { 1359 int rangeCount = styleCount << 1; 1360 int modifyStart = getRangeIndex(start, -1, rangeCount); 1361 if (modifyStart == rangeCount) return; 1362 int end = start + replaceCharCount; 1363 int modifyEnd = getRangeIndex(end, modifyStart - 1, rangeCount); 1364 int offset = newCharCount - replaceCharCount; 1365 if (modifyStart == modifyEnd && ranges[modifyStart] < start && end < ranges[modifyEnd] + ranges[modifyEnd + 1]) { 1366 if (newCharCount == 0) { 1367 ranges[modifyStart + 1] -= replaceCharCount; 1368 modifyEnd += 2; 1369 } else { 1370 if (rangeCount + 2 > ranges.length) { 1371 int[] newRanges = new int[ranges.length + (GROW << 1)]; 1372 System.arraycopy(ranges, 0, newRanges, 0, rangeCount); 1373 ranges = newRanges; 1374 StyleRange[] newStyles = new StyleRange[styles.length + GROW]; 1375 System.arraycopy(styles, 0, newStyles, 0, styleCount); 1376 styles = newStyles; 1377 } 1378 System.arraycopy(ranges, modifyStart + 2, ranges, modifyStart + 4, rangeCount - (modifyStart + 2)); 1379 System.arraycopy(styles, (modifyStart + 2) >> 1, styles, (modifyStart + 4) >> 1, styleCount - ((modifyStart + 2) >> 1)); 1380 ranges[modifyStart + 3] = ranges[modifyStart] + ranges[modifyStart + 1] - end; 1381 ranges[modifyStart + 2] = start + newCharCount; 1382 ranges[modifyStart + 1] = start - ranges[modifyStart]; 1383 styles[(modifyStart >> 1) + 1] = styles[modifyStart >> 1]; 1384 rangeCount += 2; 1385 styleCount++; 1386 modifyEnd += 4; 1387 } 1388 if (offset != 0) { 1389 for (int i = modifyEnd; i < rangeCount; i += 2) { 1390 ranges[i] += offset; 1391 } 1392 } 1393 } else { 1394 if (ranges[modifyStart] < start && start < ranges[modifyStart] + ranges[modifyStart + 1]) { 1395 ranges[modifyStart + 1] = start - ranges[modifyStart]; 1396 modifyStart += 2; 1397 } 1398 if (modifyEnd < rangeCount && ranges[modifyEnd] < end && end < ranges[modifyEnd] + ranges[modifyEnd + 1]) { 1399 ranges[modifyEnd + 1] = ranges[modifyEnd] + ranges[modifyEnd + 1] - end; 1400 ranges[modifyEnd] = end; 1401 } 1402 if (offset != 0) { 1403 for (int i = modifyEnd; i < rangeCount; i += 2) { 1404 ranges[i] += offset; 1405 } 1406 } 1407 System.arraycopy(ranges, modifyEnd, ranges, modifyStart, rangeCount - modifyEnd); 1408 System.arraycopy(styles, modifyEnd >> 1, styles, modifyStart >> 1, styleCount - (modifyEnd >> 1)); 1409 styleCount -= (modifyEnd - modifyStart) >> 1; 1410 } 1411 } else { 1412 int modifyStart = getRangeIndex(start, -1, styleCount); 1413 if (modifyStart == styleCount) return; 1414 int end = start + replaceCharCount; 1415 int modifyEnd = getRangeIndex(end, modifyStart - 1, styleCount); 1416 int offset = newCharCount - replaceCharCount; 1417 if (modifyStart == modifyEnd && styles[modifyStart].start < start && end < styles[modifyEnd].start + styles[modifyEnd].length) { 1418 if (newCharCount == 0) { 1419 styles[modifyStart].length -= replaceCharCount; 1420 modifyEnd++; 1421 } else { 1422 if (styleCount + 1 > styles.length) { 1423 StyleRange[] newStyles = new StyleRange[styles.length + GROW]; 1424 System.arraycopy(styles, 0, newStyles, 0, styleCount); 1425 styles = newStyles; 1426 } 1427 System.arraycopy(styles, modifyStart + 1, styles, modifyStart + 2, styleCount - (modifyStart + 1)); 1428 styles[modifyStart + 1] = (StyleRange)styles[modifyStart].clone(); 1429 styles[modifyStart + 1].length = styles[modifyStart].start + styles[modifyStart].length - end; 1430 styles[modifyStart + 1].start = start + newCharCount; 1431 styles[modifyStart].length = start - styles[modifyStart].start; 1432 styleCount++; 1433 modifyEnd += 2; 1434 } 1435 if (offset != 0) { 1436 for (int i = modifyEnd; i < styleCount; i++) { 1437 styles[i].start += offset; 1438 } 1439 } 1440 } else { 1441 if (styles[modifyStart].start < start && start < styles[modifyStart].start + styles[modifyStart].length) { 1442 styles[modifyStart].length = start - styles[modifyStart].start; 1443 modifyStart++; 1444 } 1445 if (modifyEnd < styleCount && styles[modifyEnd].start < end && end < styles[modifyEnd].start + styles[modifyEnd].length) { 1446 styles[modifyEnd].length = styles[modifyEnd].start + styles[modifyEnd].length - end; 1447 styles[modifyEnd].start = end; 1448 } 1449 if (offset != 0) { 1450 for (int i = modifyEnd; i < styleCount; i++) { 1451 styles[i].start += offset; 1452 } 1453 } 1454 System.arraycopy(styles, modifyEnd, styles, modifyStart, styleCount - modifyEnd); 1455 styleCount -= modifyEnd - modifyStart; 1456 } 1457 } 1458} 1459} 1460 | Popular Tags |