Mercurial > projects > dwt2
diff 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 |
line wrap: on
line diff
--- a/org.eclipse.swt.win32.win32.x86/src/org/eclipse/swt/graphics/TextLayout.d Sun Apr 17 17:58:36 2011 +0200 +++ b/org.eclipse.swt.win32.win32.x86/src/org/eclipse/swt/graphics/TextLayout.d Sat Jul 09 15:50:20 2011 +0300 @@ -23,7 +23,7 @@ + 'text' is the original user text, 'segmentsText' is the user text stuffed with + RTL/LTR markers for each line or in addition for User supplied segments. A segment + is a range where Bidi char reordering can happen. - + The 'runs' are those ranges with an idiviual style. + + The 'runs' are those ranges with an idividual style. +/ import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; @@ -46,6 +46,7 @@ import org.eclipse.swt.graphics.TextStyle; import java.lang.all; +import java.nonstandard.SafeUtf; /** @@ -68,8 +69,8 @@ * @since 3.0 */ public final class TextLayout : Resource { - alias Resource.init_ init_; +private: /++ + SWT doku @@ -89,8 +90,8 @@ String16 wtext; String segmentsText; String16 segmentsWText; // DWT - int[] index8to16; // DWT - int[] index16to8; // DWT + UTF16index[] index8to16; // DWT + UTF8index[] index16to8; // DWT int lineSpacing; int ascent, descent; int alignment; @@ -99,36 +100,40 @@ int indent; bool justify; int[] tabs; - int[] segments; // indices in 'text' - int[] wsegments; // SWT indices in 'wtext' + UTF8index[] segments; // indices in 'text' + UTF16index[] wsegments; // SWT indices in 'wtext' StyleItem[] styles; int stylesCount; StyleItem[] allRuns; StyleItem[][] runs; - int[] lineOffset, lineY, lineWidth; + UTF8index[] lineOffset; + int[] lineY, lineWidth; void* mLangFontLink2; static const dchar LTR_MARK = '\u200E', RTL_MARK = '\u200F'; static const wchar LTR_MARKw = '\u200E', RTL_MARKw = '\u200F'; static const String STR_LTR_MARK = "\u200E", STR_RTL_MARK = "\u200F"; static const wchar[] WSTR_LTR_MARK = "\u200E"w, WSTR_RTL_MARK = "\u200F"w; - static const int MARK_SIZE = 3; - static const int WMARK_SIZE = 1; + static const UTF8shift MARK_SIZE = { STR_LTR_MARK.length }; + static const UTF16shift WMARK_SIZE = WSTR_LTR_MARK.length; + static assert(MARK_SIZE.internalValue == 3 && WMARK_SIZE == 1); static const int SCRIPT_VISATTR_SIZEOF = 2; static const int GOFFSET_SIZEOF = 8; - private static byte[16] CLSID_CMultiLanguage; - private static byte[16] IID_IMLangFontLink2; - private static bool static_this_completed = false; - private static void static_this() { +mixin(gshared!(" + static byte[16] CLSID_CMultiLanguage; + static byte[16] IID_IMLangFontLink2; + static bool static_this_completed = false; +")); + static void static_this() { // in case of allready initialized, we can check and leave without lock if( static_this_completed ){ return; } synchronized { if( !static_this_completed ){ - OS.IIDFromString("{275c23e2-3747-11d0-9fea-00aa003f8646}\0".toWCharArray().ptr, CLSID_CMultiLanguage.ptr); - OS.IIDFromString("{DCCFC162-2B38-11d2-B7EC-00C04F8F5D9A}\0".toWCharArray().ptr, IID_IMLangFontLink2.ptr); + OS.IIDFromString("{275c23e2-3747-11d0-9fea-00aa003f8646}\0"w.ptr, CLSID_CMultiLanguage.ptr); + OS.IIDFromString("{DCCFC162-2B38-11d2-B7EC-00C04F8F5D9A}\0"w.ptr, IID_IMLangFontLink2.ptr); static_this_completed = true; } } @@ -139,10 +144,14 @@ static const int UNDERLINE_IME_DASH = 2 << 16; static const int UNDERLINE_IME_THICK = 3 << 16; - class StyleItem { + static class StyleItem { TextStyle style; - // SWT: start, lenght relative to segmentsText - int start, length; + // DWT: start, lenght relative to segmentsText + UTF8index UTF8start; + UTF8shift UTF8length; + UTF8index UTF8end() { + return UTF8start + UTF8length; + } bool lineBreak, softBreak, tab; /*Script cache and analysis */ @@ -221,7 +230,7 @@ lineBreak = softBreak = false; } override public String toString () { - return Format( "StyleItem {{{}, {}}", start, style ); + return Format( "StyleItem {{{}, {}}", UTF8start, style ); } } @@ -261,11 +270,11 @@ void breakRun(StyleItem run) { if (run.psla !is null) return; - String16 chars = segmentsWText[ index8to16[ run.start ] .. index8to16[ run.start + run.length ] ]; + String16 wchars = segmentsWText[ getUTF16index(run.UTF8start) .. getUTF16index(run.UTF8start + run.UTF8length) ]; auto hHeap = OS.GetProcessHeap(); - run.psla = cast(SCRIPT_LOGATTR*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, SCRIPT_LOGATTR.sizeof * chars.length); + run.psla = cast(SCRIPT_LOGATTR*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, SCRIPT_LOGATTR.sizeof * wchars.length); if (run.psla is null) SWT.error(SWT.ERROR_NO_HANDLES); - OS.ScriptBreak(chars.ptr, chars.length, &run.analysis, run.psla); + OS.ScriptBreak(wchars.ptr, wchars.length, &run.analysis, run.psla); } void checkLayout () { @@ -276,7 +285,13 @@ * Compute the runs: itemize, shape, place, and reorder the runs. * Break paragraphs into lines, wraps the text, and initialize caches. */ -void computeRuns (GC gc) { +void computeRuns (GC gc) +out { + foreach(run; allRuns) { + segmentsText.validateUTF8index(run.UTF8start); + segmentsText.validateUTF8index(run.UTF8start + run.UTF8length); + } +} body { if (runs !is null) return; auto hDC = gc !is null ? gc.handle : device.internal_new_GC(null); auto srcHdc = OS.CreateCompatibleDC(hDC); @@ -291,8 +306,9 @@ int lineWidth = indent, lineStart = 0, lineCount = 1; for (int i=0; i<allRuns.length - 1; i++) { StyleItem run = allRuns[i]; - if (run.length is 1) { - char ch = segmentsText.charAt(run.start); + if (run.UTF8length.internalValue is 1) { + char ch = segmentsText.charAt( run.UTF8start.internalValue ); + assert(ch == segmentsText.dcharAt(run.UTF8start)); switch (ch) { case '\t': { run.tab = true; @@ -321,8 +337,8 @@ case '\r': { run.lineBreak = true; StyleItem next = allRuns[i + 1]; - if (next.length !is 0 && segmentsText.charAt(next.start) is '\n') { - run.length += 1; + if (next.UTF8length.internalValue !is 0 && segmentsText.charAt( next.UTF8start.internalValue ) is '\n') { + run.UTF8length.internalValue += 1; next.free(); StyleItem[] newAllRuns = new StyleItem[allRuns.length - 1]; System.arraycopy(allRuns, 0, newAllRuns, 0, i + 1); @@ -335,26 +351,27 @@ } } if (wrapWidth !is -1 && lineWidth + run.width > wrapWidth && !run.tab) { - int start = 0; - int[] piDx = new int[run.length]; + UTF16index wstart = 0; + UTF16shift cChars = getUTF16length(run); + int[] piDx = new int[cChars]; if (run.style !is null && run.style.metrics !is null) { piDx[0] = run.width; } else { - OS.ScriptGetLogicalWidths(&run.analysis, run.length, run.glyphCount, run.advances, run.clusters, run.visAttrs, piDx.ptr); + OS.ScriptGetLogicalWidths(&run.analysis, cChars, run.glyphCount, run.advances, run.clusters, run.visAttrs, piDx.ptr); } int width = 0, maxWidth = wrapWidth - lineWidth; - while (width + piDx[start] < maxWidth) { - width += piDx[start++]; + while (width + piDx[wstart] < maxWidth) { + width += piDx[wstart++]; } - int firstStart = start; + UTF16index firstWstart = wstart; int firstIndice = i; while (i >= lineStart) { breakRun(run); - while (start >= 0) { - logAttr = run.psla + start; + while (wstart >= 0) { + logAttr = run.psla + wstart; //OS.MoveMemory(logAttr, run.psla + (start * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof); if (logAttr.fSoftBreak || logAttr.fWhiteSpace) break; - start--; + wstart--; } /* @@ -362,7 +379,7 @@ * after a letter with an accent. This cause a break line to be set in the middle of a word. * The fix is to detect the case and ignore fSoftBreak forcing the algorithm keep searching. */ - if (start is 0 && i !is lineStart && !run.tab) { + if (wstart is 0 && i !is lineStart && !run.tab) { if (logAttr.fSoftBreak && !logAttr.fWhiteSpace) { properties = device.scripts[run.analysis.eScript]; //OS.MoveMemory(properties, device.scripts[run.analysis.eScript], SCRIPT_PROPERTIES.sizeof); @@ -371,44 +388,46 @@ //OS.MoveMemory(properties, device.scripts[pRun.analysis.eScript], SCRIPT_PROPERTIES.sizeof); if (properties.langid is langID || langID is OS.LANG_NEUTRAL || properties.langid is OS.LANG_NEUTRAL) { breakRun(pRun); - logAttr = pRun.psla + (pRun.length - 1); + logAttr = pRun.psla + (getUTF16length(pRun) - 1); //OS.MoveMemory(logAttr, pRun.psla + ((pRun.length - 1) * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof); - if (!logAttr.fWhiteSpace) start = -1; + if (!logAttr.fWhiteSpace) wstart = cast(UTF16index)-1; } } } - if (start >= 0 || i is lineStart) break; + if (wstart >= 0 || i is lineStart) break; run = allRuns[--i]; - start = run.length - 1; + wstart = cast(UTF16index)(getUTF16length(run) - 1); } - if (start is 0 && i !is lineStart && !run.tab) { + if (wstart is 0 && i !is lineStart && !run.tab) { run = allRuns[--i]; - } else if (start <= 0 && i is lineStart) { + } else if (wstart <= 0 && i is lineStart) { if (lineWidth is wrapWidth && firstIndice > 0) { i = firstIndice - 1; run = allRuns[i]; - start = run.length; + wstart = cast(UTF16index)getUTF16length(run); } else { i = firstIndice; run = allRuns[i]; - start = Math.max(1, firstStart); + wstart = cast(UTF16index)Math.max(1, firstWstart); } } breakRun(run); - while (start < run.length) { - logAttr = run.psla + start; + UTF16shift runWlength = getUTF16length(run); + while (wstart < runWlength) { + logAttr = run.psla + wstart; //OS.MoveMemory(logAttr, run.psla + (start * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof); if (!logAttr.fWhiteSpace) break; - start++; + wstart++; } - if (0 < start && start < run.length) { + if (0 < wstart && wstart < runWlength) { StyleItem newRun = new StyleItem(); - newRun.start = run.start + start; - newRun.length = run.length - start; + UTF8shift UTF8startShift = getUTF8index(getUTF16index(run.UTF8start) + wstart) - run.UTF8start; + newRun.UTF8start = run.UTF8start + UTF8startShift; + newRun.UTF8length = run.UTF8length - UTF8startShift; newRun.style = run.style; newRun.analysis = cloneScriptAnalysis(run.analysis); run.free(); - run.length = start; + run.UTF8length = UTF8startShift; OS.SelectObject(srcHdc, getItemFont(run)); run.analysis.fNoGlyphIndex = false; shape (srcHdc, run); @@ -434,7 +453,7 @@ } lineWidth = 0; runs = new StyleItem[][](lineCount); - lineOffset = new int[lineCount + 1]; + lineOffset = new UTF8index[lineCount + 1]; lineY = new int[lineCount + 1]; this.lineWidth = new int[lineCount]; int lineRunCount = 0, line = 0; @@ -489,7 +508,7 @@ this.lineWidth[line] = lineWidth; StyleItem lastRun = runs[line][lineRunCount - 1]; - int lastOffset = lastRun.start + lastRun.length; + UTF8index lastOffset = lastRun.UTF8start + lastRun.UTF8length; runs[line] = reorder(runs[line], i is allRuns.length - 1); lastRun = runs[line][lineRunCount - 1]; if (run.softBreak && run !is lastRun) { @@ -596,8 +615,8 @@ * <li>ERROR_NULL_ARGUMENT - if the gc is null</li> * </ul> */ -public void draw (GC gc, int x, int y, int selectionStart, int selectionEnd, Color selectionForeground, Color selectionBackground) { - draw(gc, x, y, selectionStart, selectionEnd, selectionForeground, selectionBackground, 0); +public void draw (GC gc, int x, int y, int i_selectionStart, int i_selectionEnd, Color selectionForeground, Color selectionBackground) { + draw(gc, x, y, i_selectionStart, i_selectionEnd, selectionForeground, selectionBackground, 0); } /** @@ -627,9 +646,11 @@ * * @since 3.3 */ -public void draw (GC gc, int x, int y, int selectionStart, int selectionEnd, Color selectionForeground, Color selectionBackground, int flags) { +public void draw (GC gc, int x, int y, int i_selectionStart, int i_selectionEnd, Color selectionForeground, Color selectionBackground, int flags) { checkLayout(); computeRuns(gc); + UTF8index selectionStart = text.takeIndexArg(i_selectionStart, "selectionStart@draw"); + UTF8index selectionEnd = text.takeIndexArg(i_selectionEnd, "selectionEnd@draw"); if (gc is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (gc.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); if (selectionForeground !is null && selectionForeground.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); @@ -694,10 +715,10 @@ OS.DeleteObject(clipRgn); } } - bool hasSelection = selectionStart <= selectionEnd && selectionStart !is -1 && selectionEnd !is -1; + bool hasSelection = selectionStart <= selectionEnd && selectionStart.internalValue !is -1 && selectionEnd.internalValue !is -1; if (hasSelection || (flags & SWT.LAST_LINE_SELECTION) !is 0) { - selectionStart = Math.min(Math.max(0, selectionStart), length - 1); - selectionEnd = Math.min(Math.max(0, selectionEnd), length - 1); + selectionStart = Math.min(Math.max(text.firstIndex(), selectionStart), text.beforeEndIndex()); + selectionEnd = Math.min(Math.max(text.firstIndex(), selectionEnd), text.beforeEndIndex()); if (selectionForeground is null) selectionForeground = device.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT); if (selectionBackground is null) selectionBackground = device.getSystemColor(SWT.COLOR_LIST_SELECTION); selectionStart = translateOffset(selectionStart); @@ -740,9 +761,9 @@ } else { StyleItem run = lineRuns[lineRuns.length - 1]; if (run.lineBreak && !run.softBreak) { - if (selectionStart <= run.start && run.start <= selectionEnd) extents = true; + if (selectionStart <= run.UTF8start && run.UTF8start <= selectionEnd) extents = true; } else { - int endOffset = segmentsText.getAbsoluteCodePointOffset( run.start + run.length, -1 ); + UTF8index endOffset = segmentsText.offsetBefore(run.UTF8start + run.UTF8length); if (selectionStart <= endOffset && endOffset < selectionEnd && (flags & SWT.FULL_SELECTION) !is 0) { extents = true; } @@ -774,12 +795,12 @@ int alignmentX = drawX; for (int i = 0; i < lineRuns.length; i++) { StyleItem run = lineRuns[i]; - if (run.length is 0) continue; + if (run.UTF8length.internalValue is 0) continue; if (drawX > clip.x + clip.width) break; if (drawX + run.width >= clip.x) { if (!run.lineBreak || run.softBreak) { - int end = segmentsText.getAbsoluteCodePointOffset( run.start + run.length, -1 ); - bool fullSelection = hasSelection && selectionStart <= run.start && selectionEnd >= end; + UTF8index end = segmentsText.offsetBefore(run.UTF8start + run.UTF8length); + bool fullSelection = hasSelection && selectionStart <= run.UTF8start && selectionEnd >= end; if (fullSelection) { if (gdip) { Gdip.Graphics_FillRectangle(gdipGraphics, cast(Gdip.Brush)selBrush, drawX, drawY, run.width, lineHeight); @@ -805,11 +826,11 @@ OS.DeleteObject(hBrush); } } - bool partialSelection = hasSelection && !(selectionStart > end || run.start > selectionEnd); + bool partialSelection = hasSelection && !(selectionStart > end || run.UTF8start > selectionEnd); if (partialSelection) { - int selStart = index8to16[ Math.max(selectionStart, run.start) ] - index8to16[run.start]; - int selEnd = index8to16[ Math.min(selectionEnd, end) ] - index8to16[ run.start ]; - int cChars = index8to16[run.start+run.length] - index8to16[run.start]; // make it wchar + UTF16index selStart = getUTF16index(Math.max(selectionStart, run.UTF8start)) - getUTF16index(run.UTF8start); + UTF16index selEnd = getUTF16index(Math.min(selectionEnd, end)) - getUTF16index(run.UTF8start); + UTF16shift cChars = getUTF16length(run); // make it wchar int gGlyphs = run.glyphCount; int piX; int* advances = run.justify !is null ? run.justify : run.advances; @@ -842,19 +863,19 @@ drawX = alignmentX; for (int i = 0; i < lineRuns.length; i++) { StyleItem run = lineRuns[i]; - if (run.length is 0) continue; + if (run.UTF8length.internalValue is 0) continue; if (drawX > clip.x + clip.width) break; if (drawX + run.width >= clip.x) { if (!run.tab && (!run.lineBreak || run.softBreak) && !(run.style !is null && run.style.metrics !is null)) { - int end = run.start + run.length - 1; - bool fullSelection = hasSelection && selectionStart <= run.start && selectionEnd >= end; - bool partialSelection = hasSelection && !fullSelection && !(selectionStart > end || run.start > selectionEnd); + UTF8index end = segmentsText.offsetBefore(run.UTF8start + run.UTF8length); + bool fullSelection = hasSelection && selectionStart <= run.UTF8start && selectionEnd >= end; + bool partialSelection = hasSelection && !fullSelection && !(selectionStart > end || run.UTF8start > selectionEnd); OS.SelectObject(hdc, getItemFont(run)); int drawRunY = drawY + (baseline - run.ascent); if (partialSelection) { - int selStart = Math.max(index8to16[selectionStart], index8to16[run.start]) - index8to16[run.start]; - int selEnd = Math.min(index8to16[selectionEnd], index8to16[end]) - index8to16[run.start]; - int cChars = index8to16[run.start+run.length] - index8to16[run.start]; // make it wchar + UTF16index selStart = Math.max(getUTF16index(selectionStart), getUTF16index(run.UTF8start)) - getUTF16index(run.UTF8start); + UTF16index selEnd = Math.min(getUTF16index(selectionEnd), getUTF16index(end)) - getUTF16index(run.UTF8start); + UTF16shift cChars = getUTF16length(run); // make it wchar int gGlyphs = run.glyphCount; int piX; int* advances = run.justify !is null ? run.justify : run.advances; @@ -1185,7 +1206,7 @@ } } -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) { +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) { StyleItem run = line[index]; TextStyle style = run.style; if (style is null) return null; @@ -1196,14 +1217,14 @@ OS.SetRect(clipRect, -1, rect.top, -1, rect.bottom); } bool isRTL = (orientation & SWT.RIGHT_TO_LEFT) !is 0; - if (run.start <= selectionStart && selectionStart <= run.start + run.length) { + if (run.UTF8start <= selectionStart && selectionStart <= run.UTF8start + run.UTF8length) { if (run.analysis.fRTL ^ isRTL) { clipRect.right = rect.left; } else { clipRect.left = rect.left; } } - if (run.start <= selectionEnd && selectionEnd <= run.start + run.length) { + if (run.UTF8start <= selectionEnd && selectionEnd <= run.UTF8start + run.UTF8length) { if (run.analysis.fRTL ^ isRTL) { clipRect.left = rect.right; } else { @@ -1433,14 +1454,15 @@ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> * </ul> */ -public Rectangle getBounds (int start, int end) { +public Rectangle getBounds (int i_start, int i_end) { checkLayout(); computeRuns(null); - int length = text.length; - if (length is 0) return new Rectangle(0, 0, 0, 0); + UTF8index start = text.takeIndexArg(i_start, "start@getBounds"); + UTF8index end = text.takeIndexArg(i_end, "end@getBounds"); + if (text.length is 0) return new Rectangle(0, 0, 0, 0); if (start > end) return new Rectangle(0, 0, 0, 0); - start = Math.min(Math.max(0, start), length - 1); - end = Math.min(Math.max(0, end), length - 1); + start = Math.min(Math.max(text.firstIndex(), start), text.beforeEndIndex()); + end = Math.min(Math.max(text.firstIndex(), end), text.beforeEndIndex()); start = translateOffset(start); end = translateOffset(end); int left = 0x7fffffff, right = 0; @@ -1448,21 +1470,22 @@ bool isRTL = (orientation & SWT.RIGHT_TO_LEFT) !is 0; for (int i = 0; i < allRuns.length - 1; i++) { StyleItem run = allRuns[i]; - int runEnd = run.start + run.length; + UTF8index runEnd = run.UTF8start + run.UTF8length; if (runEnd <= start) continue; - if (run.start > end) break; + if (run.UTF8start > end) break; int runLead = run.x; int runTrail = run.x + run.width; - if (run.start <= start && start < runEnd) { + if (run.UTF8start <= start && start < runEnd) { int cx = 0; if (run.style !is null && run.style.metrics !is null) { GlyphMetrics metrics = run.style.metrics; - cx = metrics.width * (index8to16[start] - index8to16[run.start]); + cx = metrics.width * (getUTF16index(start) - getUTF16index(run.UTF8start)); } else if (!run.tab) { + UTF16index iCP = getUTF16index(start) - getUTF16index(run.UTF8start); + UTF16shift cChars = getUTF16length(run); int piX; int* advances = run.justify !is null ? run.justify : run.advances; - int wlength = index8to16[ run.start+run.length] - index8to16[run.start]; - OS.ScriptCPtoX(index8to16[start] - index8to16[run.start], false, wlength, run.glyphCount, run.clusters, run.visAttrs, advances, &run.analysis, &piX); + OS.ScriptCPtoX(iCP, false, cChars, run.glyphCount, run.clusters, run.visAttrs, advances, &run.analysis, &piX); cx = isRTL ? run.width - piX : piX; } if (run.analysis.fRTL ^ isRTL) { @@ -1471,16 +1494,17 @@ runLead = run.x + cx; } } - if (run.start <= end && end < runEnd) { + if (run.UTF8start <= end && end < runEnd) { int cx = run.width; if (run.style !is null && run.style.metrics !is null) { GlyphMetrics metrics = run.style.metrics; - cx = metrics.width * (index8to16[end] - index8to16[run.start] + 1); + cx = metrics.width * (getUTF16index(end) - getUTF16index(run.UTF8start) + 1); } else if (!run.tab) { + UTF16index iCP = getUTF16index(end) - getUTF16index(run.UTF8start); + UTF16shift cChars = getUTF16length(run); int piX; int* advances = run.justify !is null ? run.justify : run.advances; - int wlength = index8to16[ run.start+run.length] - index8to16[run.start]; - OS.ScriptCPtoX(index8to16[end] - index8to16[run.start], true, wlength, run.glyphCount, run.clusters, run.visAttrs, advances, &run.analysis, &piX); + OS.ScriptCPtoX(iCP, true, cChars, run.glyphCount, run.clusters, run.visAttrs, advances, &run.analysis, &piX); cx = isRTL ? run.width - piX : piX; } if (run.analysis.fRTL ^ isRTL) { @@ -1490,7 +1514,7 @@ } } int lineIndex = 0; - while (lineIndex < runs.length && lineOffset[lineIndex + 1] <= run.start) { + while (lineIndex < runs.length && lineOffset[lineIndex + 1] <= run.UTF8start) { lineIndex++; } left = Math.min(left, runLead); @@ -1592,14 +1616,15 @@ * @exception SWTException <ul> * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> */ -public int getLevel (int offset) { +public int getLevel (int i_offset) { checkLayout(); computeRuns(null); + UTF8index offset = text.takeIndexArg(i_offset, "offset@getLevel"); int length = text.length; - if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); + if (!(0 <= offset.internalValue && offset.internalValue <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); offset = translateOffset(offset); for (int i=1; i<allRuns.length; i++) { - if (allRuns[i].start > offset) { + if (allRuns[i].UTF8start > offset) { return allRuns[i - 1].analysis.s.uBidiLevel; } } @@ -1691,11 +1716,12 @@ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> * </ul> */ -public int getLineIndex (int offset) { +public int getLineIndex (int i_offset) { checkLayout(); computeRuns(null); + UTF8index offset = text.takeIndexArg(i_offset, "offset@getLineIndex"); int length = text.length; - if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); + if (!(0 <= offset.internalValue && offset.internalValue <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); offset = translateOffset(offset); for (int line=0; line<runs.length; line++) { if (lineOffset[line + 1] > offset) { @@ -1789,12 +1815,13 @@ * @see #getOffset(Point, int[]) * @see #getOffset(int, int, int[]) */ -public Point getLocation (int offset, bool trailing) { +public Point getLocation (int i_offset, bool trailing) { checkLayout(); computeRuns(null); - int length = text.length; - if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); - length = segmentsText.length; + UTF8index offset = text.takeIndexArg(i_offset, "offset@getLocation"); + UTF8index length = text.endIndex(); + if (!(0 <= offset.internalValue && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); + length = segmentsText.endIndex(); offset = translateOffset(offset); int line; for (line=0; line<runs.length; line++) { @@ -1809,20 +1836,20 @@ while (high - low > 1) { int index = ((high + low) / 2); StyleItem run = allRuns[index]; - if (run.start > offset) { + if (run.UTF8start > offset) { high = index; - } else if (run.start + run.length <= offset) { + } else if (run.UTF8start + run.UTF8length <= offset) { low = index; } else { int width; if (run.style !is null && run.style.metrics !is null) { GlyphMetrics metrics = run.style.metrics; - width = metrics.width * (offset - run.start + (trailing ? 1 : 0)); + width = metrics.width * (getUTF16index(offset) - getUTF16index(run.UTF8start) + trailing); } else if (run.tab) { width = (trailing || (offset is length)) ? run.width : 0; } else { - int runOffset = index8to16[offset] - index8to16[run.start]; - int cChars = index8to16[run.start+run.length] - index8to16[run.start]; // make it wchar + UTF16index runOffset = getUTF16index(offset) - getUTF16index(run.UTF8start); + UTF16shift cChars = getUTF16length(run); // make it wchar int gGlyphs = run.glyphCount; int piX; int* advances = run.justify !is null ? run.justify : run.advances; @@ -1854,20 +1881,21 @@ * * @see #getPreviousOffset(int, int) */ -public int getNextOffset (int offset, int movement) { +public int getNextOffset (int i_offset, int movement) { checkLayout(); - return _getOffset (offset, movement, true); + return _getOffset (i_offset, movement, true); } -int _getOffset(int offset, int movement, bool forward) { +int _getOffset(int i_offset, int movement, bool forward) { computeRuns(null); - int length = text.length; - if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); - if (forward && offset is length) return length; - if (!forward && offset is 0) return 0; + UTF8index offset = text.takeIndexArg(i_offset, "offset@_getOffset"); + UTF8index length = text.endIndex(); + if (!(0 <= offset.internalValue && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); + if (forward && offset is length) return length.internalValue; + if (!forward && offset.internalValue is 0) return 0; int step = forward ? 1 : -1; - if ((movement & SWT.MOVEMENT_CHAR) !is 0) return offset + step; - length = segmentsText.length; + if ((movement & SWT.MOVEMENT_CHAR) !is 0) return (offset + text.toUTF8shift(offset, step)).internalValue; + length = segmentsText.endIndex(); offset = translateOffset(offset); SCRIPT_LOGATTR* logAttr; SCRIPT_PROPERTIES* properties; @@ -1875,15 +1903,15 @@ offset = validadeOffset(offset, step); do { StyleItem run = allRuns[i]; - if (run.start <= offset && offset < run.start + run.length) { - if (run.lineBreak && !run.softBreak) return untranslateOffset(run.start); - if (run.tab) return untranslateOffset(run.start); + if (run.UTF8start <= offset && offset < run.UTF8start + run.UTF8length) { + if (run.lineBreak && !run.softBreak) return untranslateOffset(run.UTF8start); + if (run.tab) return untranslateOffset(run.UTF8start); properties = device.scripts[run.analysis.eScript]; bool isComplex = properties.fNeedsCaretInfo || properties.fNeedsWordBreaking; if (isComplex) breakRun(run); - while (run.start <= offset && offset < run.start + run.length) { + while (run.UTF8start <= offset && offset < run.UTF8start + run.UTF8length) { if (isComplex) { - logAttr = run.psla + (index8to16[offset] - index8to16[run.start]); + logAttr = run.psla + (getUTF16index(offset) - getUTF16index(run.UTF8start)); } switch (movement) { case SWT.MOVEMENT_CLUSTER: { @@ -1899,11 +1927,11 @@ if (properties.fNeedsWordBreaking) { if (!logAttr.fInvalid && logAttr.fWordStop) return untranslateOffset(offset); } else { - if (offset > 0) { - bool letterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset)); - bool previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset - 1)); + if (offset.internalValue > 0) { + bool letterOrDigit = Compatibility.isLetterOrDigit(segmentsText.dcharAt(offset)); + bool previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.dcharBefore(offset)); if (letterOrDigit !is previousLetterOrDigit || !letterOrDigit) { - if (!Compatibility.isWhitespace(segmentsText[offset..$].firstCodePoint())) { + if (!Compatibility.isWhitespace(segmentsText.dcharAt(offset))) { return untranslateOffset(offset); } } @@ -1912,9 +1940,9 @@ break; } case SWT.MOVEMENT_WORD_END: { - if (offset > 0) { - bool isLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset)); - bool previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText[offset - 1.. $].firstCodePoint()); + if (offset.internalValue > 0) { + bool isLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.dcharAt(offset)); + bool previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.dcharBefore(offset)); if (!isLetterOrDigit && previousLetterOrDigit) { return untranslateOffset(offset); } @@ -1927,7 +1955,7 @@ } } i += step; - } while (0 <= i && i < allRuns.length - 1 && 0 <= offset && offset < length); + } while (0 <= i && i < allRuns.length - 1 && 0 <= offset.internalValue && offset < length); return forward ? text.length : 0; } @@ -2008,35 +2036,38 @@ } else if (run.x + run.width <= x) { low = index; } else { - if (run.lineBreak && !run.softBreak) return untranslateOffset(run.start); + if (run.lineBreak && !run.softBreak) return untranslateOffset(run.UTF8start); int xRun = x - run.x; if (run.style !is null && run.style.metrics !is null) { GlyphMetrics metrics = run.style.metrics; if (metrics.width > 0) { + UTF8index res = addUTF16shift(run.UTF8start, cast(UTF16shift)(xRun / metrics.width)); if (trailing !is null) { - trailing[0] = (xRun % metrics.width < metrics.width / 2) ? 0 : 1; + trailing[0] = (xRun % metrics.width < metrics.width / 2) ? 0 : segmentsText.UTF8strideAt(res).internalValue; } - return untranslateOffset(run.start + xRun / metrics.width); + return untranslateOffset(res); } } if (run.tab) { - if (trailing !is null) trailing[0] = x < (run.x + run.width / 2) ? 0 : 1; - return untranslateOffset(run.start); + UTF8index res = run.UTF8start; + if (trailing !is null) trailing[0] = x < (run.x + run.width / 2) ? 0 : segmentsText.UTF8strideAt(res).internalValue; + return untranslateOffset(res); } - int cChars = index8to16[run.start+run.length] - index8to16[run.start]; // make it wchar + UTF16shift cChars = getUTF16length(run); // make it wchar int cGlyphs = run.glyphCount; - int piCP; - int piTrailing; + UTF16shift piCP; + UTF16shift piTrailing; if ((orientation & SWT.RIGHT_TO_LEFT) !is 0) { xRun = run.width - xRun; } int* advances = run.justify !is null ? run.justify : run.advances; OS.ScriptXtoCP(xRun, cChars, cGlyphs, run.clusters, run.visAttrs, advances, &run.analysis, &piCP, &piTrailing); - if (trailing !is null) trailing[0] = piTrailing; - - // SWT: back from codepoints to utf8 index - int offsetIndex = segmentsText[ run.start .. $ ].codepointIndexToIndex( piCP ); - return untranslateOffset(run.start + offsetIndex); + + // DWT: back from UTF-16 to UTF-8 + UTF8index res = addUTF16shift(run.UTF8start, piCP); + if (trailing !is null) + trailing[0] = (addUTF16shift(res, piTrailing) - res).internalValue; + return untranslateOffset(res); } } if (trailing !is null) trailing[0] = 0; @@ -2076,9 +2107,9 @@ * * @see #getNextOffset(int, int) */ -public int getPreviousOffset (int offset, int movement) { +public int getPreviousOffset (int i_offset, int movement) { checkLayout(); - return _getOffset (offset, movement, false); + return _getOffset (i_offset, movement, false); } /** @@ -2101,8 +2132,8 @@ int count = 0; for (int i=0; i<stylesCount - 1; i++) { if (styles[i].style !is null) { - result[count++] = styles[i].start; - result[count++] = styles[i + 1].start - 1; + result[count++] = styles[i].UTF8start.internalValue; + result[count++] = getUTF8index(cast(UTF16index)(getUTF16index(styles[i + 1].UTF8start) - 1)).internalValue; } } if (count !is result.length) { @@ -2124,28 +2155,30 @@ */ public int[] getSegments () { checkLayout(); - return segments; + return cast(int[])segments; } void getSegmentsText( out String resUtf8, out String16 resUtf16 ) { void buildIndexTables() { // build the index translation tables. + index16to8.length = resUtf16.length + 1; index8to16.length = resUtf8.length + 1; - index16to8.length = resUtf16.length + 1; + index16to8[] = resUtf8.preFirstIndex(); + index8to16[] = -1; - int idx8, idx16; - while( idx8 < resUtf8.length ){ - int ate8, ate16; - dchar d8 = resUtf8[ idx8 .. $ ].firstCodePoint( ate8 ); - dchar d16 = resUtf16[ idx16 .. $ ].firstCodePoint( ate16 ); - assert( d8 is d16 ); - index16to8[ idx16 .. idx16 +ate16 ] = idx8; - index8to16[ idx8 .. idx8 +ate8 ] = idx16; - idx8 += ate8; - idx16 += ate16; + UTF8index idx8; + UTF16index idx16; + for(;;) { + index16to8[ idx16 ] = idx8; + index8to16[ idx8.internalValue ] = idx16; + if(idx8 == resUtf8.endIndex()) { + assert(idx16 == resUtf16.length); + break; + } + assert(resUtf8.dcharAt(idx8) == resUtf16.dcharAt(idx16)); + idx8 += resUtf8.UTF8strideAt(idx8); + idx16 += resUtf16.UTF16strideAt(idx16); } - index16to8[ resUtf16.length ] = resUtf8.length; - index8to16[ resUtf8.length ] = resUtf16.length; } if (segments is null) { @@ -2170,7 +2203,7 @@ return; } if (nSegments is 2) { - if (segments[0] is 0 && segments[1] is length_) { + if (segments[0].internalValue is 0 && segments[1].internalValue is length_) { resUtf8 = text; resUtf16 = wtext; buildIndexTables(); @@ -2179,29 +2212,28 @@ } { auto oldChars = text; - // SWT: MARK is now 3 chars long + // DWT: MARK is now 3 chars long String separator = orientation is SWT.RIGHT_TO_LEFT ? STR_RTL_MARK : STR_LTR_MARK; - assert( separator.length is MARK_SIZE ); - char[] newChars = new char[length_ + nSegments*MARK_SIZE]; + char[] newChars = new char[length_ + nSegments*MARK_SIZE.internalValue]; int charCount = 0, segmentCount = 0; while (charCount < length_) { - if (segmentCount < nSegments && charCount is segments[segmentCount]) { - int start = charCount + (segmentCount*MARK_SIZE); - newChars[ start .. start + MARK_SIZE ] = separator; + if (segmentCount < nSegments && charCount is segments[segmentCount].internalValue) { + int start = charCount + (segmentCount*MARK_SIZE.internalValue); + newChars[ start .. start + MARK_SIZE.internalValue ] = separator; segmentCount++; } else { - newChars[charCount + (segmentCount*MARK_SIZE)] = oldChars[charCount]; + newChars[charCount + (segmentCount*MARK_SIZE.internalValue)] = oldChars[charCount]; charCount++; } } if (segmentCount < nSegments) { - segments[segmentCount] = charCount; - int start = charCount + (segmentCount*MARK_SIZE); - newChars[ start .. start + MARK_SIZE ] = separator; + segments[segmentCount] = asUTF8index( charCount ); + int start = charCount + (segmentCount*MARK_SIZE.internalValue); + newChars[ start .. start + MARK_SIZE.internalValue ] = separator; segmentCount++; } - resUtf8 = cast(String)newChars[ 0 .. Math.min(charCount + (segmentCount*MARK_SIZE), newChars.length)]; + resUtf8 = cast(String)newChars[ 0 .. Math.min(charCount + (segmentCount*MARK_SIZE.internalValue), newChars.length)]; } // now for the wide chars { @@ -2222,7 +2254,7 @@ } } if (segmentCount < nSegments) { - wsegments[segmentCount] = charCount; + wsegments[segmentCount] = cast(UTF16index) charCount; int start = charCount + (segmentCount*WMARK_SIZE); newWChars[ start .. start + WMARK_SIZE ] = wseparator; segmentCount++; @@ -2259,12 +2291,13 @@ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> * </ul> */ -public TextStyle getStyle (int offset) { +public TextStyle getStyle (int i_offset) { checkLayout(); + UTF8index offset = text.takeIndexArg(i_offset, "offset@getStyle"); int length = text.length; - if (!(0 <= offset && offset < length)) SWT.error(SWT.ERROR_INVALID_RANGE); + if (!(0 <= offset.internalValue && offset.internalValue < length)) SWT.error(SWT.ERROR_INVALID_RANGE); for (int i=1; i<stylesCount; i++) { - if (styles[i].start > offset) { + if (styles[i].UTF8start > offset) { return styles[i - 1].style; } } @@ -2363,7 +2396,7 @@ * Itemize the receiver text */ StyleItem[] itemize () { - // SWT: itemize is the process of finding changes in direction + // DWT: itemize is the process of finding changes in direction getSegmentsText(segmentsText, segmentsWText ); int length = segmentsText.length; SCRIPT_CONTROL scriptControl; @@ -2379,11 +2412,11 @@ } auto hHeap = OS.GetProcessHeap(); - auto pItems = cast(SCRIPT_ITEM*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, MAX_ITEM * SCRIPT_ITEM.sizeof); + auto pItems = cast(SCRIPT_ITEM*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, MAX_ITEM * SCRIPT_ITEM.sizeof + 1); if (pItems is null) SWT.error(SWT.ERROR_NO_HANDLES); int pcItems; - String16 chars = segmentsWText; - OS.ScriptItemize(chars.ptr, chars.length, MAX_ITEM, &scriptControl, &scriptState, pItems, &pcItems); + String16 wchars = segmentsWText; + OS.ScriptItemize(wchars.ptr, wchars.length, MAX_ITEM, &scriptControl, &scriptState, pItems, &pcItems); // if (hr is E_OUTOFMEMORY) //TODO handle it // SWT pcItems is not inclusive the trailing item @@ -2401,13 +2434,14 @@ System.arraycopy(styles, 0, newStyles, 0, stylesCount); styles = newStyles; } - int count = 0, start = 0, end = segmentsText.length, itemIndex = 0, styleIndex = 0; + int count = 0, itemIndex = 0, styleIndex = 0; + UTF8index start = segmentsText.firstIndex(), end = segmentsText.endIndex(); StyleItem[] runs = new StyleItem[itemCount + stylesCount]; SCRIPT_ITEM* scriptItem; bool linkBefore = false; while (start < end) { StyleItem item = new StyleItem(); - item.start = start; + item.UTF8start = start; item.style = styles[styleIndex].style; runs[count++] = item; scriptItem = items + itemIndex; @@ -2418,14 +2452,14 @@ } //scriptItem.a = new SCRIPT_ANALYSIS(); scriptItem = items + (itemIndex + 1); - int itemLimit = index16to8[scriptItem.iCharPos]; - int styleLimit = translateOffset(styles[styleIndex + 1].start); + UTF8index itemLimit = getUTF8index(scriptItem.iCharPos); + UTF8index styleLimit = translateOffset(styles[styleIndex + 1].UTF8start); if (styleLimit <= itemLimit) { styleIndex++; start = styleLimit; - if (start < itemLimit && 0 < start && start < end) { - dchar pChar = segmentsText[ segmentsText.getAbsoluteCodePointOffset(start, -1) ..$].firstCodePoint(); - dchar tChar = segmentsText[start ..$].firstCodePoint(); + if (start < itemLimit && 0 < start.internalValue && start < end) { + dchar pChar = segmentsText.dcharBefore(start); + dchar tChar = segmentsText.dcharAt(start); if (Compatibility.isLetter(pChar) && Compatibility.isLetter(tChar)) { item.analysis.fLinkAfter = true; linkBefore = true; @@ -2436,10 +2470,10 @@ itemIndex++; start = itemLimit; } - item.length = start - item.start; + item.UTF8length = start - item.UTF8start; } StyleItem item = new StyleItem(); - item.start = end; + item.UTF8start = end; scriptItem = items + itemCount; item.analysis = scriptItem.a; runs[count++] = item; @@ -2674,41 +2708,35 @@ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> * </ul> */ -public void setSegments(int[] segments) { +public void setSegments(int[] i_segments) { checkLayout(); - if (this.segments is null && segments is null) return; - if (this.segments !is null && segments !is null) { - if (this.segments.length is segments.length) { + if (this.segments is null && i_segments is null) return; + if (this.segments !is null && i_segments !is null) + if (this.segments.length is i_segments.length) { int i; - for (i = 0; i <segments.length; i++) { - if (this.segments[i] !is segments[i]) break; + for (i = 0; i <i_segments.length; i++) { + if (this.segments[i] !is text.takeIndexArg(i_segments[i], "segments@setSegments")) break; } - if (i is segments.length) return; + if (i is i_segments.length) return; } - } freeRuns(); - this.segments = segments.dup; + this.segments.length = i_segments.length; + foreach(i, ref s; this.segments) + s = text.takeIndexArg(i_segments[i], "segments@setSegments"); - // SWT: create the wsegments ... - this.wsegments.length = segments.length; - uint index8, index16; - uint segIndex = 1; - while(index8 < text.length ){ - int ate8; - int ate16; - dchar d8 = text[ index8 .. $ ].firstCodePoint( ate8 ); - dchar d16 = wtext[ index16 .. $ ].firstCodePoint( ate16 ); - assert( d8 is d16 ); - assert( ate8 > 0 ); - assert( ate16 > 0 ); - index8 += ate8; - index16 += ate16; - if( segments[segIndex] is index8 ){ - wsegments[segIndex] = index16; + // DWT: create the wsegments ... + this.wsegments.length = this.segments.length; + UTF8index idx8; + UTF16index idx16; + foreach(i, ref wsegment; this.wsegments) { + while( this.segments[i] != idx8 ) { + assert(text.dcharAt(idx8) == wtext.dcharAt(idx16)); + idx8 += text.UTF8strideAt(idx8); + idx16 += wtext.UTF16strideAt(idx16); + assert(idx8 <= this.segments[i]); } + wsegment = idx16; } - assert( index16 is wtext.length ); - assert( segIndex is segments.length ); } /** @@ -2745,18 +2773,21 @@ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> * </ul> */ -public void setStyle (TextStyle style, int start, int end) { +public void setStyle (TextStyle style, int i_start, int i_end) { checkLayout(); + UTF8index start = text.takeIndexArg(i_start, "start@setStyle"); + UTF8index end = text.takeIndexArg(i_end, "end@setStyle"); int length = text.length; if (length is 0) return; + UTF8index endOffset = text.beforeEndIndex(); if (start > end) return; - start = Math.min(Math.max(0, start), length - 1); - end = Math.min(Math.max(0, end), length - 1); + start = Math.min(Math.max(text.firstIndex(), start), endOffset); + end = Math.min(Math.max(text.firstIndex(), end), endOffset); int low = -1; int high = stylesCount; while (high - low > 1) { int index = (high + low) / 2; - if (styles[index + 1].start > start) { + if (styles[index + 1].UTF8start > start) { high = index; } else { low = index; @@ -2764,7 +2795,7 @@ } if (0 <= high && high < stylesCount) { StyleItem item = styles[high]; - if (item.start is start && styles[high + 1].start - 1 is end) { + if (item.UTF8start is start && text.offsetBefore(styles[high + 1].UTF8start) is end) { if (style is null) { if (item.style is null) return; } else { @@ -2776,12 +2807,12 @@ int modifyStart = high; int modifyEnd = modifyStart; while (modifyEnd < stylesCount) { - if (styles[modifyEnd + 1].start > end) break; + if (styles[modifyEnd + 1].UTF8start > end) break; modifyEnd++; } if (modifyStart is modifyEnd) { - int styleStart = styles[modifyStart].start; - int styleEnd = styles[modifyEnd + 1].start - 1; + UTF8index styleStart = styles[modifyStart].UTF8start; + UTF8index styleEnd = text.offsetBefore(styles[modifyEnd + 1].UTF8start); if (styleStart is start && styleEnd is end) { styles[modifyStart].style = style; return; @@ -2796,19 +2827,19 @@ } System.arraycopy(styles, modifyEnd + 1, styles, modifyEnd + 3, stylesCount - modifyEnd - 1); StyleItem item = new StyleItem(); - item.start = start; + item.UTF8start = start; item.style = style; styles[modifyStart + 1] = item; item = new StyleItem(); - item.start = end + 1; + item.UTF8start = text.offsetAfter(end); item.style = styles[modifyStart].style; styles[modifyStart + 2] = item; stylesCount = newLength; return; } } - if (start is styles[modifyStart].start) modifyStart--; - if (end is styles[modifyEnd + 1].start - 1) modifyEnd++; + if (start is styles[modifyStart].UTF8start) modifyStart--; + if (end is text.offsetBefore(styles[modifyEnd + 1].UTF8start)) modifyEnd++; int newLength = stylesCount + 1 - (modifyEnd - modifyStart - 1); if (newLength > styles.length) { int newSize = Math.min(newLength + 1024, Math.max(64, newLength * 2)); @@ -2818,10 +2849,10 @@ } System.arraycopy(styles, modifyEnd, styles, modifyStart + 2, stylesCount - modifyEnd); StyleItem item = new StyleItem(); - item.start = start; + item.UTF8start = start; item.style = style; styles[modifyStart + 1] = item; - styles[modifyStart + 2].start = end + 1; + styles[modifyStart + 2].UTF8start = text.offsetAfter(end); stylesCount = newLength; } @@ -2876,7 +2907,7 @@ styles = new StyleItem[2]; styles[0] = new StyleItem(); styles[1] = new StyleItem(); - styles[1].start = text.length; + styles[1].UTF8start = text.endIndex(); stylesCount = 2; } @@ -2949,7 +2980,7 @@ */ void shape (HDC hdc, StyleItem run) { int[1] buffer; - auto wchars = segmentsWText[ index8to16[ run.start ] .. index8to16[ run.start + run.length ] ]; + auto wchars = segmentsWText[ getUTF16index(run.UTF8start) .. getUTF16index(run.UTF8start + run.UTF8length) ]; int maxGlyphs = (wchars.length * 3 / 2) + 16; auto hHeap = OS.GetProcessHeap(); run.glyphs = cast(ushort*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, maxGlyphs * 2); @@ -2963,7 +2994,7 @@ short script = cast(short) run.analysis.eScript; SCRIPT_PROPERTIES sp = *device.scripts[script]; bool shapeSucceed = shape(hdc, run, wchars, buffer, maxGlyphs, &sp); -int res; + int res; if (!shapeSucceed) { auto hFont = OS.GetCurrentObject(hdc, OS.OBJ_FONT); auto ssa = cast(SCRIPT_STRING_ANALYSIS*) OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, SCRIPT_STRING_ANALYSIS.sizeof); @@ -3110,18 +3141,34 @@ } } -int validadeOffset(int offset, int step) { - offset = segmentsText.toAbsoluteCodePointStartOffset( offset ); - offset += segmentsText.getRelativeCodePointOffset( offset, step ); - if (segments !is null && segments.length > 2) { - for (int i = 0; i < segments.length; i++) { - if (translateOffset(segments[i]) - 1 is offset) { - offset += step; - break; - } - } - } - return offset; +UTF8index getUTF8index(UTF16index i) +out(res) { + assert(res != segmentsText.preFirstIndex()); +} +body { + return index16to8[i]; +} + +UTF16index getUTF16index(UTF8index i) +out(res) { + assert(res != -1); +} +body { + return index8to16[i.internalValue]; +} + +UTF8index addUTF16shift(UTF8index i, UTF16shift dw) { + return getUTF8index(cast(UTF16index)(getUTF16index(i) + dw)); +} + +UTF16shift getUTF16length(StyleItem run) { + return cast(UTF16shift)(getUTF16index(run.UTF8start + run.UTF8length) - getUTF16index(run.UTF8start)); +} + +UTF8index validadeOffset(UTF8index offset, UCSindex step) { + offset = asUTF8index( untranslateOffset(offset) ); + offset += text.toUTF8shift(offset, step); + return translateOffset(offset); } /** @@ -3135,33 +3182,33 @@ return "TextLayout {}"; } -int translateOffset(int offset) { +UTF8index translateOffset(UTF8index offset) { if (segments is null) return offset; int nSegments = segments.length; if (nSegments <= 1) return offset; int length = text.length; if (length is 0) return offset; if (nSegments is 2) { - if (segments[0] is 0 && segments[1] is length) return offset; + if (segments[0].internalValue is 0 && segments[1].internalValue is length) return offset; } - for (int i = 0; i < nSegments && offset - i >= segments[i]; i++) { + for (int i = 0; i < nSegments && offset.internalValue - i >= segments[i].internalValue; i++) { offset+=MARK_SIZE; } return offset; } -int untranslateOffset(int offset) { - if (segments is null) return offset; +int untranslateOffset(UTF8index offset) { + if (segments is null) return offset.internalValue; int nSegments = segments.length; - if (nSegments <= 1) return offset; + if (nSegments <= 1) return offset.internalValue; int length = text.length; - if (length is 0) return offset; + if (length is 0) return offset.internalValue; if (nSegments is 2) { - if (segments[0] is 0 && segments[1] is length) return offset; + if (segments[0].internalValue is 0 && segments[1].internalValue is length) return offset.internalValue; } for (int i = 0; i < nSegments && offset > segments[i]; i++) { offset-=MARK_SIZE; } - return offset; + return offset.internalValue; } }