Changeset 287:35d730fb5e9f
- Timestamp:
- 08/21/08 03:57:23
(3 months ago)
- Author:
- Frank Benoit <benoit@tionex.de>
- branch:
- default
- Message:
TextLayout? with wchar[] segments text and translation tables
-
Files:
-
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
| r283 |
r287 |
|
| 422 | 422 | return res[0]; |
|---|
| 423 | 423 | } |
|---|
| | 424 | dchar firstCodePoint( wchar[] str, out int consumed ){ |
|---|
| | 425 | dchar[1] buf; |
|---|
| | 426 | uint ate; |
|---|
| | 427 | dchar[] res = str.toString32( buf, &ate ); |
|---|
| | 428 | consumed = ate; |
|---|
| | 429 | if( ate is 0 || res.length is 0 ){ |
|---|
| | 430 | Trace.formatln( "dwthelper.utils {}: str.length={} str={:X2}", __LINE__, str.length, cast(ubyte[])str ); |
|---|
| | 431 | } |
|---|
| | 432 | assert( ate > 0 ); |
|---|
| | 433 | assert( res.length is 1 ); |
|---|
| | 434 | return res[0]; |
|---|
| | 435 | } |
|---|
| 424 | 436 | |
|---|
| 425 | 437 | String dcharToString( dchar key ){ |
|---|
| … | … | |
| 441 | 453 | |
|---|
| 442 | 454 | int getRelativeCodePointOffset( String str, int startIndex, int searchRelCp ){ |
|---|
| | 455 | return getAbsoluteCodePointOffset( str, startIndex, searchRelCp ) - startIndex; |
|---|
| | 456 | } |
|---|
| | 457 | int getAbsoluteCodePointOffset( String str, int startIndex, int searchRelCp ){ |
|---|
| 443 | 458 | int ignore; |
|---|
| 444 | 459 | int i = startIndex; |
|---|
| … | … | |
| 484 | 499 | i--; |
|---|
| 485 | 500 | if( i < 0 ){ |
|---|
| 486 | | return -1; |
|---|
| | 501 | return startIndex-1; |
|---|
| 487 | 502 | //Trace.formatln( "dwthelper.utils getRelativeCodePointOffset {}: str={}, startIndex={}, searchRelCp={}", __LINE__, str, startIndex, searchRelCp ); |
|---|
| 488 | 503 | //tango.text.convert.Utf.onUnicodeError( "invalid utf8 input", i ); |
|---|
| … | … | |
| 492 | 507 | } |
|---|
| 493 | 508 | } |
|---|
| 494 | | return i - startIndex; |
|---|
| | 509 | return i; |
|---|
| | 510 | } |
|---|
| | 511 | int getAbsoluteCodePointOffset( wchar[] str, int startIndex, int searchRelCp ){ |
|---|
| | 512 | int ignore; |
|---|
| | 513 | int i = startIndex; |
|---|
| | 514 | if( searchRelCp > 0 ){ |
|---|
| | 515 | while( searchRelCp !is 0 ){ |
|---|
| | 516 | |
|---|
| | 517 | if( ( i < str.length ) |
|---|
| | 518 | && ( str[i] & 0xD800 ) !is 0xD800 ) |
|---|
| | 519 | { |
|---|
| | 520 | i+=1; |
|---|
| | 521 | } |
|---|
| | 522 | else if( ( i+1 < str.length ) |
|---|
| | 523 | && (( str[i+1] & 0xDC00 ) is 0xDC00 ) |
|---|
| | 524 | && (( str[i ] & 0xDC00 ) is 0xD800 )) |
|---|
| | 525 | { |
|---|
| | 526 | i+=2; |
|---|
| | 527 | } |
|---|
| | 528 | else{ |
|---|
| | 529 | Trace.formatln( "invalid utf8 characters: {:X2}", cast(ubyte[]) str ); |
|---|
| | 530 | tango.text.convert.Utf.onUnicodeError( "invalid utf8 input", i ); |
|---|
| | 531 | } |
|---|
| | 532 | searchRelCp--; |
|---|
| | 533 | } |
|---|
| | 534 | } |
|---|
| | 535 | else if( searchRelCp < 0 ){ |
|---|
| | 536 | while( searchRelCp !is 0 ){ |
|---|
| | 537 | do{ |
|---|
| | 538 | i--; |
|---|
| | 539 | if( i < 0 ){ |
|---|
| | 540 | return startIndex-1; |
|---|
| | 541 | //Trace.formatln( "dwthelper.utils getRelativeCodePointOffset {}: str={}, startIndex={}, searchRelCp={}", __LINE__, str, startIndex, searchRelCp ); |
|---|
| | 542 | //tango.text.convert.Utf.onUnicodeError( "invalid utf8 input", i ); |
|---|
| | 543 | } |
|---|
| | 544 | } while(( str[i] & 0xDC00 ) is 0xDC00 ); |
|---|
| | 545 | searchRelCp++; |
|---|
| | 546 | } |
|---|
| | 547 | } |
|---|
| | 548 | return i; |
|---|
| 495 | 549 | } |
|---|
| 496 | 550 | dchar getRelativeCodePoint( String str, int startIndex, int searchRelCp, out int relIndex ){ |
|---|
| r278 |
r287 |
|
| 12 | 12 | *******************************************************************************/ |
|---|
| 13 | 13 | module dwt.graphics.TextLayout; |
|---|
| | 14 | |
|---|
| | 15 | import tango.util.log.Trace; |
|---|
| 14 | 16 | |
|---|
| 15 | 17 | import dwt.DWT; |
|---|
| … | … | |
| 76 | 78 | |
|---|
| 77 | 79 | Font font; |
|---|
| 78 | | String text, segmentsText; |
|---|
| | 80 | String text; |
|---|
| | 81 | wchar[] wtext; |
|---|
| | 82 | char[] segmentsText; |
|---|
| | 83 | wchar[] segmentsWText; // DWT |
|---|
| | 84 | int[] index8to16; // DWT |
|---|
| | 85 | int[] index16to8; // DWT |
|---|
| 79 | 86 | int lineSpacing; |
|---|
| 80 | 87 | int ascent, descent; |
|---|
| … | … | |
| 85 | 92 | bool justify; |
|---|
| 86 | 93 | int[] tabs; |
|---|
| 87 | | int[] segments; |
|---|
| | 94 | int[] segments; // indices in 'text' |
|---|
| | 95 | int[] wsegments; // DWT indices in 'wtext' |
|---|
| 88 | 96 | StyleItem[] styles; |
|---|
| 89 | 97 | int stylesCount; |
|---|
| … | … | |
| 95 | 103 | |
|---|
| 96 | 104 | static const dchar LTR_MARK = '\u200E', RTL_MARK = '\u200F'; |
|---|
| | 105 | static const wchar LTR_MARKw = '\u200E', RTL_MARKw = '\u200F'; |
|---|
| 97 | 106 | static const String STR_LTR_MARK = "\u200E", STR_RTL_MARK = "\u200F"; |
|---|
| | 107 | static const wchar[] WSTR_LTR_MARK = "\u200E"w, WSTR_RTL_MARK = "\u200F"w; |
|---|
| 98 | 108 | static const int MARK_SIZE = 3; |
|---|
| | 109 | static const int WMARK_SIZE = 1; |
|---|
| 99 | 110 | static const int SCRIPT_VISATTR_SIZEOF = 2; |
|---|
| 100 | 111 | static const int GOFFSET_SIZEOF = 8; |
|---|
| … | … | |
| 232 | 243 | stylesCount = 2; |
|---|
| 233 | 244 | text = ""; //$NON-NLS-1$ |
|---|
| | 245 | wtext = ""w; |
|---|
| 234 | 246 | void* ppv; |
|---|
| 235 | 247 | OS.OleInitialize(null); |
|---|
| … | … | |
| 242 | 254 | void breakRun(StyleItem run) { |
|---|
| 243 | 255 | if (run.psla !is null) return; |
|---|
| 244 | | wchar[] chars = StrToWCHARs( 0, segmentsText[ run.start .. run.start + run.length ] ); |
|---|
| | 256 | wchar[] chars = segmentsWText[ index8to16[ run.start ] .. index8to16[ run.start + run.length ] ]; |
|---|
| 245 | 257 | auto hHeap = OS.GetProcessHeap(); |
|---|
| 246 | 258 | run.psla = cast(SCRIPT_LOGATTR*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, SCRIPT_LOGATTR.sizeof * chars.length); |
|---|
| … | … | |
| 499 | 511 | font = null; |
|---|
| 500 | 512 | text = null; |
|---|
| | 513 | wtext = null; |
|---|
| 501 | 514 | segmentsText = null; |
|---|
| | 515 | segmentsWText = null; |
|---|
| 502 | 516 | tabs = null; |
|---|
| 503 | 517 | styles = null; |
|---|
| … | … | |
| 614 | 628 | if (selectionBackground !is null && selectionBackground.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); |
|---|
| 615 | 629 | int length = text.length; |
|---|
| | 630 | int wlength = wtext.length; |
|---|
| 616 | 631 | if (length is 0 && flags is 0) return; |
|---|
| 617 | 632 | auto hdc = gc.handle; |
|---|
| … | … | |
| 756 | 771 | if (drawX + run.width >= clip.x) { |
|---|
| 757 | 772 | if (!run.lineBreak || run.softBreak) { |
|---|
| 758 | | int end = run.start + run.length - 1; |
|---|
| | 773 | int end = segmentsText.getAbsoluteCodePointOffset( run.start + run.length, -1 ); |
|---|
| 759 | 774 | bool fullSelection = hasSelection && selectionStart <= run.start && selectionEnd >= end; |
|---|
| 760 | 775 | if (fullSelection) { |
|---|
| … | … | |
| 787 | 802 | int selStart = Math.max(selectionStart, run.start) - run.start; |
|---|
| 788 | 803 | int selEnd = Math.min(selectionEnd, end) - run.start; |
|---|
| 789 | | int cChars = run.length; |
|---|
| | 804 | int cChars = index8to16[run.start+run.length] - index8to16[run.start]; // make it wchar |
|---|
| 790 | 805 | int gGlyphs = run.glyphCount; |
|---|
| 791 | 806 | int piX; |
|---|
| 792 | 807 | int* advances = run.justify !is null ? run.justify : run.advances; |
|---|
| 793 | | OS.ScriptCPtoX(selStart, false, cChars, gGlyphs, run.clusters, run.visAttrs, advances, &run.analysis, &piX); |
|---|
| | 808 | OS.ScriptCPtoX(index8to16[selStart], false, cChars, gGlyphs, run.clusters, run.visAttrs, advances, &run.analysis, &piX); |
|---|
| 794 | 809 | int runX = (orientation & DWT.RIGHT_TO_LEFT) !is 0 ? run.width - piX : piX; |
|---|
| 795 | 810 | rect.left = drawX + runX; |
|---|
| 796 | 811 | rect.top = drawY; |
|---|
| 797 | | OS.ScriptCPtoX(selEnd, true, cChars, gGlyphs, run.clusters, run.visAttrs, advances, &run.analysis, &piX); |
|---|
| | 812 | OS.ScriptCPtoX(index8to16[selEnd], true, cChars, gGlyphs, run.clusters, run.visAttrs, advances, &run.analysis, &piX); |
|---|
| 798 | 813 | runX = (orientation & DWT.RIGHT_TO_LEFT) !is 0 ? run.width - piX : piX; |
|---|
| 799 | 814 | rect.right = drawX + runX; |
|---|
| … | … | |
| 830 | 845 | int drawRunY = drawY + (baseline - run.ascent); |
|---|
| 831 | 846 | if (partialSelection) { |
|---|
| 832 | | int selStart = Math.max(selectionStart, run.start) - run.start; |
|---|
| 833 | | int selEnd = Math.min(selectionEnd, end) - run.start; |
|---|
| 834 | | int cChars = run.length; |
|---|
| | 847 | int selStart = Math.max(index8to16[selectionStart], index8to16[run.start]) - index8to16[run.start]; |
|---|
| | 848 | int selEnd = Math.min(index8to16[selectionEnd], index8to16[end]) - index8to16[run.start]; |
|---|
| | 849 | int cChars = index8to16[run.start+run.length] - index8to16[run.start]; // make it wchar |
|---|
| 835 | 850 | int gGlyphs = run.glyphCount; |
|---|
| 836 | 851 | int piX; |
|---|
| … | … | |
| 1331 | 1346 | runs = null; |
|---|
| 1332 | 1347 | segmentsText = null; |
|---|
| | 1348 | segmentsWText = null; |
|---|
| 1333 | 1349 | } |
|---|
| 1334 | 1350 | |
|---|
| … | … | |
| 1434 | 1450 | if (run.style !is null && run.style.metrics !is null) { |
|---|
| 1435 | 1451 | GlyphMetrics metrics = run.style.metrics; |
|---|
| 1436 | | cx = metrics.width * (start - run.start); |
|---|
| | 1452 | cx = metrics.width * (index8to16[start] - index8to16[run.start]); |
|---|
| 1437 | 1453 | } else if (!run.tab) { |
|---|
| 1438 | 1454 | int piX; |
|---|
| 1439 | 1455 | int* advances = run.justify !is null ? run.justify : run.advances; |
|---|
| 1440 | | OS.ScriptCPtoX(start - run.start, false, run.length, run.glyphCount, run.clusters, run.visAttrs, advances, &run.analysis, &piX); |
|---|
| | 1456 | int wlength = index8to16[ run.start+run.length] - index8to16[run.start]; |
|---|
| | 1457 | OS.ScriptCPtoX(index8to16[start] - index8to16[run.start], false, wlength, run.glyphCount, run.clusters, run.visAttrs, advances, &run.analysis, &piX); |
|---|
| 1441 | 1458 | cx = isRTL ? run.width - piX : piX; |
|---|
| 1442 | 1459 | } |
|---|
| … | … | |
| 1451 | 1468 | if (run.style !is null && run.style.metrics !is null) { |
|---|
| 1452 | 1469 | GlyphMetrics metrics = run.style.metrics; |
|---|
| 1453 | | cx = metrics.width * (end - run.start + 1); |
|---|
| | 1470 | cx = metrics.width * (index8to16[end] - index8to16[run.start] + 1); |
|---|
| 1454 | 1471 | } else if (!run.tab) { |
|---|
| 1455 | 1472 | int piX; |
|---|
| 1456 | 1473 | int* advances = run.justify !is null ? run.justify : run.advances; |
|---|
| 1457 | | OS.ScriptCPtoX(end - run.start, true, run.length, run.glyphCount, run.clusters, run.visAttrs, advances, &run.analysis, &piX); |
|---|
| | 1474 | int wlength = index8to16[ run.start+run.length] - index8to16[run.start]; |
|---|
| | 1475 | OS.ScriptCPtoX(index8to16[end] - index8to16[run.start], true, wlength, run.glyphCount, run.clusters, run.visAttrs, advances, &run.analysis, &piX); |
|---|
| 1458 | 1476 | cx = isRTL ? run.width - piX : piX; |
|---|
| 1459 | 1477 | } |
|---|
| … | … | |
| 1796 | 1814 | width = (trailing || (offset is length)) ? run.width : 0; |
|---|
| 1797 | 1815 | } else { |
|---|
| 1798 | | // DWT: runOffset now in codepoints |
|---|
| 1799 | | int runOffset = segmentsText[ run.start .. $ ].indexToCodepointIndex( offset - run.start ); |
|---|
| 1800 | | int cChars = run.length; |
|---|
| | 1816 | int runOffset = index8to16[offset] - index8to16[run.start]; |
|---|
| | 1817 | int cChars = index8to16[run.start+run.length] - index8to16[run.start]; // make it wchar |
|---|
| 1801 | 1818 | int gGlyphs = run.glyphCount; |
|---|
| 1802 | 1819 | int piX; |
|---|
| … | … | |
| 1859 | 1876 | while (run.start <= offset && offset < run.start + run.length) { |
|---|
| 1860 | 1877 | if (isComplex) { |
|---|
| 1861 | | logAttr = run.psla + (offset - run.start); |
|---|
| | 1878 | logAttr = run.psla + (index8to16[offset] - index8to16[run.start]); |
|---|
| 1862 | 1879 | } |
|---|
| 1863 | 1880 | switch (movement) { |
|---|
| … | … | |
| 1879 | 1896 | bool previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset - 1)); |
|---|
| 1880 | 1897 | if (letterOrDigit !is previousLetterOrDigit || !letterOrDigit) { |
|---|
| 1881 | | if (!Compatibility.isWhitespace(segmentsText.charAt(offset))) { |
|---|
| | 1898 | if (!Compatibility.isWhitespace(segmentsText[offset..$].firstCodePoint())) { |
|---|
| 1882 | 1899 | return untranslateOffset(offset); |
|---|
| 1883 | 1900 | } |
|---|
| … | … | |
| 1890 | 1907 | if (offset > 0) { |
|---|
| 1891 | 1908 | bool isLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset)); |
|---|
| 1892 | | bool previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset - 1)); |
|---|
| | 1909 | bool previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText[offset - 1.. $].firstCodePoint()); |
|---|
| 1893 | 1910 | if (!isLetterOrDigit && previousLetterOrDigit) { |
|---|
| 1894 | 1911 | return untranslateOffset(offset); |
|---|
| … | … | |
| 1999 | 2016 | return untranslateOffset(run.start); |
|---|
| 2000 | 2017 | } |
|---|
| 2001 | | int cChars = run.length; |
|---|
| | 2018 | int cChars = index8to16[run.start+run.length] - index8to16[run.start]; // make it wchar |
|---|
| 2002 | 2019 | int cGlyphs = run.glyphCount; |
|---|
| 2003 | 2020 | int piCP; |
|---|
| … | … | |
| 2103 | 2120 | } |
|---|
| 2104 | 2121 | |
|---|
| 2105 | | String getSegmentsText() { |
|---|
| 2106 | | if (segments is null) return text; |
|---|
| | 2122 | void getSegmentsText( out char[] resUtf8, out wchar[] resUtf16 ) { |
|---|
| | 2123 | |
|---|
| | 2124 | void buildIndexTables() { // build the index translation tables. |
|---|
| | 2125 | index8to16.length = resUtf8.length + 1; |
|---|
| | 2126 | index16to8.length = resUtf16.length + 1; |
|---|
| | 2127 | |
|---|
| | 2128 | int idx8, idx16; |
|---|
| | 2129 | while( idx8 < resUtf8.length ){ |
|---|
| | 2130 | int ate8, ate16; |
|---|
| | 2131 | dchar d8 = resUtf8[ idx8 .. $ ].firstCodePoint( ate8 ); |
|---|
| | 2132 | dchar d16 = resUtf16[ idx16 .. $ ].firstCodePoint( ate16 ); |
|---|
| | 2133 | assert( d8 is d16 ); |
|---|
| | 2134 | index16to8[ idx16 .. idx16 +ate16 ] = idx8; |
|---|
| | 2135 | index8to16[ idx8 .. idx8 +ate8 ] = idx16; |
|---|
| | 2136 | idx8 += ate8; |
|---|
| | 2137 | idx16 += ate16; |
|---|
| | 2138 | } |
|---|
| | 2139 | index16to8[ resUtf16.length ] = resUtf8.length; |
|---|
| | 2140 | index8to16[ resUtf8.length ] = resUtf16.length; |
|---|
| | 2141 | } |
|---|
| | 2142 | |
|---|
| | 2143 | if (segments is null) { |
|---|
| | 2144 | resUtf8 = text; |
|---|
| | 2145 | resUtf16 = wtext; |
|---|
| | 2146 | buildIndexTables(); |
|---|
| | 2147 | return; |
|---|
| | 2148 | } |
|---|
| 2107 | 2149 | int nSegments = segments.length; |
|---|
| 2108 | | if (nSegments <= 1) return text; |
|---|
| | 2150 | if (nSegments <= 1) { |
|---|
| | 2151 | resUtf8 = text; |
|---|
| | 2152 | resUtf16 = wtext; |
|---|
| | 2153 | buildIndexTables(); |
|---|
| | 2154 | return; |
|---|
| | 2155 | } |
|---|
| 2109 | 2156 | int length_ = text.length; |
|---|
| 2110 | | if (length_ is 0) return text; |
|---|
| | 2157 | int wlength_ = wtext.length; |
|---|
| | 2158 | if (length_ is 0) { |
|---|
| | 2159 | resUtf8 = text; |
|---|
| | 2160 | resUtf16 = wtext; |
|---|
| | 2161 | buildIndexTables(); |
|---|
| | 2162 | return; |
|---|
| | 2163 | } |
|---|
| 2111 | 2164 | if (nSegments is 2) { |
|---|
| 2112 | | if (segments[0] is 0 && segments[1] is length_) return text; |
|---|
| 2113 | | } |
|---|
| 2114 | | char[] oldChars = new char[length_]; |
|---|
| 2115 | | text.getChars(0, length_, oldChars, 0); |
|---|
| 2116 | | // DWT: MARK is now 3 chars long |
|---|
| 2117 | | String separator = orientation is DWT.RIGHT_TO_LEFT ? STR_RTL_MARK : STR_LTR_MARK; |
|---|
| 2118 | | assert( separator.length is MARK_SIZE ); |
|---|
| 2119 | | char[] newChars = new char[length_ + nSegments*MARK_SIZE]; |
|---|
| 2120 | | int charCount = 0, segmentCount = 0; |
|---|
| 2121 | | while (charCount < length_) { |
|---|
| 2122 | | if (segmentCount < nSegments && charCount is segments[segmentCount]) { |
|---|
| | 2165 | if (segments[0] is 0 && segments[1] is length_) { |
|---|
| | 2166 | resUtf8 = text; |
|---|
| | 2167 | resUtf16 = wtext; |
|---|
| | 2168 | buildIndexTables(); |
|---|
| | 2169 | return; |
|---|
| | 2170 | } |
|---|
| | 2171 | } |
|---|
| | 2172 | { |
|---|
| | 2173 | char[] oldChars = text; |
|---|
| | 2174 | // DWT: MARK is now 3 chars long |
|---|
| | 2175 | String separator = orientation is DWT.RIGHT_TO_LEFT ? STR_RTL_MARK : STR_LTR_MARK; |
|---|
| | 2176 | assert( separator.length is MARK_SIZE ); |
|---|
| | 2177 | char[] newChars = new char[length_ + nSegments*MARK_SIZE]; |
|---|
| | 2178 | |
|---|
| | 2179 | int charCount = 0, segmentCount = 0; |
|---|
| | 2180 | while (charCount < length_) { |
|---|
| | 2181 | if (segmentCount < nSegments && charCount is segments[segmentCount]) { |
|---|
| | 2182 | int start = charCount + (segmentCount*MARK_SIZE); |
|---|
| | 2183 | newChars[ start .. start + MARK_SIZE ] = separator; |
|---|
| | 2184 | segmentCount++; |
|---|
| | 2185 | } else { |
|---|
| | 2186 | newChars[charCount + (segmentCount*MARK_SIZE)] = oldChars[charCount]; |
|---|
| | 2187 | charCount++; |
|---|
| | 2188 | } |
|---|
| | 2189 | } |
|---|
| | 2190 | if (segmentCount < nSegments) { |
|---|
| | 2191 | segments[segmentCount] = charCount; |
|---|
| 2123 | 2192 | int start = charCount + (segmentCount*MARK_SIZE); |
|---|
| 2124 | 2193 | newChars[ start .. start + MARK_SIZE ] = separator; |
|---|
| 2125 | 2194 | segmentCount++; |
|---|
| 2126 | | } else { |
|---|
| 2127 | | newChars[charCount + (segmentCount*MARK_SIZE)] = oldChars[charCount]; |
|---|
| 2128 | | charCount++; |
|---|
| 2129 | | } |
|---|
| 2130 | | } |
|---|
| 2131 | | if (segmentCount < nSegments) { |
|---|
| 2132 | | segments[segmentCount] = charCount; |
|---|
| 2133 | | int start = charCount + (segmentCount*MARK_SIZE); |
|---|
| 2134 | | newChars[ start .. start + MARK_SIZE ] = separator; |
|---|
| 2135 | | segmentCount++; |
|---|
| 2136 | | } |
|---|
| 2137 | | return newChars[ 0 .. Math.min(charCount + (segmentCount*MARK_SIZE), newChars.length)].dup; |
|---|
| | 2195 | } |
|---|
| | 2196 | resUtf8 = newChars[ 0 .. Math.min(charCount + (segmentCount*MARK_SIZE), newChars.length)]; |
|---|
| | 2197 | } |
|---|
| | 2198 | // now for the wide chars |
|---|
| | 2199 | { |
|---|
| | 2200 | wchar[] oldWChars = wtext; |
|---|
| | 2201 | wchar[] wseparator = orientation is DWT.RIGHT_TO_LEFT ? WSTR_RTL_MARK : WSTR_LTR_MARK; |
|---|
| | 2202 | assert( wseparator.length is 1 ); |
|---|
| | 2203 | wchar[] newWChars = new wchar[wlength_ + nSegments]; |
|---|
| | 2204 | |
|---|
| | 2205 | int charCount = 0, segmentCount = 0; |
|---|
| | 2206 | while (charCount < wlength_) { |
|---|
| | 2207 | if (segmentCount < nSegments && charCount is wsegments[segmentCount]) { |
|---|
| | 2208 | int start = charCount + (segmentCount*WMARK_SIZE); |
|---|
| | 2209 | newWChars[ start .. start + WMARK_SIZE ] = wseparator; |
|---|
| | 2210 | segmentCount++; |
|---|
| | 2211 | } else { |
|---|
| | 2212 | newWChars[charCount + (segmentCount*WMARK_SIZE)] = oldWChars[charCount]; |
|---|
| | 2213 | charCount++; |
|---|
| | 2214 | } |
|---|
| | 2215 | } |
|---|
| | 2216 | if (segmentCount < nSegments) { |
|---|
| | 2217 | wsegments[segmentCount] = charCount; |
|---|
| | 2218 | int start = charCount + (segmentCount*WMARK_SIZE); |
|---|
| | 2219 | newWChars[ start .. start + WMARK_SIZE ] = wseparator; |
|---|
| | 2220 | segmentCount++; |
|---|
| | 2221 | } |
|---|
| | 2222 | resUtf16 = newWChars[ 0 .. Math.min(charCount + (segmentCount*WMARK_SIZE), newWChars.length)]; |
|---|
| | 2223 | } |
|---|
| | 2224 | buildIndexTables(); |
|---|
| 2138 | 2225 | } |
|---|
| 2139 | 2226 | |
|---|
| … | … | |
| 2270 | 2357 | StyleItem[] itemize () { |
|---|
| 2271 | 2358 | // DWT: itemize is the process of finding changes in direction |
|---|
| 2272 | | segmentsText = getSegmentsText(); |
|---|
| | 2359 | getSegmentsText(segmentsText, segmentsWText ); |
|---|
| 2273 | 2360 | int length = segmentsText.length; |
|---|
| 2274 | 2361 | SCRIPT_CONTROL scriptControl; |
|---|
| … | … | |
| 2288 | 2375 | if (pItems is null) DWT.error(DWT.ERROR_NO_HANDLES); |
|---|
| 2289 | 2376 | int pcItems; |
|---|
| 2290 | | wchar[] chars = StrToWCHARs( segmentsText ); |
|---|
| | 2377 | wchar[] chars = segmentsWText; |
|---|
| 2291 | 2378 | OS.ScriptItemize(chars.ptr, chars.length, MAX_ITEM, &scriptControl, &scriptState, pItems, &pcItems); |
|---|
| 2292 | 2379 | // if (hr is E_OUTOFMEMORY) //TODO handle it |
|---|
| 2293 | 2380 | // DWT pcItems is not inclusive the trailing item |
|---|
| 2294 | | |
|---|
| 2295 | | // Translate the utf16 indices to utf8 indices |
|---|
| 2296 | | int utf8idx = 0; |
|---|
| 2297 | | int utf16idx = 0; |
|---|
| 2298 | | int i = 0; |
|---|
| 2299 | | SCRIPT_ITEM* si = pItems; |
|---|
| 2300 | | while( utf16idx < chars.length ){ |
|---|
| 2301 | | |
|---|
| 2302 | | if( si.iCharPos is utf16idx ){ |
|---|
| 2303 | | si.iCharPos = utf8idx; |
|---|
| 2304 | | i++; |
|---|
| 2305 | | si++; |
|---|
| 2306 | | } |
|---|
| 2307 | | |
|---|
| 2308 | | // goto next codepoint |
|---|
| 2309 | | uint ate16; |
|---|
| 2310 | | dchar[1] buf32; |
|---|
| 2311 | | dchar[] res32 = Utf.toString32( chars[ utf16idx .. $ ], buf32, &ate16 ); |
|---|
| 2312 | | uint ate32; |
|---|
| 2313 | | char[4] buf8; |
|---|
| 2314 | | char[] res8 = Utf.toString( res32, buf8, &ate32 ); |
|---|
| 2315 | | utf16idx += ate16; |
|---|
| 2316 | | utf8idx += res8.length; |
|---|
| 2317 | | } |
|---|
| 2318 | | assert( si.iCharPos is chars.length ); |
|---|
| 2319 | | si.iCharPos = utf8idx; |
|---|
| 2320 | | assert( si.iCharPos is segmentsText.length ); |
|---|
| 2321 | | assert( i is pcItems ); |
|---|
| 2322 | 2381 | |
|---|
| 2323 | 2382 | StyleItem[] runs = merge(pItems, pcItems); |
|---|
| … | … | |
| 2352 | 2411 | //scriptItem.a = new SCRIPT_ANALYSIS(); |
|---|
| 2353 | 2412 | scriptItem = items + (itemIndex + 1); |
|---|
| 2354 | | int itemLimit = scriptItem.iCharPos; |
|---|
| | 2413 | int itemLimit = index16to8[scriptItem.iCharPos]; |
|---|
| 2355 | 2414 | int styleLimit = translateOffset(styles[styleIndex + 1].start); |
|---|
| 2356 | 2415 | if (styleLimit <= itemLimit) { |
|---|
| … | … | |
| 2358 | 2417 | start = styleLimit; |
|---|
| 2359 | 2418 | if (start < itemLimit && 0 < start && start < end) { |
|---|
| 2360 | | char pChar = segmentsText.charAt(start - 1); |
|---|
| 2361 | | char tChar = segmentsText.charAt(start); |
|---|
| | 2419 | dchar pChar = segmentsText[ segmentsText.getAbsoluteCodePointOffset(start, -1) ..$].firstCodePoint(); |
|---|
| | 2420 | dchar tChar = segmentsText[start ..$].firstCodePoint(); |
|---|
| 2362 | 2421 | if (Compatibility.isLetter(pChar) && Compatibility.isLetter(tChar)) { |
|---|
| 2363 | 2422 | item.analysis.fLinkAfter = true; |
|---|
| … | … | |
| 2621 | 2680 | } |
|---|
| 2622 | 2681 | freeRuns(); |
|---|
| 2623 | | this.segments = segments; |
|---|
| | 2682 | this.segments = segments.dup; |
|---|
| | 2683 | |
|---|
| | 2684 | // DWT: create the wsegments ... |
|---|
| | 2685 | this.wsegments.length = segments.length; |
|---|
| | 2686 | uint index8, index16; |
|---|
| | 2687 | uint segIndex = 1; |
|---|
| | 2688 | while(index8 < text.length ){ |
|---|
| | 2689 | int ate8; |
|---|
| | 2690 | int ate16; |
|---|
| | 2691 | dchar d8 = text[ index8 .. $ ].firstCodePoint( ate8 ); |
|---|
| | 2692 | dchar d16 = wtext[ index16 .. $ ].firstCodePoint( ate16 ); |
|---|
| | 2693 | assert( d8 is d16 ); |
|---|
| | 2694 | assert( ate8 > 0 ); |
|---|
| | 2695 | assert( ate16 > 0 ); |
|---|
| | 2696 | index8 += ate8; |
|---|
| | 2697 | index16 += ate16; |
|---|
| | 2698 | if( segments[segIndex] is index8 ){ |
|---|
| | 2699 | wsegments[segIndex] = index16; |
|---|
| | 2700 | } |
|---|
| | 2701 | } |
|---|
| | 2702 | assert( index16 is wtext.length ); |
|---|
| | 2703 | assert( segIndex is segments.length ); |
|---|
| 2624 | 2704 | } |
|---|
| 2625 | 2705 | |
|---|
| … | … | |
| 2784 | 2864 | if (text.equals(this.text)) return; |
|---|
| 2785 | 2865 | freeRuns(); |
|---|
| 2786 | | this.text = text; |
|---|
| | 2866 | this.text = text.dup; |
|---|
| | 2867 | this.wtext = StrToWCHARs(text); |
|---|
| 2787 | 2868 | styles = new StyleItem[2]; |
|---|
| 2788 | 2869 | styles[0] = new StyleItem(); |
|---|
| … | … | |
| 2817 | 2898 | |
|---|
| 2818 | 2899 | bool shape (HDC hdc, StyleItem run, wchar[] wchars, int[] glyphCount, int maxGlyphs, SCRIPT_PROPERTIES* sp) { |
|---|
| 2819 | | //wchar[] wchars = StrToWCHARs( chars ); |
|---|
| 2820 | 2900 | bool useCMAPcheck = !sp.fComplex && !run.analysis.fNoGlyphIndex; |
|---|
| 2821 | 2901 | if (useCMAPcheck) { |
|---|
| 2822 | 2902 | ushort[] glyphs = new ushort[wchars.length]; |
|---|
| 2823 | | scope(exit) delete glyphs; |
|---|
| 2824 | 2903 | if (OS.ScriptGetCMap(hdc, run.psc, wchars.ptr, wchars.length, 0, glyphs.ptr) !is OS.S_OK) { |
|---|
| 2825 | 2904 | if (run.psc !is null) { |
|---|
| 2826 | 2905 | OS.ScriptFreeCache(run.psc); |
|---|
| 2827 | 2906 | glyphCount[0] = 0; |
|---|
| 2828 | | *cast(int*)run.psc = 1; |
|---|
| | 2907 | int[1] one = 1; |
|---|
| | 2908 | // OS.MoveMemory( run.psc, one.ptr, (void*).sizeof ); |
|---|
| | 2909 | // DWT: FIXME This should be checked, it works in Java with the MoveMemory |
|---|
| 2829 | 2910 | } |
|---|
| 2830 | 2911 | return false; |
|---|
| 2831 | 2912 | } |
|---|
| | 2913 | //delete glyphs; |
|---|
| 2832 | 2914 | } |
|---|
| 2833 | 2915 | auto hr = OS.ScriptShape(hdc, run.psc, wchars.ptr, wchars.length, maxGlyphs, &run.analysis, run.glyphs, run.clusters, run.visAttrs, glyphCount.ptr); |
|---|
| … | … | |
| 2850 | 2932 | OS.ScriptFreeCache(run.psc); |
|---|
| 2851 | 2933 | glyphCount[0] = 0; |
|---|
| 2852 | | *cast(int*)run.psc = 0; |
|---|
| | 2934 | int[1] one = 1; |
|---|
| | 2935 | OS.MoveMemory( run.psc, one.ptr, (void*).sizeof ); |
|---|
| 2853 | 2936 | } |
|---|
| 2854 | 2937 | run.glyphCount = 0; |
|---|
| … | … | |
| 2856 | 2939 | } |
|---|
| 2857 | 2940 | |
|---|
| 2858 | | struct CallbackDataEnumFontFamExProc { |
|---|
| 2859 | | int delegate ( ENUMLOGFONTEX* lpelfe, NEWTEXTMETRICEX* lpntme, int FontType, int lParam) EnumFontFamExProc; |
|---|
| 2860 | | int lParam; |
|---|
| 2861 | | } |
|---|
| 2862 | | extern(Windows) private static int EnumFontFamExProcFunc( ENUMLOGFONTEX* lpelfe, NEWTEXTMETRICEX* lpntme, int FontType, int lParam) { |
|---|
| 2863 | | auto cb = cast(CallbackDataEnumFontFamExProc*)cast(void*)lParam; |
|---|
| 2864 | | return cb.EnumFontFamExProc( lpelfe, lpntme, FontType, cb.lParam ); |
|---|
| 2865 | | } |
|---|
| 2866 | 2941 | |
|---|
| 2867 | 2942 | /* |
|---|
| … | … | |
| 2870 | 2945 | void shape (HDC hdc, StyleItem run) { |
|---|
| 2871 | 2946 | int[1] buffer; |
|---|
| 2872 | | char[] chars = new char[run.length]; |
|---|
| 2873 | | segmentsText.getChars(run.start, run.start + run.length, chars, 0); |
|---|
| 2874 | | wchar[] wchars = StrToWCHARs( chars ); |
|---|
| | 2947 | wchar[] wchars = segmentsWText[ index8to16[ run.start ] .. index8to16[ run.start + run.length ] ]; |
|---|
| 2875 | 2948 | int maxGlyphs = (wchars.length * 3 / 2) + 16; |
|---|
| 2876 | 2949 | auto hHeap = OS.GetProcessHeap(); |
|---|
| … | … | |
| 2884 | 2957 | if (run.psc is null) DWT.error(DWT.ERROR_NO_HANDLES); |
|---|
| 2885 | 2958 | short script = run.analysis.eScript; |
|---|
| 2886 | | auto sp = device.scripts[script]; |
|---|
| 2887 | | bool shapeSucceed = shape(hdc, run, wchars, buffer, maxGlyphs, sp); |
|---|
| | 2959 | SCRIPT_PROPERTIES sp = *device.scripts[script]; |
|---|
| | 2960 | bool shapeSucceed = shape(hdc, run, wchars, buffer, maxGlyphs, &sp); |
|---|
| | 2961 | int res; |
|---|
| 2888 | 2962 | if (!shapeSucceed) { |
|---|
| 2889 | 2963 | auto hFont = OS.GetCurrentObject(hdc, OS.OBJ_FONT); |
|---|
| … | … | |
| 2893 | 2967 | int flags = OS.SSA_METAFILE | OS.SSA_FALLBACK | OS.SSA_GLYPHS | OS.SSA_LINK; |
|---|
| 2894 | 2968 | if (OS.ScriptStringAnalyse(metaFileDc, wchars.ptr, wchars.length, 0, -1, flags, 0, null, null, null, null, null, ssa) is OS.S_OK) { |
|---|
| 2895 | | OS.ScriptStringOut(ssa, 0, 0, 0, null, 0, 0, false); |
|---|
| | 2969 | OS.ScriptStringOut(*ssa, 0, 0, 0, null, 0, 0, false); |
|---|
| 2896 | 2970 | OS.ScriptStringFree(ssa); |
|---|
| 2897 | 2971 | } |
|---|
| … | … | |
| 2899 | 2973 | OS.SelectObject(metaFileDc, oldMetaFont); |
|---|
| 2900 | 2974 | auto metaFile = OS.CloseEnhMetaFile(metaFileDc); |
|---|
| 2901 | | EMREXTCREATEFONTINDIRECTW emr; |
|---|
| 2902 | 2975 | static extern(Windows) int metaFileEnumProc (HDC hDC, HANDLETABLE* table, ENHMETARECORD* record, int nObj, LPARAM lpData) { |
|---|
| 2903 | | EMREXTCREATEFONTINDIRECTW* emr_; |
|---|
| | 2976 | EMREXTCREATEFONTINDIRECTW* emr_ = cast(EMREXTCREATEFONTINDIRECTW*)lpData; |
|---|
| 2904 | 2977 | OS.MoveMemory(&emr_.emr, record, EMR.sizeof); |
|---|
| 2905 | 2978 | switch (emr_.emr.iType) { |
|---|
| … | … | |
| 2909 | 2982 | case OS.EMR_EXTTEXTOUTW: |
|---|
| 2910 | 2983 | return 0; |
|---|
| | 2984 | default: |
|---|
| 2911 | 2985 | } |
|---|
| 2912 | 2986 | return 1; |
|---|
| 2913 | 2987 | } |
|---|
| | 2988 | |
|---|
| | 2989 | EMREXTCREATEFONTINDIRECTW emr; |
|---|
| 2914 | 2990 | OS.EnumEnhMetaFile(null, metaFile, &metaFileEnumProc, &emr, null); |
|---|
| 2915 | | OS.DeleteEnhMetaFile(metaFile); |
|---|
| | 2991 | res = OS.DeleteEnhMetaFile(metaFile); |
|---|
| | 2992 | assert( res !is 0 ); |
|---|
| 2916 | 2993 | |
|---|
| 2917 | 2994 | auto newFont = OS.CreateFontIndirectW(&emr.elfw.elfLogFont); |
|---|
| | 2995 | assert( newFont !is null ); |
|---|
| | 2996 | |
|---|
| 2918 | 2997 | OS.SelectObject(hdc, newFont); |
|---|
| 2919 | | if ((shapeSucceed = shape(hdc, run, wchars, buffer, maxGlyphs, sp)) is true ) { |
|---|
| | 2998 | if ((shapeSucceed = shape(hdc, run, wchars, buffer, maxGlyphs, &sp)) is true ) { |
|---|
| 2920 | 2999 | run.fallbackFont = newFont; |
|---|
| 2921 | 3000 | } |
|---|
| … | … | |
| 2923 | 3002 | if (!sp.fComplex) { |
|---|
| 2924 | 3003 | run.analysis.fNoGlyphIndex = true; |
|---|
| 2925 | | if ((shapeSucceed = shape(hdc, run, wchars, buffer, maxGlyphs, sp)) is true ) { |
|---|
| | 3004 | if ((shapeSucceed = shape(hdc, run, wchars, buffer, maxGlyphs, &sp)) is true ) { |
|---|
| 2926 | 3005 | run.fallbackFont = newFont; |
|---|
| 2927 | 3006 | } else { |
|---|
| … | … | |
| 2931 | 3010 | } |
|---|
| 2932 | 3011 | if (!shapeSucceed) { |
|---|
| 2933 | | if (mLangFontLink2 !is null) { |
|---|
| 2934 | | HANDLE hNewFont; |
|---|
| 2935 | | int dwCodePages, cchCodePages; |
|---|
| | 3012 | if (mLangFontLink2 !is null) { |
|---|
| | 3013 | HANDLE hNewFont; |
|---|
| | 3014 | int dwCodePages, cchCodePages; |
|---|
| 2936 | 3015 | /* GetStrCodePages() */ |
|---|
| 2937 | | OS.VtblCall(4, mLangFontLink2, cast(int)wchars.ptr, wchars.length, 0, cast(int)&dwCodePages, cast(int)&cchCodePages); |
|---|
| | 3016 | OS.VtblCall(4, mLangFontLink2, cast(int)wchars.ptr, wchars.length, 0, cast(int)&dwCodePages, cast(int)&cchCodePages); |
|---|
| 2938 | 3017 | /* MapFont() */ |
|---|
| 2939 | | if (OS.VtblCall(10, mLangFontLink2, cast(int)hdc, dwCodePages, cast(int)wchars[0], cast(int)&hNewFont) is OS.S_OK) { |
|---|
| | 3018 | if (OS.VtblCall(10, mLangFontLink2, cast(int)hdc, dwCodePages, cast(int)wchars[0], cast(int)&hNewFont) is OS.S_OK) { |
|---|
| 2940 | 3019 | LOGFONT logFont; |
|---|
| 2941 | 3020 | OS.GetObject( hNewFont, LOGFONT.sizeof, &logFont ); |
|---|
| … | … | |
| 2944 | 3023 | auto mLangFont = OS.CreateFontIndirect(&logFont); |
|---|
| 2945 | 3024 | auto oldFont = OS.SelectObject(hdc, mLangFont); |
|---|
| 2946 | | if ((shapeSucceed = shape(hdc, run, wchars, buffer, maxGlyphs, sp)) is true ) { |
|---|
| | 3025 | if ((shapeSucceed = shape(hdc, run, wchars, buffer, maxGlyphs, &sp)) is true ) { |
|---|
| 2947 | 3026 | run.fallbackFont = mLangFont; |
|---|
| 2948 | 3027 | } else { |
|---|
| … | … | |
| 2963 | 3042 | * Missing glyphs typically will be represent as black boxes in the text. |
|---|
| 2964 | 3043 | */ |
|---|
| 2965 | | auto wchars_ = StrToWCHARs(chars); |
|---|
| 2966 | | OS.ScriptShape(hdc, run.psc, wchars_.ptr, wchars_.length, maxGlyphs, &run.analysis, run.glyphs, run.clusters, run.visAttrs, buffer.ptr); |
|---|
| | 3044 | OS.ScriptShape(hdc, run.psc, wchars.ptr, wchars.length, maxGlyphs, &run.analysis, run.glyphs, run.clusters, run.visAttrs, buffer.ptr); |
|---|
| 2967 | 3045 | run.glyphCount = buffer[0]; |
|---|
| 2968 | 3046 | } |
|---|