diff 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
line wrap: on
line diff
--- a/dwt/graphics/TextLayout.d	Tue Oct 21 15:20:04 2008 +0200
+++ b/dwt/graphics/TextLayout.d	Mon Dec 01 17:07:00 2008 +0100
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -9,12 +9,16 @@
  *     IBM Corporation - initial API and implementation
  *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Jacob Carlborg <doob@me.com>
  *******************************************************************************/
 module dwt.graphics.TextLayout;
 
 import dwt.DWT;
 import dwt.DWTException;
+import dwt.internal.Compatibility;
+import dwt.internal.cocoa.NSArray;
+import dwt.internal.cocoa.NSAutoreleasePool;
+import dwt.internal.cocoa.NSBezierPath;
 import dwt.internal.cocoa.NSColor;
 import dwt.internal.cocoa.NSFont;
 import dwt.internal.cocoa.NSLayoutManager;
@@ -27,6 +31,8 @@
 import dwt.internal.cocoa.NSString;
 import dwt.internal.cocoa.NSTextContainer;
 import dwt.internal.cocoa.NSTextStorage;
+import dwt.internal.cocoa.NSTextTab;
+import dwt.internal.cocoa.NSThread;
 import dwt.internal.cocoa.OS;
 
 import tango.text.convert.Format;
@@ -61,7 +67,11 @@
  * when those instances are no longer required.
  * </p>
  * 
