KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > custom > StyledTextRenderer


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

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 /**
19  * A StyledTextRenderer renders the content of a StyledText widget.
20  * This class can be used to render to the display or to a printer.
21  */

22 class StyledTextRenderer {
23     Device device;
24     StyledText styledText;
25     StyledTextContent content;
26
27     /* Font info */
28     Font regularFont, boldFont, italicFont, boldItalicFont;
29     int tabWidth;
30     int ascent, descent;
31     int averageCharWidth;
32     
33     /* Line data */
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     /* Bullet */
45     Bullet[] bullets;
46     int[] bulletsIndices;
47     int[] redrawLines;
48     
49     /* Style data */
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 JavaDoc runnable = new Runnable JavaDoc() {
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 JavaDoc 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 JavaDoc 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     // draw objects
392
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 JavaDoc 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 JavaDoc tabBuffer = new StringBuffer JavaDoc(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