# HG changeset patch # User Frank Benoit # Date 1219305443 -7200 # Node ID 35d730fb5e9fbbc6ecaa2b918bc7cd9b31ca05e4 # Parent 0cb208cf22ea92a1fc15d785713209b362240051 TextLayout with wchar[] segments text and translation tables diff -r 0cb208cf22ea -r 35d730fb5e9f dwt/dwthelper/utils.d --- 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 ); diff -r 0cb208cf22ea -r 35d730fb5e9f dwt/graphics/TextLayout.d --- 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;