comparison dwt/graphics/TextLayout.d @ 45:d8635bb48c7c

Merge with SWT 3.5
author Jacob Carlborg <doob@me.com>
date Mon, 01 Dec 2008 17:07:00 +0100
parents 642f460a0908
children cfa563df4fdd
comparison
equal deleted inserted replaced
44:ca5e494f2bbf 45:d8635bb48c7c
1 /******************************************************************************* 1 /*******************************************************************************
2 * Copyright (c) 2000, 2007 IBM Corporation and others. 2 * Copyright (c) 2000, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials 3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0 4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at 5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html 6 * http://www.eclipse.org/legal/epl-v10.html
7 * 7 *
8 * Contributors: 8 * Contributors:
9 * IBM Corporation - initial API and implementation 9 * IBM Corporation - initial API and implementation
10 * 10 *
11 * Port to the D programming language: 11 * Port to the D programming language:
12 * Jacob Carlborg <jacob.carlborg@gmail.com> 12 * Jacob Carlborg <doob@me.com>
13 *******************************************************************************/ 13 *******************************************************************************/
14 module dwt.graphics.TextLayout; 14 module dwt.graphics.TextLayout;
15 15
16 import dwt.DWT; 16 import dwt.DWT;
17 import dwt.DWTException; 17 import dwt.DWTException;
18 import dwt.internal.Compatibility;
19 import dwt.internal.cocoa.NSArray;
20 import dwt.internal.cocoa.NSAutoreleasePool;
21 import dwt.internal.cocoa.NSBezierPath;
18 import dwt.internal.cocoa.NSColor; 22 import dwt.internal.cocoa.NSColor;
19 import dwt.internal.cocoa.NSFont; 23 import dwt.internal.cocoa.NSFont;
20 import dwt.internal.cocoa.NSLayoutManager; 24 import dwt.internal.cocoa.NSLayoutManager;
21 import dwt.internal.cocoa.NSMutableParagraphStyle; 25 import dwt.internal.cocoa.NSMutableParagraphStyle;
22 import dwt.internal.cocoa.NSNumber; 26 import dwt.internal.cocoa.NSNumber;
25 import dwt.internal.cocoa.NSRect; 29 import dwt.internal.cocoa.NSRect;
26 import dwt.internal.cocoa.NSSize; 30 import dwt.internal.cocoa.NSSize;
27 import dwt.internal.cocoa.NSString; 31 import dwt.internal.cocoa.NSString;
28 import dwt.internal.cocoa.NSTextContainer; 32 import dwt.internal.cocoa.NSTextContainer;
29 import dwt.internal.cocoa.NSTextStorage; 33 import dwt.internal.cocoa.NSTextStorage;
34 import dwt.internal.cocoa.NSTextTab;
35 import dwt.internal.cocoa.NSThread;
30 import dwt.internal.cocoa.OS; 36 import dwt.internal.cocoa.OS;
31 37
32 import tango.text.convert.Format; 38 import tango.text.convert.Format;
33 39
34 import dwt.dwthelper.utils; 40 import dwt.dwthelper.utils;
59 * Application code must explicitly invoke the <code>TextLayout#dispose()</code> 65 * Application code must explicitly invoke the <code>TextLayout#dispose()</code>
60 * method to release the operating system resources managed by each instance 66 * method to release the operating system resources managed by each instance
61 * when those instances are no longer required. 67 * when those instances are no longer required.
62 * </p> 68 * </p>
63 * 69 *
64 * @since 3.0 70 * @see <a href="http://www.eclipse.org/swt/snippets/#textlayout">TextLayout, TextStyle snippets</a>
71 * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Example: CustomControlExample, StyledText tab</a>
72 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
73 *
74 * @since 3.0
65 */ 75 */
66 public final class TextLayout : Resource { 76 public final class TextLayout : Resource {
67 77
68 alias Resource.init_ init_; 78 alias Resource.init_ init_;
69 79
81 int wrapWidth; 91 int wrapWidth;
82 int orientation; 92 int orientation;
83 93
84 int[] lineOffsets; 94 int[] lineOffsets;
85 NSRect[] lineBounds; 95 NSRect[] lineBounds;
96
97 static final int UNDERLINE_THICK = 1 << 16;
86 98
87 static class StyleItem { 99 static class StyleItem {
88 TextStyle style; 100 TextStyle style;
89 int start; 101 int start;
90 102
128 140
129 void checkLayout() { 141 void checkLayout() {
130 if (isDisposed()) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); 142 if (isDisposed()) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
131 } 143 }
132 144
145 float[] computePolyline(int left, int top, int right, int bottom) {
146 int height = bottom - top; // can be any number
147 int width = 2 * height; // must be even
148 int peaks = Compatibility.ceil(right - left, width);
149 if (peaks is 0 && right - left > 2) {
150 peaks = 1;
151 }
152 int length = ((2 * peaks) + 1) * 2;
153 if (length < 0) return new float[0];
154
155 float[] coordinates = new float[length];
156 for (int i = 0; i < peaks; i++) {
157 int index = 4 * i;
158 coordinates[index] = left + (width * i);
159 coordinates[index+1] = bottom;
160 coordinates[index+2] = coordinates[index] + width / 2;
161 coordinates[index+3] = top;
162 }
163 coordinates[length-2] = left + (width * peaks);
164 coordinates[length-1] = bottom;
165 return coordinates;
166 }
167
133 void computeRuns() { 168 void computeRuns() {
134 if (textStorage !is null) return; 169 if (textStorage !is null) return;
135 NSString str = NSString.stringWith(text); 170 NSString str = NSString.stringWith(text);
136 textStorage = (cast(NSTextStorage)(new NSTextStorage()).alloc()); 171 textStorage = (cast(NSTextStorage)(new NSTextStorage()).alloc());
137 textStorage.initWithString_(str); 172 textStorage.initWithString(str);
138 layoutManager = cast(NSLayoutManager)(new NSLayoutManager()).alloc().init(); 173 layoutManager = cast(NSLayoutManager)(new NSLayoutManager()).alloc().init();
139 textContainer = cast(NSTextContainer)(new NSTextContainer()).alloc(); 174 textContainer = cast(NSTextContainer)(new NSTextContainer()).alloc();
140 NSSize size = NSSize(); 175 NSSize size = NSSize();
141 size.width = wrapWidth !is -1 ? wrapWidth : Float.MAX_VALUE; 176 size.width = wrapWidth !is -1 ? wrapWidth : Float.MAX_VALUE;
142 size.height = Float.MAX_VALUE; 177 size.height = Float.MAX_VALUE;
146 181
147 textStorage.beginEditing(); 182 textStorage.beginEditing();
148 Font defaultFont = font !is null ? font : device.systemFont; 183 Font defaultFont = font !is null ? font : device.systemFont;
149 NSRange range = NSRange(); 184 NSRange range = NSRange();
150 range.length = str.length(); 185 range.length = str.length();
151 textStorage.addAttribute(OS.NSFontAttributeName(), defaultFont.handle, range); 186 textStorage.addAttribute(OS.NSFontAttributeName, defaultFont.handle, range);
152 187
153 NSMutableParagraphStyle paragraph = cast(NSMutableParagraphStyle)(new NSMutableParagraphStyle()).alloc().init(); 188 NSMutableParagraphStyle paragraph = cast(NSMutableParagraphStyle)(new NSMutableParagraphStyle()).alloc().init();
154 NSTextAlignment align_ = NSLeftTextAlignment; 189 NSTextAlignment align_ = NSLeftTextAlignment;
155 if (justify) { 190 if (justify) {
156 align_ = NSJustifiedTextAlignment; 191 align_ = NSJustifiedTextAlignment;
164 } 199 }
165 } 200 }
166 paragraph.setAlignment(align_); 201 paragraph.setAlignment(align_);
167 paragraph.setLineSpacing(spacing); 202 paragraph.setLineSpacing(spacing);
168 paragraph.setFirstLineHeadIndent(indent); 203 paragraph.setFirstLineHeadIndent(indent);
204 paragraph.setLineBreakMode(wrapWidth !is -1 ? OS.NSLineBreakByWordWrapping : OS.NSLineBreakByClipping);
205 paragraph.setTabStops(NSArray.array());
206 if (tabs !is null) {
207 int count = tabs.length;
208 for (int i = 0, pos = 0; i < count; i++) {
209 pos += tabs[i];
210 NSTextTab tab = (NSTextTab)new NSTextTab().alloc();
211 tab = tab.initWithType(OS.NSLeftTabStopType, pos);
212 paragraph.addTabStop(tab);
213 tab.release();
214 }
215 int width = count - 2 >= 0 ? tabs[count - 1] - tabs[count - 2] : tabs[count - 1];
216 paragraph.setDefaultTabInterval(width);
217 }
169 218
170 //TODO tabs ascend descent wrap 219 //TODO ascend descent wrap
171 220
172 textStorage.addAttribute(OS.NSParagraphStyleAttributeName(), paragraph, range); 221 textStorage.addAttribute(OS.NSParagraphStyleAttributeName, paragraph, range);
173 paragraph.release(); 222 paragraph.release();
174 223
175 int textLength = str.length(); 224 int /*long*/ textLength = str.length();
176 for (int i = 0; i < styles.length - 1; i++) { 225 for (int i = 0; i < styles.length - 1; i++) {
177 StyleItem run = styles[i]; 226 StyleItem run = styles[i];
178 if (run.style is null) continue; 227 if (run.style is null) continue;
179 TextStyle style = run.style; 228 TextStyle style = run.style;
180 range.location = textLength !is 0 ? translateOffset(run.start) : 0; 229 range.location = textLength !is 0 ? translateOffset(run.start) : 0;
181 range.length = translateOffset(styles[i + 1].start) - range.location; 230 range.length = translateOffset(styles[i + 1].start) - range.location;
182 Font font = style.font; 231 Font font = style.font;
183 if (font !is null) { 232 if (font !is null) {
184 textStorage.addAttribute(OS.NSFontAttributeName(), font.handle, range); 233 textStorage.addAttribute(OS.NSFontAttributeName, font.handle, range);
185 } 234 }
186 Color foreground = style.foreground; 235 Color foreground = style.foreground;
187 if (foreground !is null) { 236 if (foreground !is null) {
188 NSColor color = NSColor.colorWithDeviceRed(foreground.handle[0], foreground.handle[1], foreground.handle[2], 1); 237 NSColor color = NSColor.colorWithDeviceRed(foreground.handle[0], foreground.handle[1], foreground.handle[2], 1);
189 textStorage.addAttribute(OS.NSForegroundColorAttributeName(), color, range); 238 textStorage.addAttribute(OS.NSForegroundColorAttributeName, color, range);
190 } 239 }
191 Color background = style.background; 240 Color background = style.background;
192 if (background !is null) { 241 if (background !is null) {
193 NSColor color = NSColor.colorWithDeviceRed(background.handle[0], background.handle[1], background.handle[2], 1); 242 NSColor color = NSColor.colorWithDeviceRed(background.handle[0], background.handle[1], background.handle[2], 1);
194 textStorage.addAttribute(OS.NSBackgroundColorAttributeName, color, range); 243 textStorage.addAttribute(OS.NSBackgroundColorAttributeName, color, range);
195 } 244 }
196 if (style.strikeout) { 245 if (style.strikeout) {
197 textStorage.addAttribute(OS.NSStrikethroughStyleAttributeName(), NSNumber.numberWithInt(OS.NSUnderlineStyleSingle), range); 246 textStorage.addAttribute(OS.NSStrikethroughStyleAttributeName, NSNumber.numberWithInt(OS.NSUnderlineStyleSingle), range);
198 Color strikeColor = style.strikeoutColor; 247 Color strikeColor = style.strikeoutColor;
199 if (strikeColor !is null) { 248 if (strikeColor !is null) {
200 NSColor color = NSColor.colorWithDeviceRed(strikeColor.handle[0], strikeColor.handle[1], strikeColor.handle[2], 1); 249 NSColor color = NSColor.colorWithDeviceRed(strikeColor.handle[0], strikeColor.handle[1], strikeColor.handle[2], 1);
201 textStorage.addAttribute(OS.NSStrikethroughColorAttributeName(), color, range); 250 textStorage.addAttribute(OS.NSStrikethroughColorAttributeName, color, range);
202 } 251 }
203 } 252 }
204 if (style.underline) { 253 if (style.underline) {
205 //TODO - IME - thick
206 int underlineStyle = 0; 254 int underlineStyle = 0;
207 switch (style.underlineStyle) { 255 switch (style.underlineStyle) {
208 case DWT.UNDERLINE_SINGLE: 256 case DWT.UNDERLINE_SINGLE:
209 underlineStyle = OS.NSUnderlineStyleSingle; 257 underlineStyle = OS.NSUnderlineStyleSingle;
210 break; 258 break;
211 case DWT.UNDERLINE_DOUBLE: 259 case DWT.UNDERLINE_DOUBLE:
212 underlineStyle = OS.NSUnderlineStyleDouble; 260 underlineStyle = OS.NSUnderlineStyleDouble;
213 break; 261 break;
262 case UNDERLINE_THICK:
263 underlineStyle = OS.NSUnderlineStyleThick;
264 break;
214 } 265 }
215 if (underlineStyle !is 0) { 266 if (underlineStyle !is 0) {
216 textStorage.addAttribute(OS.NSUnderlineStyleAttributeName(), NSNumber.numberWithInt(underlineStyle), range); 267 textStorage.addAttribute(OS.NSUnderlineStyleAttributeName, NSNumber.numberWithInt(underlineStyle), range);
217 Color underlineColor = style.underlineColor; 268 Color underlineColor = style.underlineColor;
218 if (underlineColor !is null) { 269 if (underlineColor !is null) {
219 NSColor color = NSColor.colorWithDeviceRed(underlineColor.handle[0], underlineColor.handle[1], underlineColor.handle[2], 1); 270 NSColor color = NSColor.colorWithDeviceRed(underlineColor.handle[0], underlineColor.handle[1], underlineColor.handle[2], 1);
220 textStorage.addAttribute(OS.NSUnderlineColorAttributeName(), color, range); 271 textStorage.addAttribute(OS.NSUnderlineColorAttributeName, color, range);
221 } 272 }
222 } 273 }
223 } 274 }
224 if (style.rise !is 0) { 275 if (style.rise !is 0) {
225 textStorage.addAttribute(OS.NSBaselineOffsetAttributeName(), NSNumber.numberWithInt(style.rise), range); 276 textStorage.addAttribute(OS.NSBaselineOffsetAttributeName, NSNumber.numberWithInt(style.rise), range);
226 } 277 }
227 if (style.metrics !is null) { 278 if (style.metrics !is null) {
228 //TODO 279 //TODO
229 } 280 }
230 } 281 }
231 textStorage.endEditing(); 282 textStorage.endEditing();
232 283
233 textContainer.setLineFragmentPadding(0); 284 textContainer.setLineFragmentPadding(0);
234 layoutManager.glyphRangeForTextContainer(textContainer); 285 layoutManager.glyphRangeForTextContainer(textContainer);
235 286
236 int numberOfLines, index, numberOfGlyphs = layoutManager.numberOfGlyphs(); 287 int numberOfLines;
288 NSUInteger numberOfGlyphs = layoutManager.numberOfGlyphs(), index;
237 NSRangePointer rangePtr = cast(NSRangePointer) OS.malloc(NSRange.sizeof); 289 NSRangePointer rangePtr = cast(NSRangePointer) OS.malloc(NSRange.sizeof);
238 NSRange lineRange = NSRange();
239 for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){ 290 for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){
240 layoutManager.lineFragmentUsedRectForGlyphAtIndex_effectiveRange_withoutAdditionalLayout_(index, rangePtr, true); 291 layoutManager.lineFragmentUsedRectForGlyphAtIndex(index, rangePtr, true);
241 OS.memmove(&lineRange, rangePtr, NSRange.sizeof); 292 OS.memmove(&lineRange, rangePtr, NSRange.sizeof);
242 index = lineRange.location + lineRange.length; 293 index = lineRange.location + lineRange.length;
243 } 294 }
244 if (numberOfLines is 0) numberOfLines++; 295 if (numberOfLines is 0) numberOfLines++;
245 int[] offsets = new int[numberOfLines + 1]; 296 int[] offsets = new int[numberOfLines + 1];
246 NSRect[] bounds = new NSRect[numberOfLines]; 297 NSRect[] bounds = new NSRect[numberOfLines];
247 for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){ 298 for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){
248 bounds[numberOfLines] = layoutManager.lineFragmentUsedRectForGlyphAtIndex_effectiveRange_withoutAdditionalLayout_(index, rangePtr, true); 299 bounds[numberOfLines] = layoutManager.lineFragmentUsedRectForGlyphAtIndex(index, rangePtr, true);
300 if (numberOfLines < bounds.length - 1) bounds[numberOfLines].height -= spacing;
249 OS.memmove(&lineRange, rangePtr, NSRange.sizeof); 301 OS.memmove(&lineRange, rangePtr, NSRange.sizeof);
250 offsets[numberOfLines] = lineRange.location; 302 offsets[numberOfLines] = (int)/*64*/lineRange.location;
251 index = lineRange.location + lineRange.length; 303 index = lineRange.location + lineRange.length;
252 } 304 }
253 if (numberOfLines is 0) { 305 if (numberOfLines is 0) {
254 Font font = this.font !is null ? this.font : device.systemFont; 306 Font font = this.font !is null ? this.font : device.systemFont;
255 NSFont nsFont = font.handle; 307 NSFont nsFont = font.handle;
256 bounds[0] = NSRect(); 308 bounds[0] = NSRect();
257 bounds[0].height = Math.max(layoutManager.defaultLineHeightForFont(nsFont), ascent + descent); 309 bounds[0].height = Math.max(layoutManager.defaultLineHeightForFont(nsFont), ascent + descent);
258 } 310 }
259 OS.free(rangePtr); 311 OS.free(rangePtr);
260 offsets[numberOfLines] = textStorage.length(); 312 offsets[numberOfLines] = (int)/*64*/textStorage.length();
261 this.lineOffsets = offsets; 313 this.lineOffsets = offsets;
262 this.lineBounds = bounds; 314 this.lineBounds = bounds;
263 } 315 }
264 316
265 void destroy() { 317 void destroy() {
343 computeRuns(); 395 computeRuns();
344 if (gc is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); 396 if (gc is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
345 if (gc.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); 397 if (gc.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
346 if (selectionForeground !is null && selectionForeground.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); 398 if (selectionForeground !is null && selectionForeground.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
347 if (selectionBackground !is null && selectionBackground.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); 399 if (selectionBackground !is null && selectionBackground.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
348 gc.checkGC(GC.CLIPPING | GC.TRANSFORM | GC.FOREGROUND); 400 int length = translateOffset(text.length());
349 // float[] foreground = gc.data.foreground; 401 if (length is 0 && flags is 0) return;
350 // NSColor color = NSColor.colorWithDeviceRed(foreground[0], foreground[1], foreground[2], foreground[3]); 402 NSAutoreleasePool pool = gc.checkGC(GC.CLIPPING | GC.TRANSFORM | GC.FOREGROUND);
351 // textStorage.setForegroundColor(color); 403 try {
352 NSPoint pt = NSPoint(); 404 gc.handle.saveGraphicsState();
353 pt.x = x; 405 float[] fg = gc.data.foreground;
354 pt.y = y; 406 NSColor foreground = NSColor.colorWithDeviceRed(fg[0], fg[1], fg[2], fg[3]);
355 NSRange range = NSRange(); 407 NSPoint pt = NSPoint();
356 range.length = layoutManager.numberOfGlyphs(); 408 pt.x = x;
357 bool hasSelection = selectionStart <= selectionEnd && selectionStart !is -1 && selectionEnd !is -1; 409 pt.y = y;
410 bool hasSelection = selectionStart <= selectionEnd && selectionStart !is -1 && selectionEnd !is -1;
358 NSRange* selectionRange = null; 411 NSRange* selectionRange = null;
359 if (hasSelection) { 412 NSColor selectionColor = null;
360 selectionRange = new NSRange(); 413 if (hasSelection || (flags & DWT.LAST_LINE_SELECTION) !is 0) {
361 selectionRange.location = selectionStart; 414 if (selectionBackground is null) selectionBackground = device.getSystemColor(DWT.COLOR_LIST_SELECTION);
362 selectionRange.length = selectionEnd - selectionStart + 1; 415 selectionColor = NSColor.colorWithDeviceRed(selectionBackground.handle[0], selectionBackground.handle[1], selectionBackground.handle[2], selectionBackground.handle[3]);
363 if (selectionBackground is null) selectionBackground = device.getSystemColor(DWT.COLOR_LIST_SELECTION); 416 }
364 NSColor selectionColor = NSColor.colorWithDeviceRed(selectionBackground.handle[0], selectionBackground.handle[1], selectionBackground.handle[2], selectionBackground.handle[3]); 417 if (hasSelection) {
418 selectionRange = new NSRange();
419 selectionRange.location = selectionStart;
420 selectionRange.length = selectionEnd - selectionStart + 1;
365 layoutManager.addTemporaryAttribute(OS.NSBackgroundColorAttributeName, selectionColor, *selectionRange); 421 layoutManager.addTemporaryAttribute(OS.NSBackgroundColorAttributeName, selectionColor, *selectionRange);
366 } 422 }
367 //TODO draw selection for flags (LAST_LINE_SELECTION and FULL_SELECTION) 423 //TODO draw selection for flags (DELIMITER_SELECTION)
368 if (range.length > 0) { 424 int numberOfGlyphs = layoutManager.numberOfGlyphs();
369 layoutManager.drawBackgroundForGlyphRange(range, pt); 425 if (numberOfGlyphs > 0) {
370 layoutManager.drawGlyphsForGlyphRange(range, pt); 426 NSRange range = new NSRange();
371 } 427 for (int i = 0; i < styles.length - 1; i++) {
372 if (selectionRange !is null) { 428 StyleItem run = styles[i];
429 if (run.style !is null && run.style.foreground !is null) continue;
430 range.location = length !is 0 ? translateOffset(run.start) : 0;
431 range.length = translateOffset(styles[i + 1].start) - range.location;
432 layoutManager.addTemporaryAttribute(OS.NSForegroundColorAttributeName, foreground, range);
433 }
434 range.location = 0;
435 range.length = numberOfGlyphs;
436 layoutManager.drawBackgroundForGlyphRange(range, pt);
437 layoutManager.drawGlyphsForGlyphRange(range, pt);
438 range.length = length;
439 layoutManager.removeTemporaryAttribute(OS.NSForegroundColorAttributeName, range);
440 NSPoint point = new NSPoint();
441 for (int j = 0; j < styles.length; j++) {
442 StyleItem run = styles[j];
443 TextStyle style = run.style;
444 if (style is null) continue;
445 bool drawUnderline = style.underline && style.underlineStyle !is DWT.UNDERLINE_SINGLE && style.underlineStyle !is DWT.UNDERLINE_DOUBLE;
446 drawUnderline = drawUnderline && (j + 1 is styles.length || !style.isAdherentUnderline(styles[j + 1].style));
447 bool drawBorder = style.borderStyle !is DWT.NONE;
448 drawBorder = drawBorder && (j + 1 is styles.length || !style.isAdherentBorder(styles[j + 1].style));
449 if (!drawUnderline && !drawBorder) continue;
450 int end = j + 1 < styles.length ? translateOffset(styles[j + 1].start - 1) : length;
451 for (int i = 0; i < lineOffsets.length - 1; i++) {
452 int lineStart = untranslateOffset(lineOffsets[i]);
453 int lineEnd = untranslateOffset(lineOffsets[i + 1] - 1);
454 if (drawUnderline) {
455 int start = run.start;
456 for (int k = j; k > 0 && style.isAdherentUnderline(styles[k - 1].style); k--) {
457 start = styles[k - 1].start;
458 }
459 start = translateOffset(start);
460 if (!(start > lineEnd || end < lineStart)) {
461 range.location = layoutManager.glyphIndexForCharacterAtIndex(Math.max(lineStart, start));
462 range.length = layoutManager.glyphIndexForCharacterAtIndex(Math.min(lineEnd, end) + 1) - range.location;
463 if (range.length > 0) {
464 gc.handle.saveGraphicsState();
465 NSRect rect = layoutManager.boundingRectForGlyphRange(range, textContainer);
466 float baseline = layoutManager.typesetter().baselineOffsetInLayoutManager(layoutManager, lineStart);
467 float underlineX = pt.x + rect.x;
468 float underlineY = pt.y + rect.y + rect.height - baseline;
469 float[] color = null;
470 if (style.underlineColor !is null) color = style.underlineColor.handle;
471 if (color is null && style.foreground !is null) color = style.foreground.handle;
472 if (color !is null) {
473 NSColor.colorWithDeviceRed(color[0], color[1], color[2], color[3]).setStroke();
474 }
475 NSBezierPath path = NSBezierPath.bezierPath();
476 switch (style.underlineStyle) {
477 case DWT.UNDERLINE_ERROR: {
478 path.setLineWidth(2f);
479 path.setLineCapStyle(OS.NSRoundLineCapStyle);
480 path.setLineJoinStyle(OS.NSRoundLineJoinStyle);
481 path.setLineDash(new float[]{1, 3f}, 2, 0);
482 point.x = underlineX;
483 point.y = underlineY + 0.5f;
484 path.moveToPoint(point);
485 point.x = underlineX + rect.width;
486 point.y = underlineY + 0.5f;
487 path.lineToPoint(point);
488 break;
489 }
490 case DWT.UNDERLINE_SQUIGGLE: {
491 gc.handle.setShouldAntialias(false);
492 path.setLineWidth(1.0f);
493 path.setLineCapStyle(OS.NSButtLineCapStyle);
494 path.setLineJoinStyle(OS.NSMiterLineJoinStyle);
495 float lineBottom = pt.y + rect.y + rect.height;
496 float squigglyThickness = 1;
497 float squigglyHeight = 2 * squigglyThickness;
498 float squigglyY = Math.min(underlineY - squigglyHeight / 2, lineBottom - squigglyHeight - 1);
499 float[] points = computePolyline((int)underlineX, (int)squigglyY, (int)(underlineX + rect.width), (int)(squigglyY + squigglyHeight));
500 point.x = points[0] + 0.5f;
501 point.y = points[1] + 0.5f;
502 path.moveToPoint(point);
503 for (int p = 2; p < points.length; p+=2) {
504 point.x = points[p] + 0.5f;
505 point.y = points[p+1] + 0.5f;
506 path.lineToPoint(point);
507 }
508 break;
509 }
510 }
511 path.stroke();
512 gc.handle.restoreGraphicsState();
513 }
514 }
515 }
516 if (drawBorder) {
517 int start = run.start;
518 for (int k = j; k > 0 && style.isAdherentBorder(styles[k - 1].style); k--) {
519 start = styles[k - 1].start;
520 }
521 start = translateOffset(start);
522 if (!(start > lineEnd || end < lineStart)) {
523 range.location = layoutManager.glyphIndexForCharacterAtIndex(Math.max(lineStart, start));
524 range.length = layoutManager.glyphIndexForCharacterAtIndex(Math.min(lineEnd, end) + 1) - range.location;
525 if (range.length > 0) {
526 gc.handle.saveGraphicsState();
527 NSRect rect = layoutManager.boundingRectForGlyphRange(range, textContainer);
528 rect.x += pt.x + 0.5f;
529 rect.y += pt.y + 0.5f;
530 rect.width -= 0.5f;
531 rect.height -= 0.5f;
532 float[] color = null;
533 if (style.borderColor !is null) color = style.borderColor.handle;
534 if (color is null && style.foreground !is null) color = style.foreground.handle;
535 if (color !is null) {
536 NSColor.colorWithDeviceRed(color[0], color[1], color[2], color[3]).setStroke();
537 }
538 int width = 1;
539 float[] dashes = null;
540 switch (style.borderStyle) {
541 case DWT.BORDER_SOLID: break;
542 case DWT.BORDER_DASH: dashes = width !is 0 ? GC.LINE_DASH : GC.LINE_DASH_ZERO; break;
543 case DWT.BORDER_DOT: dashes = width !is 0 ? GC.LINE_DOT : GC.LINE_DOT_ZERO; break;
544 }
545 NSBezierPath path = NSBezierPath.bezierPath();
546 path.setLineDash(dashes, dashes !is null ? dashes.length : 0, 0);
547 path.appendBezierPathWithRect(rect);
548 path.stroke();
549 gc.handle.restoreGraphicsState();
550 }
551 }
552 }
553 }
554
555 }
556 }
557 if ((flags & DWT.LAST_LINE_SELECTION) !is 0) {
558 NSRect bounds = lineBounds[lineBounds.length - 1];
559 NSRect rect = new NSRect();
560 rect.x = pt.x + bounds.x + bounds.width;
561 rect.y = y + bounds.y;
562 rect.width = (flags & DWT.FULL_SELECTION) !is 0 ? 0x7fffffff : bounds.height / 3;
563 rect.height = bounds.height;
564 selectionColor.setFill();
565 NSBezierPath path = NSBezierPath.bezierPath();
566 path.appendBezierPathWithRect(rect);
567 path.fill();
568 }
569 if (selectionRange !is null) {
373 layoutManager.removeTemporaryAttribute(OS.NSBackgroundColorAttributeName, *selectionRange); 570 layoutManager.removeTemporaryAttribute(OS.NSBackgroundColorAttributeName, *selectionRange);
571 }
572 gc.handle.restoreGraphicsState();
573 } finally {
574 gc.uncheckGC(pool);
374 } 575 }
375 } 576 }
376 577
377 void freeRuns() { 578 void freeRuns() {
378 if (textStorage is null) return; 579 if (textStorage is null) return;
424 checkLayout(); 625 checkLayout();
425 return ascent; 626 return ascent;
426 } 627 }
427 628
428 /** 629 /**
429 * Returns the bounds of the receiver. 630 * Returns the bounds of the receiver. The width returned is either the
631 * width of the longest line or the width set using {@link TextLayout#setWidth(int)}.
632 * To obtain the text bounds of a line use {@link TextLayout#getLineBounds(int)}.
430 * 633 *
431 * @return the bounds of the receiver 634 * @return the bounds of the receiver
432 * 635 *
433 * @exception DWTException <ul> 636 * @exception DWTException <ul>
434 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 637 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
435 * </ul> 638 * </ul>
639 *
640 * @see #setWidth(int)
641 * @see #getLineBounds(int)
436 */ 642 */
437 public Rectangle getBounds() { 643 public Rectangle getBounds() {
438 checkLayout(); 644 checkLayout();
439 computeRuns(); 645 NSAutoreleasePool pool = null;
440 NSRect rect = layoutManager.usedRectForTextContainer(textContainer); 646 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
441 if (wrapWidth !is -1) rect.width = wrapWidth; 647 try {
442 if (text.length() is 0) { 648 computeRuns();
443 Font font = this.font !is null ? this.font : device.systemFont; 649 NSRect rect = layoutManager.usedRectForTextContainer(textContainer);
444 NSFont nsFont = font.handle; 650 if (wrapWidth !is -1) rect.width = wrapWidth;
445 rect.height = Math.max(rect.height, layoutManager.defaultLineHeightForFont(nsFont)); 651 if (text.length() is 0) {
446 } 652 Font font = this.font !is null ? this.font : device.systemFont;
447 rect.height = Math.max(rect.height, ascent + descent); 653 NSFont nsFont = font.handle;
654 rect.height = Math.max(rect.height, layoutManager.defaultLineHeightForFont(nsFont));
655 }
656 rect.height = Math.max(rect.height, ascent + descent) + spacing;
448 return new Rectangle(0, 0, cast(int)rect.width, cast(int)rect.height); 657 return new Rectangle(0, 0, cast(int)rect.width, cast(int)rect.height);
658 } finally {
659 if (pool !is null) pool.release();
660 }
449 } 661 }
450 662
451 /** 663 /**
452 * Returns the bounds for the specified range of characters. The 664 * Returns the bounds for the specified range of characters. The
453 * bounds is the smallest rectangle that encompasses all characters 665 * bounds is the smallest rectangle that encompasses all characters
462 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 674 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
463 * </ul> 675 * </ul>
464 */ 676 */
465 public Rectangle getBounds(int start, int end) { 677 public Rectangle getBounds(int start, int end) {
466 checkLayout(); 678 checkLayout();
467 computeRuns(); 679 NSAutoreleasePool pool = null;
468 int length = text.length(); 680 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
469 if (length is 0) return new Rectangle(0, 0, 0, 0); 681 try {
470 if (start > end) return new Rectangle(0, 0, 0, 0); 682 computeRuns();
471 start = Math.min(Math.max(0, start), length - 1); 683 int length = text.length();
472 end = Math.min(Math.max(0, end), length - 1); 684 if (length is 0) return new Rectangle(0, 0, 0, 0);
473 start = translateOffset(start); 685 if (start > end) return new Rectangle(0, 0, 0, 0);
474 end = translateOffset(end); 686 start = Math.min(Math.max(0, start), length - 1);
687 end = Math.min(Math.max(0, end), length - 1);
688 start = translateOffset(start);
689 end = translateOffset(end);
475 NSRange range = NSRange(); 690 NSRange range = NSRange();
476 range.location = layoutManager.glyphIndexForCharacterAtIndex(start); 691 range.location = layoutManager.glyphIndexForCharacterAtIndex(start);
477 range.length = layoutManager.glyphIndexForCharacterAtIndex(end + 1) - range.location; 692 range.length = layoutManager.glyphIndexForCharacterAtIndex(end + 1) - range.location;
478 NSRect rect = layoutManager.boundingRectForGlyphRange(range, textContainer); 693 NSRect rect = layoutManager.boundingRectForGlyphRange(range, textContainer);
479 return new Rectangle(cast(int)rect.x, cast(int)rect.y, cast(int)Math.ceil(rect.width), cast(int)Math.ceil(rect.height)); 694 return new Rectangle(cast(int)rect.x, cast(int)rect.y, cast(int)Math.ceil(rect.width), cast(int)Math.ceil(rect.height));
695 } finally {
696 if (pool !is null) pool.release();
697 }
480 } 698 }
481 699
482 /** 700 /**
483 * Returns the descent of the receiver. 701 * Returns the descent of the receiver.
484 * 702 *
559 * @exception DWTException <ul> 777 * @exception DWTException <ul>
560 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 778 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
561 */ 779 */
562 public int getLevel(int offset) { 780 public int getLevel(int offset) {
563 checkLayout(); 781 checkLayout();
564 computeRuns(); 782 NSAutoreleasePool pool = null;
565 int length = text.length(); 783 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
566 if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE); 784 try {
567 offset = translateOffset(offset); 785 computeRuns();
568 int level = 0; 786 int length = text.length();
569 //TODO 787 if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE);
570 return level; 788 offset = translateOffset(offset);
789 int level = 0;
790 //TODO
791 return level;
792 } finally {
793 if (pool !is null) pool.release();
794 }
571 } 795 }
572 796
573 /** 797 /**
574 * Returns the line offsets. Each value in the array is the 798 * Returns the line offsets. Each value in the array is the
575 * offset for the first character in a line except for the last 799 * offset for the first character in a line except for the last
581 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 805 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
582 * </ul> 806 * </ul>
583 */ 807 */
584 public int[] getLineOffsets() { 808 public int[] getLineOffsets() {
585 checkLayout (); 809 checkLayout ();
586 computeRuns(); 810 NSAutoreleasePool pool = null;
587 int[] offsets = new int[lineOffsets.length]; 811 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
588 for (int i = 0; i < offsets.length; i++) { 812 try {
589 offsets[i] = untranslateOffset(lineOffsets[i]); 813 computeRuns();
590 } 814 int[] offsets = new int[lineOffsets.length];
591 return offsets; 815 for (int i = 0; i < offsets.length; i++) {
816 offsets[i] = untranslateOffset(lineOffsets[i]);
817 }
818 return offsets;
819 } finally {
820 if (pool !is null) pool.release();
821 }
592 } 822 }
593 823
594 /** 824 /**
595 * Returns the index of the line that contains the specified 825 * Returns the index of the line that contains the specified
596 * character offset. 826 * character offset.
605 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 835 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
606 * </ul> 836 * </ul>
607 */ 837 */
608 public int getLineIndex(int offset) { 838 public int getLineIndex(int offset) {
609 checkLayout (); 839 checkLayout ();
610 computeRuns(); 840 NSAutoreleasePool pool = null;
611 int length = text.length(); 841 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
612 if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE); 842 try {
613 offset = translateOffset(offset); 843 computeRuns();
614 for (int line=0; line<lineOffsets.length - 1; line++) { 844 int length = text.length();
615 if (lineOffsets[line + 1] > offset) { 845 if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE);
616 return line; 846 offset = translateOffset(offset);
617 } 847 for (int line=0; line<lineOffsets.length - 1; line++) {
618 } 848 if (lineOffsets[line + 1] > offset) {
619 return lineBounds.length - 1; 849 return line;
850 }
851 }
852 return lineBounds.length - 1;
853 } finally {
854 if (pool !is null) pool.release();
855 }
620 } 856 }
621 857
622 /** 858 /**
623 * Returns the bounds of the line for the specified line index. 859 * Returns the bounds of the line for the specified line index.
624 * 860 *
632 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 868 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
633 * </ul> 869 * </ul>
634 */ 870 */
635 public Rectangle getLineBounds(int lineIndex) { 871 public Rectangle getLineBounds(int lineIndex) {
636 checkLayout(); 872 checkLayout();
637 computeRuns(); 873 NSAutoreleasePool pool = null;
638 if (!(0 <= lineIndex && lineIndex < lineBounds.length)) DWT.error(DWT.ERROR_INVALID_RANGE); 874 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
639 NSRect rect = lineBounds[lineIndex]; 875 try {
876 computeRuns();
877 if (!(0 <= lineIndex && lineIndex < lineBounds.length)) DWT.error(DWT.ERROR_INVALID_RANGE);
878 NSRect rect = lineBounds[lineIndex];
640 return new Rectangle(cast(int)rect.x, cast(int)rect.y, cast(int)rect.width, cast(int)rect.height); 879 return new Rectangle(cast(int)rect.x, cast(int)rect.y, cast(int)rect.width, cast(int)rect.height);
880 } finally {
881 if (pool !is null) pool.release();
882 }
641 } 883 }
642 884
643 /** 885 /**
644 * Returns the receiver's line count. This includes lines caused 886 * Returns the receiver's line count. This includes lines caused
645 * by wrapping. 887 * by wrapping.
650 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 892 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
651 * </ul> 893 * </ul>
652 */ 894 */
653 public int getLineCount() { 895 public int getLineCount() {
654 checkLayout (); 896 checkLayout ();
655 computeRuns(); 897 NSAutoreleasePool pool = null;
656 return lineOffsets.length - 1; 898 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
899 try {
900 computeRuns();
901 return lineOffsets.length - 1;
902 } finally {
903 if (pool !is null) pool.release();
904 }
657 } 905 }
658 906
659 /** 907 /**
660 * Returns the font metrics for the specified line index. 908 * Returns the font metrics for the specified line index.
661 * 909 *
669 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 917 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
670 * </ul> 918 * </ul>
671 */ 919 */
672 public FontMetrics getLineMetrics (int lineIndex) { 920 public FontMetrics getLineMetrics (int lineIndex) {
673 checkLayout (); 921 checkLayout ();
674 computeRuns(); 922 NSAutoreleasePool pool = null;
675 int lineCount = getLineCount(); 923 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
676 if (!(0 <= lineIndex && lineIndex < lineCount)) DWT.error(DWT.ERROR_INVALID_RANGE); 924 try {
677 int length = text.length(); 925 computeRuns();
678 if (length is 0) { 926 int lineCount = getLineCount();
679 Font font = this.font !is null ? this.font : device.systemFont; 927 if (!(0 <= lineIndex && lineIndex < lineCount)) DWT.error(DWT.ERROR_INVALID_RANGE);
680 NSFont nsFont = font.handle; 928 int length = text.length();
929 if (length is 0) {
930 Font font = this.font !is null ? this.font : device.systemFont;
931 NSFont nsFont = font.handle;
681 int ascent = cast(int)(0.5f + nsFont.ascender()); 932 int ascent = cast(int)(0.5f + nsFont.ascender());
682 int descent = cast(int)(0.5f + (-nsFont.descender() + nsFont.leading())); 933 int descent = cast(int)(0.5f + (-nsFont.descender() + nsFont.leading()));
683 ascent = Math.max(ascent, this.ascent); 934 ascent = Math.max(ascent, this.ascent);
684 descent = Math.max(descent, this.descent); 935 descent = Math.max(descent, this.descent);
685 return FontMetrics.cocoa_new(ascent, descent, 0, 0, ascent + descent); 936 return FontMetrics.cocoa_new(ascent, descent, 0, 0, ascent + descent);
686 } 937 }
687 Rectangle rect = getLineBounds(lineIndex); 938 Rectangle rect = getLineBounds(lineIndex);
688 int baseline = cast(int)layoutManager.typesetter().baselineOffsetInLayoutManager(layoutManager, getLineOffsets()[lineIndex]); 939 int baseline = cast(int)layoutManager.typesetter().baselineOffsetInLayoutManager(layoutManager, getLineOffsets()[lineIndex]);
689 return FontMetrics.cocoa_new(rect.height - baseline, baseline, 0, 0, rect.height); 940 return FontMetrics.cocoa_new(rect.height - baseline, baseline, 0, 0, rect.height);
941 } finally {
942 if (pool !is null) pool.release();
943 }
690 } 944 }
691 945
692 /** 946 /**
693 * Returns the location for the specified character offset. The 947 * Returns the location for the specified character offset. The
694 * <code>trailing</code> argument indicates whether the offset 948 * <code>trailing</code> argument indicates whether the offset
705 * @see #getOffset(Point, int[]) 959 * @see #getOffset(Point, int[])
706 * @see #getOffset(int, int, int[]) 960 * @see #getOffset(int, int, int[])
707 */ 961 */
708 public Point getLocation(int offset, bool trailing) { 962 public Point getLocation(int offset, bool trailing) {
709 checkLayout(); 963 checkLayout();
710 computeRuns(); 964 NSAutoreleasePool pool = null;
711 int length = text.length(); 965 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
712 if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE); 966 try {
713 if (length is 0) return new Point(0, 0); 967 computeRuns();
714 offset = translateOffset(offset); 968 int length = text.length();
969 if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE);
970 if (length is 0) return new Point(0, 0);
971 offset = translateOffset(offset);
715 NSUInteger glyphIndex = layoutManager.glyphIndexForCharacterAtIndex(offset); 972 NSUInteger glyphIndex = layoutManager.glyphIndexForCharacterAtIndex(offset);
716 NSRect rect = layoutManager.lineFragmentUsedRectForGlyphAtIndex_effectiveRange_(glyphIndex, null); 973 NSRect rect = layoutManager.lineFragmentUsedRectForGlyphAtIndex_effectiveRange_(glyphIndex, null);
717 NSPoint point = layoutManager.locationForGlyphAtIndex(glyphIndex); 974 NSPoint point = layoutManager.locationForGlyphAtIndex(glyphIndex);
718 if (trailing) { 975 if (trailing) {
719 NSRange range = NSRange(); 976 NSRange range = NSRange();
720 range.location = glyphIndex; 977 range.location = glyphIndex;
721 range.length = 1; 978 range.length = 1;
722 NSRect bounds = layoutManager.boundingRectForGlyphRange(range, textContainer); 979 NSRect bounds = layoutManager.boundingRectForGlyphRange(range, textContainer);
723 point.x += bounds.width; 980 point.x += bounds.width;
724 } 981 }
725 return new Point(cast(int)point.x, cast(int)rect.y); 982 return new Point(cast(int)point.x, cast(int)rect.y);
983 } finally {
984 if (pool !is null) pool.release();
985 }
726 } 986 }
727 987
728 /** 988 /**
729 * Returns the next offset for the specified offset and movement 989 * Returns the next offset for the specified offset and movement
730 * type. The movement is one of <code>DWT.MOVEMENT_CHAR</code>, 990 * type. The movement is one of <code>DWT.MOVEMENT_CHAR</code>,
743 * </ul> 1003 * </ul>
744 * 1004 *
745 * @see #getPreviousOffset(int, int) 1005 * @see #getPreviousOffset(int, int)
746 */ 1006 */
747 public int getNextOffset (int offset, int movement) { 1007 public int getNextOffset (int offset, int movement) {
748 return _getOffset(offset, movement, true); 1008 NSAutoreleasePool pool = null;
1009 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
1010 try {
1011 return _getOffset(offset, movement, true);
1012 } finally {
1013 if (pool !is null) pool.release();
1014 }
749 } 1015 }
750 1016
751 int _getOffset (int offset, int movement, bool forward) { 1017 int _getOffset (int offset, int movement, bool forward) {
752 checkLayout(); 1018 checkLayout();
753 computeRuns(); 1019 computeRuns();
761 if (forward) { 1027 if (forward) {
762 offset++; 1028 offset++;
763 } else { 1029 } else {
764 offset--; 1030 offset--;
765 } 1031 }
766 return untranslateOffset(offset); 1032 return Math.max(0, Math.min(length, untranslateOffset(offset)));
767 } 1033 }
768 case DWT.MOVEMENT_WORD: { 1034 case DWT.MOVEMENT_WORD: {
769 return untranslateOffset(textStorage.nextWordFromIndex(offset, forward)); 1035 return untranslateOffset((int)/*64*/textStorage.nextWordFromIndex(offset, forward));
770 } 1036 }
771 case DWT.MOVEMENT_WORD_END: { 1037 case DWT.MOVEMENT_WORD_END: {
772 NSRange range = textStorage.doubleClickAtIndex(length is offset ? length - 1 : offset); 1038 NSRange range = textStorage.doubleClickAtIndex(length is offset ? length - 1 : offset);
773 return untranslateOffset(range.location + range.length); 1039 return untranslateOffset((int)/*64*/(range.location + range.length));
774 } 1040 }
775 case DWT.MOVEMENT_WORD_START: { 1041 case DWT.MOVEMENT_WORD_START: {
776 NSRange range = textStorage.doubleClickAtIndex(length is offset ? length - 1 : offset); 1042 NSRange range = textStorage.doubleClickAtIndex(length is offset ? length - 1 : offset);
777 return untranslateOffset(range.location); 1043 return untranslateOffset((int)/*64*/range.location);
778 } 1044 }
779 default: 1045 default:
780 break; 1046 break;
781 } 1047 }
782 return -1; 1048 return -1;
805 * 1071 *
806 * @see #getLocation(int, bool) 1072 * @see #getLocation(int, bool)
807 */ 1073 */
808 public int getOffset(Point point, int[] trailing) { 1074 public int getOffset(Point point, int[] trailing) {
809 checkLayout(); 1075 checkLayout();
810 computeRuns(); 1076 NSAutoreleasePool pool = null;
811 if (point is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); 1077 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
812 return getOffset(point.x, point.y, trailing); 1078 try {
1079 computeRuns();
1080 if (point is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
1081 return getOffset(point.x, point.y, trailing);
1082 } finally {
1083 if (pool !is null) pool.release();
1084 }
813 } 1085 }
814 1086
815 /** 1087 /**
816 * Returns the character offset for the specified point. 1088 * Returns the character offset for the specified point.
817 * For a typical character, the trailing argument will be filled in to 1089 * For a typical character, the trailing argument will be filled in to
835 * 1107 *
836 * @see #getLocation(int, bool) 1108 * @see #getLocation(int, bool)
837 */ 1109 */
838 public int getOffset(int x, int y, int[] trailing) { 1110 public int getOffset(int x, int y, int[] trailing) {
839 checkLayout(); 1111 checkLayout();
840 computeRuns(); 1112 NSAutoreleasePool pool = null;
841 if (trailing !is null && trailing.length < 1) DWT.error(DWT.ERROR_INVALID_ARGUMENT); 1113 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
842 int length = text.length(); 1114 try {
843 if (length is 0) return 0; 1115 computeRuns();
1116 if (trailing !is null && trailing.length < 1) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
1117 int length = text.length();
1118 if (length is 0) return 0;
844 NSPoint pt = NSPoint(); 1119 NSPoint pt = NSPoint();
845 pt.x = x; 1120 pt.x = x;
846 pt.y = y; 1121 pt.y = y;
847 CGFloat partialFration; 1122 CGFloat partialFration;
848 NSUInteger glyphIndex = layoutManager.glyphIndexForPoint_inTextContainer_fractionOfDistanceThroughGlyph_(pt, textContainer, &partialFration); 1123 NSUInteger glyphIndex = layoutManager.glyphIndexForPoint(pt, textContainer, &partialFration);
849 int offset = layoutManager.characterIndexForGlyphAtIndex(glyphIndex); 1124 int /*long*/ offset = layoutManager.characterIndexForGlyphAtIndex(glyphIndex);
850 if (trailing !is null) trailing[0] = cast(int) Math.round(partialFration); 1125 if (trailing !is null) trailing[0] = cast(int) Math.round(partialFration);
851 return Math.min(untranslateOffset(offset), length - 1); 1126 return Math.min(untranslateOffset((int)/*64*/offset), length - 1);
1127 } finally {
1128 if (pool !is null) pool.release();
1129 }
852 } 1130 }
853 1131
854 /** 1132 /**
855 * Returns the orientation of the receiver. 1133 * Returns the orientation of the receiver.
856 * 1134 *
883 * </ul> 1161 * </ul>
884 * 1162 *
885 * @see #getNextOffset(int, int) 1163 * @see #getNextOffset(int, int)
886 */ 1164 */
887 public int getPreviousOffset (int index, int movement) { 1165 public int getPreviousOffset (int index, int movement) {
888 return _getOffset(index, movement, false); 1166 NSAutoreleasePool pool = null;
1167 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
1168 try {
1169 return _getOffset(index, movement, false);
1170 } finally {
1171 if (pool !is null) pool.release();
1172 }
889 } 1173 }
890 1174
891 /** 1175 /**
892 * Gets the ranges of text that are associated with a <code>TextStyle</code>. 1176 * Gets the ranges of text that are associated with a <code>TextStyle</code>.
893 * 1177 *
1086 alignment &= mask; 1370 alignment &= mask;
1087 if (alignment is 0) return; 1371 if (alignment is 0) return;
1088 if ((alignment & DWT.LEFT) !is 0) alignment = DWT.LEFT; 1372 if ((alignment & DWT.LEFT) !is 0) alignment = DWT.LEFT;
1089 if ((alignment & DWT.RIGHT) !is 0) alignment = DWT.RIGHT; 1373 if ((alignment & DWT.RIGHT) !is 0) alignment = DWT.RIGHT;
1090 if (this.alignment is alignment) return; 1374 if (this.alignment is alignment) return;
1091 freeRuns(); 1375 NSAutoreleasePool pool = null;
1092 this.alignment = alignment; 1376 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
1377 try {
1378 freeRuns();
1379 this.alignment = alignment;
1380 } finally {
1381 if (pool !is null) pool.release();
1382 }
1093 } 1383 }
1094 1384
1095 /** 1385 /**
1096 * Sets the ascent of the receiver. The ascent is distance in pixels 1386 * Sets the ascent of the receiver. The ascent is distance in pixels
1097 * from the baseline to the top of the line and it is applied to all 1387 * from the baseline to the top of the line and it is applied to all
1112 */ 1402 */
1113 public void setAscent (int ascent) { 1403 public void setAscent (int ascent) {
1114 checkLayout (); 1404 checkLayout ();
1115 if (ascent < -1) DWT.error(DWT.ERROR_INVALID_ARGUMENT); 1405 if (ascent < -1) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
1116 if (this.ascent is ascent) return; 1406 if (this.ascent is ascent) return;
1117 freeRuns(); 1407 NSAutoreleasePool pool = null;
1118 this.ascent = ascent; 1408 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
1409 try {
1410 freeRuns();
1411 this.ascent = ascent;
1412 } finally {
1413 if (pool !is null) pool.release();
1414 }
1119 } 1415 }
1120 1416
1121 /** 1417 /**
1122 * Sets the descent of the receiver. The descent is distance in pixels 1418 * Sets the descent of the receiver. The descent is distance in pixels
1123 * from the baseline to the bottom of the line and it is applied to all 1419 * from the baseline to the bottom of the line and it is applied to all
1138 */ 1434 */
1139 public void setDescent (int descent) { 1435 public void setDescent (int descent) {
1140 checkLayout (); 1436 checkLayout ();
1141 if (descent < -1) DWT.error(DWT.ERROR_INVALID_ARGUMENT); 1437 if (descent < -1) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
1142 if (this.descent is descent) return; 1438 if (this.descent is descent) return;
1143 freeRuns(); 1439 NSAutoreleasePool pool = null;
1144 this.descent = descent; 1440 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
1441 try {
1442 freeRuns();
1443 this.descent = descent;
1444 } finally {
1445 if (pool !is null) pool.release();
1446 }
1145 } 1447 }
1146 1448
1147 /** 1449 /**
1148 * Sets the default font which will be used by the receiver 1450 * Sets the default font which will be used by the receiver
1149 * to draw and measure text. If the 1451 * to draw and measure text. If the
1165 if (font !is null && font.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); 1467 if (font !is null && font.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
1166 Font oldFont = this.font; 1468 Font oldFont = this.font;
1167 if (oldFont is font) return; 1469 if (oldFont is font) return;
1168 this.font = font; 1470 this.font = font;
1169 if (oldFont !is null && oldFont.equals(font)) return; 1471 if (oldFont !is null && oldFont.equals(font)) return;
1170 freeRuns(); 1472 NSAutoreleasePool pool = null;
1473 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
1474 try {
1475 freeRuns();
1476 } finally {
1477 if (pool !is null) pool.release();
1478 }
1171 } 1479 }
1172 1480
1173 /** 1481 /**
1174 * Sets the indent of the receiver. This indent it applied of the first line of 1482 * Sets the indent of the receiver. This indent it applied of the first line of
1175 * each paragraph. 1483 * each paragraph.
1184 */ 1492 */
1185 public void setIndent (int indent) { 1493 public void setIndent (int indent) {
1186 checkLayout (); 1494 checkLayout ();
1187 if (indent < 0) return; 1495 if (indent < 0) return;
1188 if (this.indent is indent) return; 1496 if (this.indent is indent) return;
1189 freeRuns(); 1497 NSAutoreleasePool pool = null;
1190 this.indent = indent; 1498 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
1499 try {
1500 freeRuns();
1501 this.indent = indent;
1502 } finally {
1503 if (pool !is null) pool.release();
1504 }
1191 } 1505 }
1192 1506
1193 /** 1507 /**
1194 * Sets the justification of the receiver. Note that the receiver's 1508 * Sets the justification of the receiver. Note that the receiver's
1195 * width must be set in order to use justification. 1509 * width must be set in order to use justification.
1203 * @since 3.2 1517 * @since 3.2
1204 */ 1518 */
1205 public void setJustify (bool justify) { 1519 public void setJustify (bool justify) {
1206 checkLayout (); 1520 checkLayout ();
1207 if (justify is this.justify) return; 1521 if (justify is this.justify) return;
1208 freeRuns(); 1522 NSAutoreleasePool pool = null;
1209 this.justify = justify; 1523 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
1524 try {
1525 freeRuns();
1526 this.justify = justify;
1527 } finally {
1528 if (pool !is null) pool.release();
1529 }
1210 } 1530 }
1211 1531
1212 /** 1532 /**
1213 * Sets the orientation of the receiver, which must be one 1533 * Sets the orientation of the receiver, which must be one
1214 * of <code>DWT.LEFT_TO_RIGHT</code> or <code>DWT.RIGHT_TO_LEFT</code>. 1534 * of <code>DWT.LEFT_TO_RIGHT</code> or <code>DWT.RIGHT_TO_LEFT</code>.
1225 orientation &= mask; 1545 orientation &= mask;
1226 if (orientation is 0) return; 1546 if (orientation is 0) return;
1227 if ((orientation & DWT.LEFT_TO_RIGHT) !is 0) orientation = DWT.LEFT_TO_RIGHT; 1547 if ((orientation & DWT.LEFT_TO_RIGHT) !is 0) orientation = DWT.LEFT_TO_RIGHT;
1228 if (this.orientation is orientation) return; 1548 if (this.orientation is orientation) return;
1229 this.orientation = orientation; 1549 this.orientation = orientation;
1230 freeRuns(); 1550 NSAutoreleasePool pool = null;
1551 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
1552 try {
1553 freeRuns();
1554 } finally {
1555 if (pool !is null) pool.release();
1556 }
1231 } 1557 }
1232 1558
1233 /** 1559 /**
1234 * Sets the offsets of the receiver's text segments. Text segments are used to 1560 * Sets the offsets of the receiver's text segments. Text segments are used to
1235 * override the default behaviour of the bidirectional algorithm. 1561 * override the default behaviour of the bidirectional algorithm.
1258 if (this.segments[i] !is segments[i]) break; 1584 if (this.segments[i] !is segments[i]) break;
1259 } 1585 }
1260 if (i is segments.length) return; 1586 if (i is segments.length) return;
1261 } 1587 }
1262 } 1588 }
1263 freeRuns(); 1589 NSAutoreleasePool pool = null;
1264 this.segments = segments; 1590 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
1591 try {
1592 freeRuns();
1593 this.segments = segments;
1594 } finally {
1595 if (pool !is null) pool.release();
1596 }
1265 } 1597 }
1266 1598
1267 /** 1599 /**
1268 * Sets the line spacing of the receiver. The line spacing 1600 * Sets the line spacing of the receiver. The line spacing
1269 * is the space left between lines. 1601 * is the space left between lines.
1279 */ 1611 */
1280 public void setSpacing (int spacing) { 1612 public void setSpacing (int spacing) {
1281 checkLayout(); 1613 checkLayout();
1282 if (spacing < 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT); 1614 if (spacing < 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
1283 if (this.spacing is spacing) return; 1615 if (this.spacing is spacing) return;
1284 freeRuns(); 1616 NSAutoreleasePool pool = null;
1285 this.spacing = spacing; 1617 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
1618 try {
1619 freeRuns();
1620 this.spacing = spacing;
1621 } finally {
1622 if (pool !is null) pool.release();
1623 }
1286 } 1624 }
1287 1625
1288 /** 1626 /**
1289 * Sets the style of the receiver for the specified range. Styles previously 1627 * Sets the style of the receiver for the specified range. Styles previously
1290 * set for that range will be overwritten. The start and end offsets are 1628 * set for that range will be overwritten. The start and end offsets are
1298 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 1636 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
1299 * </ul> 1637 * </ul>
1300 */ 1638 */
1301 public void setStyle (TextStyle style, int start, int end) { 1639 public void setStyle (TextStyle style, int start, int end) {
1302 checkLayout(); 1640 checkLayout();
1303 int length = text.length(); 1641 NSAutoreleasePool pool = null;
1304 if (length is 0) return; 1642 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
1305 if (start > end) return; 1643 try {
1306 start = Math.min(Math.max(0, start), length - 1); 1644 int length = text.length();
1307 end = Math.min(Math.max(0, end), length - 1); 1645 if (length is 0) return;
1308 int low = -1; 1646 if (start > end) return;
1309 int high = styles.length; 1647 start = Math.min(Math.max(0, start), length - 1);
1310 while (high - low > 1) { 1648 end = Math.min(Math.max(0, end), length - 1);
1311 int index = (high + low) / 2; 1649 int low = -1;
1312 if (styles[index + 1].start > start) { 1650 int high = styles.length;
1313 high = index; 1651 while (high - low > 1) {
1314 } else { 1652 int index = (high + low) / 2;
1315 low = index; 1653 if (styles[index + 1].start > start) {
1316 } 1654 high = index;
1317 }
1318 if (0 <= high && high < styles.length) {
1319 StyleItem item = styles[high];
1320 if (item.start is start && styles[high + 1].start - 1 is end) {
1321 if (style is null) {
1322 if (item.style is null) return;
1323 } else { 1655 } else {
1324 if (style.equals(item.style)) return; 1656 low = index;
1325 } 1657 }
1326 } 1658 }
1327 } 1659 if (0 <= high && high < styles.length) {
1328 freeRuns(); 1660 StyleItem item = styles[high];
1329 int modifyStart = high; 1661 if (item.start is start && styles[high + 1].start - 1 is end) {
1330 int modifyEnd = modifyStart; 1662 if (style is null) {
1331 while (modifyEnd < styles.length) { 1663 if (item.style is null) return;
1332 if (styles[modifyEnd + 1].start > end) break; 1664 } else {
1333 modifyEnd++; 1665 if (style.equals(item.style)) return;
1334 } 1666 }
1335 if (modifyStart is modifyEnd) { 1667 }
1336 int styleStart = styles[modifyStart].start; 1668 }
1337 int styleEnd = styles[modifyEnd + 1].start - 1; 1669 freeRuns();
1338 if (styleStart is start && styleEnd is end) { 1670 int modifyStart = high;
1339 styles[modifyStart].style = style; 1671 int modifyEnd = modifyStart;
1340 return; 1672 while (modifyEnd < styles.length) {
1341 } 1673 if (styles[modifyEnd + 1].start > end) break;
1342 if (styleStart !is start && styleEnd !is end) { 1674 modifyEnd++;
1343 StyleItem[] newStyles = new StyleItem[styles.length + 2]; 1675 }
1344 System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1); 1676 if (modifyStart is modifyEnd) {
1345 StyleItem item = new StyleItem(); 1677 int styleStart = styles[modifyStart].start;
1346 item.start = start; 1678 int styleEnd = styles[modifyEnd + 1].start - 1;
1347 item.style = style; 1679 if (styleStart is start && styleEnd is end) {
1348 newStyles[modifyStart + 1] = item; 1680 styles[modifyStart].style = style;
1349 item = new StyleItem(); 1681 return;
1350 item.start = end + 1; 1682 }
1351 item.style = styles[modifyStart].style; 1683 if (styleStart !is start && styleEnd !is end) {
1352 newStyles[modifyStart + 2] = item; 1684 StyleItem[] newStyles = new StyleItem[styles.length + 2];
1353 System.arraycopy(styles, modifyEnd + 1, newStyles, modifyEnd + 3, styles.length - modifyEnd - 1); 1685 System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1);
1354 styles = newStyles; 1686 StyleItem item = new StyleItem();
1355 return; 1687 item.start = start;
1356 } 1688 item.style = style;
1357 } 1689 newStyles[modifyStart + 1] = item;
1358 if (start is styles[modifyStart].start) modifyStart--; 1690 item = new StyleItem();
1359 if (end is styles[modifyEnd + 1].start - 1) modifyEnd++; 1691 item.start = end + 1;
1360 int newLength = styles.length + 1 - (modifyEnd - modifyStart - 1); 1692 item.style = styles[modifyStart].style;
1361 StyleItem[] newStyles = new StyleItem[newLength]; 1693 newStyles[modifyStart + 2] = item;
1362 System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1); 1694 System.arraycopy(styles, modifyEnd + 1, newStyles, modifyEnd + 3, styles.length - modifyEnd - 1);
1363 StyleItem item = new StyleItem(); 1695 styles = newStyles;
1364 item.start = start; 1696 return;
1365 item.style = style; 1697 }
1366 newStyles[modifyStart + 1] = item; 1698 }
1367 styles[modifyEnd].start = end + 1; 1699 if (start is styles[modifyStart].start) modifyStart--;
1368 System.arraycopy(styles, modifyEnd, newStyles, modifyStart + 2, styles.length - modifyEnd); 1700 if (end is styles[modifyEnd + 1].start - 1) modifyEnd++;
1369 styles = newStyles; 1701 int newLength = styles.length + 1 - (modifyEnd - modifyStart - 1);
1702 StyleItem[] newStyles = new StyleItem[newLength];
1703 System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1);
1704 StyleItem item = new StyleItem();
1705 item.start = start;
1706 item.style = style;
1707 newStyles[modifyStart + 1] = item;
1708 styles[modifyEnd].start = end + 1;
1709 System.arraycopy(styles, modifyEnd, newStyles, modifyStart + 2, styles.length - modifyEnd);
1710 styles = newStyles;
1711 } finally {
1712 if (pool !is null) pool.release();
1713 }
1370 } 1714 }
1371 1715
1372 /** 1716 /**
1373 * Sets the receiver's tab list. Each value in the tab list specifies 1717 * Sets the receiver's tab list. Each value in the tab list specifies
1374 * the space in pixels from the origin of the text layout to the respective 1718 * the space in pixels from the origin of the text layout to the respective
1390 if (this.tabs[i] !is tabs[i]) break; 1734 if (this.tabs[i] !is tabs[i]) break;
1391 } 1735 }
1392 if (i is tabs.length) return; 1736 if (i is tabs.length) return;
1393 } 1737 }
1394 } 1738 }
1395 freeRuns(); 1739 NSAutoreleasePool pool = null;
1396 this.tabs = tabs; 1740 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
1741 try {
1742 freeRuns();
1743 this.tabs = tabs;
1744 } finally {
1745 if (pool !is null) pool.release();
1746 }
1397 } 1747 }
1398 1748
1399 /** 1749 /**
1400 * Sets the receiver's text. 1750 * Sets the receiver's text.
1401 * 1751 *
1410 */ 1760 */
1411 public void setText (String text) { 1761 public void setText (String text) {
1412 checkLayout (); 1762 checkLayout ();
1413 if (text is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); 1763 if (text is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
1414 if (text.equals(this.text)) return; 1764 if (text.equals(this.text)) return;
1415 freeRuns(); 1765 NSAutoreleasePool pool = null;
1416 this.text = text; 1766 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
1417 styles = new StyleItem[2]; 1767 try {
1418 styles[0] = new StyleItem(); 1768 freeRuns();
1419 styles[1] = new StyleItem(); 1769 this.text = text;
1420 styles[styles.length - 1].start = text.length(); 1770 styles = new StyleItem[2];
1771 styles[0] = new StyleItem();
1772 styles[1] = new StyleItem();
1773 styles[styles.length - 1].start = text.length();
1774 } finally {
1775 if (pool !is null) pool.release();
1776 }
1421 } 1777 }
1422 1778
1423 /** 1779 /**
1424 * Sets the line width of the receiver, which determines how 1780 * Sets the line width of the receiver, which determines how
1425 * text should be wrapped and aligned. The default value is 1781 * text should be wrapped and aligned. The default value is
1438 */ 1794 */
1439 public void setWidth (int width) { 1795 public void setWidth (int width) {
1440 checkLayout(); 1796 checkLayout();
1441 if (width < -1 || width is 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT); 1797 if (width < -1 || width is 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
1442 if (this.wrapWidth is width) return; 1798 if (this.wrapWidth is width) return;
1443 freeRuns(); 1799 NSAutoreleasePool pool = null;
1444 this.wrapWidth = width; 1800 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
1801 try {
1802 freeRuns();
1803 this.wrapWidth = width;
1804 } finally {
1805 if (pool !is null) pool.release();
1806 }
1445 } 1807 }
1446 1808
1447 /** 1809 /**
1448 * Returns a string containing a concise, human-readable 1810 * Returns a string containing a concise, human-readable
1449 * description of the receiver. 1811 * description of the receiver.