changeset 287:35d730fb5e9f

TextLayout with wchar[] segments text and translation tables
author Frank Benoit <benoit@tionex.de>
date Thu, 21 Aug 2008 09:57:23 +0200
parents 0cb208cf22ea
children af37dd280317
files dwt/dwthelper/utils.d dwt/graphics/TextLayout.d
diffstat 2 files changed, 246 insertions(+), 114 deletions(-) [+]
line wrap: on
line diff
--- a/dwt/dwthelper/utils.d	Thu Aug 21 09:52:10 2008 +0200
+++ b/dwt/dwthelper/utils.d	Thu Aug 21 09:57:23 2008 +0200
@@ -421,6 +421,18 @@
     assert( res.length is 1 );
     return res[0];
 }
+dchar firstCodePoint( wchar[] str, out int consumed ){
+    dchar[1] buf;
+    uint ate;
+    dchar[] res = str.toString32( buf, &ate );
+    consumed = ate;
+    if( ate is 0 || res.length is 0 ){
+        Trace.formatln( "dwthelper.utils {}: str.length={} str={:X2}", __LINE__, str.length, cast(ubyte[])str );
+    }
+    assert( ate > 0 );
+    assert( res.length is 1 );
+    return res[0];
+}
 
 String dcharToString( dchar key ){
     dchar[1] buf;
@@ -440,6 +452,9 @@
 alias tango.text.convert.Utf.toString toString;
 
 int getRelativeCodePointOffset( String str, int startIndex, int searchRelCp ){
+    return getAbsoluteCodePointOffset( str, startIndex, searchRelCp ) - startIndex;
+}
+int getAbsoluteCodePointOffset( String str, int startIndex, int searchRelCp ){
     int ignore;
     int i = startIndex;
     if( searchRelCp > 0 ){
@@ -483,7 +498,7 @@
             do{
                 i--;
                 if( i < 0 ){
-                    return -1;
+                    return startIndex-1;
                     //Trace.formatln( "dwthelper.utils getRelativeCodePointOffset {}: str={}, startIndex={}, searchRelCp={}", __LINE__, str, startIndex, searchRelCp );
                     //tango.text.convert.Utf.onUnicodeError( "invalid utf8 input", i );
                 }
@@ -491,7 +506,46 @@
             searchRelCp++;
         }
     }
-    return i - startIndex;
+    return i;
+}
+int getAbsoluteCodePointOffset( wchar[] str, int startIndex, int searchRelCp ){
+    int ignore;
+    int i = startIndex;
+    if( searchRelCp > 0 ){
+        while( searchRelCp !is 0 ){
+
+            if( ( i < str.length )
+                && ( str[i] & 0xD800 ) !is 0xD800 )
+            {
+                i+=1;
+            }
+            else if( ( i+1 < str.length )
+                && (( str[i+1] & 0xDC00 ) is 0xDC00 )
+                && (( str[i  ] & 0xDC00 ) is 0xD800 ))
+            {
+                i+=2;
+            }
+            else{
+                Trace.formatln( "invalid utf8 characters:  {:X2}", cast(ubyte[]) str );
+                tango.text.convert.Utf.onUnicodeError( "invalid utf8 input", i );
+            }
+            searchRelCp--;
+        }
+    }
+    else if( searchRelCp < 0 ){
+        while( searchRelCp !is 0 ){
+            do{
+                i--;
+                if( i < 0 ){
+                    return startIndex-1;
+                    //Trace.formatln( "dwthelper.utils getRelativeCodePointOffset {}: str={}, startIndex={}, searchRelCp={}", __LINE__, str, startIndex, searchRelCp );
+                    //tango.text.convert.Utf.onUnicodeError( "invalid utf8 input", i );
+                }
+            } while(( str[i] & 0xDC00 ) is 0xDC00 );
+            searchRelCp++;
+        }
+    }
+    return i;
 }
 dchar getRelativeCodePoint( String str, int startIndex, int searchRelCp, out int relIndex ){
     relIndex = getRelativeCodePointOffset( str, startIndex, searchRelCp );
--- a/dwt/graphics/TextLayout.d	Thu Aug 21 09:52:10 2008 +0200
+++ b/dwt/graphics/TextLayout.d	Thu Aug 21 09:57:23 2008 +0200
@@ -12,6 +12,8 @@
  *******************************************************************************/
 module dwt.graphics.TextLayout;
 
+import tango.util.log.Trace;
+
 import dwt.DWT;
 import dwt.DWTException;
 import dwt.internal.Compatibility;
@@ -75,7 +77,12 @@
 
 
     Font font;
-    String text, segmentsText;
+    String  text;
+    wchar[] wtext;
+    char[]  segmentsText;
+    wchar[] segmentsWText; // DWT
+    int[]   index8to16; // DWT
+    int[]   index16to8; // DWT
     int lineSpacing;
     int ascent, descent;
     int alignment;
@@ -84,7 +91,8 @@
     int indent;
     bool justify;
     int[] tabs;
-    int[] segments;
+    int[] segments; // indices in 'text'
+    int[] wsegments; // DWT indices in 'wtext'
     StyleItem[] styles;
     int stylesCount;
 
@@ -94,8 +102,11 @@
     void* mLangFontLink2;
 
     static const dchar LTR_MARK = '\u200E', RTL_MARK = '\u200F';
+    static const wchar LTR_MARKw = '\u200E', RTL_MARKw = '\u200F';
     static const String STR_LTR_MARK = "\u200E", STR_RTL_MARK = "\u200F";
+    static const wchar[] WSTR_LTR_MARK = "\u200E"w, WSTR_RTL_MARK = "\u200F"w;
     static const int MARK_SIZE = 3;
+    static const int WMARK_SIZE = 1;
     static const int SCRIPT_VISATTR_SIZEOF = 2;
     static const int GOFFSET_SIZEOF = 8;
     private static byte[16] CLSID_CMultiLanguage;
@@ -231,6 +242,7 @@
     styles[1] = new StyleItem();
     stylesCount = 2;
     text = ""; //$NON-NLS-1$
+    wtext = ""w;
     void* ppv;
     OS.OleInitialize(null);
     if (OS.CoCreateInstance(CLSID_CMultiLanguage.ptr, null, OS.CLSCTX_INPROC_SERVER, IID_IMLangFontLink2.ptr, cast(void*)&ppv) is OS.S_OK) {
@@ -241,7 +253,7 @@
 
 void breakRun(StyleItem run) {
     if (run.psla !is null) return;
-    wchar[] chars = StrToWCHARs( 0, segmentsText[ run.start .. run.start + run.length ] );
+    wchar[] chars = segmentsWText[ index8to16[ run.start ] .. index8to16[ run.start + run.length ] ];
     auto hHeap = OS.GetProcessHeap();
     run.psla = cast(SCRIPT_LOGATTR*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, SCRIPT_LOGATTR.sizeof * chars.length);
     if (run.psla is null) DWT.error(DWT.ERROR_NO_HANDLES);
@@ -498,7 +510,9 @@
     freeRuns();
     font = null;
     text = null;
+    wtext = null;
     segmentsText = null;
+    segmentsWText = null;
     tabs = null;
     styles = null;
     runs = null;
@@ -613,6 +627,7 @@
     if (selectionForeground !is null && selectionForeground.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     if (selectionBackground !is null && selectionBackground.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     int length = text.length;
+    int wlength = wtext.length;
     if (length is 0 && flags is 0) return;
     auto hdc = gc.handle;
     Rectangle clip = gc.getClipping();
@@ -755,7 +770,7 @@
             if (drawX > clip.x + clip.width) break;
             if (drawX + run.width >= clip.x) {
                 if (!run.lineBreak || run.softBreak) {
-                    int end = run.start + run.length - 1;
+                    int end = segmentsText.getAbsoluteCodePointOffset( run.start + run.length, -1 );
                     bool fullSelection = hasSelection && selectionStart <= run.start && selectionEnd >= end;
                     if (fullSelection) {
                         if (gdip) {
@@ -786,15 +801,15 @@
                         if (partialSelection) {
                             int selStart = Math.max(selectionStart, run.start) - run.start;
                             int selEnd = Math.min(selectionEnd, end) - run.start;
-                            int cChars = run.length;
+                            int cChars = index8to16[run.start+run.length] - index8to16[run.start]; // make it wchar
                             int gGlyphs = run.glyphCount;
                             int piX;
                             int* advances = run.justify !is null ? run.justify : run.advances;
-                            OS.ScriptCPtoX(selStart, false, cChars, gGlyphs, run.clusters, run.visAttrs, advances, &run.analysis, &piX);
+                            OS.ScriptCPtoX(index8to16[selStart], false, cChars, gGlyphs, run.clusters, run.visAttrs, advances, &run.analysis, &piX);
                             int runX = (orientation & DWT.RIGHT_TO_LEFT) !is 0 ? run.width - piX : piX;
                             rect.left = drawX + runX;
                             rect.top = drawY;
-                            OS.ScriptCPtoX(selEnd, true, cChars, gGlyphs, run.clusters, run.visAttrs, advances, &run.analysis, &piX);
+                            OS.ScriptCPtoX(index8to16[selEnd], true, cChars, gGlyphs, run.clusters, run.visAttrs, advances, &run.analysis, &piX);
                             runX = (orientation & DWT.RIGHT_TO_LEFT) !is 0 ? run.width - piX : piX;
                             rect.right = drawX + runX;
                             rect.bottom = drawY + lineHeight;
@@ -829,9 +844,9 @@
                     OS.SelectObject(hdc, getItemFont(run));
                     int drawRunY = drawY + (baseline - run.ascent);
                     if (partialSelection) {
-                        int selStart = Math.max(selectionStart, run.start) - run.start;
-                        int selEnd = Math.min(selectionEnd, end) - run.start;
-                        int cChars = run.length;
+                        int selStart = Math.max(index8to16[selectionStart], index8to16[run.start]) - index8to16[run.start];
+                        int selEnd = Math.min(index8to16[selectionEnd], index8to16[end]) - index8to16[run.start];
+                        int cChars = index8to16[run.start+run.length] - index8to16[run.start]; // make it wchar
                         int gGlyphs = run.glyphCount;
                         int piX;
                         int* advances = run.justify !is null ? run.justify : run.advances;
@@ -1330,6 +1345,7 @@
     allRuns = null;
     runs = null;
     segmentsText = null;
+    segmentsWText = null;
 }
 
 /**
@@ -1433,11 +1449,12 @@
             int cx = 0;
             if (run.style !is null && run.style.metrics !is null) {
                 GlyphMetrics metrics = run.style.metrics;
-                cx = metrics.width * (start - run.start);
+                cx = metrics.width * (index8to16[start] - index8to16[run.start]);
             } else if (!run.tab) {
                 int piX;
                 int* advances = run.justify !is null ? run.justify : run.advances;
-                OS.ScriptCPtoX(start - run.start, false, run.length, run.glyphCount, run.clusters, run.visAttrs, advances, &run.analysis, &piX);
+                int wlength = index8to16[ run.start+run.length] - index8to16[run.start];
+                OS.ScriptCPtoX(index8to16[start] - index8to16[run.start], false, wlength, run.glyphCount, run.clusters, run.visAttrs, advances, &run.analysis, &piX);
                 cx = isRTL ? run.width - piX : piX;
             }
             if (run.analysis.fRTL ^ isRTL) {
@@ -1450,11 +1467,12 @@
             int cx = run.width;
             if (run.style !is null && run.style.metrics !is null) {
                 GlyphMetrics metrics = run.style.metrics;
-                cx = metrics.width * (end - run.start + 1);
+                cx = metrics.width * (index8to16[end] - index8to16[run.start] + 1);
             } else if (!run.tab) {
                 int piX;
                 int* advances = run.justify !is null ? run.justify : run.advances;
-                OS.ScriptCPtoX(end - run.start, true, run.length, run.glyphCount, run.clusters, run.visAttrs, advances, &run.analysis, &piX);
+                int wlength = index8to16[ run.start+run.length] - index8to16[run.start];
+                OS.ScriptCPtoX(index8to16[end] - index8to16[run.start], true, wlength, run.glyphCount, run.clusters, run.visAttrs, advances, &run.analysis, &piX);
                 cx = isRTL ? run.width - piX : piX;
             }
             if (run.analysis.fRTL ^ isRTL) {
@@ -1795,9 +1813,8 @@
             } else if (run.tab) {
                 width = (trailing || (offset is length)) ? run.width : 0;
             } else {
-                // DWT: runOffset now in codepoints
-                int runOffset = segmentsText[ run.start .. $ ].indexToCodepointIndex( offset - run.start );
-                int cChars = run.length;
+                int runOffset = index8to16[offset] - index8to16[run.start];
+                int cChars = index8to16[run.start+run.length] - index8to16[run.start]; // make it wchar
                 int gGlyphs = run.glyphCount;
                 int piX;
                 int* advances = run.justify !is null ? run.justify : run.advances;
@@ -1858,7 +1875,7 @@
             if (isComplex) breakRun(run);
             while (run.start <= offset && offset < run.start + run.length) {
                 if (isComplex) {
-                    logAttr = run.psla + (offset - run.start);
+                    logAttr = run.psla + (index8to16[offset] - index8to16[run.start]);
                 }
                 switch (movement) {
                     case DWT.MOVEMENT_CLUSTER: {
@@ -1878,7 +1895,7 @@
                                 bool letterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset));
                                 bool previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset - 1));
                                 if (letterOrDigit !is previousLetterOrDigit || !letterOrDigit) {
-                                    if (!Compatibility.isWhitespace(segmentsText.charAt(offset))) {
+                                    if (!Compatibility.isWhitespace(segmentsText[offset..$].firstCodePoint())) {
                                         return untranslateOffset(offset);
                                     }
                                 }
@@ -1889,7 +1906,7 @@
                     case DWT.MOVEMENT_WORD_END: {
                         if (offset > 0) {
                             bool isLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset));
-                            bool previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset - 1));
+                            bool previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText[offset - 1.. $].firstCodePoint());
                             if (!isLetterOrDigit && previousLetterOrDigit) {
                                 return untranslateOffset(offset);
                             }
@@ -1998,7 +2015,7 @@
                 if (trailing !is null) trailing[0] = x < (run.x + run.width / 2) ? 0 : 1;
                 return untranslateOffset(run.start);
             }
-            int cChars = run.length;
+            int cChars = index8to16[run.start+run.length] - index8to16[run.start]; // make it wchar
             int cGlyphs = run.glyphCount;
             int piCP;
             int piTrailing;
@@ -2102,39 +2119,109 @@
     return segments;
 }
 
-String getSegmentsText() {
-    if (segments is null) return text;
+void getSegmentsText( out char[] resUtf8, out wchar[] resUtf16 ) {
+
+    void buildIndexTables() { // build the index translation tables.
+        index8to16.length = resUtf8.length + 1;
+        index16to8.length = resUtf16.length + 1;
+
+        int idx8, idx16;
+        while( idx8 < resUtf8.length ){
+            int ate8, ate16;
+            dchar d8 = resUtf8[ idx8 .. $ ].firstCodePoint( ate8 );
+            dchar d16 = resUtf16[ idx16 .. $ ].firstCodePoint( ate16 );
+            assert( d8 is d16 );
+            index16to8[ idx16 .. idx16 +ate16 ] = idx8;
+            index8to16[ idx8  .. idx8  +ate8  ] = idx16;
+            idx8  += ate8;
+            idx16 += ate16;
+        }
+        index16to8[ resUtf16.length ] = resUtf8.length;
+        index8to16[ resUtf8.length  ] = resUtf16.length;
+    }
+
+    if (segments is null) {
+        resUtf8 = text;
+        resUtf16 = wtext;
+        buildIndexTables();
+        return;
+    }
     int nSegments = segments.length;
-    if (nSegments <= 1) return text;
-    int length_ = text.length;
-    if (length_ is 0) return text;
-    if (nSegments is 2) {
-        if (segments[0] is 0 && segments[1] is length_) return text;
+    if (nSegments <= 1) {
+        resUtf8 = text;
+        resUtf16 = wtext;
+        buildIndexTables();
+        return;
     }
-    char[] oldChars = new char[length_];
-    text.getChars(0, length_, oldChars, 0);
-    // DWT: MARK is now 3 chars long
-    String separator = orientation is DWT.RIGHT_TO_LEFT ? STR_RTL_MARK : STR_LTR_MARK;
-    assert( separator.length is MARK_SIZE );
-    char[] newChars = new char[length_ + nSegments*MARK_SIZE];
-    int charCount = 0, segmentCount = 0;
-    while (charCount < length_) {
-        if (segmentCount < nSegments && charCount is segments[segmentCount]) {
+    int length_ = text.length;
+    int wlength_ = wtext.length;
+    if (length_ is 0) {
+        resUtf8 = text;
+        resUtf16 = wtext;
+        buildIndexTables();
+        return;
+    }
+    if (nSegments is 2) {
+        if (segments[0] is 0 && segments[1] is length_) {
+            resUtf8 = text;
+            resUtf16 = wtext;
+            buildIndexTables();
+            return;
+        }
+    }
+    {
+        char[] oldChars = text;
+        // DWT: MARK is now 3 chars long
+        String separator = orientation is DWT.RIGHT_TO_LEFT ? STR_RTL_MARK : STR_LTR_MARK;
+        assert( separator.length is MARK_SIZE );
+        char[] newChars = new char[length_ + nSegments*MARK_SIZE];
+
+        int charCount = 0, segmentCount = 0;
+        while (charCount < length_) {
+            if (segmentCount < nSegments && charCount is segments[segmentCount]) {
+                int start = charCount + (segmentCount*MARK_SIZE);
+                newChars[ start .. start + MARK_SIZE ] = separator;
+                segmentCount++;
+            } else {
+                newChars[charCount + (segmentCount*MARK_SIZE)] = oldChars[charCount];
+                charCount++;
+            }
+        }
+        if (segmentCount < nSegments) {
+            segments[segmentCount] = charCount;
             int start = charCount + (segmentCount*MARK_SIZE);
             newChars[ start .. start + MARK_SIZE ] = separator;
             segmentCount++;
-        } else {
-            newChars[charCount + (segmentCount*MARK_SIZE)] = oldChars[charCount];
-            charCount++;
         }
+        resUtf8 = newChars[ 0 .. Math.min(charCount + (segmentCount*MARK_SIZE), newChars.length)];
     }
-    if (segmentCount < nSegments) {
-        segments[segmentCount] = charCount;
-        int start = charCount + (segmentCount*MARK_SIZE);
-        newChars[ start .. start + MARK_SIZE ] = separator;
-        segmentCount++;
+    // now for the wide chars
+    {
+        wchar[] oldWChars = wtext;
+        wchar[] wseparator = orientation is DWT.RIGHT_TO_LEFT ? WSTR_RTL_MARK : WSTR_LTR_MARK;
+        assert( wseparator.length is 1 );
+        wchar[] newWChars = new wchar[wlength_ + nSegments];
+
+        int charCount = 0, segmentCount = 0;
+        while (charCount < wlength_) {
+            if (segmentCount < nSegments && charCount is wsegments[segmentCount]) {
+                int start = charCount + (segmentCount*WMARK_SIZE);
+                newWChars[ start .. start + WMARK_SIZE ] = wseparator;
+                segmentCount++;
+            } else {
+                newWChars[charCount + (segmentCount*WMARK_SIZE)] = oldWChars[charCount];
+                charCount++;
+            }
+        }
+        if (segmentCount < nSegments) {
+            wsegments[segmentCount] = charCount;
+            int start = charCount + (segmentCount*WMARK_SIZE);
+            newWChars[ start .. start + WMARK_SIZE ] = wseparator;
+            segmentCount++;
+        }
+        resUtf16 = newWChars[ 0 .. Math.min(charCount + (segmentCount*WMARK_SIZE), newWChars.length)];
     }
-    return newChars[ 0 .. Math.min(charCount + (segmentCount*MARK_SIZE), newChars.length)].dup;
+    buildIndexTables();
 }
 
 /**
@@ -2269,7 +2356,7 @@
  */
 StyleItem[] itemize () {
     // DWT: itemize is the process of finding changes in direction
-    segmentsText = getSegmentsText();
+    getSegmentsText(segmentsText, segmentsWText );
     int length = segmentsText.length;
     SCRIPT_CONTROL scriptControl;
     SCRIPT_STATE scriptState;
@@ -2287,39 +2374,11 @@
     auto pItems = cast(SCRIPT_ITEM*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, MAX_ITEM * SCRIPT_ITEM.sizeof);
     if (pItems is null) DWT.error(DWT.ERROR_NO_HANDLES);
     int pcItems;
-    wchar[] chars = StrToWCHARs( segmentsText );
+    wchar[] chars = segmentsWText;
     OS.ScriptItemize(chars.ptr, chars.length, MAX_ITEM, &scriptControl, &scriptState, pItems, &pcItems);
 //  if (hr is E_OUTOFMEMORY) //TODO handle it
     // DWT pcItems is not inclusive the trailing item
 
-    // Translate the utf16 indices to utf8 indices
-    int utf8idx = 0;
-    int utf16idx = 0;
-    int i = 0;
-    SCRIPT_ITEM* si = pItems;
-    while( utf16idx < chars.length ){
-
-        if( si.iCharPos is utf16idx ){
-            si.iCharPos = utf8idx;
-            i++;
-            si++;
-        }
-
-        // goto next codepoint
-        uint ate16;
-        dchar[1] buf32;
-        dchar[] res32 = Utf.toString32( chars[ utf16idx .. $ ], buf32, &ate16 );
-        uint ate32;
-        char[4] buf8;
-        char[] res8 = Utf.toString( res32, buf8, &ate32 );
-        utf16idx += ate16;
-        utf8idx += res8.length;
-    }
-    assert( si.iCharPos is chars.length );
-    si.iCharPos = utf8idx;
-    assert( si.iCharPos is segmentsText.length );
-    assert( i is pcItems );
-
     StyleItem[] runs = merge(pItems, pcItems);
     OS.HeapFree(hHeap, 0, pItems);
     return runs;
@@ -2351,14 +2410,14 @@
         }
         //scriptItem.a = new SCRIPT_ANALYSIS();
         scriptItem = items + (itemIndex + 1);
-        int itemLimit = scriptItem.iCharPos;
+        int itemLimit = index16to8[scriptItem.iCharPos];
         int styleLimit = translateOffset(styles[styleIndex + 1].start);
         if (styleLimit <= itemLimit) {
             styleIndex++;
             start = styleLimit;
             if (start < itemLimit && 0 < start && start < end) {
-                char pChar = segmentsText.charAt(start - 1);
-                char tChar = segmentsText.charAt(start);
+                dchar pChar = segmentsText[ segmentsText.getAbsoluteCodePointOffset(start, -1) ..$].firstCodePoint();
+                dchar tChar = segmentsText[start     ..$].firstCodePoint();
                 if (Compatibility.isLetter(pChar) && Compatibility.isLetter(tChar)) {
                     item.analysis.fLinkAfter = true;
                     linkBefore = true;
@@ -2620,7 +2679,28 @@
         }
     }
     freeRuns();
-    this.segments = segments;
+    this.segments  = segments.dup;
+
+    // DWT: create the wsegments ...
+    this.wsegments.length = segments.length;
+    uint index8, index16;
+    uint segIndex = 1;
+    while(index8 < text.length ){
+        int ate8;
+        int ate16;
+        dchar d8 = text[ index8 .. $ ].firstCodePoint( ate8 );
+        dchar d16 = wtext[ index16 .. $ ].firstCodePoint( ate16 );
+        assert( d8 is d16 );
+        assert( ate8 > 0 );
+        assert( ate16 > 0 );
+        index8 += ate8;
+        index16 += ate16;
+        if( segments[segIndex] is index8 ){
+            wsegments[segIndex] = index16;
+        }
+    }
+    assert( index16 is wtext.length );
+    assert( segIndex is segments.length );
 }
 
 /**
@@ -2783,7 +2863,8 @@
     //if (text is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     if (text.equals(this.text)) return;
     freeRuns();
-    this.text = text;
+    this.text  = text.dup;
+    this.wtext = StrToWCHARs(text);
     styles = new StyleItem[2];
     styles[0] = new StyleItem();
     styles[1] = new StyleItem();
@@ -2816,19 +2897,20 @@
 }
 
 bool shape (HDC hdc, StyleItem run, wchar[] wchars, int[] glyphCount, int maxGlyphs, SCRIPT_PROPERTIES* sp) {
-    //wchar[] wchars = StrToWCHARs( chars );
     bool useCMAPcheck = !sp.fComplex && !run.analysis.fNoGlyphIndex;
     if (useCMAPcheck) {
         ushort[] glyphs = new ushort[wchars.length];
-        scope(exit) delete glyphs;
         if (OS.ScriptGetCMap(hdc, run.psc, wchars.ptr, wchars.length, 0, glyphs.ptr) !is OS.S_OK) {
             if (run.psc !is null) {
                 OS.ScriptFreeCache(run.psc);
                 glyphCount[0] = 0;
-                *cast(int*)run.psc = 1;
+                int[1] one = 1;
+        //        OS.MoveMemory( run.psc, one.ptr, (void*).sizeof );
+        // DWT: FIXME This should be checked, it works in Java with the MoveMemory
             }
             return false;
         }
+        //delete glyphs;
     }
     auto hr = OS.ScriptShape(hdc, run.psc, wchars.ptr, wchars.length, maxGlyphs, &run.analysis, run.glyphs, run.clusters, run.visAttrs, glyphCount.ptr);
     run.glyphCount = glyphCount[0];
@@ -2849,29 +2931,20 @@
     if (run.psc !is null) {
         OS.ScriptFreeCache(run.psc);
         glyphCount[0] = 0;
-        *cast(int*)run.psc = 0;
+        int[1] one = 1;
+        OS.MoveMemory( run.psc, one.ptr, (void*).sizeof );
     }
     run.glyphCount = 0;
     return false;
 }
 
-struct CallbackDataEnumFontFamExProc {
-    int delegate ( ENUMLOGFONTEX* lpelfe, NEWTEXTMETRICEX* lpntme, int FontType, int lParam) EnumFontFamExProc;
-    int lParam;
-}
-extern(Windows) private static int EnumFontFamExProcFunc( ENUMLOGFONTEX* lpelfe, NEWTEXTMETRICEX* lpntme, int FontType, int lParam) {
-    auto cb = cast(CallbackDataEnumFontFamExProc*)cast(void*)lParam;
-    return cb.EnumFontFamExProc( lpelfe, lpntme, FontType, cb.lParam );
-}
 
 /*
  * Generate glyphs for one Run.
  */
 void shape (HDC hdc, StyleItem run) {
     int[1] buffer;
-    char[] chars = new char[run.length];
-    segmentsText.getChars(run.start, run.start + run.length, chars, 0);
-    wchar[] wchars = StrToWCHARs( chars );
+    wchar[] wchars = segmentsWText[ index8to16[ run.start ] .. index8to16[ run.start + run.length ] ];
     int maxGlyphs = (wchars.length * 3 / 2) + 16;
     auto hHeap = OS.GetProcessHeap();
     run.glyphs = cast(ushort*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, maxGlyphs * 2);
@@ -2883,8 +2956,9 @@
     run.psc = cast(SCRIPT_CACHE*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, (void*).sizeof);
     if (run.psc is null) DWT.error(DWT.ERROR_NO_HANDLES);
     short script = run.analysis.eScript;
-    auto sp = device.scripts[script];
-    bool shapeSucceed = shape(hdc, run, wchars, buffer,  maxGlyphs, sp);
+    SCRIPT_PROPERTIES sp = *device.scripts[script];
+    bool shapeSucceed = shape(hdc, run, wchars, buffer,  maxGlyphs, &sp);
+int res;
     if (!shapeSucceed) {
         auto hFont = OS.GetCurrentObject(hdc, OS.OBJ_FONT);
         auto ssa = cast(SCRIPT_STRING_ANALYSIS*) OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, SCRIPT_STRING_ANALYSIS.sizeof);
@@ -2892,15 +2966,14 @@
         auto oldMetaFont = OS.SelectObject(metaFileDc, hFont);
         int flags = OS.SSA_METAFILE | OS.SSA_FALLBACK | OS.SSA_GLYPHS | OS.SSA_LINK;
         if (OS.ScriptStringAnalyse(metaFileDc, wchars.ptr, wchars.length, 0, -1, flags, 0, null, null, null, null, null, ssa) is OS.S_OK) {
-            OS.ScriptStringOut(ssa, 0, 0, 0, null, 0, 0, false);
+            OS.ScriptStringOut(*ssa, 0, 0, 0, null, 0, 0, false);
             OS.ScriptStringFree(ssa);
         }
         OS.HeapFree(hHeap, 0, ssa);
         OS.SelectObject(metaFileDc, oldMetaFont);
         auto metaFile = OS.CloseEnhMetaFile(metaFileDc);
-        EMREXTCREATEFONTINDIRECTW emr;
         static extern(Windows) int metaFileEnumProc (HDC hDC, HANDLETABLE* table, ENHMETARECORD* record, int nObj, LPARAM lpData) {
-            EMREXTCREATEFONTINDIRECTW* emr_;
+            EMREXTCREATEFONTINDIRECTW* emr_ = cast(EMREXTCREATEFONTINDIRECTW*)lpData;
             OS.MoveMemory(&emr_.emr, record, EMR.sizeof);
             switch (emr_.emr.iType) {
                 case OS.EMR_EXTCREATEFONTINDIRECTW:
@@ -2908,21 +2981,27 @@
                     break;
                 case OS.EMR_EXTTEXTOUTW:
                     return 0;
+                default:
             }
             return 1;
         }
+
+        EMREXTCREATEFONTINDIRECTW emr;
         OS.EnumEnhMetaFile(null, metaFile, &metaFileEnumProc, &emr, null);
-        OS.DeleteEnhMetaFile(metaFile);
+        res = OS.DeleteEnhMetaFile(metaFile);
+        assert( res !is 0 );
 
         auto newFont = OS.CreateFontIndirectW(&emr.elfw.elfLogFont);
+        assert( newFont !is null );
+
         OS.SelectObject(hdc, newFont);
-        if ((shapeSucceed = shape(hdc, run, wchars, buffer,  maxGlyphs, sp)) is true ) {
+        if ((shapeSucceed = shape(hdc, run, wchars, buffer,  maxGlyphs, &sp)) is true ) {
             run.fallbackFont = newFont;
         }
         if (!shapeSucceed) {
             if (!sp.fComplex) {
                 run.analysis.fNoGlyphIndex = true;
-                if ((shapeSucceed = shape(hdc, run, wchars, buffer,  maxGlyphs, sp)) is true ) {
+                if ((shapeSucceed = shape(hdc, run, wchars, buffer,  maxGlyphs, &sp)) is true ) {
                     run.fallbackFont = newFont;
                 } else {
                     run.analysis.fNoGlyphIndex = false;
@@ -2930,20 +3009,20 @@
             }
         }
         if (!shapeSucceed) {
-        if (mLangFontLink2 !is null) {
-            HANDLE hNewFont;
-            int dwCodePages, cchCodePages;
+            if (mLangFontLink2 !is null) {
+                HANDLE hNewFont;
+                int dwCodePages, cchCodePages;
                 /* GetStrCodePages() */
-            OS.VtblCall(4, mLangFontLink2, cast(int)wchars.ptr, wchars.length, 0, cast(int)&dwCodePages, cast(int)&cchCodePages);
+                OS.VtblCall(4, mLangFontLink2, cast(int)wchars.ptr, wchars.length, 0, cast(int)&dwCodePages, cast(int)&cchCodePages);
                 /* MapFont() */
-            if (OS.VtblCall(10, mLangFontLink2, cast(int)hdc, dwCodePages, cast(int)wchars[0], cast(int)&hNewFont) is OS.S_OK) {
+                if (OS.VtblCall(10, mLangFontLink2, cast(int)hdc, dwCodePages, cast(int)wchars[0], cast(int)&hNewFont) is OS.S_OK) {
                     LOGFONT logFont;
                     OS.GetObject( hNewFont, LOGFONT.sizeof, &logFont );
                     /* ReleaseFont() */
                     OS.VtblCall(8, mLangFontLink2, cast(int)hNewFont);
                     auto mLangFont = OS.CreateFontIndirect(&logFont);
                     auto oldFont = OS.SelectObject(hdc, mLangFont);
-                    if ((shapeSucceed = shape(hdc, run, wchars, buffer,  maxGlyphs, sp)) is true ) {
+                    if ((shapeSucceed = shape(hdc, run, wchars, buffer,  maxGlyphs, &sp)) is true ) {
                         run.fallbackFont = mLangFont;
                     } else {
                         OS.SelectObject(hdc, oldFont);
@@ -2962,8 +3041,7 @@
         * Give up and shape the run with the default font.
         * Missing glyphs typically will be represent as black boxes in the text.
         */
-        auto wchars_ = StrToWCHARs(chars);
-        OS.ScriptShape(hdc, run.psc, wchars_.ptr, wchars_.length, maxGlyphs, &run.analysis, run.glyphs, run.clusters, run.visAttrs, buffer.ptr);
+        OS.ScriptShape(hdc, run.psc, wchars.ptr, wchars.length, maxGlyphs, &run.analysis, run.glyphs, run.clusters, run.visAttrs, buffer.ptr);
         run.glyphCount = buffer[0];
     }
     int[3] abc;