comparison org.eclipse.swt.win32.win32.x86/src/org/eclipse/swt/graphics/TextLayout.d @ 120:536e43f63c81

Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661 ===D2=== * added [Try]Immutable/Const/Shared templates to work with differenses in D1/D2 instead of version statements used these templates to work with strict type storage rules of dmd-2.053 * com.ibm.icu now also compilable with D2, but not tested yet * small fixes Snippet288 - shared data is in TLS ===Phobos=== * fixed critical bugs in Phobos implemention completely incorrect segfault prone fromStringz (Linux's port ruthless killer) terrible, incorrect StringBuffer realization (StyledText killer) * fixed small bugs as well Snippet72 - misprint in the snippet * implemented missed functionality for Phobos ByteArrayOutputStream implemented (image loading available) formatting correctly works for all DWT's cases As a result, folowing snippets now works with Phobos (Snippet### - what is fixed): Snippet24, 42, 111, 115, 130, 235, 276 - bad string formatting Snippet48, 282 - crash on image loading Snippet163, 189, 211, 213, 217, 218, 222 - crash on copy/cut in StyledText Snippet244 - hang-up ===Tango=== * few changes for the latest Tango trunc-r5661 * few small performance improvments ===General=== * implMissing-s for only one version changed to implMissingInTango/InPhobos * incorrect calls to Format in toString-s fixed * fixed loading \uXXXX characters in ResourceBundle * added good UTF-8 support for StyledText, TextLayout (Win32) and friends UTF functions revised and tested. It is now in java.nonstandard.*Utf modules StyledText and TextLayout (Win32) modules revised for UTF-8 support * removed small diferences in most identical files in *.swt.* folders *.swt.internal.image, *.swt.events and *.swt.custom are identical in Win32/Linux32 now 179 of 576 (~31%) files in *.swt.* folders are fully identical * Win32: snippets now have right subsystem, pretty icons and native system style controls * small fixes in snippets Snippet44 - it's not Snippet44 Snippet212 - functions work with different images and offsets arrays Win32: Snippet282 - crash on close if the button has an image Snippet293 - setGrayed is commented and others Win32: As a result, folowing snippets now works Snippet68 - color doesn't change Snippet163, 189, 211, 213, 217, 218, 222 - UTF-8 issues (see above) Snippet193 - no tabel headers
author Denis Shelomovskij <verylonglogin.reg@gmail.com>
date Sat, 09 Jul 2011 15:50:20 +0300
parents 9f4c18c268b2
children
comparison
equal deleted inserted replaced
119:d00e8db0a568 120:536e43f63c81
21 + index16to8: translate indexes from segmentsWText to segmentsText 21 + index16to8: translate indexes from segmentsWText to segmentsText
22 + 22 +
23 + 'text' is the original user text, 'segmentsText' is the user text stuffed with 23 + 'text' is the original user text, 'segmentsText' is the user text stuffed with
24 + RTL/LTR markers for each line or in addition for User supplied segments. A segment 24 + RTL/LTR markers for each line or in addition for User supplied segments. A segment
25 + is a range where Bidi char reordering can happen. 25 + is a range where Bidi char reordering can happen.
26 + The 'runs' are those ranges with an idiviual style. 26 + The 'runs' are those ranges with an idividual style.
27 +/ 27 +/
28 import org.eclipse.swt.SWT; 28 import org.eclipse.swt.SWT;
29 import org.eclipse.swt.SWTException; 29 import org.eclipse.swt.SWTException;
30 import org.eclipse.swt.internal.Compatibility; 30 import org.eclipse.swt.internal.Compatibility;
31 import org.eclipse.swt.internal.gdip.Gdip; 31 import org.eclipse.swt.internal.gdip.Gdip;
44 import org.eclipse.swt.graphics.Region; 44 import org.eclipse.swt.graphics.Region;
45 import org.eclipse.swt.graphics.Resource; 45 import org.eclipse.swt.graphics.Resource;
46 import org.eclipse.swt.graphics.TextStyle; 46 import org.eclipse.swt.graphics.TextStyle;
47 47
48 import java.lang.all; 48 import java.lang.all;
49 import java.nonstandard.SafeUtf;
49 50
50 51
51 /** 52 /**
52 * <code>TextLayout</code> is a graphic object that represents 53 * <code>TextLayout</code> is a graphic object that represents
53 * styled text. 54 * styled text.
66 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> 67 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
67 * 68 *
68 * @since 3.0 69 * @since 3.0
69 */ 70 */
70 public final class TextLayout : Resource { 71 public final class TextLayout : Resource {
71
72 alias Resource.init_ init_; 72 alias Resource.init_ init_;
73 private:
73 74
74 /++ 75 /++
75 + SWT doku 76 + SWT doku
76 + The styles has at minimum 2 member, each with a start. The last element is the end marker. 77 + The styles has at minimum 2 member, each with a start. The last element is the end marker.
77 + 78 +
87 Font font; 88 Font font;
88 String text; 89 String text;
89 String16 wtext; 90 String16 wtext;
90 String segmentsText; 91 String segmentsText;
91 String16 segmentsWText; // DWT 92 String16 segmentsWText; // DWT
92 int[] index8to16; // DWT 93 UTF16index[] index8to16; // DWT
93 int[] index16to8; // DWT 94 UTF8index[] index16to8; // DWT
94 int lineSpacing; 95 int lineSpacing;
95 int ascent, descent; 96 int ascent, descent;
96 int alignment; 97 int alignment;
97 int wrapWidth; 98 int wrapWidth;
98 int orientation; 99 int orientation;
99 int indent; 100 int indent;
100 bool justify; 101 bool justify;
101 int[] tabs; 102 int[] tabs;
102 int[] segments; // indices in 'text' 103 UTF8index[] segments; // indices in 'text'
103 int[] wsegments; // SWT indices in 'wtext' 104 UTF16index[] wsegments; // SWT indices in 'wtext'
104 StyleItem[] styles; 105 StyleItem[] styles;
105 int stylesCount; 106 int stylesCount;
106 107
107 StyleItem[] allRuns; 108 StyleItem[] allRuns;
108 StyleItem[][] runs; 109 StyleItem[][] runs;
109 int[] lineOffset, lineY, lineWidth; 110 UTF8index[] lineOffset;
111 int[] lineY, lineWidth;
110 void* mLangFontLink2; 112 void* mLangFontLink2;
111 113
112 static const dchar LTR_MARK = '\u200E', RTL_MARK = '\u200F'; 114 static const dchar LTR_MARK = '\u200E', RTL_MARK = '\u200F';
113 static const wchar LTR_MARKw = '\u200E', RTL_MARKw = '\u200F'; 115 static const wchar LTR_MARKw = '\u200E', RTL_MARKw = '\u200F';
114 static const String STR_LTR_MARK = "\u200E", STR_RTL_MARK = "\u200F"; 116 static const String STR_LTR_MARK = "\u200E", STR_RTL_MARK = "\u200F";
115 static const wchar[] WSTR_LTR_MARK = "\u200E"w, WSTR_RTL_MARK = "\u200F"w; 117 static const wchar[] WSTR_LTR_MARK = "\u200E"w, WSTR_RTL_MARK = "\u200F"w;
116 static const int MARK_SIZE = 3; 118 static const UTF8shift MARK_SIZE = { STR_LTR_MARK.length };
117 static const int WMARK_SIZE = 1; 119 static const UTF16shift WMARK_SIZE = WSTR_LTR_MARK.length;
120 static assert(MARK_SIZE.internalValue == 3 && WMARK_SIZE == 1);
118 static const int SCRIPT_VISATTR_SIZEOF = 2; 121 static const int SCRIPT_VISATTR_SIZEOF = 2;
119 static const int GOFFSET_SIZEOF = 8; 122 static const int GOFFSET_SIZEOF = 8;
120 private static byte[16] CLSID_CMultiLanguage; 123 mixin(gshared!("
121 private static byte[16] IID_IMLangFontLink2; 124 static byte[16] CLSID_CMultiLanguage;
122 private static bool static_this_completed = false; 125 static byte[16] IID_IMLangFontLink2;
123 private static void static_this() { 126 static bool static_this_completed = false;
127 "));
128 static void static_this() {
124 // in case of allready initialized, we can check and leave without lock 129 // in case of allready initialized, we can check and leave without lock
125 if( static_this_completed ){ 130 if( static_this_completed ){
126 return; 131 return;
127 } 132 }
128 synchronized { 133 synchronized {
129 if( !static_this_completed ){ 134 if( !static_this_completed ){
130 OS.IIDFromString("{275c23e2-3747-11d0-9fea-00aa003f8646}\0".toWCharArray().ptr, CLSID_CMultiLanguage.ptr); 135 OS.IIDFromString("{275c23e2-3747-11d0-9fea-00aa003f8646}\0"w.ptr, CLSID_CMultiLanguage.ptr);
131 OS.IIDFromString("{DCCFC162-2B38-11d2-B7EC-00C04F8F5D9A}\0".toWCharArray().ptr, IID_IMLangFontLink2.ptr); 136 OS.IIDFromString("{DCCFC162-2B38-11d2-B7EC-00C04F8F5D9A}\0"w.ptr, IID_IMLangFontLink2.ptr);
132 static_this_completed = true; 137 static_this_completed = true;
133 } 138 }
134 } 139 }
135 } 140 }
136 141
137 /* IME has a copy of these constants */ 142 /* IME has a copy of these constants */
138 static const int UNDERLINE_IME_DOT = 1 << 16; 143 static const int UNDERLINE_IME_DOT = 1 << 16;
139 static const int UNDERLINE_IME_DASH = 2 << 16; 144 static const int UNDERLINE_IME_DASH = 2 << 16;
140 static const int UNDERLINE_IME_THICK = 3 << 16; 145 static const int UNDERLINE_IME_THICK = 3 << 16;
141 146
142 class StyleItem { 147 static class StyleItem {
143 TextStyle style; 148 TextStyle style;
144 // SWT: start, lenght relative to segmentsText 149 // DWT: start, lenght relative to segmentsText
145 int start, length; 150 UTF8index UTF8start;
151 UTF8shift UTF8length;
152 UTF8index UTF8end() {
153 return UTF8start + UTF8length;
154 }
146 bool lineBreak, softBreak, tab; 155 bool lineBreak, softBreak, tab;
147 156
148 /*Script cache and analysis */ 157 /*Script cache and analysis */
149 SCRIPT_ANALYSIS analysis; 158 SCRIPT_ANALYSIS analysis;
150 SCRIPT_CACHE* psc; 159 SCRIPT_CACHE* psc;
219 descent = 0; 228 descent = 0;
220 x = 0; 229 x = 0;
221 lineBreak = softBreak = false; 230 lineBreak = softBreak = false;
222 } 231 }
223 override public String toString () { 232 override public String toString () {
224 return Format( "StyleItem {{{}, {}}", start, style ); 233 return Format( "StyleItem {{{}, {}}", UTF8start, style );
225 } 234 }
226 } 235 }
227 236
228 /** 237 /**
229 * Constructs a new instance of this class on the given device. 238 * Constructs a new instance of this class on the given device.
259 init_(); 268 init_();
260 } 269 }
261 270
262 void breakRun(StyleItem run) { 271 void breakRun(StyleItem run) {
263 if (run.psla !is null) return; 272 if (run.psla !is null) return;
264 String16 chars = segmentsWText[ index8to16[ run.start ] .. index8to16[ run.start + run.length ] ]; 273 String16 wchars = segmentsWText[ getUTF16index(run.UTF8start) .. getUTF16index(run.UTF8start + run.UTF8length) ];
265 auto hHeap = OS.GetProcessHeap(); 274 auto hHeap = OS.GetProcessHeap();
266 run.psla = cast(SCRIPT_LOGATTR*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, SCRIPT_LOGATTR.sizeof * chars.length); 275 run.psla = cast(SCRIPT_LOGATTR*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, SCRIPT_LOGATTR.sizeof * wchars.length);
267 if (run.psla is null) SWT.error(SWT.ERROR_NO_HANDLES); 276 if (run.psla is null) SWT.error(SWT.ERROR_NO_HANDLES);
268 OS.ScriptBreak(chars.ptr, chars.length, &run.analysis, run.psla); 277 OS.ScriptBreak(wchars.ptr, wchars.length, &run.analysis, run.psla);
269 } 278 }
270 279
271 void checkLayout () { 280 void checkLayout () {
272 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 281 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
273 } 282 }
274 283
275 /* 284 /*
276 * Compute the runs: itemize, shape, place, and reorder the runs. 285 * Compute the runs: itemize, shape, place, and reorder the runs.
277 * Break paragraphs into lines, wraps the text, and initialize caches. 286 * Break paragraphs into lines, wraps the text, and initialize caches.
278 */ 287 */
279 void computeRuns (GC gc) { 288 void computeRuns (GC gc)
289 out {
290 foreach(run; allRuns) {
291 segmentsText.validateUTF8index(run.UTF8start);
292 segmentsText.validateUTF8index(run.UTF8start + run.UTF8length);
293 }
294 } body {
280 if (runs !is null) return; 295 if (runs !is null) return;
281 auto hDC = gc !is null ? gc.handle : device.internal_new_GC(null); 296 auto hDC = gc !is null ? gc.handle : device.internal_new_GC(null);
282 auto srcHdc = OS.CreateCompatibleDC(hDC); 297 auto srcHdc = OS.CreateCompatibleDC(hDC);
283 allRuns = itemize(); 298 allRuns = itemize();
284 for (int i=0; i<allRuns.length - 1; i++) { 299 for (int i=0; i<allRuns.length - 1; i++) {
289 SCRIPT_LOGATTR* logAttr; 304 SCRIPT_LOGATTR* logAttr;
290 SCRIPT_PROPERTIES* properties; 305 SCRIPT_PROPERTIES* properties;
291 int lineWidth = indent, lineStart = 0, lineCount = 1; 306 int lineWidth = indent, lineStart = 0, lineCount = 1;
292 for (int i=0; i<allRuns.length - 1; i++) { 307 for (int i=0; i<allRuns.length - 1; i++) {
293 StyleItem run = allRuns[i]; 308 StyleItem run = allRuns[i];
294 if (run.length is 1) { 309 if (run.UTF8length.internalValue is 1) {
295 char ch = segmentsText.charAt(run.start); 310 char ch = segmentsText.charAt( run.UTF8start.internalValue );
311 assert(ch == segmentsText.dcharAt(run.UTF8start));
296 switch (ch) { 312 switch (ch) {
297 case '\t': { 313 case '\t': {
298 run.tab = true; 314 run.tab = true;
299 if (tabs is null) break; 315 if (tabs is null) break;
300 int tabsLength = tabs.length, j; 316 int tabsLength = tabs.length, j;
319 break; 335 break;
320 } 336 }
321 case '\r': { 337 case '\r': {
322 run.lineBreak = true; 338 run.lineBreak = true;
323 StyleItem next = allRuns[i + 1]; 339 StyleItem next = allRuns[i + 1];
324 if (next.length !is 0 && segmentsText.charAt(next.start) is '\n') { 340 if (next.UTF8length.internalValue !is 0 && segmentsText.charAt( next.UTF8start.internalValue ) is '\n') {
325 run.length += 1; 341 run.UTF8length.internalValue += 1;
326 next.free(); 342 next.free();
327 StyleItem[] newAllRuns = new StyleItem[allRuns.length - 1]; 343 StyleItem[] newAllRuns = new StyleItem[allRuns.length - 1];
328 System.arraycopy(allRuns, 0, newAllRuns, 0, i + 1); 344 System.arraycopy(allRuns, 0, newAllRuns, 0, i + 1);
329 System.arraycopy(allRuns, i + 2, newAllRuns, i + 1, allRuns.length - i - 2); 345 System.arraycopy(allRuns, i + 2, newAllRuns, i + 1, allRuns.length - i - 2);
330 allRuns = newAllRuns; 346 allRuns = newAllRuns;
333 } 349 }
334 default: 350 default:
335 } 351 }
336 } 352 }
337 if (wrapWidth !is -1 && lineWidth + run.width > wrapWidth && !run.tab) { 353 if (wrapWidth !is -1 && lineWidth + run.width > wrapWidth && !run.tab) {
338 int start = 0; 354 UTF16index wstart = 0;
339 int[] piDx = new int[run.length]; 355 UTF16shift cChars = getUTF16length(run);
356 int[] piDx = new int[cChars];
340 if (run.style !is null && run.style.metrics !is null) { 357 if (run.style !is null && run.style.metrics !is null) {
341 piDx[0] = run.width; 358 piDx[0] = run.width;
342 } else { 359 } else {
343 OS.ScriptGetLogicalWidths(&run.analysis, run.length, run.glyphCount, run.advances, run.clusters, run.visAttrs, piDx.ptr); 360 OS.ScriptGetLogicalWidths(&run.analysis, cChars, run.glyphCount, run.advances, run.clusters, run.visAttrs, piDx.ptr);
344 } 361 }
345 int width = 0, maxWidth = wrapWidth - lineWidth; 362 int width = 0, maxWidth = wrapWidth - lineWidth;
346 while (width + piDx[start] < maxWidth) { 363 while (width + piDx[wstart] < maxWidth) {
347 width += piDx[start++]; 364 width += piDx[wstart++];
348 } 365 }
349 int firstStart = start; 366 UTF16index firstWstart = wstart;
350 int firstIndice = i; 367 int firstIndice = i;
351 while (i >= lineStart) { 368 while (i >= lineStart) {
352 breakRun(run); 369 breakRun(run);
353 while (start >= 0) { 370 while (wstart >= 0) {
354 logAttr = run.psla + start; 371 logAttr = run.psla + wstart;
355 //OS.MoveMemory(logAttr, run.psla + (start * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof); 372 //OS.MoveMemory(logAttr, run.psla + (start * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof);
356 if (logAttr.fSoftBreak || logAttr.fWhiteSpace) break; 373 if (logAttr.fSoftBreak || logAttr.fWhiteSpace) break;
357 start--; 374 wstart--;
358 } 375 }
359 376
360 /* 377 /*
361 * Bug in Windows. For some reason Uniscribe sets the fSoftBreak flag for the first letter 378 * Bug in Windows. For some reason Uniscribe sets the fSoftBreak flag for the first letter
362 * after a letter with an accent. This cause a break line to be set in the middle of a word. 379 * after a letter with an accent. This cause a break line to be set in the middle of a word.
363 * The fix is to detect the case and ignore fSoftBreak forcing the algorithm keep searching. 380 * The fix is to detect the case and ignore fSoftBreak forcing the algorithm keep searching.
364 */ 381 */
365 if (start is 0 && i !is lineStart && !run.tab) { 382 if (wstart is 0 && i !is lineStart && !run.tab) {
366 if (logAttr.fSoftBreak && !logAttr.fWhiteSpace) { 383 if (logAttr.fSoftBreak && !logAttr.fWhiteSpace) {
367 properties = device.scripts[run.analysis.eScript]; 384 properties = device.scripts[run.analysis.eScript];
368 //OS.MoveMemory(properties, device.scripts[run.analysis.eScript], SCRIPT_PROPERTIES.sizeof); 385 //OS.MoveMemory(properties, device.scripts[run.analysis.eScript], SCRIPT_PROPERTIES.sizeof);
369 int langID = properties.langid; 386 int langID = properties.langid;
370 StyleItem pRun = allRuns[i - 1]; 387 StyleItem pRun = allRuns[i - 1];
371 //OS.MoveMemory(properties, device.scripts[pRun.analysis.eScript], SCRIPT_PROPERTIES.sizeof); 388 //OS.MoveMemory(properties, device.scripts[pRun.analysis.eScript], SCRIPT_PROPERTIES.sizeof);
372 if (properties.langid is langID || langID is OS.LANG_NEUTRAL || properties.langid is OS.LANG_NEUTRAL) { 389 if (properties.langid is langID || langID is OS.LANG_NEUTRAL || properties.langid is OS.LANG_NEUTRAL) {
373 breakRun(pRun); 390 breakRun(pRun);
374 logAttr = pRun.psla + (pRun.length - 1); 391 logAttr = pRun.psla + (getUTF16length(pRun) - 1);
375 //OS.MoveMemory(logAttr, pRun.psla + ((pRun.length - 1) * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof); 392 //OS.MoveMemory(logAttr, pRun.psla + ((pRun.length - 1) * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof);
376 if (!logAttr.fWhiteSpace) start = -1; 393 if (!logAttr.fWhiteSpace) wstart = cast(UTF16index)-1;
377 } 394 }
378 } 395 }
379 } 396 }
380 if (start >= 0 || i is lineStart) break; 397 if (wstart >= 0 || i is lineStart) break;
381 run = allRuns[--i]; 398 run = allRuns[--i];
382 start = run.length - 1; 399 wstart = cast(UTF16index)(getUTF16length(run) - 1);
383 } 400 }
384 if (start is 0 && i !is lineStart && !run.tab) { 401 if (wstart is 0 && i !is lineStart && !run.tab) {
385 run = allRuns[--i]; 402 run = allRuns[--i];
386 } else if (start <= 0 && i is lineStart) { 403 } else if (wstart <= 0 && i is lineStart) {
387 if (lineWidth is wrapWidth && firstIndice > 0) { 404 if (lineWidth is wrapWidth && firstIndice > 0) {
388 i = firstIndice - 1; 405 i = firstIndice - 1;
389 run = allRuns[i]; 406 run = allRuns[i];
390 start = run.length; 407 wstart = cast(UTF16index)getUTF16length(run);
391 } else { 408 } else {
392 i = firstIndice; 409 i = firstIndice;
393 run = allRuns[i]; 410 run = allRuns[i];
394 start = Math.max(1, firstStart); 411 wstart = cast(UTF16index)Math.max(1, firstWstart);
395 } 412 }
396 } 413 }
397 breakRun(run); 414 breakRun(run);
398 while (start < run.length) { 415 UTF16shift runWlength = getUTF16length(run);
399 logAttr = run.psla + start; 416 while (wstart < runWlength) {
417 logAttr = run.psla + wstart;
400 //OS.MoveMemory(logAttr, run.psla + (start * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof); 418 //OS.MoveMemory(logAttr, run.psla + (start * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof);
401 if (!logAttr.fWhiteSpace) break; 419 if (!logAttr.fWhiteSpace) break;
402 start++; 420 wstart++;
403 } 421 }
404 if (0 < start && start < run.length) { 422 if (0 < wstart && wstart < runWlength) {
405 StyleItem newRun = new StyleItem(); 423 StyleItem newRun = new StyleItem();
406 newRun.start = run.start + start; 424 UTF8shift UTF8startShift = getUTF8index(getUTF16index(run.UTF8start) + wstart) - run.UTF8start;
407 newRun.length = run.length - start; 425 newRun.UTF8start = run.UTF8start + UTF8startShift;
426 newRun.UTF8length = run.UTF8length - UTF8startShift;
408 newRun.style = run.style; 427 newRun.style = run.style;
409 newRun.analysis = cloneScriptAnalysis(run.analysis); 428 newRun.analysis = cloneScriptAnalysis(run.analysis);
410 run.free(); 429 run.free();
411 run.length = start; 430 run.UTF8length = UTF8startShift;
412 OS.SelectObject(srcHdc, getItemFont(run)); 431 OS.SelectObject(srcHdc, getItemFont(run));
413 run.analysis.fNoGlyphIndex = false; 432 run.analysis.fNoGlyphIndex = false;
414 shape (srcHdc, run); 433 shape (srcHdc, run);
415 OS.SelectObject(srcHdc, getItemFont(newRun)); 434 OS.SelectObject(srcHdc, getItemFont(newRun));
416 newRun.analysis.fNoGlyphIndex = false; 435 newRun.analysis.fNoGlyphIndex = false;
432 lineCount++; 451 lineCount++;
433 } 452 }
434 } 453 }
435 lineWidth = 0; 454 lineWidth = 0;
436 runs = new StyleItem[][](lineCount); 455 runs = new StyleItem[][](lineCount);
437 lineOffset = new int[lineCount + 1]; 456 lineOffset = new UTF8index[lineCount + 1];
438 lineY = new int[lineCount + 1]; 457 lineY = new int[lineCount + 1];
439 this.lineWidth = new int[lineCount]; 458 this.lineWidth = new int[lineCount];
440 int lineRunCount = 0, line = 0; 459 int lineRunCount = 0, line = 0;
441 int ascent = Math.max(0, this.ascent); 460 int ascent = Math.max(0, this.ascent);
442 int descent = Math.max(0, this.descent); 461 int descent = Math.max(0, this.descent);
487 lineWidth = newLineWidth; 506 lineWidth = newLineWidth;
488 } 507 }
489 this.lineWidth[line] = lineWidth; 508 this.lineWidth[line] = lineWidth;
490 509
491 StyleItem lastRun = runs[line][lineRunCount - 1]; 510 StyleItem lastRun = runs[line][lineRunCount - 1];
492 int lastOffset = lastRun.start + lastRun.length; 511 UTF8index lastOffset = lastRun.UTF8start + lastRun.UTF8length;
493 runs[line] = reorder(runs[line], i is allRuns.length - 1); 512 runs[line] = reorder(runs[line], i is allRuns.length - 1);
494 lastRun = runs[line][lineRunCount - 1]; 513 lastRun = runs[line][lineRunCount - 1];
495 if (run.softBreak && run !is lastRun) { 514 if (run.softBreak && run !is lastRun) {
496 run.softBreak = run.lineBreak = false; 515 run.softBreak = run.lineBreak = false;
497 lastRun.softBreak = lastRun.lineBreak = true; 516 lastRun.softBreak = lastRun.lineBreak = true;
594 * </ul> 613 * </ul>
595 * @exception IllegalArgumentException <ul> 614 * @exception IllegalArgumentException <ul>
596 * <li>ERROR_NULL_ARGUMENT - if the gc is null</li> 615 * <li>ERROR_NULL_ARGUMENT - if the gc is null</li>
597 * </ul> 616 * </ul>
598 */ 617 */
599 public void draw (GC gc, int x, int y, int selectionStart, int selectionEnd, Color selectionForeground, Color selectionBackground) { 618 public void draw (GC gc, int x, int y, int i_selectionStart, int i_selectionEnd, Color selectionForeground, Color selectionBackground) {
600 draw(gc, x, y, selectionStart, selectionEnd, selectionForeground, selectionBackground, 0); 619 draw(gc, x, y, i_selectionStart, i_selectionEnd, selectionForeground, selectionBackground, 0);
601 } 620 }
602 621
603 /** 622 /**
604 * Draws the receiver's text using the specified GC at the specified 623 * Draws the receiver's text using the specified GC at the specified
605 * point. 624 * point.
625 * <li>ERROR_NULL_ARGUMENT - if the gc is null</li> 644 * <li>ERROR_NULL_ARGUMENT - if the gc is null</li>
626 * </ul> 645 * </ul>
627 * 646 *
628 * @since 3.3 647 * @since 3.3
629 */ 648 */
630 public void draw (GC gc, int x, int y, int selectionStart, int selectionEnd, Color selectionForeground, Color selectionBackground, int flags) { 649 public void draw (GC gc, int x, int y, int i_selectionStart, int i_selectionEnd, Color selectionForeground, Color selectionBackground, int flags) {
631 checkLayout(); 650 checkLayout();
632 computeRuns(gc); 651 computeRuns(gc);
652 UTF8index selectionStart = text.takeIndexArg(i_selectionStart, "selectionStart@draw");
653 UTF8index selectionEnd = text.takeIndexArg(i_selectionEnd, "selectionEnd@draw");
633 if (gc is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 654 if (gc is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
634 if (gc.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 655 if (gc.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
635 if (selectionForeground !is null && selectionForeground.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 656 if (selectionForeground !is null && selectionForeground.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
636 if (selectionBackground !is null && selectionBackground.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 657 if (selectionBackground !is null && selectionBackground.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
637 int length = text.length; 658 int length = text.length;
692 if (clipRgn !is null) { 713 if (clipRgn !is null) {
693 OS.SelectClipRgn(hdc, clipRgn); 714 OS.SelectClipRgn(hdc, clipRgn);
694 OS.DeleteObject(clipRgn); 715 OS.DeleteObject(clipRgn);
695 } 716 }
696 } 717 }
697 bool hasSelection = selectionStart <= selectionEnd && selectionStart !is -1 && selectionEnd !is -1; 718 bool hasSelection = selectionStart <= selectionEnd && selectionStart.internalValue !is -1 && selectionEnd.internalValue !is -1;
698 if (hasSelection || (flags & SWT.LAST_LINE_SELECTION) !is 0) { 719 if (hasSelection || (flags & SWT.LAST_LINE_SELECTION) !is 0) {
699 selectionStart = Math.min(Math.max(0, selectionStart), length - 1); 720 selectionStart = Math.min(Math.max(text.firstIndex(), selectionStart), text.beforeEndIndex());
700 selectionEnd = Math.min(Math.max(0, selectionEnd), length - 1); 721 selectionEnd = Math.min(Math.max(text.firstIndex(), selectionEnd), text.beforeEndIndex());
701 if (selectionForeground is null) selectionForeground = device.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT); 722 if (selectionForeground is null) selectionForeground = device.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT);
702 if (selectionBackground is null) selectionBackground = device.getSystemColor(SWT.COLOR_LIST_SELECTION); 723 if (selectionBackground is null) selectionBackground = device.getSystemColor(SWT.COLOR_LIST_SELECTION);
703 selectionStart = translateOffset(selectionStart); 724 selectionStart = translateOffset(selectionStart);
704 selectionEnd = translateOffset(selectionEnd); 725 selectionEnd = translateOffset(selectionEnd);
705 } 726 }
738 if (line is runs.length - 1 && (flags & SWT.LAST_LINE_SELECTION) !is 0) { 759 if (line is runs.length - 1 && (flags & SWT.LAST_LINE_SELECTION) !is 0) {
739 extents = true; 760 extents = true;
740 } else { 761 } else {
741 StyleItem run = lineRuns[lineRuns.length - 1]; 762 StyleItem run = lineRuns[lineRuns.length - 1];
742 if (run.lineBreak && !run.softBreak) { 763 if (run.lineBreak && !run.softBreak) {
743 if (selectionStart <= run.start && run.start <= selectionEnd) extents = true; 764 if (selectionStart <= run.UTF8start && run.UTF8start <= selectionEnd) extents = true;
744 } else { 765 } else {
745 int endOffset = segmentsText.getAbsoluteCodePointOffset( run.start + run.length, -1 ); 766 UTF8index endOffset = segmentsText.offsetBefore(run.UTF8start + run.UTF8length);
746 if (selectionStart <= endOffset && endOffset < selectionEnd && (flags & SWT.FULL_SELECTION) !is 0) { 767 if (selectionStart <= endOffset && endOffset < selectionEnd && (flags & SWT.FULL_SELECTION) !is 0) {
747 extents = true; 768 extents = true;
748 } 769 }
749 } 770 }
750 } 771 }
772 lineUnderlinePos = Math.min(lineUnderlinePos, lineRuns[i].underlinePos); 793 lineUnderlinePos = Math.min(lineUnderlinePos, lineRuns[i].underlinePos);
773 } 794 }
774 int alignmentX = drawX; 795 int alignmentX = drawX;
775 for (int i = 0; i < lineRuns.length; i++) { 796 for (int i = 0; i < lineRuns.length; i++) {
776 StyleItem run = lineRuns[i]; 797 StyleItem run = lineRuns[i];
777 if (run.length is 0) continue; 798 if (run.UTF8length.internalValue is 0) continue;
778 if (drawX > clip.x + clip.width) break; 799 if (drawX > clip.x + clip.width) break;
779 if (drawX + run.width >= clip.x) { 800 if (drawX + run.width >= clip.x) {
780 if (!run.lineBreak || run.softBreak) { 801 if (!run.lineBreak || run.softBreak) {
781 int end = segmentsText.getAbsoluteCodePointOffset( run.start + run.length, -1 ); 802 UTF8index end = segmentsText.offsetBefore(run.UTF8start + run.UTF8length);
782 bool fullSelection = hasSelection && selectionStart <= run.start && selectionEnd >= end; 803 bool fullSelection = hasSelection && selectionStart <= run.UTF8start && selectionEnd >= end;
783 if (fullSelection) { 804 if (fullSelection) {
784 if (gdip) { 805 if (gdip) {
785 Gdip.Graphics_FillRectangle(gdipGraphics, cast(Gdip.Brush)selBrush, drawX, drawY, run.width, lineHeight); 806 Gdip.Graphics_FillRectangle(gdipGraphics, cast(Gdip.Brush)selBrush, drawX, drawY, run.width, lineHeight);
786 } else { 807 } else {
787 OS.SelectObject(hdc, selBrush); 808 OS.SelectObject(hdc, selBrush);
803 OS.PatBlt(hdc, drawX, drawY, run.width, lineHeight, OS.PATCOPY); 824 OS.PatBlt(hdc, drawX, drawY, run.width, lineHeight, OS.PATCOPY);
804 OS.SelectObject(hdc, oldBrush); 825 OS.SelectObject(hdc, oldBrush);
805 OS.DeleteObject(hBrush); 826 OS.DeleteObject(hBrush);
806 } 827 }
807 } 828 }
808 bool partialSelection = hasSelection && !(selectionStart > end || run.start > selectionEnd); 829 bool partialSelection = hasSelection && !(selectionStart > end || run.UTF8start > selectionEnd);
809 if (partialSelection) { 830 if (partialSelection) {
810 int selStart = index8to16[ Math.max(selectionStart, run.start) ] - index8to16[run.start]; 831 UTF16index selStart = getUTF16index(Math.max(selectionStart, run.UTF8start)) - getUTF16index(run.UTF8start);
811 int selEnd = index8to16[ Math.min(selectionEnd, end) ] - index8to16[ run.start ]; 832 UTF16index selEnd = getUTF16index(Math.min(selectionEnd, end)) - getUTF16index(run.UTF8start);
812 int cChars = index8to16[run.start+run.length] - index8to16[run.start]; // make it wchar 833 UTF16shift cChars = getUTF16length(run); // make it wchar
813 int gGlyphs = run.glyphCount; 834 int gGlyphs = run.glyphCount;
814 int piX; 835 int piX;
815 int* advances = run.justify !is null ? run.justify : run.advances; 836 int* advances = run.justify !is null ? run.justify : run.advances;
816 OS.ScriptCPtoX(selStart, false, cChars, gGlyphs, run.clusters, run.visAttrs, advances, &run.analysis, &piX); 837 OS.ScriptCPtoX(selStart, false, cChars, gGlyphs, run.clusters, run.visAttrs, advances, &run.analysis, &piX);
817 int runX = (orientation & SWT.RIGHT_TO_LEFT) !is 0 ? run.width - piX : piX; 838 int runX = (orientation & SWT.RIGHT_TO_LEFT) !is 0 ? run.width - piX : piX;
840 } 861 }
841 RECT* borderClip = null; 862 RECT* borderClip = null;
842 drawX = alignmentX; 863 drawX = alignmentX;
843 for (int i = 0; i < lineRuns.length; i++) { 864 for (int i = 0; i < lineRuns.length; i++) {
844 StyleItem run = lineRuns[i]; 865 StyleItem run = lineRuns[i];
845 if (run.length is 0) continue; 866 if (run.UTF8length.internalValue is 0) continue;
846 if (drawX > clip.x + clip.width) break; 867 if (drawX > clip.x + clip.width) break;
847 if (drawX + run.width >= clip.x) { 868 if (drawX + run.width >= clip.x) {
848 if (!run.tab && (!run.lineBreak || run.softBreak) && !(run.style !is null && run.style.metrics !is null)) { 869 if (!run.tab && (!run.lineBreak || run.softBreak) && !(run.style !is null && run.style.metrics !is null)) {
849 int end = run.start + run.length - 1; 870 UTF8index end = segmentsText.offsetBefore(run.UTF8start + run.UTF8length);
850 bool fullSelection = hasSelection && selectionStart <= run.start && selectionEnd >= end; 871 bool fullSelection = hasSelection && selectionStart <= run.UTF8start && selectionEnd >= end;
851 bool partialSelection = hasSelection && !fullSelection && !(selectionStart > end || run.start > selectionEnd); 872 bool partialSelection = hasSelection && !fullSelection && !(selectionStart > end || run.UTF8start > selectionEnd);
852 OS.SelectObject(hdc, getItemFont(run)); 873 OS.SelectObject(hdc, getItemFont(run));
853 int drawRunY = drawY + (baseline - run.ascent); 874 int drawRunY = drawY + (baseline - run.ascent);
854 if (partialSelection) { 875 if (partialSelection) {
855 int selStart = Math.max(index8to16[selectionStart], index8to16[run.start]) - index8to16[run.start]; 876 UTF16index selStart = Math.max(getUTF16index(selectionStart), getUTF16index(run.UTF8start)) - getUTF16index(run.UTF8start);
856 int selEnd = Math.min(index8to16[selectionEnd], index8to16[end]) - index8to16[run.start]; 877 UTF16index selEnd = Math.min(getUTF16index(selectionEnd), getUTF16index(end)) - getUTF16index(run.UTF8start);
857 int cChars = index8to16[run.start+run.length] - index8to16[run.start]; // make it wchar 878 UTF16shift cChars = getUTF16length(run); // make it wchar
858 int gGlyphs = run.glyphCount; 879 int gGlyphs = run.glyphCount;
859 int piX; 880 int piX;
860 int* advances = run.justify !is null ? run.justify : run.advances; 881 int* advances = run.justify !is null ? run.justify : run.advances;
861 OS.ScriptCPtoX(selStart, false, cChars, gGlyphs, run.clusters, run.visAttrs, advances, &run.analysis, &piX); 882 OS.ScriptCPtoX(selStart, false, cChars, gGlyphs, run.clusters, run.visAttrs, advances, &run.analysis, &piX);
862 int runX = (orientation & SWT.RIGHT_TO_LEFT) !is 0 ? run.width - piX : piX; 883 int runX = (orientation & SWT.RIGHT_TO_LEFT) !is 0 ? run.width - piX : piX;
1183 if (brushUnderline !is 0) OS.DeleteObject(cast(void*)brushUnderline); 1204 if (brushUnderline !is 0) OS.DeleteObject(cast(void*)brushUnderline);
1184 if (brushStrikeout !is 0 && brushStrikeout !is brushUnderline) OS.DeleteObject(cast(void*)brushStrikeout); 1205 if (brushStrikeout !is 0 && brushStrikeout !is brushUnderline) OS.DeleteObject(cast(void*)brushStrikeout);
1185 } 1206 }
1186 } 1207 }
1187 1208
1188 RECT* drawBorder(bool advance, void* graphics, int x, int y, int lineHeight, void* color, void* selectionColor, bool fullSelection, RECT* clipRect, RECT* rect, int alpha, StyleItem[] line, int index, int selectionStart, int selectionEnd) { 1209 RECT* drawBorder(bool advance, void* graphics, int x, int y, int lineHeight, void* color, void* selectionColor, bool fullSelection, RECT* clipRect, RECT* rect, int alpha, StyleItem[] line, int index, UTF8index selectionStart, UTF8index selectionEnd) {
1189 StyleItem run = line[index]; 1210 StyleItem run = line[index];
1190 TextStyle style = run.style; 1211 TextStyle style = run.style;
1191 if (style is null) return null; 1212 if (style is null) return null;
1192 if (style.borderStyle is SWT.NONE) return null; 1213 if (style.borderStyle is SWT.NONE) return null;
1193 if (rect !is null) { 1214 if (rect !is null) {
1194 if (clipRect is null) { 1215 if (clipRect is null) {
1195 clipRect = new RECT (); 1216 clipRect = new RECT ();
1196 OS.SetRect(clipRect, -1, rect.top, -1, rect.bottom); 1217 OS.SetRect(clipRect, -1, rect.top, -1, rect.bottom);
1197 } 1218 }
1198 bool isRTL = (orientation & SWT.RIGHT_TO_LEFT) !is 0; 1219 bool isRTL = (orientation & SWT.RIGHT_TO_LEFT) !is 0;
1199 if (run.start <= selectionStart && selectionStart <= run.start + run.length) { 1220 if (run.UTF8start <= selectionStart && selectionStart <= run.UTF8start + run.UTF8length) {
1200 if (run.analysis.fRTL ^ isRTL) { 1221 if (run.analysis.fRTL ^ isRTL) {
1201 clipRect.right = rect.left; 1222 clipRect.right = rect.left;
1202 } else { 1223 } else {
1203 clipRect.left = rect.left; 1224 clipRect.left = rect.left;
1204 } 1225 }
1205 } 1226 }
1206 if (run.start <= selectionEnd && selectionEnd <= run.start + run.length) { 1227 if (run.UTF8start <= selectionEnd && selectionEnd <= run.UTF8start + run.UTF8length) {
1207 if (run.analysis.fRTL ^ isRTL) { 1228 if (run.analysis.fRTL ^ isRTL) {
1208 clipRect.left = rect.right; 1229 clipRect.left = rect.right;
1209 } else { 1230 } else {
1210 clipRect.right = rect.right; 1231 clipRect.right = rect.right;
1211 } 1232 }
1431 * 1452 *
1432 * @exception SWTException <ul> 1453 * @exception SWTException <ul>
1433 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 1454 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
1434 * </ul> 1455 * </ul>
1435 */ 1456 */
1436 public Rectangle getBounds (int start, int end) { 1457 public Rectangle getBounds (int i_start, int i_end) {
1437 checkLayout(); 1458 checkLayout();
1438 computeRuns(null); 1459 computeRuns(null);
1439 int length = text.length; 1460 UTF8index start = text.takeIndexArg(i_start, "start@getBounds");
1440 if (length is 0) return new Rectangle(0, 0, 0, 0); 1461 UTF8index end = text.takeIndexArg(i_end, "end@getBounds");
1462 if (text.length is 0) return new Rectangle(0, 0, 0, 0);
1441 if (start > end) return new Rectangle(0, 0, 0, 0); 1463 if (start > end) return new Rectangle(0, 0, 0, 0);
1442 start = Math.min(Math.max(0, start), length - 1); 1464 start = Math.min(Math.max(text.firstIndex(), start), text.beforeEndIndex());
1443 end = Math.min(Math.max(0, end), length - 1); 1465 end = Math.min(Math.max(text.firstIndex(), end), text.beforeEndIndex());
1444 start = translateOffset(start); 1466 start = translateOffset(start);
1445 end = translateOffset(end); 1467 end = translateOffset(end);
1446 int left = 0x7fffffff, right = 0; 1468 int left = 0x7fffffff, right = 0;
1447 int top = 0x7fffffff, bottom = 0; 1469 int top = 0x7fffffff, bottom = 0;
1448 bool isRTL = (orientation & SWT.RIGHT_TO_LEFT) !is 0; 1470 bool isRTL = (orientation & SWT.RIGHT_TO_LEFT) !is 0;
1449 for (int i = 0; i < allRuns.length - 1; i++) { 1471 for (int i = 0; i < allRuns.length - 1; i++) {
1450 StyleItem run = allRuns[i]; 1472 StyleItem run = allRuns[i];
1451 int runEnd = run.start + run.length; 1473 UTF8index runEnd = run.UTF8start + run.UTF8length;
1452 if (runEnd <= start) continue; 1474 if (runEnd <= start) continue;
1453 if (run.start > end) break; 1475 if (run.UTF8start > end) break;
1454 int runLead = run.x; 1476 int runLead = run.x;
1455 int runTrail = run.x + run.width; 1477 int runTrail = run.x + run.width;
1456 if (run.start <= start && start < runEnd) { 1478 if (run.UTF8start <= start && start < runEnd) {
1457 int cx = 0; 1479 int cx = 0;
1458 if (run.style !is null && run.style.metrics !is null) { 1480 if (run.style !is null && run.style.metrics !is null) {
1459 GlyphMetrics metrics = run.style.metrics; 1481 GlyphMetrics metrics = run.style.metrics;
1460 cx = metrics.width * (index8to16[start] - index8to16[run.start]); 1482 cx = metrics.width * (getUTF16index(start) - getUTF16index(run.UTF8start));
1461 } else if (!run.tab) { 1483 } else if (!run.tab) {
1484 UTF16index iCP = getUTF16index(start) - getUTF16index(run.UTF8start);
1485 UTF16shift cChars = getUTF16length(run);
1462 int piX; 1486 int piX;
1463 int* advances = run.justify !is null ? run.justify : run.advances; 1487 int* advances = run.justify !is null ? run.justify : run.advances;
1464 int wlength = index8to16[ run.start+run.length] - index8to16[run.start]; 1488 OS.ScriptCPtoX(iCP, false, cChars, run.glyphCount, run.clusters, run.visAttrs, advances, &run.analysis, &piX);
1465 OS.ScriptCPtoX(index8to16[start] - index8to16[run.start], false, wlength, run.glyphCount, run.clusters, run.visAttrs, advances, &run.analysis, &piX);
1466 cx = isRTL ? run.width - piX : piX; 1489 cx = isRTL ? run.width - piX : piX;
1467 } 1490 }
1468 if (run.analysis.fRTL ^ isRTL) { 1491 if (run.analysis.fRTL ^ isRTL) {
1469 runTrail = run.x + cx; 1492 runTrail = run.x + cx;
1470 } else { 1493 } else {
1471 runLead = run.x + cx; 1494 runLead = run.x + cx;
1472 } 1495 }
1473 } 1496 }
1474 if (run.start <= end && end < runEnd) { 1497 if (run.UTF8start <= end && end < runEnd) {
1475 int cx = run.width; 1498 int cx = run.width;
1476 if (run.style !is null && run.style.metrics !is null) { 1499 if (run.style !is null && run.style.metrics !is null) {
1477 GlyphMetrics metrics = run.style.metrics; 1500 GlyphMetrics metrics = run.style.metrics;
1478 cx = metrics.width * (index8to16[end] - index8to16[run.start] + 1); 1501 cx = metrics.width * (getUTF16index(end) - getUTF16index(run.UTF8start) + 1);
1479 } else if (!run.tab) { 1502 } else if (!run.tab) {
1503 UTF16index iCP = getUTF16index(end) - getUTF16index(run.UTF8start);
1504 UTF16shift cChars = getUTF16length(run);
1480 int piX; 1505 int piX;
1481 int* advances = run.justify !is null ? run.justify : run.advances; 1506 int* advances = run.justify !is null ? run.justify : run.advances;
1482 int wlength = index8to16[ run.start+run.length] - index8to16[run.start]; 1507 OS.ScriptCPtoX(iCP, true, cChars, run.glyphCount, run.clusters, run.visAttrs, advances, &run.analysis, &piX);
1483 OS.ScriptCPtoX(index8to16[end] - index8to16[run.start], true, wlength, run.glyphCount, run.clusters, run.visAttrs, advances, &run.analysis, &piX);
1484 cx = isRTL ? run.width - piX : piX; 1508 cx = isRTL ? run.width - piX : piX;
1485 } 1509 }
1486 if (run.analysis.fRTL ^ isRTL) { 1510 if (run.analysis.fRTL ^ isRTL) {
1487 runLead = run.x + cx; 1511 runLead = run.x + cx;
1488 } else { 1512 } else {
1489 runTrail = run.x + cx; 1513 runTrail = run.x + cx;
1490 } 1514 }
1491 } 1515 }
1492 int lineIndex = 0; 1516 int lineIndex = 0;
1493 while (lineIndex < runs.length && lineOffset[lineIndex + 1] <= run.start) { 1517 while (lineIndex < runs.length && lineOffset[lineIndex + 1] <= run.UTF8start) {
1494 lineIndex++; 1518 lineIndex++;
1495 } 1519 }
1496 left = Math.min(left, runLead); 1520 left = Math.min(left, runLead);
1497 right = Math.max(right, runTrail); 1521 right = Math.max(right, runTrail);
1498 top = Math.min(top, lineY[lineIndex]); 1522 top = Math.min(top, lineY[lineIndex]);
1590 * <li>ERROR_INVALID_ARGUMENT - if the character offset is out of range</li> 1614 * <li>ERROR_INVALID_ARGUMENT - if the character offset is out of range</li>
1591 * </ul> 1615 * </ul>
1592 * @exception SWTException <ul> 1616 * @exception SWTException <ul>
1593 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 1617 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
1594 */ 1618 */
1595 public int getLevel (int offset) { 1619 public int getLevel (int i_offset) {
1596 checkLayout(); 1620 checkLayout();
1597 computeRuns(null); 1621 computeRuns(null);
1622 UTF8index offset = text.takeIndexArg(i_offset, "offset@getLevel");
1598 int length = text.length; 1623 int length = text.length;
1599 if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); 1624 if (!(0 <= offset.internalValue && offset.internalValue <= length)) SWT.error(SWT.ERROR_INVALID_RANGE);
1600 offset = translateOffset(offset); 1625 offset = translateOffset(offset);
1601 for (int i=1; i<allRuns.length; i++) { 1626 for (int i=1; i<allRuns.length; i++) {
1602 if (allRuns[i].start > offset) { 1627 if (allRuns[i].UTF8start > offset) {
1603 return allRuns[i - 1].analysis.s.uBidiLevel; 1628 return allRuns[i - 1].analysis.s.uBidiLevel;
1604 } 1629 }
1605 } 1630 }
1606 return (orientation & SWT.RIGHT_TO_LEFT) !is 0 ? 1 : 0; 1631 return (orientation & SWT.RIGHT_TO_LEFT) !is 0 ? 1 : 0;
1607 } 1632 }
1689 * </ul> 1714 * </ul>
1690 * @exception SWTException <ul> 1715 * @exception SWTException <ul>
1691 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 1716 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
1692 * </ul> 1717 * </ul>
1693 */ 1718 */
1694 public int getLineIndex (int offset) { 1719 public int getLineIndex (int i_offset) {
1695 checkLayout(); 1720 checkLayout();
1696 computeRuns(null); 1721 computeRuns(null);
1722 UTF8index offset = text.takeIndexArg(i_offset, "offset@getLineIndex");
1697 int length = text.length; 1723 int length = text.length;
1698 if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); 1724 if (!(0 <= offset.internalValue && offset.internalValue <= length)) SWT.error(SWT.ERROR_INVALID_RANGE);
1699 offset = translateOffset(offset); 1725 offset = translateOffset(offset);
1700 for (int line=0; line<runs.length; line++) { 1726 for (int line=0; line<runs.length; line++) {
1701 if (lineOffset[line + 1] > offset) { 1727 if (lineOffset[line + 1] > offset) {
1702 return line; 1728 return line;
1703 } 1729 }
1787 * </ul> 1813 * </ul>
1788 * 1814 *
1789 * @see #getOffset(Point, int[]) 1815 * @see #getOffset(Point, int[])
1790 * @see #getOffset(int, int, int[]) 1816 * @see #getOffset(int, int, int[])
1791 */ 1817 */
1792 public Point getLocation (int offset, bool trailing) { 1818 public Point getLocation (int i_offset, bool trailing) {
1793 checkLayout(); 1819 checkLayout();
1794 computeRuns(null); 1820 computeRuns(null);
1795 int length = text.length; 1821 UTF8index offset = text.takeIndexArg(i_offset, "offset@getLocation");
1796 if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); 1822 UTF8index length = text.endIndex();
1797 length = segmentsText.length; 1823 if (!(0 <= offset.internalValue && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE);
1824 length = segmentsText.endIndex();
1798 offset = translateOffset(offset); 1825 offset = translateOffset(offset);
1799 int line; 1826 int line;
1800 for (line=0; line<runs.length; line++) { 1827 for (line=0; line<runs.length; line++) {
1801 if (lineOffset[line + 1] > offset) break; 1828 if (lineOffset[line + 1] > offset) break;
1802 } 1829 }
1807 int low = -1; 1834 int low = -1;
1808 int high = allRuns.length; 1835 int high = allRuns.length;
1809 while (high - low > 1) { 1836 while (high - low > 1) {
1810 int index = ((high + low) / 2); 1837 int index = ((high + low) / 2);
1811 StyleItem run = allRuns[index]; 1838 StyleItem run = allRuns[index];
1812 if (run.start > offset) { 1839 if (run.UTF8start > offset) {
1813 high = index; 1840 high = index;
1814 } else if (run.start + run.length <= offset) { 1841 } else if (run.UTF8start + run.UTF8length <= offset) {
1815 low = index; 1842 low = index;
1816 } else { 1843 } else {
1817 int width; 1844 int width;
1818 if (run.style !is null && run.style.metrics !is null) { 1845 if (run.style !is null && run.style.metrics !is null) {
1819 GlyphMetrics metrics = run.style.metrics; 1846 GlyphMetrics metrics = run.style.metrics;
1820 width = metrics.width * (offset - run.start + (trailing ? 1 : 0)); 1847 width = metrics.width * (getUTF16index(offset) - getUTF16index(run.UTF8start) + trailing);
1821 } else if (run.tab) { 1848 } else if (run.tab) {
1822 width = (trailing || (offset is length)) ? run.width : 0; 1849 width = (trailing || (offset is length)) ? run.width : 0;
1823 } else { 1850 } else {
1824 int runOffset = index8to16[offset] - index8to16[run.start]; 1851 UTF16index runOffset = getUTF16index(offset) - getUTF16index(run.UTF8start);
1825 int cChars = index8to16[run.start+run.length] - index8to16[run.start]; // make it wchar 1852 UTF16shift cChars = getUTF16length(run); // make it wchar
1826 int gGlyphs = run.glyphCount; 1853 int gGlyphs = run.glyphCount;
1827 int piX; 1854 int piX;
1828 int* advances = run.justify !is null ? run.justify : run.advances; 1855 int* advances = run.justify !is null ? run.justify : run.advances;
1829 OS.ScriptCPtoX(runOffset, trailing, cChars, gGlyphs, run.clusters, run.visAttrs, advances, &run.analysis, &piX); 1856 OS.ScriptCPtoX(runOffset, trailing, cChars, gGlyphs, run.clusters, run.visAttrs, advances, &run.analysis, &piX);
1830 width = (orientation & SWT.RIGHT_TO_LEFT) !is 0 ? run.width - piX : piX; 1857 width = (orientation & SWT.RIGHT_TO_LEFT) !is 0 ? run.width - piX : piX;
1852 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 1879 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
1853 * </ul> 1880 * </ul>
1854 * 1881 *
1855 * @see #getPreviousOffset(int, int) 1882 * @see #getPreviousOffset(int, int)
1856 */ 1883 */
1857 public int getNextOffset (int offset, int movement) { 1884 public int getNextOffset (int i_offset, int movement) {
1858 checkLayout(); 1885 checkLayout();
1859 return _getOffset (offset, movement, true); 1886 return _getOffset (i_offset, movement, true);
1860 } 1887 }
1861 1888
1862 int _getOffset(int offset, int movement, bool forward) { 1889 int _getOffset(int i_offset, int movement, bool forward) {
1863 computeRuns(null); 1890 computeRuns(null);
1864 int length = text.length; 1891 UTF8index offset = text.takeIndexArg(i_offset, "offset@_getOffset");
1865 if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); 1892 UTF8index length = text.endIndex();
1866 if (forward && offset is length) return length; 1893 if (!(0 <= offset.internalValue && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE);
1867 if (!forward && offset is 0) return 0; 1894 if (forward && offset is length) return length.internalValue;
1895 if (!forward && offset.internalValue is 0) return 0;
1868 int step = forward ? 1 : -1; 1896 int step = forward ? 1 : -1;
1869 if ((movement & SWT.MOVEMENT_CHAR) !is 0) return offset + step; 1897 if ((movement & SWT.MOVEMENT_CHAR) !is 0) return (offset + text.toUTF8shift(offset, step)).internalValue;
1870 length = segmentsText.length; 1898 length = segmentsText.endIndex();
1871 offset = translateOffset(offset); 1899 offset = translateOffset(offset);
1872 SCRIPT_LOGATTR* logAttr; 1900 SCRIPT_LOGATTR* logAttr;
1873 SCRIPT_PROPERTIES* properties; 1901 SCRIPT_PROPERTIES* properties;
1874 int i = forward ? 0 : allRuns.length - 1; 1902 int i = forward ? 0 : allRuns.length - 1;
1875 offset = validadeOffset(offset, step); 1903 offset = validadeOffset(offset, step);
1876 do { 1904 do {
1877 StyleItem run = allRuns[i]; 1905 StyleItem run = allRuns[i];
1878 if (run.start <= offset && offset < run.start + run.length) { 1906 if (run.UTF8start <= offset && offset < run.UTF8start + run.UTF8length) {
1879 if (run.lineBreak && !run.softBreak) return untranslateOffset(run.start); 1907 if (run.lineBreak && !run.softBreak) return untranslateOffset(run.UTF8start);
1880 if (run.tab) return untranslateOffset(run.start); 1908 if (run.tab) return untranslateOffset(run.UTF8start);
1881 properties = device.scripts[run.analysis.eScript]; 1909 properties = device.scripts[run.analysis.eScript];
1882 bool isComplex = properties.fNeedsCaretInfo || properties.fNeedsWordBreaking; 1910 bool isComplex = properties.fNeedsCaretInfo || properties.fNeedsWordBreaking;
1883 if (isComplex) breakRun(run); 1911 if (isComplex) breakRun(run);
1884 while (run.start <= offset && offset < run.start + run.length) { 1912 while (run.UTF8start <= offset && offset < run.UTF8start + run.UTF8length) {
1885 if (isComplex) { 1913 if (isComplex) {
1886 logAttr = run.psla + (index8to16[offset] - index8to16[run.start]); 1914 logAttr = run.psla + (getUTF16index(offset) - getUTF16index(run.UTF8start));
1887 } 1915 }
1888 switch (movement) { 1916 switch (movement) {
1889 case SWT.MOVEMENT_CLUSTER: { 1917 case SWT.MOVEMENT_CLUSTER: {
1890 if (properties.fNeedsCaretInfo) { 1918 if (properties.fNeedsCaretInfo) {
1891 if (!logAttr.fInvalid && logAttr.fCharStop) return untranslateOffset(offset); 1919 if (!logAttr.fInvalid && logAttr.fCharStop) return untranslateOffset(offset);
1897 case SWT.MOVEMENT_WORD_START: 1925 case SWT.MOVEMENT_WORD_START:
1898 case SWT.MOVEMENT_WORD: { 1926 case SWT.MOVEMENT_WORD: {
1899 if (properties.fNeedsWordBreaking) { 1927 if (properties.fNeedsWordBreaking) {
1900 if (!logAttr.fInvalid && logAttr.fWordStop) return untranslateOffset(offset); 1928 if (!logAttr.fInvalid && logAttr.fWordStop) return untranslateOffset(offset);
1901 } else { 1929 } else {
1902 if (offset > 0) { 1930 if (offset.internalValue > 0) {
1903 bool letterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset)); 1931 bool letterOrDigit = Compatibility.isLetterOrDigit(segmentsText.dcharAt(offset));
1904 bool previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset - 1)); 1932 bool previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.dcharBefore(offset));
1905 if (letterOrDigit !is previousLetterOrDigit || !letterOrDigit) { 1933 if (letterOrDigit !is previousLetterOrDigit || !letterOrDigit) {
1906 if (!Compatibility.isWhitespace(segmentsText[offset..$].firstCodePoint())) { 1934 if (!Compatibility.isWhitespace(segmentsText.dcharAt(offset))) {
1907 return untranslateOffset(offset); 1935 return untranslateOffset(offset);
1908 } 1936 }
1909 } 1937 }
1910 } 1938 }
1911 } 1939 }
1912 break; 1940 break;
1913 } 1941 }
1914 case SWT.MOVEMENT_WORD_END: { 1942 case SWT.MOVEMENT_WORD_END: {
1915 if (offset > 0) { 1943 if (offset.internalValue > 0) {
1916 bool isLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset)); 1944 bool isLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.dcharAt(offset));
1917 bool previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText[offset - 1.. $].firstCodePoint()); 1945 bool previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.dcharBefore(offset));
1918 if (!isLetterOrDigit && previousLetterOrDigit) { 1946 if (!isLetterOrDigit && previousLetterOrDigit) {
1919 return untranslateOffset(offset); 1947 return untranslateOffset(offset);
1920 } 1948 }
1921 } 1949 }
1922 break; 1950 break;
1925 } 1953 }
1926 offset = validadeOffset(offset, step); 1954 offset = validadeOffset(offset, step);
1927 } 1955 }
1928 } 1956 }
1929 i += step; 1957 i += step;
1930 } while (0 <= i && i < allRuns.length - 1 && 0 <= offset && offset < length); 1958 } while (0 <= i && i < allRuns.length - 1 && 0 <= offset.internalValue && offset < length);
1931 return forward ? text.length : 0; 1959 return forward ? text.length : 0;
1932 } 1960 }
1933 1961
1934 /** 1962 /**
1935 * Returns the character offset for the specified point. 1963 * Returns the character offset for the specified point.
2006 if (run.x > x) { 2034 if (run.x > x) {
2007 high = index; 2035 high = index;
2008 } else if (run.x + run.width <= x) { 2036 } else if (run.x + run.width <= x) {
2009 low = index; 2037 low = index;
2010 } else { 2038 } else {
2011 if (run.lineBreak && !run.softBreak) return untranslateOffset(run.start); 2039 if (run.lineBreak && !run.softBreak) return untranslateOffset(run.UTF8start);
2012 int xRun = x - run.x; 2040 int xRun = x - run.x;
2013 if (run.style !is null && run.style.metrics !is null) { 2041 if (run.style !is null && run.style.metrics !is null) {
2014 GlyphMetrics metrics = run.style.metrics; 2042 GlyphMetrics metrics = run.style.metrics;
2015 if (metrics.width > 0) { 2043 if (metrics.width > 0) {
2044 UTF8index res = addUTF16shift(run.UTF8start, cast(UTF16shift)(xRun / metrics.width));
2016 if (trailing !is null) { 2045 if (trailing !is null) {
2017 trailing[0] = (xRun % metrics.width < metrics.width / 2) ? 0 : 1; 2046 trailing[0] = (xRun % metrics.width < metrics.width / 2) ? 0 : segmentsText.UTF8strideAt(res).internalValue;
2018 } 2047 }
2019 return untranslateOffset(run.start + xRun / metrics.width); 2048 return untranslateOffset(res);
2020 } 2049 }
2021 } 2050 }
2022 if (run.tab) { 2051 if (run.tab) {
2023 if (trailing !is null) trailing[0] = x < (run.x + run.width / 2) ? 0 : 1; 2052 UTF8index res = run.UTF8start;
2024 return untranslateOffset(run.start); 2053 if (trailing !is null) trailing[0] = x < (run.x + run.width / 2) ? 0 : segmentsText.UTF8strideAt(res).internalValue;
2025 } 2054 return untranslateOffset(res);
2026 int cChars = index8to16[run.start+run.length] - index8to16[run.start]; // make it wchar 2055 }
2056 UTF16shift cChars = getUTF16length(run); // make it wchar
2027 int cGlyphs = run.glyphCount; 2057 int cGlyphs = run.glyphCount;
2028 int piCP; 2058 UTF16shift piCP;
2029 int piTrailing; 2059 UTF16shift piTrailing;
2030 if ((orientation & SWT.RIGHT_TO_LEFT) !is 0) { 2060 if ((orientation & SWT.RIGHT_TO_LEFT) !is 0) {
2031 xRun = run.width - xRun; 2061 xRun = run.width - xRun;
2032 } 2062 }
2033 int* advances = run.justify !is null ? run.justify : run.advances; 2063 int* advances = run.justify !is null ? run.justify : run.advances;
2034 OS.ScriptXtoCP(xRun, cChars, cGlyphs, run.clusters, run.visAttrs, advances, &run.analysis, &piCP, &piTrailing); 2064 OS.ScriptXtoCP(xRun, cChars, cGlyphs, run.clusters, run.visAttrs, advances, &run.analysis, &piCP, &piTrailing);
2035 if (trailing !is null) trailing[0] = piTrailing; 2065
2036 2066 // DWT: back from UTF-16 to UTF-8
2037 // SWT: back from codepoints to utf8 index 2067 UTF8index res = addUTF16shift(run.UTF8start, piCP);
2038 int offsetIndex = segmentsText[ run.start .. $ ].codepointIndexToIndex( piCP ); 2068 if (trailing !is null)
2039 return untranslateOffset(run.start + offsetIndex); 2069 trailing[0] = (addUTF16shift(res, piTrailing) - res).internalValue;
2070 return untranslateOffset(res);
2040 } 2071 }
2041 } 2072 }
2042 if (trailing !is null) trailing[0] = 0; 2073 if (trailing !is null) trailing[0] = 0;
2043 return untranslateOffset(lineOffset[line + 1]); 2074 return untranslateOffset(lineOffset[line + 1]);
2044 } 2075 }
2074 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 2105 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2075 * </ul> 2106 * </ul>
2076 * 2107 *
2077 * @see #getNextOffset(int, int) 2108 * @see #getNextOffset(int, int)
2078 */ 2109 */
2079 public int getPreviousOffset (int offset, int movement) { 2110 public int getPreviousOffset (int i_offset, int movement) {
2080 checkLayout(); 2111 checkLayout();
2081 return _getOffset (offset, movement, false); 2112 return _getOffset (i_offset, movement, false);
2082 } 2113 }
2083 2114
2084 /** 2115 /**
2085 * Gets the ranges of text that are associated with a <code>TextStyle</code>. 2116 * Gets the ranges of text that are associated with a <code>TextStyle</code>.
2086 * 2117 *
2099 checkLayout(); 2130 checkLayout();
2100 int[] result = new int[stylesCount * 2]; 2131 int[] result = new int[stylesCount * 2];
2101 int count = 0; 2132 int count = 0;
2102 for (int i=0; i<stylesCount - 1; i++) { 2133 for (int i=0; i<stylesCount - 1; i++) {
2103 if (styles[i].style !is null) { 2134 if (styles[i].style !is null) {
2104 result[count++] = styles[i].start; 2135 result[count++] = styles[i].UTF8start.internalValue;
2105 result[count++] = styles[i + 1].start - 1; 2136 result[count++] = getUTF8index(cast(UTF16index)(getUTF16index(styles[i + 1].UTF8start) - 1)).internalValue;
2106 } 2137 }
2107 } 2138 }
2108 if (count !is result.length) { 2139 if (count !is result.length) {
2109 int[] newResult = new int[count]; 2140 int[] newResult = new int[count];
2110 System.arraycopy(result, 0, newResult, 0, count); 2141 System.arraycopy(result, 0, newResult, 0, count);
2122 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 2153 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2123 * </ul> 2154 * </ul>
2124 */ 2155 */
2125 public int[] getSegments () { 2156 public int[] getSegments () {
2126 checkLayout(); 2157 checkLayout();
2127 return segments; 2158 return cast(int[])segments;
2128 } 2159 }
2129 2160
2130 void getSegmentsText( out String resUtf8, out String16 resUtf16 ) { 2161 void getSegmentsText( out String resUtf8, out String16 resUtf16 ) {
2131 2162
2132 void buildIndexTables() { // build the index translation tables. 2163 void buildIndexTables() { // build the index translation tables.
2164 index16to8.length = resUtf16.length + 1;
2133 index8to16.length = resUtf8.length + 1; 2165 index8to16.length = resUtf8.length + 1;
2134 index16to8.length = resUtf16.length + 1; 2166 index16to8[] = resUtf8.preFirstIndex();
2135 2167 index8to16[] = -1;
2136 int idx8, idx16; 2168
2137 while( idx8 < resUtf8.length ){ 2169 UTF8index idx8;
2138 int ate8, ate16; 2170 UTF16index idx16;
2139 dchar d8 = resUtf8[ idx8 .. $ ].firstCodePoint( ate8 ); 2171 for(;;) {
2140 dchar d16 = resUtf16[ idx16 .. $ ].firstCodePoint( ate16 ); 2172 index16to8[ idx16 ] = idx8;
2141 assert( d8 is d16 ); 2173 index8to16[ idx8.internalValue ] = idx16;
2142 index16to8[ idx16 .. idx16 +ate16 ] = idx8; 2174 if(idx8 == resUtf8.endIndex()) {
2143 index8to16[ idx8 .. idx8 +ate8 ] = idx16; 2175 assert(idx16 == resUtf16.length);
2144 idx8 += ate8; 2176 break;
2145 idx16 += ate16; 2177 }
2146 } 2178 assert(resUtf8.dcharAt(idx8) == resUtf16.dcharAt(idx16));
2147 index16to8[ resUtf16.length ] = resUtf8.length; 2179 idx8 += resUtf8.UTF8strideAt(idx8);
2148 index8to16[ resUtf8.length ] = resUtf16.length; 2180 idx16 += resUtf16.UTF16strideAt(idx16);
2181 }
2149 } 2182 }
2150 2183
2151 if (segments is null) { 2184 if (segments is null) {
2152 resUtf8 = text; 2185 resUtf8 = text;
2153 resUtf16 = wtext; 2186 resUtf16 = wtext;
2168 resUtf16 = wtext; 2201 resUtf16 = wtext;
2169 buildIndexTables(); 2202 buildIndexTables();
2170 return; 2203 return;
2171 } 2204 }
2172 if (nSegments is 2) { 2205 if (nSegments is 2) {
2173 if (segments[0] is 0 && segments[1] is length_) { 2206 if (segments[0].internalValue is 0 && segments[1].internalValue is length_) {
2174 resUtf8 = text; 2207 resUtf8 = text;
2175 resUtf16 = wtext; 2208 resUtf16 = wtext;
2176 buildIndexTables(); 2209 buildIndexTables();
2177 return; 2210 return;
2178 } 2211 }
2179 } 2212 }
2180 { 2213 {
2181 auto oldChars = text; 2214 auto oldChars = text;
2182 // SWT: MARK is now 3 chars long 2215 // DWT: MARK is now 3 chars long
2183 String separator = orientation is SWT.RIGHT_TO_LEFT ? STR_RTL_MARK : STR_LTR_MARK; 2216 String separator = orientation is SWT.RIGHT_TO_LEFT ? STR_RTL_MARK : STR_LTR_MARK;
2184 assert( separator.length is MARK_SIZE ); 2217 char[] newChars = new char[length_ + nSegments*MARK_SIZE.internalValue];
2185 char[] newChars = new char[length_ + nSegments*MARK_SIZE];
2186 2218
2187 int charCount = 0, segmentCount = 0; 2219 int charCount = 0, segmentCount = 0;
2188 while (charCount < length_) { 2220 while (charCount < length_) {
2189 if (segmentCount < nSegments && charCount is segments[segmentCount]) { 2221 if (segmentCount < nSegments && charCount is segments[segmentCount].internalValue) {
2190 int start = charCount + (segmentCount*MARK_SIZE); 2222 int start = charCount + (segmentCount*MARK_SIZE.internalValue);
2191 newChars[ start .. start + MARK_SIZE ] = separator; 2223 newChars[ start .. start + MARK_SIZE.internalValue ] = separator;
2192 segmentCount++; 2224 segmentCount++;
2193 } else { 2225 } else {
2194 newChars[charCount + (segmentCount*MARK_SIZE)] = oldChars[charCount]; 2226 newChars[charCount + (segmentCount*MARK_SIZE.internalValue)] = oldChars[charCount];
2195 charCount++; 2227 charCount++;
2196 } 2228 }
2197 } 2229 }
2198 if (segmentCount < nSegments) { 2230 if (segmentCount < nSegments) {
2199 segments[segmentCount] = charCount; 2231 segments[segmentCount] = asUTF8index( charCount );
2200 int start = charCount + (segmentCount*MARK_SIZE); 2232 int start = charCount + (segmentCount*MARK_SIZE.internalValue);
2201 newChars[ start .. start + MARK_SIZE ] = separator; 2233 newChars[ start .. start + MARK_SIZE.internalValue ] = separator;
2202 segmentCount++; 2234 segmentCount++;
2203 } 2235 }
2204 resUtf8 = cast(String)newChars[ 0 .. Math.min(charCount + (segmentCount*MARK_SIZE), newChars.length)]; 2236 resUtf8 = cast(String)newChars[ 0 .. Math.min(charCount + (segmentCount*MARK_SIZE.internalValue), newChars.length)];
2205 } 2237 }
2206 // now for the wide chars 2238 // now for the wide chars
2207 { 2239 {
2208 String16 oldWChars = wtext; 2240 String16 oldWChars = wtext;
2209 auto wseparator = orientation is SWT.RIGHT_TO_LEFT ? WSTR_RTL_MARK : WSTR_LTR_MARK; 2241 auto wseparator = orientation is SWT.RIGHT_TO_LEFT ? WSTR_RTL_MARK : WSTR_LTR_MARK;
2220 newWChars[charCount + (segmentCount*WMARK_SIZE)] = oldWChars[charCount]; 2252 newWChars[charCount + (segmentCount*WMARK_SIZE)] = oldWChars[charCount];
2221 charCount++; 2253 charCount++;
2222 } 2254 }
2223 } 2255 }
2224 if (segmentCount < nSegments) { 2256 if (segmentCount < nSegments) {
2225 wsegments[segmentCount] = charCount; 2257 wsegments[segmentCount] = cast(UTF16index) charCount;
2226 int start = charCount + (segmentCount*WMARK_SIZE); 2258 int start = charCount + (segmentCount*WMARK_SIZE);
2227 newWChars[ start .. start + WMARK_SIZE ] = wseparator; 2259 newWChars[ start .. start + WMARK_SIZE ] = wseparator;
2228 segmentCount++; 2260 segmentCount++;
2229 } 2261 }
2230 resUtf16 = cast(String16)newWChars[ 0 .. Math.min(charCount + (segmentCount*WMARK_SIZE), newWChars.length)]; 2262 resUtf16 = cast(String16)newWChars[ 0 .. Math.min(charCount + (segmentCount*WMARK_SIZE), newWChars.length)];
2257 * </ul> 2289 * </ul>
2258 * @exception SWTException <ul> 2290 * @exception SWTException <ul>
2259 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 2291 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2260 * </ul> 2292 * </ul>
2261 */ 2293 */
2262 public TextStyle getStyle (int offset) { 2294 public TextStyle getStyle (int i_offset) {
2263 checkLayout(); 2295 checkLayout();
2296 UTF8index offset = text.takeIndexArg(i_offset, "offset@getStyle");
2264 int length = text.length; 2297 int length = text.length;
2265 if (!(0 <= offset && offset < length)) SWT.error(SWT.ERROR_INVALID_RANGE); 2298 if (!(0 <= offset.internalValue && offset.internalValue < length)) SWT.error(SWT.ERROR_INVALID_RANGE);
2266 for (int i=1; i<stylesCount; i++) { 2299 for (int i=1; i<stylesCount; i++) {
2267 if (styles[i].start > offset) { 2300 if (styles[i].UTF8start > offset) {
2268 return styles[i - 1].style; 2301 return styles[i - 1].style;
2269 } 2302 }
2270 } 2303 }
2271 return null; 2304 return null;
2272 } 2305 }
2361 2394
2362 /* 2395 /*
2363 * Itemize the receiver text 2396 * Itemize the receiver text
2364 */ 2397 */
2365 StyleItem[] itemize () { 2398 StyleItem[] itemize () {
2366 // SWT: itemize is the process of finding changes in direction 2399 // DWT: itemize is the process of finding changes in direction
2367 getSegmentsText(segmentsText, segmentsWText ); 2400 getSegmentsText(segmentsText, segmentsWText );
2368 int length = segmentsText.length; 2401 int length = segmentsText.length;
2369 SCRIPT_CONTROL scriptControl; 2402 SCRIPT_CONTROL scriptControl;
2370 SCRIPT_STATE scriptState; 2403 SCRIPT_STATE scriptState;
2371 int MAX_ITEM = length + 1; 2404 int MAX_ITEM = length + 1;
2377 OS.ScriptRecordDigitSubstitution(OS.LOCALE_USER_DEFAULT, &psds); 2410 OS.ScriptRecordDigitSubstitution(OS.LOCALE_USER_DEFAULT, &psds);
2378 OS.ScriptApplyDigitSubstitution(&psds, &scriptControl, &scriptState); 2411 OS.ScriptApplyDigitSubstitution(&psds, &scriptControl, &scriptState);
2379 } 2412 }
2380 2413
2381 auto hHeap = OS.GetProcessHeap(); 2414 auto hHeap = OS.GetProcessHeap();
2382 auto pItems = cast(SCRIPT_ITEM*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, MAX_ITEM * SCRIPT_ITEM.sizeof); 2415 auto pItems = cast(SCRIPT_ITEM*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, MAX_ITEM * SCRIPT_ITEM.sizeof + 1);
2383 if (pItems is null) SWT.error(SWT.ERROR_NO_HANDLES); 2416 if (pItems is null) SWT.error(SWT.ERROR_NO_HANDLES);
2384 int pcItems; 2417 int pcItems;
2385 String16 chars = segmentsWText; 2418 String16 wchars = segmentsWText;
2386 OS.ScriptItemize(chars.ptr, chars.length, MAX_ITEM, &scriptControl, &scriptState, pItems, &pcItems); 2419 OS.ScriptItemize(wchars.ptr, wchars.length, MAX_ITEM, &scriptControl, &scriptState, pItems, &pcItems);
2387 // if (hr is E_OUTOFMEMORY) //TODO handle it 2420 // if (hr is E_OUTOFMEMORY) //TODO handle it
2388 // SWT pcItems is not inclusive the trailing item 2421 // SWT pcItems is not inclusive the trailing item
2389 2422
2390 StyleItem[] runs = merge(pItems, pcItems); 2423 StyleItem[] runs = merge(pItems, pcItems);
2391 OS.HeapFree(hHeap, 0, pItems); 2424 OS.HeapFree(hHeap, 0, pItems);
2399 if (styles.length > stylesCount) { 2432 if (styles.length > stylesCount) {
2400 StyleItem[] newStyles = new StyleItem[stylesCount]; 2433 StyleItem[] newStyles = new StyleItem[stylesCount];
2401 System.arraycopy(styles, 0, newStyles, 0, stylesCount); 2434 System.arraycopy(styles, 0, newStyles, 0, stylesCount);
2402 styles = newStyles; 2435 styles = newStyles;
2403 } 2436 }
2404 int count = 0, start = 0, end = segmentsText.length, itemIndex = 0, styleIndex = 0; 2437 int count = 0, itemIndex = 0, styleIndex = 0;
2438 UTF8index start = segmentsText.firstIndex(), end = segmentsText.endIndex();
2405 StyleItem[] runs = new StyleItem[itemCount + stylesCount]; 2439 StyleItem[] runs = new StyleItem[itemCount + stylesCount];
2406 SCRIPT_ITEM* scriptItem; 2440 SCRIPT_ITEM* scriptItem;
2407 bool linkBefore = false; 2441 bool linkBefore = false;
2408 while (start < end) { 2442 while (start < end) {
2409 StyleItem item = new StyleItem(); 2443 StyleItem item = new StyleItem();
2410 item.start = start; 2444 item.UTF8start = start;
2411 item.style = styles[styleIndex].style; 2445 item.style = styles[styleIndex].style;
2412 runs[count++] = item; 2446 runs[count++] = item;
2413 scriptItem = items + itemIndex; 2447 scriptItem = items + itemIndex;
2414 item.analysis = scriptItem.a; 2448 item.analysis = scriptItem.a;
2415 if (linkBefore) { 2449 if (linkBefore) {
2416 item.analysis.fLinkBefore = true; 2450 item.analysis.fLinkBefore = true;
2417 linkBefore = false; 2451 linkBefore = false;
2418 } 2452 }
2419 //scriptItem.a = new SCRIPT_ANALYSIS(); 2453 //scriptItem.a = new SCRIPT_ANALYSIS();
2420 scriptItem = items + (itemIndex + 1); 2454 scriptItem = items + (itemIndex + 1);
2421 int itemLimit = index16to8[scriptItem.iCharPos]; 2455 UTF8index itemLimit = getUTF8index(scriptItem.iCharPos);
2422 int styleLimit = translateOffset(styles[styleIndex + 1].start); 2456 UTF8index styleLimit = translateOffset(styles[styleIndex + 1].UTF8start);
2423 if (styleLimit <= itemLimit) { 2457 if (styleLimit <= itemLimit) {
2424 styleIndex++; 2458 styleIndex++;
2425 start = styleLimit; 2459 start = styleLimit;
2426 if (start < itemLimit && 0 < start && start < end) { 2460 if (start < itemLimit && 0 < start.internalValue && start < end) {
2427 dchar pChar = segmentsText[ segmentsText.getAbsoluteCodePointOffset(start, -1) ..$].firstCodePoint(); 2461 dchar pChar = segmentsText.dcharBefore(start);
2428 dchar tChar = segmentsText[start ..$].firstCodePoint(); 2462 dchar tChar = segmentsText.dcharAt(start);
2429 if (Compatibility.isLetter(pChar) && Compatibility.isLetter(tChar)) { 2463 if (Compatibility.isLetter(pChar) && Compatibility.isLetter(tChar)) {
2430 item.analysis.fLinkAfter = true; 2464 item.analysis.fLinkAfter = true;
2431 linkBefore = true; 2465 linkBefore = true;
2432 } 2466 }
2433 } 2467 }
2434 } 2468 }
2435 if (itemLimit <= styleLimit) { 2469 if (itemLimit <= styleLimit) {
2436 itemIndex++; 2470 itemIndex++;
2437 start = itemLimit; 2471 start = itemLimit;
2438 } 2472 }
2439 item.length = start - item.start; 2473 item.UTF8length = start - item.UTF8start;
2440 } 2474 }
2441 StyleItem item = new StyleItem(); 2475 StyleItem item = new StyleItem();
2442 item.start = end; 2476 item.UTF8start = end;
2443 scriptItem = items + itemCount; 2477 scriptItem = items + itemCount;
2444 item.analysis = scriptItem.a; 2478 item.analysis = scriptItem.a;
2445 runs[count++] = item; 2479 runs[count++] = item;
2446 if (runs.length !is count) { 2480 if (runs.length !is count) {
2447 StyleItem[] result = new StyleItem[count]; 2481 StyleItem[] result = new StyleItem[count];
2672 * 2706 *
2673 * @exception SWTException <ul> 2707 * @exception SWTException <ul>
2674 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 2708 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2675 * </ul> 2709 * </ul>
2676 */ 2710 */
2677 public void setSegments(int[] segments) { 2711 public void setSegments(int[] i_segments) {
2678 checkLayout(); 2712 checkLayout();
2679 if (this.segments is null && segments is null) return; 2713 if (this.segments is null && i_segments is null) return;
2680 if (this.segments !is null && segments !is null) { 2714 if (this.segments !is null && i_segments !is null)
2681 if (this.segments.length is segments.length) { 2715 if (this.segments.length is i_segments.length) {
2682 int i; 2716 int i;
2683 for (i = 0; i <segments.length; i++) { 2717 for (i = 0; i <i_segments.length; i++) {
2684 if (this.segments[i] !is segments[i]) break; 2718 if (this.segments[i] !is text.takeIndexArg(i_segments[i], "segments@setSegments")) break;
2685 } 2719 }
2686 if (i is segments.length) return; 2720 if (i is i_segments.length) return;
2687 } 2721 }
2688 }
2689 freeRuns(); 2722 freeRuns();
2690 this.segments = segments.dup; 2723 this.segments.length = i_segments.length;
2691 2724 foreach(i, ref s; this.segments)
2692 // SWT: create the wsegments ... 2725 s = text.takeIndexArg(i_segments[i], "segments@setSegments");
2693 this.wsegments.length = segments.length; 2726
2694 uint index8, index16; 2727 // DWT: create the wsegments ...
2695 uint segIndex = 1; 2728 this.wsegments.length = this.segments.length;
2696 while(index8 < text.length ){ 2729 UTF8index idx8;
2697 int ate8; 2730 UTF16index idx16;
2698 int ate16; 2731 foreach(i, ref wsegment; this.wsegments) {
2699 dchar d8 = text[ index8 .. $ ].firstCodePoint( ate8 ); 2732 while( this.segments[i] != idx8 ) {
2700 dchar d16 = wtext[ index16 .. $ ].firstCodePoint( ate16 ); 2733 assert(text.dcharAt(idx8) == wtext.dcharAt(idx16));
2701 assert( d8 is d16 ); 2734 idx8 += text.UTF8strideAt(idx8);
2702 assert( ate8 > 0 ); 2735 idx16 += wtext.UTF16strideAt(idx16);
2703 assert( ate16 > 0 ); 2736 assert(idx8 <= this.segments[i]);
2704 index8 += ate8; 2737 }
2705 index16 += ate16; 2738 wsegment = idx16;
2706 if( segments[segIndex] is index8 ){ 2739 }
2707 wsegments[segIndex] = index16;
2708 }
2709 }
2710 assert( index16 is wtext.length );
2711 assert( segIndex is segments.length );
2712 } 2740 }
2713 2741
2714 /** 2742 /**
2715 * Sets the line spacing of the receiver. The line spacing 2743 * Sets the line spacing of the receiver. The line spacing
2716 * is the space left between lines. 2744 * is the space left between lines.
2743 * 2771 *
2744 * @exception SWTException <ul> 2772 * @exception SWTException <ul>
2745 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 2773 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2746 * </ul> 2774 * </ul>
2747 */ 2775 */
2748 public void setStyle (TextStyle style, int start, int end) { 2776 public void setStyle (TextStyle style, int i_start, int i_end) {
2749 checkLayout(); 2777 checkLayout();
2778 UTF8index start = text.takeIndexArg(i_start, "start@setStyle");
2779 UTF8index end = text.takeIndexArg(i_end, "end@setStyle");
2750 int length = text.length; 2780 int length = text.length;
2751 if (length is 0) return; 2781 if (length is 0) return;
2782 UTF8index endOffset = text.beforeEndIndex();
2752 if (start > end) return; 2783 if (start > end) return;
2753 start = Math.min(Math.max(0, start), length - 1); 2784 start = Math.min(Math.max(text.firstIndex(), start), endOffset);
2754 end = Math.min(Math.max(0, end), length - 1); 2785 end = Math.min(Math.max(text.firstIndex(), end), endOffset);
2755 int low = -1; 2786 int low = -1;
2756 int high = stylesCount; 2787 int high = stylesCount;
2757 while (high - low > 1) { 2788 while (high - low > 1) {
2758 int index = (high + low) / 2; 2789 int index = (high + low) / 2;
2759 if (styles[index + 1].start > start) { 2790 if (styles[index + 1].UTF8start > start) {
2760 high = index; 2791 high = index;
2761 } else { 2792 } else {
2762 low = index; 2793 low = index;
2763 } 2794 }
2764 } 2795 }
2765 if (0 <= high && high < stylesCount) { 2796 if (0 <= high && high < stylesCount) {
2766 StyleItem item = styles[high]; 2797 StyleItem item = styles[high];
2767 if (item.start is start && styles[high + 1].start - 1 is end) { 2798 if (item.UTF8start is start && text.offsetBefore(styles[high + 1].UTF8start) is end) {
2768 if (style is null) { 2799 if (style is null) {
2769 if (item.style is null) return; 2800 if (item.style is null) return;
2770 } else { 2801 } else {
2771 if (style.opEquals(item.style)) return; 2802 if (style.opEquals(item.style)) return;
2772 } 2803 }
2774 } 2805 }
2775 freeRuns(); 2806 freeRuns();
2776 int modifyStart = high; 2807 int modifyStart = high;
2777 int modifyEnd = modifyStart; 2808 int modifyEnd = modifyStart;
2778 while (modifyEnd < stylesCount) { 2809 while (modifyEnd < stylesCount) {
2779 if (styles[modifyEnd + 1].start > end) break; 2810 if (styles[modifyEnd + 1].UTF8start > end) break;
2780 modifyEnd++; 2811 modifyEnd++;
2781 } 2812 }
2782 if (modifyStart is modifyEnd) { 2813 if (modifyStart is modifyEnd) {
2783 int styleStart = styles[modifyStart].start; 2814 UTF8index styleStart = styles[modifyStart].UTF8start;
2784 int styleEnd = styles[modifyEnd + 1].start - 1; 2815 UTF8index styleEnd = text.offsetBefore(styles[modifyEnd + 1].UTF8start);
2785 if (styleStart is start && styleEnd is end) { 2816 if (styleStart is start && styleEnd is end) {
2786 styles[modifyStart].style = style; 2817 styles[modifyStart].style = style;
2787 return; 2818 return;
2788 } 2819 }
2789 if (styleStart !is start && styleEnd !is end) { 2820 if (styleStart !is start && styleEnd !is end) {
2794 System.arraycopy(styles, 0, newStyles, 0, stylesCount); 2825 System.arraycopy(styles, 0, newStyles, 0, stylesCount);
2795 styles = newStyles; 2826 styles = newStyles;
2796 } 2827 }
2797 System.arraycopy(styles, modifyEnd + 1, styles, modifyEnd + 3, stylesCount - modifyEnd - 1); 2828 System.arraycopy(styles, modifyEnd + 1, styles, modifyEnd + 3, stylesCount - modifyEnd - 1);
2798 StyleItem item = new StyleItem(); 2829 StyleItem item = new StyleItem();
2799 item.start = start; 2830 item.UTF8start = start;
2800 item.style = style; 2831 item.style = style;
2801 styles[modifyStart + 1] = item; 2832 styles[modifyStart + 1] = item;
2802 item = new StyleItem(); 2833 item = new StyleItem();
2803 item.start = end + 1; 2834 item.UTF8start = text.offsetAfter(end);
2804 item.style = styles[modifyStart].style; 2835 item.style = styles[modifyStart].style;
2805 styles[modifyStart + 2] = item; 2836 styles[modifyStart + 2] = item;
2806 stylesCount = newLength; 2837 stylesCount = newLength;
2807 return; 2838 return;
2808 } 2839 }
2809 } 2840 }
2810 if (start is styles[modifyStart].start) modifyStart--; 2841 if (start is styles[modifyStart].UTF8start) modifyStart--;
2811 if (end is styles[modifyEnd + 1].start - 1) modifyEnd++; 2842 if (end is text.offsetBefore(styles[modifyEnd + 1].UTF8start)) modifyEnd++;
2812 int newLength = stylesCount + 1 - (modifyEnd - modifyStart - 1); 2843 int newLength = stylesCount + 1 - (modifyEnd - modifyStart - 1);
2813 if (newLength > styles.length) { 2844 if (newLength > styles.length) {
2814 int newSize = Math.min(newLength + 1024, Math.max(64, newLength * 2)); 2845 int newSize = Math.min(newLength + 1024, Math.max(64, newLength * 2));
2815 StyleItem[] newStyles = new StyleItem[newSize]; 2846 StyleItem[] newStyles = new StyleItem[newSize];
2816 System.arraycopy(styles, 0, newStyles, 0, stylesCount); 2847 System.arraycopy(styles, 0, newStyles, 0, stylesCount);
2817 styles = newStyles; 2848 styles = newStyles;
2818 } 2849 }
2819 System.arraycopy(styles, modifyEnd, styles, modifyStart + 2, stylesCount - modifyEnd); 2850 System.arraycopy(styles, modifyEnd, styles, modifyStart + 2, stylesCount - modifyEnd);
2820 StyleItem item = new StyleItem(); 2851 StyleItem item = new StyleItem();
2821 item.start = start; 2852 item.UTF8start = start;
2822 item.style = style; 2853 item.style = style;
2823 styles[modifyStart + 1] = item; 2854 styles[modifyStart + 1] = item;
2824 styles[modifyStart + 2].start = end + 1; 2855 styles[modifyStart + 2].UTF8start = text.offsetAfter(end);
2825 stylesCount = newLength; 2856 stylesCount = newLength;
2826 } 2857 }
2827 2858
2828 /** 2859 /**
2829 * Sets the receiver's tab list. Each value in the tab list specifies 2860 * Sets the receiver's tab list. Each value in the tab list specifies
2874 this.text = text._idup(); 2905 this.text = text._idup();
2875 this.wtext = StrToWCHARs(text); 2906 this.wtext = StrToWCHARs(text);
2876 styles = new StyleItem[2]; 2907 styles = new StyleItem[2];
2877 styles[0] = new StyleItem(); 2908 styles[0] = new StyleItem();
2878 styles[1] = new StyleItem(); 2909 styles[1] = new StyleItem();
2879 styles[1].start = text.length; 2910 styles[1].UTF8start = text.endIndex();
2880 stylesCount = 2; 2911 stylesCount = 2;
2881 } 2912 }
2882 2913
2883 /** 2914 /**
2884 * Sets the line width of the receiver, which determines how 2915 * Sets the line width of the receiver, which determines how
2947 /* 2978 /*
2948 * Generate glyphs for one Run. 2979 * Generate glyphs for one Run.
2949 */ 2980 */
2950 void shape (HDC hdc, StyleItem run) { 2981 void shape (HDC hdc, StyleItem run) {
2951 int[1] buffer; 2982 int[1] buffer;
2952 auto wchars = segmentsWText[ index8to16[ run.start ] .. index8to16[ run.start + run.length ] ]; 2983 auto wchars = segmentsWText[ getUTF16index(run.UTF8start) .. getUTF16index(run.UTF8start + run.UTF8length) ];
2953 int maxGlyphs = (wchars.length * 3 / 2) + 16; 2984 int maxGlyphs = (wchars.length * 3 / 2) + 16;
2954 auto hHeap = OS.GetProcessHeap(); 2985 auto hHeap = OS.GetProcessHeap();
2955 run.glyphs = cast(ushort*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, maxGlyphs * 2); 2986 run.glyphs = cast(ushort*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, maxGlyphs * 2);
2956 if (run.glyphs is null) SWT.error(SWT.ERROR_NO_HANDLES); 2987 if (run.glyphs is null) SWT.error(SWT.ERROR_NO_HANDLES);
2957 run.clusters = cast(WORD*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, maxGlyphs * 2); 2988 run.clusters = cast(WORD*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, maxGlyphs * 2);
2961 run.psc = cast(SCRIPT_CACHE*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, (void*).sizeof); 2992 run.psc = cast(SCRIPT_CACHE*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, (void*).sizeof);
2962 if (run.psc is null) SWT.error(SWT.ERROR_NO_HANDLES); 2993 if (run.psc is null) SWT.error(SWT.ERROR_NO_HANDLES);
2963 short script = cast(short) run.analysis.eScript; 2994 short script = cast(short) run.analysis.eScript;
2964 SCRIPT_PROPERTIES sp = *device.scripts[script]; 2995 SCRIPT_PROPERTIES sp = *device.scripts[script];
2965 bool shapeSucceed = shape(hdc, run, wchars, buffer, maxGlyphs, &sp); 2996 bool shapeSucceed = shape(hdc, run, wchars, buffer, maxGlyphs, &sp);
2966 int res; 2997 int res;
2967 if (!shapeSucceed) { 2998 if (!shapeSucceed) {
2968 auto hFont = OS.GetCurrentObject(hdc, OS.OBJ_FONT); 2999 auto hFont = OS.GetCurrentObject(hdc, OS.OBJ_FONT);
2969 auto ssa = cast(SCRIPT_STRING_ANALYSIS*) OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, SCRIPT_STRING_ANALYSIS.sizeof); 3000 auto ssa = cast(SCRIPT_STRING_ANALYSIS*) OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, SCRIPT_STRING_ANALYSIS.sizeof);
2970 auto metaFileDc = OS.CreateEnhMetaFile(hdc, null, null, null); 3001 auto metaFileDc = OS.CreateEnhMetaFile(hdc, null, null, null);
2971 auto oldMetaFont = OS.SelectObject(metaFileDc, hFont); 3002 auto oldMetaFont = OS.SelectObject(metaFileDc, hFont);
3108 run.descent = lptm.tmDescent; 3139 run.descent = lptm.tmDescent;
3109 run.leading = lptm.tmInternalLeading; 3140 run.leading = lptm.tmInternalLeading;
3110 } 3141 }
3111 } 3142 }
3112 3143
3113 int validadeOffset(int offset, int step) { 3144 UTF8index getUTF8index(UTF16index i)
3114 offset = segmentsText.toAbsoluteCodePointStartOffset( offset ); 3145 out(res) {
3115 offset += segmentsText.getRelativeCodePointOffset( offset, step ); 3146 assert(res != segmentsText.preFirstIndex());
3116 if (segments !is null && segments.length > 2) { 3147 }
3117 for (int i = 0; i < segments.length; i++) { 3148 body {
3118 if (translateOffset(segments[i]) - 1 is offset) { 3149 return index16to8[i];
3119 offset += step; 3150 }
3120 break; 3151
3121 } 3152 UTF16index getUTF16index(UTF8index i)
3122 } 3153 out(res) {
3123 } 3154 assert(res != -1);
3124 return offset; 3155 }
3156 body {
3157 return index8to16[i.internalValue];
3158 }
3159
3160 UTF8index addUTF16shift(UTF8index i, UTF16shift dw) {
3161 return getUTF8index(cast(UTF16index)(getUTF16index(i) + dw));
3162 }
3163
3164 UTF16shift getUTF16length(StyleItem run) {
3165 return cast(UTF16shift)(getUTF16index(run.UTF8start + run.UTF8length) - getUTF16index(run.UTF8start));
3166 }
3167
3168 UTF8index validadeOffset(UTF8index offset, UCSindex step) {
3169 offset = asUTF8index( untranslateOffset(offset) );
3170 offset += text.toUTF8shift(offset, step);
3171 return translateOffset(offset);
3125 } 3172 }
3126 3173
3127 /** 3174 /**
3128 * Returns a string containing a concise, human-readable 3175 * Returns a string containing a concise, human-readable
3129 * description of the receiver. 3176 * description of the receiver.
3133 override public String toString () { 3180 override public String toString () {
3134 if (isDisposed()) return "TextLayout {*DISPOSED*}"; 3181 if (isDisposed()) return "TextLayout {*DISPOSED*}";
3135 return "TextLayout {}"; 3182 return "TextLayout {}";
3136 } 3183 }
3137 3184
3138 int translateOffset(int offset) { 3185 UTF8index translateOffset(UTF8index offset) {
3139 if (segments is null) return offset; 3186 if (segments is null) return offset;
3140 int nSegments = segments.length; 3187 int nSegments = segments.length;
3141 if (nSegments <= 1) return offset; 3188 if (nSegments <= 1) return offset;
3142 int length = text.length; 3189 int length = text.length;
3143 if (length is 0) return offset; 3190 if (length is 0) return offset;
3144 if (nSegments is 2) { 3191 if (nSegments is 2) {
3145 if (segments[0] is 0 && segments[1] is length) return offset; 3192 if (segments[0].internalValue is 0 && segments[1].internalValue is length) return offset;
3146 } 3193 }
3147 for (int i = 0; i < nSegments && offset - i >= segments[i]; i++) { 3194 for (int i = 0; i < nSegments && offset.internalValue - i >= segments[i].internalValue; i++) {
3148 offset+=MARK_SIZE; 3195 offset+=MARK_SIZE;
3149 } 3196 }
3150 return offset; 3197 return offset;
3151 } 3198 }
3152 3199
3153 int untranslateOffset(int offset) { 3200 int untranslateOffset(UTF8index offset) {
3154 if (segments is null) return offset; 3201 if (segments is null) return offset.internalValue;
3155 int nSegments = segments.length; 3202 int nSegments = segments.length;
3156 if (nSegments <= 1) return offset; 3203 if (nSegments <= 1) return offset.internalValue;
3157 int length = text.length; 3204 int length = text.length;
3158 if (length is 0) return offset; 3205 if (length is 0) return offset.internalValue;
3159 if (nSegments is 2) { 3206 if (nSegments is 2) {
3160 if (segments[0] is 0 && segments[1] is length) return offset; 3207 if (segments[0].internalValue is 0 && segments[1].internalValue is length) return offset.internalValue;
3161 } 3208 }
3162 for (int i = 0; i < nSegments && offset > segments[i]; i++) { 3209 for (int i = 0; i < nSegments && offset > segments[i]; i++) {
3163 offset-=MARK_SIZE; 3210 offset-=MARK_SIZE;
3164 } 3211 }
3165 return offset; 3212 return offset.internalValue;
3166 } 3213 }
3167 } 3214 }