Mercurial > projects > dwt2
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 } |