- *  @since 3.0
+ * @see <a href="http://www.eclipse.org/swt/snippets/#textlayout">TextLayout, TextStyle snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Example: CustomControlExample, StyledText tab</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * 
+ * @since 3.0
  */
 public final class TextLayout : Resource {
 
@@ -83,6 +93,8 @@
     
     int[] lineOffsets;
     NSRect[] lineBounds;
+    
+    static final int UNDERLINE_THICK = 1 << 16;
 
     static class StyleItem {
         TextStyle style;
@@ -130,11 +142,34 @@
     if (isDisposed()) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
 }
 
+float[] computePolyline(int left, int top, int right, int bottom) {
+    int height = bottom - top; // can be any number
+    int width = 2 * height; // must be even
+    int peaks = Compatibility.ceil(right - left, width);
+    if (peaks is 0 && right - left > 2) {
+        peaks = 1;
+    }
+    int length = ((2 * peaks) + 1) * 2;
+    if (length < 0) return new float[0];
+    
+    float[] coordinates = new float[length];
+    for (int i = 0; i < peaks; i++) {
+        int index = 4 * i;
+        coordinates[index] = left + (width * i);
+        coordinates[index+1] = bottom;
+        coordinates[index+2] = coordinates[index] + width / 2;
+        coordinates[index+3] = top;
+    }
+    coordinates[length-2] = left + (width * peaks);
+    coordinates[length-1] = bottom;
+    return coordinates;
+}
+
 void computeRuns() {
     if (textStorage !is null) return;
     NSString str = NSString.stringWith(text);
     textStorage = (cast(NSTextStorage)(new NSTextStorage()).alloc());
-    textStorage.initWithString_(str);
+    textStorage.initWithString(str);
     layoutManager = cast(NSLayoutManager)(new NSLayoutManager()).alloc().init();
     textContainer = cast(NSTextContainer)(new NSTextContainer()).alloc();
     NSSize size = NSSize();
@@ -148,7 +183,7 @@
     Font defaultFont = font !is null ? font : device.systemFont;
     NSRange range = NSRange();
     range.length = str.length();
-    textStorage.addAttribute(OS.NSFontAttributeName(), defaultFont.handle, range);
+    textStorage.addAttribute(OS.NSFontAttributeName, defaultFont.handle, range);
     
     NSMutableParagraphStyle paragraph = cast(NSMutableParagraphStyle)(new NSMutableParagraphStyle()).alloc().init();
     NSTextAlignment align_ = NSLeftTextAlignment;
@@ -166,13 +201,27 @@
     paragraph.setAlignment(align_);
     paragraph.setLineSpacing(spacing);
     paragraph.setFirstLineHeadIndent(indent);
+    paragraph.setLineBreakMode(wrapWidth !is -1 ? OS.NSLineBreakByWordWrapping : OS.NSLineBreakByClipping);
+    paragraph.setTabStops(NSArray.array());
+    if (tabs !is null) {
+        int count = tabs.length;
+        for (int i = 0, pos = 0; i < count; i++) {
+            pos += tabs[i];
+            NSTextTab tab = (NSTextTab)new NSTextTab().alloc();
+            tab = tab.initWithType(OS.NSLeftTabStopType, pos);
+            paragraph.addTabStop(tab);
+            tab.release();
+        }
+        int width = count - 2 >= 0 ? tabs[count - 1] - tabs[count - 2] : tabs[count - 1];
+        paragraph.setDefaultTabInterval(width);
+    }
     
-    //TODO tabs ascend descent wrap
+    //TODO ascend descent wrap
     
-    textStorage.addAttribute(OS.NSParagraphStyleAttributeName(), paragraph, range);
+    textStorage.addAttribute(OS.NSParagraphStyleAttributeName, paragraph, range);
     paragraph.release();
     
-    int textLength = str.length();
+    int /*long*/ textLength = str.length();
     for (int i = 0; i < styles.length - 1; i++) {
         StyleItem run = styles[i];
         if (run.style is null) continue;
@@ -181,12 +230,12 @@
         range.length = translateOffset(styles[i + 1].start) - range.location;
         Font font = style.font;
         if (font !is null) {
-            textStorage.addAttribute(OS.NSFontAttributeName(), font.handle, range);
+            textStorage.addAttribute(OS.NSFontAttributeName, font.handle, range);
         }
         Color foreground = style.foreground;
         if (foreground !is null) {
             NSColor color = NSColor.colorWithDeviceRed(foreground.handle[0], foreground.handle[1], foreground.handle[2], 1);
-            textStorage.addAttribute(OS.NSForegroundColorAttributeName(), color, range);
+            textStorage.addAttribute(OS.NSForegroundColorAttributeName, color, range);
         }
         Color background = style.background;
         if (background !is null) {
@@ -194,15 +243,14 @@
             textStorage.addAttribute(OS.NSBackgroundColorAttributeName, color, range);
         }
         if (style.strikeout) {
-            textStorage.addAttribute(OS.NSStrikethroughStyleAttributeName(), NSNumber.numberWithInt(OS.NSUnderlineStyleSingle), range);
+            textStorage.addAttribute(OS.NSStrikethroughStyleAttributeName, NSNumber.numberWithInt(OS.NSUnderlineStyleSingle), range);
             Color strikeColor = style.strikeoutColor;
             if (strikeColor !is null) {
                 NSColor color = NSColor.colorWithDeviceRed(strikeColor.handle[0], strikeColor.handle[1], strikeColor.handle[2], 1);
-                textStorage.addAttribute(OS.NSStrikethroughColorAttributeName(), color, range);
+                textStorage.addAttribute(OS.NSStrikethroughColorAttributeName, color, range);
             }
         }
         if (style.underline) {
-            //TODO - IME - thick
             int underlineStyle = 0;
             switch (style.underlineStyle) {
                 case DWT.UNDERLINE_SINGLE:
@@ -211,18 +259,21 @@
                 case DWT.UNDERLINE_DOUBLE:
                     underlineStyle = OS.NSUnderlineStyleDouble;
                     break;
+                case UNDERLINE_THICK:
+                    underlineStyle = OS.NSUnderlineStyleThick;
+                    break;
             }
             if (underlineStyle !is 0) {
-                textStorage.addAttribute(OS.NSUnderlineStyleAttributeName(), NSNumber.numberWithInt(underlineStyle), range);
+                textStorage.addAttribute(OS.NSUnderlineStyleAttributeName, NSNumber.numberWithInt(underlineStyle), range);
                 Color underlineColor = style.underlineColor;
                 if (underlineColor !is null) {
                     NSColor color = NSColor.colorWithDeviceRed(underlineColor.handle[0], underlineColor.handle[1], underlineColor.handle[2], 1);
-                    textStorage.addAttribute(OS.NSUnderlineColorAttributeName(), color, range);
+                    textStorage.addAttribute(OS.NSUnderlineColorAttributeName, color, range);
                 }
             }
         }
         if (style.rise !is 0) {
-            textStorage.addAttribute(OS.NSBaselineOffsetAttributeName(), NSNumber.numberWithInt(style.rise), range);
+            textStorage.addAttribute(OS.NSBaselineOffsetAttributeName, NSNumber.numberWithInt(style.rise), range);
         }
         if (style.metrics !is null) {
             //TODO
@@ -233,11 +284,11 @@
     textContainer.setLineFragmentPadding(0);    
     layoutManager.glyphRangeForTextContainer(textContainer);
     
-    int numberOfLines, index, numberOfGlyphs = layoutManager.numberOfGlyphs();
+    int numberOfLines;
+    NSUInteger numberOfGlyphs = layoutManager.numberOfGlyphs(), index;
     NSRangePointer rangePtr = cast(NSRangePointer) OS.malloc(NSRange.sizeof);
-    NSRange lineRange = NSRange();
     for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){
-        layoutManager.lineFragmentUsedRectForGlyphAtIndex_effectiveRange_withoutAdditionalLayout_(index, rangePtr, true);
+        layoutManager.lineFragmentUsedRectForGlyphAtIndex(index, rangePtr, true);
         OS.memmove(&lineRange, rangePtr, NSRange.sizeof);
         index = lineRange.location + lineRange.length;
     }
@@ -245,9 +296,10 @@
     int[] offsets = new int[numberOfLines + 1];
     NSRect[] bounds = new NSRect[numberOfLines];
     for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){
-        bounds[numberOfLines] = layoutManager.lineFragmentUsedRectForGlyphAtIndex_effectiveRange_withoutAdditionalLayout_(index, rangePtr, true);
+        bounds[numberOfLines] = layoutManager.lineFragmentUsedRectForGlyphAtIndex(index, rangePtr, true);
+        if (numberOfLines < bounds.length - 1) bounds[numberOfLines].height -= spacing;
         OS.memmove(&lineRange, rangePtr, NSRange.sizeof);
-        offsets[numberOfLines] = lineRange.location;
+        offsets[numberOfLines] = (int)/*64*/lineRange.location;
         index = lineRange.location + lineRange.length;
     }
     if (numberOfLines is 0) {
@@ -257,7 +309,7 @@
         bounds[0].height = Math.max(layoutManager.defaultLineHeightForFont(nsFont), ascent + descent);
     }
     OS.free(rangePtr);
-    offsets[numberOfLines] = textStorage.length();
+    offsets[numberOfLines] = (int)/*64*/textStorage.length();
     this.lineOffsets = offsets;
     this.lineBounds = bounds;
 }
@@ -345,32 +397,181 @@
     if (gc.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     if (selectionForeground !is null && selectionForeground.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     if (selectionBackground !is null && selectionBackground.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-    gc.checkGC(GC.CLIPPING | GC.TRANSFORM | GC.FOREGROUND);
-//  float[] foreground = gc.data.foreground;
-//  NSColor color = NSColor.colorWithDeviceRed(foreground[0], foreground[1], foreground[2], foreground[3]);
-//  textStorage.setForegroundColor(color);
-    NSPoint pt = NSPoint();
-    pt.x = x;
-    pt.y = y;
-    NSRange range = NSRange();
-    range.length = layoutManager.numberOfGlyphs();
-    bool hasSelection = selectionStart <= selectionEnd && selectionStart !is -1 && selectionEnd !is -1;
+    int length = translateOffset(text.length());
+    if (length is 0 && flags is 0) return;
+    NSAutoreleasePool pool = gc.checkGC(GC.CLIPPING | GC.TRANSFORM | GC.FOREGROUND);
+    try {
+        gc.handle.saveGraphicsState();
+        float[] fg = gc.data.foreground;
+        NSColor foreground = NSColor.colorWithDeviceRed(fg[0], fg[1], fg[2], fg[3]);
+        NSPoint pt = NSPoint();
+        pt.x = x;
+        pt.y = y;
+        bool hasSelection = selectionStart <= selectionEnd && selectionStart !is -1 && selectionEnd !is -1;
     NSRange* selectionRange = null;
-    if (hasSelection) {
-        selectionRange = new NSRange();
-        selectionRange.location = selectionStart;
-        selectionRange.length = selectionEnd - selectionStart + 1;
-        if (selectionBackground is null) selectionBackground = device.getSystemColor(DWT.COLOR_LIST_SELECTION);
-        NSColor selectionColor = NSColor.colorWithDeviceRed(selectionBackground.handle[0], selectionBackground.handle[1], selectionBackground.handle[2], selectionBackground.handle[3]);
+        NSColor selectionColor = null;
+        if (hasSelection || (flags & DWT.LAST_LINE_SELECTION) !is 0) {
+            if (selectionBackground is null) selectionBackground = device.getSystemColor(DWT.COLOR_LIST_SELECTION);
+            selectionColor = NSColor.colorWithDeviceRed(selectionBackground.handle[0], selectionBackground.handle[1], selectionBackground.handle[2], selectionBackground.handle[3]);
+        }
+        if (hasSelection) {
+            selectionRange = new NSRange();
+            selectionRange.location = selectionStart;
+            selectionRange.length = selectionEnd - selectionStart + 1;
         layoutManager.addTemporaryAttribute(OS.NSBackgroundColorAttributeName, selectionColor, *selectionRange);
-    }
-    //TODO draw selection for flags (LAST_LINE_SELECTION and FULL_SELECTION)
-    if (range.length > 0) {
-        layoutManager.drawBackgroundForGlyphRange(range, pt);
-        layoutManager.drawGlyphsForGlyphRange(range, pt);
-    }
-    if (selectionRange !is null) {
+        }
+        //TODO draw selection for flags (DELIMITER_SELECTION)
+        int numberOfGlyphs = layoutManager.numberOfGlyphs();
+        if (numberOfGlyphs > 0) {
+            NSRange range = new NSRange();
+            for (int i = 0; i < styles.length - 1; i++) {
+                StyleItem run = styles[i];
+                if (run.style !is null && run.style.foreground !is null) continue;
+                range.location = length !is 0 ? translateOffset(run.start) : 0;
+                range.length = translateOffset(styles[i + 1].start) - range.location;
+                layoutManager.addTemporaryAttribute(OS.NSForegroundColorAttributeName, foreground, range);
+            }
+            range.location = 0;
+            range.length = numberOfGlyphs;
+            layoutManager.drawBackgroundForGlyphRange(range, pt);
+            layoutManager.drawGlyphsForGlyphRange(range, pt);
+            range.length = length;
+            layoutManager.removeTemporaryAttribute(OS.NSForegroundColorAttributeName, range);
+            NSPoint point = new NSPoint();
+            for (int j = 0; j < styles.length; j++) {
+                StyleItem run = styles[j];
+                TextStyle style = run.style;
+                if (style is null) continue;
+                bool drawUnderline = style.underline && style.underlineStyle !is DWT.UNDERLINE_SINGLE && style.underlineStyle !is DWT.UNDERLINE_DOUBLE;
+                drawUnderline = drawUnderline && (j + 1 is styles.length || !style.isAdherentUnderline(styles[j + 1].style)); 
+                bool drawBorder = style.borderStyle !is DWT.NONE;
+                drawBorder = drawBorder && (j + 1 is styles.length || !style.isAdherentBorder(styles[j + 1].style)); 
+                if (!drawUnderline && !drawBorder) continue;
+                int end = j + 1 < styles.length ? translateOffset(styles[j + 1].start - 1) : length;
+                for (int i = 0; i < lineOffsets.length - 1; i++) {
+                    int lineStart = untranslateOffset(lineOffsets[i]);
+                    int lineEnd = untranslateOffset(lineOffsets[i + 1] - 1);
+                    if (drawUnderline) {
+                        int start = run.start;
+                        for (int k = j; k > 0 && style.isAdherentUnderline(styles[k - 1].style); k--) {
+                            start = styles[k - 1].start;
+                        }
+                        start = translateOffset(start);
+                        if (!(start > lineEnd || end < lineStart)) {
+                            range.location = layoutManager.glyphIndexForCharacterAtIndex(Math.max(lineStart, start));
+                            range.length = layoutManager.glyphIndexForCharacterAtIndex(Math.min(lineEnd, end) + 1) - range.location;
+                            if (range.length > 0) {
+                                gc.handle.saveGraphicsState();
+                                NSRect rect = layoutManager.boundingRectForGlyphRange(range, textContainer);
+                                float baseline = layoutManager.typesetter().baselineOffsetInLayoutManager(layoutManager, lineStart);
+                                float underlineX = pt.x + rect.x;
+                                float underlineY = pt.y + rect.y + rect.height - baseline;
+                                float[] color = null;
+                                if (style.underlineColor !is null) color = style.underlineColor.handle;
+                                if (color is null && style.foreground !is null) color = style.foreground.handle;
+                                if (color !is null) {
+                                    NSColor.colorWithDeviceRed(color[0], color[1], color[2], color[3]).setStroke();
+                                }
+                                NSBezierPath path = NSBezierPath.bezierPath();
+                                switch (style.underlineStyle) {
+                                case DWT.UNDERLINE_ERROR: {
+                                    path.setLineWidth(2f);
+                                    path.setLineCapStyle(OS.NSRoundLineCapStyle);
+                                    path.setLineJoinStyle(OS.NSRoundLineJoinStyle);
+                                    path.setLineDash(new float[]{1, 3f}, 2, 0);
+                                    point.x = underlineX;
+                                    point.y = underlineY + 0.5f;
+                                    path.moveToPoint(point);
+                                    point.x = underlineX + rect.width;
+                                    point.y = underlineY + 0.5f;
+                                    path.lineToPoint(point);
+                                    break;
+                                }
+                                case DWT.UNDERLINE_SQUIGGLE: {
+                                    gc.handle.setShouldAntialias(false);
+                                    path.setLineWidth(1.0f);
+                                    path.setLineCapStyle(OS.NSButtLineCapStyle);
+                                    path.setLineJoinStyle(OS.NSMiterLineJoinStyle);
+                                    float lineBottom = pt.y + rect.y + rect.height;
+                                    float squigglyThickness = 1;
+                                    float squigglyHeight = 2 * squigglyThickness;
+                                    float squigglyY = Math.min(underlineY - squigglyHeight / 2, lineBottom - squigglyHeight - 1);
+                                    float[] points = computePolyline((int)underlineX, (int)squigglyY, (int)(underlineX + rect.width), (int)(squigglyY + squigglyHeight));
+                                    point.x = points[0] + 0.5f;
+                                    point.y = points[1] + 0.5f;
+                                    path.moveToPoint(point);
+                                    for (int p = 2; p < points.length; p+=2) {
+                                        point.x = points[p] + 0.5f;
+                                        point.y = points[p+1] + 0.5f;
+                                        path.lineToPoint(point);
+                                    }
+                                    break;
+                                }
+                                }
+                                path.stroke();
+                                gc.handle.restoreGraphicsState();
+                            }
+                        }
+                    }
+                    if (drawBorder) {
+                        int start = run.start;
+                        for (int k = j; k > 0 && style.isAdherentBorder(styles[k - 1].style); k--) {
+                            start = styles[k - 1].start;
+                        }
+                        start = translateOffset(start);
+                        if (!(start > lineEnd || end < lineStart)) {
+                            range.location = layoutManager.glyphIndexForCharacterAtIndex(Math.max(lineStart, start));
+                            range.length = layoutManager.glyphIndexForCharacterAtIndex(Math.min(lineEnd, end) + 1) - range.location;
+                            if (range.length > 0) {
+                                gc.handle.saveGraphicsState();
+                                NSRect rect = layoutManager.boundingRectForGlyphRange(range, textContainer);
+                                rect.x += pt.x + 0.5f;
+                                rect.y += pt.y + 0.5f;
+                                rect.width -= 0.5f;
+                                rect.height -= 0.5f;
+                                float[] color = null;
+                                if (style.borderColor !is null) color = style.borderColor.handle;
+                                if (color is null && style.foreground !is null) color = style.foreground.handle;
+                                if (color !is null) {
+                                    NSColor.colorWithDeviceRed(color[0], color[1], color[2], color[3]).setStroke();
+                                }
+                                int width = 1;
+                                float[] dashes = null;
+                                switch (style.borderStyle) {
+                                case DWT.BORDER_SOLID:  break;
+                                case DWT.BORDER_DASH: dashes = width !is 0 ? GC.LINE_DASH : GC.LINE_DASH_ZERO; break;
+                                case DWT.BORDER_DOT: dashes = width !is 0 ? GC.LINE_DOT : GC.LINE_DOT_ZERO; break;
+                                }
+                                NSBezierPath path = NSBezierPath.bezierPath();
+                                path.setLineDash(dashes, dashes !is null ? dashes.length : 0, 0);
+                                path.appendBezierPathWithRect(rect);
+                                path.stroke();
+                                gc.handle.restoreGraphicsState();
+                            }
+                        }
+                    }
+                }
+
+            }
+        }
+        if ((flags & DWT.LAST_LINE_SELECTION) !is 0) {
+            NSRect bounds = lineBounds[lineBounds.length - 1];
+            NSRect rect = new NSRect();
+            rect.x = pt.x + bounds.x + bounds.width;
+            rect.y = y + bounds.y;
+            rect.width = (flags & DWT.FULL_SELECTION) !is 0 ? 0x7fffffff : bounds.height / 3;
+            rect.height = bounds.height;
+            selectionColor.setFill();
+            NSBezierPath path = NSBezierPath.bezierPath();
+            path.appendBezierPathWithRect(rect);
+            path.fill();
+        }
+        if (selectionRange !is null) {
         layoutManager.removeTemporaryAttribute(OS.NSBackgroundColorAttributeName, *selectionRange);
+        }
+        gc.handle.restoreGraphicsState();
+    } finally {
+        gc.uncheckGC(pool);
     }
 }
 
@@ -426,26 +627,37 @@
 }
 
 /**
- * Returns the bounds of the receiver.
+ * Returns the bounds of the receiver. The width returned is either the
+ * width of the longest line or the width set using {@link TextLayout#setWidth(int)}.
+ * To obtain the text bounds of a line use {@link TextLayout#getLineBounds(int)}.
  * 
  * @return the bounds of the receiver
  * 
  * @exception DWTException <ul>
  *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
  * </ul>
+ * 
+ * @see #setWidth(int)
+ * @see #getLineBounds(int)
  */
 public Rectangle getBounds() {
     checkLayout();
-    computeRuns();
-    NSRect rect = layoutManager.usedRectForTextContainer(textContainer);
-    if (wrapWidth !is -1) rect.width = wrapWidth;
-    if (text.length() is 0) {
-        Font font = this.font !is null ? this.font : device.systemFont;
-        NSFont nsFont = font.handle;
-        rect.height = Math.max(rect.height, layoutManager.defaultLineHeightForFont(nsFont));
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        computeRuns();
+        NSRect rect = layoutManager.usedRectForTextContainer(textContainer);
+        if (wrapWidth !is -1) rect.width = wrapWidth;
+        if (text.length() is 0) {
+            Font font = this.font !is null ? this.font : device.systemFont;
+            NSFont nsFont = font.handle;
+            rect.height = Math.max(rect.height, layoutManager.defaultLineHeightForFont(nsFont));
+        }
+        rect.height = Math.max(rect.height, ascent + descent) + spacing;
+    return new Rectangle(0, 0, cast(int)rect.width, cast(int)rect.height);
+    } finally {
+        if (pool !is null) pool.release();
     }
-    rect.height = Math.max(rect.height, ascent + descent);
-    return new Rectangle(0, 0, cast(int)rect.width, cast(int)rect.height);
 }
 
 /**
@@ -464,19 +676,25 @@
  */
 public Rectangle getBounds(int start, int end) {
     checkLayout();
-    computeRuns();
-    int length = text.length();
-    if (length is 0) return new Rectangle(0, 0, 0, 0);
-    if (start > end) return new Rectangle(0, 0, 0, 0);
-    start = Math.min(Math.max(0, start), length - 1);
-    end = Math.min(Math.max(0, end), length - 1);
-    start = translateOffset(start);
-    end = translateOffset(end);
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        computeRuns();
+        int length = text.length();
+        if (length is 0) return new Rectangle(0, 0, 0, 0);
+        if (start > end) return new Rectangle(0, 0, 0, 0);
+        start = Math.min(Math.max(0, start), length - 1);
+        end = Math.min(Math.max(0, end), length - 1);
+        start = translateOffset(start);
+        end = translateOffset(end);
     NSRange range = NSRange();
-    range.location = layoutManager.glyphIndexForCharacterAtIndex(start);
-    range.length = layoutManager.glyphIndexForCharacterAtIndex(end + 1) - range.location;
-    NSRect rect = layoutManager.boundingRectForGlyphRange(range, textContainer);
+        range.location = layoutManager.glyphIndexForCharacterAtIndex(start);
+        range.length = layoutManager.glyphIndexForCharacterAtIndex(end + 1) - range.location;
+        NSRect rect = layoutManager.boundingRectForGlyphRange(range, textContainer);
     return new Rectangle(cast(int)rect.x, cast(int)rect.y, cast(int)Math.ceil(rect.width), cast(int)Math.ceil(rect.height));
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**
@@ -561,13 +779,19 @@
  */
 public int getLevel(int offset) {
     checkLayout();
-    computeRuns();
-    int length = text.length();
-    if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE);
-    offset = translateOffset(offset);   
-    int level = 0;
-    //TODO
-    return level;
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        computeRuns();
+        int length = text.length();
+        if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE);
+        offset = translateOffset(offset);   
+        int level = 0;
+        //TODO
+        return level;
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**
@@ -583,12 +807,18 @@
  */
 public int[] getLineOffsets() {
     checkLayout ();
-    computeRuns();
-    int[] offsets = new int[lineOffsets.length];
-    for (int i = 0; i < offsets.length; i++) {
-        offsets[i] = untranslateOffset(lineOffsets[i]);
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        computeRuns();
+        int[] offsets = new int[lineOffsets.length];
+        for (int i = 0; i < offsets.length; i++) {
+            offsets[i] = untranslateOffset(lineOffsets[i]);
+        }
+        return offsets;
+    } finally {
+        if (pool !is null) pool.release();
     }
-    return offsets;
 }
 
 /**
@@ -607,16 +837,22 @@
  */
 public int getLineIndex(int offset) {
     checkLayout ();
-    computeRuns();
-    int length = text.length();
-    if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE);
-    offset = translateOffset(offset);
-    for (int line=0; line<lineOffsets.length - 1; line++) {
-        if (lineOffsets[line + 1] > offset) {
-            return line;
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        computeRuns();
+        int length = text.length();
+        if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE);
+        offset = translateOffset(offset);
+        for (int line=0; line<lineOffsets.length - 1; line++) {
+            if (lineOffsets[line + 1] > offset) {
+                return line;
+            }
         }
+        return lineBounds.length - 1;
+    } finally {
+        if (pool !is null) pool.release();
     }
-    return lineBounds.length - 1;
 }
 
 /**
@@ -634,10 +870,16 @@
  */
 public Rectangle getLineBounds(int lineIndex) {
     checkLayout();
-    computeRuns();
-    if (!(0 <= lineIndex && lineIndex < lineBounds.length)) DWT.error(DWT.ERROR_INVALID_RANGE);
-    NSRect rect = lineBounds[lineIndex];
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        computeRuns();
+        if (!(0 <= lineIndex && lineIndex < lineBounds.length)) DWT.error(DWT.ERROR_INVALID_RANGE);
+        NSRect rect = lineBounds[lineIndex];
     return new Rectangle(cast(int)rect.x, cast(int)rect.y, cast(int)rect.width, cast(int)rect.height);
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**
@@ -652,8 +894,14 @@
  */
 public int getLineCount() {
     checkLayout ();
-    computeRuns();  
-    return lineOffsets.length - 1;
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        computeRuns();  
+        return lineOffsets.length - 1;
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**
@@ -671,22 +919,28 @@
  */
 public FontMetrics getLineMetrics (int lineIndex) {
     checkLayout ();
-    computeRuns();
-    int lineCount = getLineCount();
-    if (!(0 <= lineIndex && lineIndex < lineCount)) DWT.error(DWT.ERROR_INVALID_RANGE);
-    int length = text.length();
-    if (length is 0) {
-        Font font = this.font !is null ? this.font : device.systemFont;
-        NSFont nsFont = font.handle;
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        computeRuns();
+        int lineCount = getLineCount();
+        if (!(0 <= lineIndex && lineIndex < lineCount)) DWT.error(DWT.ERROR_INVALID_RANGE);
+        int length = text.length();
+        if (length is 0) {
+            Font font = this.font !is null ? this.font : device.systemFont;
+            NSFont nsFont = font.handle;
         int ascent = cast(int)(0.5f + nsFont.ascender());
         int descent = cast(int)(0.5f + (-nsFont.descender() + nsFont.leading()));   
-        ascent = Math.max(ascent, this.ascent);
-        descent = Math.max(descent, this.descent);
-        return FontMetrics.cocoa_new(ascent, descent, 0, 0, ascent + descent);
+            ascent = Math.max(ascent, this.ascent);
+            descent = Math.max(descent, this.descent);
+            return FontMetrics.cocoa_new(ascent, descent, 0, 0, ascent + descent);
+        }
+        Rectangle rect = getLineBounds(lineIndex);
+    int baseline = cast(int)layoutManager.typesetter().baselineOffsetInLayoutManager(layoutManager, getLineOffsets()[lineIndex]);
+        return FontMetrics.cocoa_new(rect.height - baseline, baseline, 0, 0, rect.height);
+    } finally {
+        if (pool !is null) pool.release();
     }
-    Rectangle rect = getLineBounds(lineIndex);
-    int baseline = cast(int)layoutManager.typesetter().baselineOffsetInLayoutManager(layoutManager, getLineOffsets()[lineIndex]);
-    return FontMetrics.cocoa_new(rect.height - baseline, baseline, 0, 0, rect.height);
 }
 
 /**
@@ -707,22 +961,28 @@
  */
 public Point getLocation(int offset, bool trailing) {
     checkLayout();
-    computeRuns();
-    int length = text.length();
-    if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE);
-    if (length is 0) return new Point(0, 0);
-    offset = translateOffset(offset);
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        computeRuns();
+        int length = text.length();
+        if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE);
+        if (length is 0) return new Point(0, 0);
+        offset = translateOffset(offset);
     NSUInteger glyphIndex = layoutManager.glyphIndexForCharacterAtIndex(offset);
     NSRect rect = layoutManager.lineFragmentUsedRectForGlyphAtIndex_effectiveRange_(glyphIndex, null);
-    NSPoint point = layoutManager.locationForGlyphAtIndex(glyphIndex);
-    if (trailing) {
+        NSPoint point = layoutManager.locationForGlyphAtIndex(glyphIndex);
+        if (trailing) {
         NSRange range = NSRange();
-        range.location = glyphIndex;
-        range.length = 1;
-        NSRect bounds = layoutManager.boundingRectForGlyphRange(range, textContainer);
-        point.x += bounds.width;
+            range.location = glyphIndex;
+            range.length = 1;
+            NSRect bounds = layoutManager.boundingRectForGlyphRange(range, textContainer);
+            point.x += bounds.width;
+        }
+    return new Point(cast(int)point.x, cast(int)rect.y);
+    } finally {
+        if (pool !is null) pool.release();
     }
-    return new Point(cast(int)point.x, cast(int)rect.y);
 }
 
 /**
@@ -745,7 +1005,13 @@
  * @see #getPreviousOffset(int, int)
  */
 public int getNextOffset (int offset, int movement) {
-    return _getOffset(offset, movement, true);
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        return _getOffset(offset, movement, true);
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 int _getOffset (int offset, int movement, bool forward) {
@@ -763,18 +1029,18 @@
             } else {
                 offset--;
             }
-            return untranslateOffset(offset);
+            return Math.max(0, Math.min(length, untranslateOffset(offset)));
         }
         case DWT.MOVEMENT_WORD: {
-            return untranslateOffset(textStorage.nextWordFromIndex(offset, forward));
+            return untranslateOffset((int)/*64*/textStorage.nextWordFromIndex(offset, forward));
         }
         case DWT.MOVEMENT_WORD_END: {
             NSRange range = textStorage.doubleClickAtIndex(length is offset ? length - 1 : offset);
-            return untranslateOffset(range.location + range.length);
+            return untranslateOffset((int)/*64*/(range.location + range.length));
         }
         case DWT.MOVEMENT_WORD_START: {
             NSRange range = textStorage.doubleClickAtIndex(length is offset ? length - 1 : offset);
-            return untranslateOffset(range.location);
+            return untranslateOffset((int)/*64*/range.location);
         }
         default:
             break;
@@ -807,9 +1073,15 @@
  */
 public int getOffset(Point point, int[] trailing) {
     checkLayout();
-    computeRuns();
-    if (point is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    return getOffset(point.x, point.y, trailing);
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        computeRuns();
+        if (point is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+        return getOffset(point.x, point.y, trailing);
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**
@@ -837,18 +1109,24 @@
  */
 public int getOffset(int x, int y, int[] trailing) {
     checkLayout();
-    computeRuns();
-    if (trailing !is null && trailing.length < 1) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-    int length = text.length();
-    if (length is 0) return 0;
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        computeRuns();
+        if (trailing !is null && trailing.length < 1) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+        int length = text.length();
+        if (length is 0) return 0;
     NSPoint pt = NSPoint();
-    pt.x = x;
-    pt.y = y;
+        pt.x = x;
+        pt.y = y;
     CGFloat partialFration;
-    NSUInteger glyphIndex = layoutManager.glyphIndexForPoint_inTextContainer_fractionOfDistanceThroughGlyph_(pt, textContainer, &partialFration);
-    int offset = layoutManager.characterIndexForGlyphAtIndex(glyphIndex);
+    NSUInteger glyphIndex = layoutManager.glyphIndexForPoint(pt, textContainer, &partialFration);
+        int /*long*/ offset = layoutManager.characterIndexForGlyphAtIndex(glyphIndex);
     if (trailing !is null) trailing[0] = cast(int) Math.round(partialFration);
-    return Math.min(untranslateOffset(offset), length - 1);
+        return Math.min(untranslateOffset((int)/*64*/offset), length - 1);
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**
@@ -885,7 +1163,13 @@
  * @see #getNextOffset(int, int)
  */
 public int getPreviousOffset (int index, int movement) {
-    return _getOffset(index, movement, false);
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        return _getOffset(index, movement, false);
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**
@@ -1088,8 +1372,14 @@
     if ((alignment & DWT.LEFT) !is 0) alignment = DWT.LEFT;
     if ((alignment & DWT.RIGHT) !is 0) alignment = DWT.RIGHT;
     if (this.alignment is alignment) return;
-    freeRuns();
-    this.alignment = alignment;
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        freeRuns();
+        this.alignment = alignment;
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**
@@ -1114,8 +1404,14 @@
     checkLayout ();
     if (ascent < -1) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     if (this.ascent is ascent) return;
-    freeRuns();
-    this.ascent = ascent;
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        freeRuns();
+        this.ascent = ascent;
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**
@@ -1140,8 +1436,14 @@
     checkLayout ();
     if (descent < -1) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     if (this.descent is descent) return;
-    freeRuns();
-    this.descent = descent;
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        freeRuns();
+        this.descent = descent;
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /** 
@@ -1167,7 +1469,13 @@
     if (oldFont is font) return;
     this.font = font;
     if (oldFont !is null && oldFont.equals(font)) return;
-    freeRuns();
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        freeRuns();
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**
@@ -1186,8 +1494,14 @@
     checkLayout ();
     if (indent < 0) return;
     if (this.indent is indent) return;
-    freeRuns();
-    this.indent = indent;
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        freeRuns();
+        this.indent = indent;
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**
@@ -1205,8 +1519,14 @@
 public void setJustify (bool justify) {
     checkLayout ();
     if (justify is this.justify) return;
-    freeRuns();
-    this.justify = justify;
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        freeRuns();
+        this.justify = justify;
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**
@@ -1227,7 +1547,13 @@
     if ((orientation & DWT.LEFT_TO_RIGHT) !is 0) orientation = DWT.LEFT_TO_RIGHT;
     if (this.orientation is orientation) return;
     this.orientation = orientation;
-    freeRuns();
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        freeRuns();
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**
@@ -1260,8 +1586,14 @@
             if (i is segments.length) return;
         }
     }
-    freeRuns();
-    this.segments = segments;
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        freeRuns();
+        this.segments = segments;
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**
@@ -1281,8 +1613,14 @@
     checkLayout();
     if (spacing < 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     if (this.spacing is spacing) return;
-    freeRuns();
-    this.spacing = spacing;
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        freeRuns();
+        this.spacing = spacing;
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**
@@ -1300,73 +1638,79 @@
  */
 public void setStyle (TextStyle style, int start, int end) {
     checkLayout();
-    int length = text.length();
-    if (length is 0) return;
-    if (start > end) return;
-    start = Math.min(Math.max(0, start), length - 1);
-    end = Math.min(Math.max(0, end), length - 1);
-    int low = -1;
-    int high = styles.length;
-    while (high - low > 1) {
-        int index = (high + low) / 2;
-        if (styles[index + 1].start > start) {
-            high = index;
-        } else {
-            low = index;
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        int length = text.length();
+        if (length is 0) return;
+        if (start > end) return;
+        start = Math.min(Math.max(0, start), length - 1);
+        end = Math.min(Math.max(0, end), length - 1);
+        int low = -1;
+        int high = styles.length;
+        while (high - low > 1) {
+            int index = (high + low) / 2;
+            if (styles[index + 1].start > start) {
+                high = index;
+            } else {
+                low = index;
+            }
         }
-    }
-    if (0 <= high && high < styles.length) {
-        StyleItem item = styles[high];
-        if (item.start is start && styles[high + 1].start - 1 is end) {
-            if (style is null) {
-                if (item.style is null) return;
-            } else {
-                if (style.equals(item.style)) return;
+        if (0 <= high && high < styles.length) {
+            StyleItem item = styles[high];
+            if (item.start is start && styles[high + 1].start - 1 is end) {
+                if (style is null) {
+                    if (item.style is null) return;
+                } else {
+                    if (style.equals(item.style)) return;
+                }
             }
         }
-    }
-    freeRuns();
-    int modifyStart = high;
-    int modifyEnd = modifyStart;
-    while (modifyEnd < styles.length) {
-        if (styles[modifyEnd + 1].start > end) break;
-        modifyEnd++;
-    }
-    if (modifyStart is modifyEnd) {
-        int styleStart = styles[modifyStart].start; 
-        int styleEnd = styles[modifyEnd + 1].start - 1;
-        if (styleStart is start && styleEnd is end) {
-            styles[modifyStart].style = style;
-            return;
+        freeRuns();
+        int modifyStart = high;
+        int modifyEnd = modifyStart;
+        while (modifyEnd < styles.length) {
+            if (styles[modifyEnd + 1].start > end) break;
+            modifyEnd++;
         }
-        if (styleStart !is start && styleEnd !is end) {
-            StyleItem[] newStyles = new StyleItem[styles.length + 2];
-            System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1);
-            StyleItem item = new StyleItem();
-            item.start = start;
-            item.style = style;
-            newStyles[modifyStart + 1] = item;  
-            item = new StyleItem();
-            item.start = end + 1;
-            item.style = styles[modifyStart].style;
-            newStyles[modifyStart + 2] = item;
-            System.arraycopy(styles, modifyEnd + 1, newStyles, modifyEnd + 3, styles.length - modifyEnd - 1);
-            styles = newStyles;
-            return;
+        if (modifyStart is modifyEnd) {
+            int styleStart = styles[modifyStart].start; 
+            int styleEnd = styles[modifyEnd + 1].start - 1;
+            if (styleStart is start && styleEnd is end) {
+                styles[modifyStart].style = style;
+                return;
+            }
+            if (styleStart !is start && styleEnd !is end) {
+                StyleItem[] newStyles = new StyleItem[styles.length + 2];
+                System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1);
+                StyleItem item = new StyleItem();
+                item.start = start;
+                item.style = style;
+                newStyles[modifyStart + 1] = item;  
+                item = new StyleItem();
+                item.start = end + 1;
+                item.style = styles[modifyStart].style;
+                newStyles[modifyStart + 2] = item;
+                System.arraycopy(styles, modifyEnd + 1, newStyles, modifyEnd + 3, styles.length - modifyEnd - 1);
+                styles = newStyles;
+                return;
+            }
         }
+        if (start is styles[modifyStart].start) modifyStart--;
+        if (end is styles[modifyEnd + 1].start - 1) modifyEnd++;
+        int newLength = styles.length + 1 - (modifyEnd - modifyStart - 1);
+        StyleItem[] newStyles = new StyleItem[newLength];
+        System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1); 
+        StyleItem item = new StyleItem();
+        item.start = start;
+        item.style = style;
+        newStyles[modifyStart + 1] = item;
+        styles[modifyEnd].start = end + 1;
+        System.arraycopy(styles, modifyEnd, newStyles, modifyStart + 2, styles.length - modifyEnd);
+        styles = newStyles;
+    } finally {
+        if (pool !is null) pool.release();
     }
-    if (start is styles[modifyStart].start) modifyStart--;
-    if (end is styles[modifyEnd + 1].start - 1) modifyEnd++;
-    int newLength = styles.length + 1 - (modifyEnd - modifyStart - 1);
-    StyleItem[] newStyles = new StyleItem[newLength];
-    System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1); 
-    StyleItem item = new StyleItem();
-    item.start = start;
-    item.style = style;
-    newStyles[modifyStart + 1] = item;
-    styles[modifyEnd].start = end + 1;
-    System.arraycopy(styles, modifyEnd, newStyles, modifyStart + 2, styles.length - modifyEnd);
-    styles = newStyles;
 }
 
 /**
@@ -1392,8 +1736,14 @@
             if (i is tabs.length) return;
         }
     }
-    freeRuns();
-    this.tabs = tabs;
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        freeRuns();
+        this.tabs = tabs;
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**
@@ -1412,12 +1762,18 @@
     checkLayout ();
     if (text is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     if (text.equals(this.text)) return;
-    freeRuns();
-    this.text = text;
-    styles = new StyleItem[2];
-    styles[0] = new StyleItem();
-    styles[1] = new StyleItem();
-    styles[styles.length - 1].start = text.length();
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        freeRuns();
+        this.text = text;
+        styles = new StyleItem[2];
+        styles[0] = new StyleItem();
+        styles[1] = new StyleItem();
+        styles[styles.length - 1].start = text.length();
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**
@@ -1440,8 +1796,14 @@
     checkLayout();
     if (width < -1 || width is 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     if (this.wrapWidth is width) return;
-    freeRuns();
-    this.wrapWidth = width;
+    NSAutoreleasePool pool = null;
+    if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
+    try {
+        freeRuns();
+        this.wrapWidth = width;
+    } finally {
+        if (pool !is null) pool.release();
+    }
 }
 
 /**