org.eclipse.swt.graphics.TextLayout Maven / Gradle / Ivy
/******************************************************************************* * Copyright (c) 2000, 2014 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.graphics; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.gdip.*; import org.eclipse.swt.internal.win32.*; import org.eclipse.swt.*; /** *
,TextLayout
is a graphic object that represents * styled text. ** Instances of this class provide support for drawing, cursor * navigation, hit testing, text wrapping, alignment, tab expansion * line breaking, etc. These are aspects required for rendering internationalized text. *
* Application code must explicitly invoke the
* * @see TextLayout, TextStyle snippets * @see SWT Example: CustomControlExample, StyledText tab * @see Sample code and further information * * @since 3.0 */ public final class TextLayout extends Resource { Font font; String text, segmentsText; int lineSpacing; int ascent, descent; int alignment; int wrapWidth; int orientation; int textDirection; int indent; int wrapIndent; boolean justify; int[] tabs; int[] segments; char[] segmentsChars; StyleItem[] styles; int stylesCount; StyleItem[] allRuns; StyleItem[][] runs; int[] lineOffset, lineY, lineWidth; int /*long*/ mLangFontLink2; static final char LTR_MARK = '\u200E', RTL_MARK = '\u200F'; static final int SCRIPT_VISATTR_SIZEOF = 2; static final int GOFFSET_SIZEOF = 8; static final byte[] CLSID_CMultiLanguage = new byte[16]; static final byte[] IID_IMLangFontLink2 = new byte[16]; static { OS.IIDFromString("{275c23e2-3747-11d0-9fea-00aa003f8646}\0".toCharArray(), CLSID_CMultiLanguage); OS.IIDFromString("{DCCFC162-2B38-11d2-B7EC-00C04F8F5D9A}\0".toCharArray(), IID_IMLangFontLink2); } static final int MERGE_MAX = 512; static final int TOO_MANY_RUNS = 1024; /* IME has a copy of these constants */ static final int UNDERLINE_IME_DOT = 1 << 16; static final int UNDERLINE_IME_DASH = 2 << 16; static final int UNDERLINE_IME_THICK = 3 << 16; class StyleItem { TextStyle style; int start, length; boolean lineBreak, softBreak, tab; /*Script cache and analysis */ SCRIPT_ANALYSIS analysis; int /*long*/ psc = 0; /*Shape info (malloc when the run is shaped) */ int /*long*/ glyphs; int glyphCount; int /*long*/ clusters; int /*long*/ visAttrs; /*Place info (malloc when the run is placed) */ int /*long*/ advances; int /*long*/ goffsets; int width; int ascent; int descent; int leading; int x; int underlinePos, underlineThickness; int strikeoutPos, strikeoutThickness; /* Justify info (malloc during computeRuns) */ int /*long*/ justify; /* ScriptBreak */ int /*long*/ psla; int /*long*/ fallbackFont; void free() { int /*long*/ hHeap = OS.GetProcessHeap(); if (psc != 0) { OS.ScriptFreeCache (psc); OS.HeapFree(hHeap, 0, psc); psc = 0; } if (glyphs != 0) { OS.HeapFree(hHeap, 0, glyphs); glyphs = 0; glyphCount = 0; } if (clusters != 0) { OS.HeapFree(hHeap, 0, clusters); clusters = 0; } if (visAttrs != 0) { OS.HeapFree(hHeap, 0, visAttrs); visAttrs = 0; } if (advances != 0) { OS.HeapFree(hHeap, 0, advances); advances = 0; } if (goffsets != 0) { OS.HeapFree(hHeap, 0, goffsets); goffsets = 0; } if (justify != 0) { OS.HeapFree(hHeap, 0, justify); justify = 0; } if (psla != 0) { OS.HeapFree(hHeap, 0, psla); psla = 0; } if (fallbackFont != 0) { OS.DeleteObject(fallbackFont); fallbackFont = 0; } width = ascent = descent = x = 0; lineBreak = softBreak = false; } public String toString () { return "StyleItem {" + start + ", " + style + "}"; } } /** * Constructs a new instance of this class on the given device. *TextLayout#dispose()
* method to release the operating system resources managed by each instance * when those instances are no longer required. ** You must dispose the text layout when it is no longer required. *
* * @param device the device on which to allocate the text layout * * @exception IllegalArgumentException*
* * @see #dispose() */ public TextLayout (Device device) { super(device); wrapWidth = ascent = descent = -1; lineSpacing = 0; orientation = SWT.LEFT_TO_RIGHT; textDirection = SWT.LEFT_TO_RIGHT; styles = new StyleItem[2]; styles[0] = new StyleItem(); styles[1] = new StyleItem(); stylesCount = 2; text = ""; //$NON-NLS-1$ int /*long*/[] ppv = new int /*long*/[1]; OS.OleInitialize(0); if (OS.CoCreateInstance(CLSID_CMultiLanguage, 0, OS.CLSCTX_INPROC_SERVER, IID_IMLangFontLink2, ppv) == OS.S_OK) { mLangFontLink2 = ppv[0]; } init(); } RECT addClipRect(StyleItem run, RECT clipRect, RECT rect, int selectionStart, int selectionEnd) { if (rect != null) { if (clipRect == null) { clipRect = new RECT (); OS.SetRect(clipRect, -1, rect.top, -1, rect.bottom); } boolean isRTL = (orientation & SWT.RIGHT_TO_LEFT) != 0; if (run.start <= selectionStart && selectionStart <= run.start + run.length) { 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.analysis.fRTL ^ isRTL) { clipRect.left = rect.right; } else { clipRect.right = rect.right; } } } return clipRect; } void breakRun(StyleItem run) { if (run.psla != 0) return; char[] chars = new char[run.length]; segmentsText.getChars(run.start, run.start + run.length, chars, 0); int /*long*/ hHeap = OS.GetProcessHeap(); run.psla = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, SCRIPT_LOGATTR.sizeof * chars.length); if (run.psla == 0) SWT.error(SWT.ERROR_NO_HANDLES); OS.ScriptBreak(chars, chars.length, run.analysis, run.psla); } void checkLayout () { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); } /* * Compute the runs: itemize, shape, place, and reorder the runs. * Break paragraphs into lines, wraps the text, and initialize caches. */ void computeRuns (GC gc) { if (runs != null) return; int /*long*/ hDC = gc != null ? gc.handle : device.internal_new_GC(null); int /*long*/ srcHdc = OS.CreateCompatibleDC(hDC); allRuns = itemize(); for (int i=0; i- ERROR_NULL_ARGUMENT - if device is null and there is no current device
*lineWidth) { run.width = tabs[j] - lineWidth; break; } } if (j == tabsLength) { int tabX = tabs[tabsLength-1]; int lastTabWidth = tabsLength > 1 ? tabs[tabsLength-1] - tabs[tabsLength-2] : tabs[0]; if (lastTabWidth > 0) { while (tabX <= lineWidth) tabX += lastTabWidth; run.width = tabX - lineWidth; } } int length = run.length; if (length > 1) { int stop = j + length - 1; if (stop < tabsLength) { run.width += tabs[stop] - tabs[j]; } else { if (j < tabsLength) { run.width += tabs[tabsLength - 1] - tabs[j]; length -= (tabsLength - 1) - j; } int lastTabWidth = tabsLength > 1 ? tabs[tabsLength-1] - tabs[tabsLength-2] : tabs[0]; run.width += lastTabWidth * (length - 1); } } } if (wrapWidth != -1 && lineWidth + run.width > wrapWidth && !run.tab && !run.lineBreak) { int start = 0; int[] piDx = new int[run.length]; if (run.style != null && run.style.metrics != null) { piDx[0] = run.width; } else { OS.ScriptGetLogicalWidths(run.analysis, run.length, run.glyphCount, run.advances, run.clusters, run.visAttrs, piDx); } int width = 0, maxWidth = wrapWidth - lineWidth; while (width + piDx[start] < maxWidth) { width += piDx[start++]; } int firstStart = start; int firstIndice = i; while (i >= lineStart) { breakRun(run); while (start >= 0) { OS.MoveMemory(logAttr, run.psla + (start * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof); if (logAttr.fSoftBreak || logAttr.fWhiteSpace) break; start--; } /* * Bug in Windows. For some reason Uniscribe sets the fSoftBreak flag for the first letter * 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 == 0 && i != lineStart && !run.tab) { if (logAttr.fSoftBreak && !logAttr.fWhiteSpace) { OS.MoveMemory(properties, device.scripts[run.analysis.eScript], SCRIPT_PROPERTIES.sizeof); int langID = properties.langid; StyleItem pRun = allRuns[i - 1]; OS.MoveMemory(properties, device.scripts[pRun.analysis.eScript], SCRIPT_PROPERTIES.sizeof); if (properties.langid == langID || langID == OS.LANG_NEUTRAL || properties.langid == OS.LANG_NEUTRAL) { breakRun(pRun); OS.MoveMemory(logAttr, pRun.psla + ((pRun.length - 1) * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof); if (!logAttr.fWhiteSpace) start = -1; } } } if (start >= 0 || i == lineStart) break; run = allRuns[--i]; start = run.length - 1; } boolean wrapEntireRun = start == 0 && i != lineStart && !run.tab; if (wrapEntireRun) { breakRun(run); OS.MoveMemory(logAttr, run.psla + (start * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof); wrapEntireRun = !logAttr.fWhiteSpace; } if (wrapEntireRun) { run = allRuns[--i]; start = run.length; } else if (start <= 0 && i == lineStart) { if (lineWidth == wrapWidth && firstIndice > 0) { i = firstIndice - 1; run = allRuns[i]; start = run.length; } else { i = firstIndice; run = allRuns[i]; start = Math.max(1, firstStart); } } breakRun(run); while (start < run.length) { OS.MoveMemory(logAttr, run.psla + (start * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof); if (!logAttr.fWhiteSpace) break; start++; } if (0 < start && start < run.length) { StyleItem newRun = new StyleItem(); newRun.start = run.start + start; newRun.length = run.length - start; newRun.style = run.style; newRun.analysis = cloneScriptAnalysis(run.analysis); run.free(); run.length = start; OS.SelectObject(srcHdc, getItemFont(run)); run.analysis.fNoGlyphIndex = false; shape (srcHdc, run); OS.SelectObject(srcHdc, getItemFont(newRun)); newRun.analysis.fNoGlyphIndex = false; shape (srcHdc, newRun); StyleItem[] newAllRuns = new StyleItem[allRuns.length + 1]; System.arraycopy(allRuns, 0, newAllRuns, 0, i + 1); System.arraycopy(allRuns, i + 1, newAllRuns, i + 2, allRuns.length - i - 1); allRuns = newAllRuns; allRuns[i + 1] = newRun; } if (i != allRuns.length - 2) { run.softBreak = run.lineBreak = true; } } lineWidth += run.width; if (run.lineBreak) { lineStart = i + 1; lineWidth = run.softBreak ? wrapIndent : indent; lineCount++; } } lineWidth = 0; runs = new StyleItem[lineCount][]; lineOffset = new int[lineCount + 1]; lineY = new int[lineCount + 1]; this.lineWidth = new int[lineCount]; int lineRunCount = 0, line = 0; int ascent = Math.max(0, this.ascent); int descent = Math.max(0, this.descent); StyleItem[] lineRuns = new StyleItem[allRuns.length]; for (int i=0; i 0) { int lineIndent = wrapIndent; if (line == 0) { lineIndent = indent; } else { StyleItem[] previousLine = runs[line - 1]; StyleItem previousRun = previousLine[previousLine.length - 1]; if (previousRun.lineBreak && !previousRun.softBreak) { lineIndent = indent; } } lineWidth += lineIndent; int /*long*/ hHeap = OS.GetProcessHeap(); int newLineWidth = 0; for (int j = 0; j < runs[line].length; j++) { StyleItem item = runs[line][j]; int iDx = item.width * wrapWidth / lineWidth; if (iDx != item.width) { item.justify = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, item.glyphCount * 4); if (item.justify == 0) SWT.error(SWT.ERROR_NO_HANDLES); OS.ScriptJustify(item.visAttrs, item.advances, item.glyphCount, iDx - item.width, 2, item.justify); item.width = iDx; } newLineWidth += item.width; } lineWidth = newLineWidth; } this.lineWidth[line] = lineWidth; StyleItem lastRun = runs[line][lineRunCount - 1]; int lastOffset = lastRun.start + lastRun.length; runs[line] = reorder(runs[line], i == allRuns.length - 1); lastRun = runs[line][lineRunCount - 1]; if (run.softBreak && run != lastRun) { run.softBreak = run.lineBreak = false; lastRun.softBreak = lastRun.lineBreak = true; } lineWidth = getLineIndent(line); for (int j = 0; j < runs[line].length; j++) { runs[line][j].x = lineWidth; lineWidth += runs[line][j].width; } line++; lineY[line] = lineY[line - 1] + ascent + descent + lineSpacing; lineOffset[line] = lastOffset; lineRunCount = lineWidth = 0; ascent = Math.max(0, this.ascent); descent = Math.max(0, this.descent); } } if (srcHdc != 0) OS.DeleteDC(srcHdc); if (gc == null) device.internal_dispose_GC(hDC, null); } void destroy () { freeRuns(); font = null; text = null; segmentsText = null; tabs = null; styles = null; runs = null; lineOffset = null; lineY = null; lineWidth = null; segments = null; segmentsChars = null; if (mLangFontLink2 != 0) { /* Release() */ OS.VtblCall(2, mLangFontLink2); mLangFontLink2 = 0; } OS.OleUninitialize(); } SCRIPT_ANALYSIS cloneScriptAnalysis (SCRIPT_ANALYSIS src) { SCRIPT_ANALYSIS dst = new SCRIPT_ANALYSIS(); dst.eScript = src.eScript; dst.fRTL = src.fRTL; dst.fLayoutRTL = src.fLayoutRTL; dst.fLinkBefore = src.fLinkBefore; dst.fLinkAfter = src.fLinkAfter; dst.fLogicalOrder = src.fLogicalOrder; dst.fNoGlyphIndex = src.fNoGlyphIndex; dst.s = new SCRIPT_STATE(); dst.s.uBidiLevel = src.s.uBidiLevel; dst.s.fOverrideDirection = src.s.fOverrideDirection; dst.s.fInhibitSymSwap = src.s.fInhibitSymSwap; dst.s.fCharShape = src.s.fCharShape; dst.s.fDigitSubstitute = src.s.fDigitSubstitute; dst.s.fInhibitLigate = src.s.fInhibitLigate; dst.s.fDisplayZWG = src.s.fDisplayZWG; dst.s.fArabicNumContext = src.s.fArabicNumContext; dst.s.fGcpClusters = src.s.fGcpClusters; dst.s.fReserved = src.s.fReserved; dst.s.fEngineReserved = src.s.fEngineReserved; return dst; } int[] computePolyline(int left, int top, int right, int bottom) { int height = bottom - top; // can be any number int width = 2 * height; // must be even int peaks = Compatibility.ceil(right - left, width); if (peaks == 0 && right - left > 2) { peaks = 1; } int length = ((2 * peaks) + 1) * 2; if (length < 0) return new int[0]; int[] coordinates = new int[length]; for (int i = 0; i < peaks; i++) { int index = 4 * i; coordinates[index] = left + (width * i); coordinates[index+1] = bottom; coordinates[index+2] = coordinates[index] + width / 2; coordinates[index+3] = top; } coordinates[length-2] = left + (width * peaks); coordinates[length-1] = bottom; return coordinates; } int /*long*/ createGdipBrush(int pixel, int alpha) { int argb = ((alpha & 0xFF) << 24) | ((pixel >> 16) & 0xFF) | (pixel & 0xFF00) | ((pixel & 0xFF) << 16); int /*long*/ gdiColor = Gdip.Color_new(argb); int /*long*/ brush = Gdip.SolidBrush_new(gdiColor); Gdip.Color_delete(gdiColor); return brush; } int /*long*/ createGdipBrush(Color color, int alpha) { return createGdipBrush(color.handle, alpha); } /** * Draws the receiver's text using the specified GC at the specified * point. * * @param gc the GC to draw * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn * * @exception SWTException *
* @exception IllegalArgumentException- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed
**
*/ public void draw (GC gc, int x, int y) { draw(gc, x, y, -1, -1, null, null); } /** * Draws the receiver's text using the specified GC at the specified * point. * * @param gc the GC to draw * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn * @param selectionStart the offset where the selections starts, or -1 indicating no selection * @param selectionEnd the offset where the selections ends, or -1 indicating no selection * @param selectionForeground selection foreground, or NULL to use the system default color * @param selectionBackground selection background, or NULL to use the system default color * * @exception SWTException- ERROR_NULL_ARGUMENT - if the gc is null
**
* @exception IllegalArgumentException- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed
**
*/ 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); } /** * Draws the receiver's text using the specified GC at the specified * point. *- ERROR_NULL_ARGUMENT - if the gc is null
** The parameter
* @param gc the GC to draw * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn * @param selectionStart the offset where the selections starts, or -1 indicating no selection * @param selectionEnd the offset where the selections ends, or -1 indicating no selection * @param selectionForeground selection foreground, or NULL to use the system default color * @param selectionBackground selection background, or NULL to use the system default color * @param flags drawing options * * @exception SWTExceptionflags
can include one ofSWT.DELIMITER_SELECTION
* orSWT.FULL_SELECTION
to specify the selection behavior on all lines except * for the last line, and can also includeSWT.LAST_LINE_SELECTION
to extend * the specified selection behavior to the last line. **
* @exception IllegalArgumentException- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed
**
* * @since 3.3 */ public void draw (GC gc, int x, int y, int selectionStart, int selectionEnd, Color selectionForeground, Color selectionBackground, int flags) { checkLayout(); computeRuns(gc); if (gc == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (gc.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); if (selectionForeground != null && selectionForeground.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); if (selectionBackground != null && selectionBackground.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); int length = text.length(); if (length == 0 && flags == 0) return; int /*long*/ hdc = gc.handle; Rectangle clip = gc.getClipping(); GCData data = gc.data; int /*long*/ gdipGraphics = data.gdipGraphics; int foreground = data.foreground; int linkColor = OS.GetSysColor (OS.COLOR_HOTLIGHT); int alpha = data.alpha; boolean gdip = gdipGraphics != 0; int /*long*/ gdipForeground = 0; int /*long*/ gdipLinkColor = 0; int state = 0; if (gdip) { gc.checkGC(GC.FOREGROUND); gdipForeground = gc.getFgBrush(); } else { state = OS.SaveDC(hdc); if ((data.style & SWT.MIRRORED) != 0) { OS.SetLayout(hdc, OS.GetLayout(hdc) | OS.LAYOUT_RTL); } } boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1; int /*long*/ gdipSelBackground = 0, gdipSelForeground = 0, gdipFont = 0, lastHFont = 0; int /*long*/ selBackground = 0; int selForeground = 0; if (hasSelection || ((flags & SWT.LAST_LINE_SELECTION) != 0 && (flags & (SWT.FULL_SELECTION | SWT.DELIMITER_SELECTION)) != 0)) { int fgSel = selectionForeground != null ? selectionForeground.handle : OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT); int bgSel = selectionBackground != null ? selectionBackground.handle : OS.GetSysColor (OS.COLOR_HIGHLIGHT); if (gdip) { gdipSelBackground = createGdipBrush(bgSel, alpha); gdipSelForeground = createGdipBrush(fgSel, alpha); } else { selBackground = OS.CreateSolidBrush(bgSel); selForeground = fgSel; } if (hasSelection) { selectionStart = translateOffset(Math.min(Math.max(0, selectionStart), length - 1)); selectionEnd = translateOffset(Math.min(Math.max(0, selectionEnd), length - 1)); } } RECT rect = new RECT(); OS.SetBkMode(hdc, OS.TRANSPARENT); for (int line=0; line- ERROR_NULL_ARGUMENT - if the gc is null
*clip.x + clip.width) continue; if (drawX + lineWidth[line] < clip.x) continue; //Draw the background of the runs in the line int alignmentX = drawX; for (int i = 0; i < lineRuns.length; i++) { StyleItem run = lineRuns[i]; if (run.length == 0) continue; if (drawX > clip.x + clip.width) break; if (drawX + run.width >= clip.x) { if (!run.lineBreak || run.softBreak) { OS.SetRect(rect, drawX, drawY, drawX + run.width, drawY + lineHeight); if (gdip) { drawRunBackgroundGDIP(run, gdipGraphics, rect, selectionStart, selectionEnd, alpha, gdipSelBackground, hasSelection); } else { drawRunBackground(run, hdc, rect, selectionStart, selectionEnd, selBackground, hasSelection); } } } drawX += run.width; } //Draw the text, underline, strikeout, and border of the runs in the line int baseline = Math.max(0, this.ascent); int lineUnderlinePos = 0; for (int i = 0; i < lineRuns.length; i++) { baseline = Math.max(baseline, lineRuns[i].ascent); lineUnderlinePos = Math.min(lineUnderlinePos, lineRuns[i].underlinePos); } RECT borderClip = null, underlineClip = null, strikeoutClip = null, pRect = null; drawX = alignmentX; for (int i = 0; i < lineRuns.length; i++) { StyleItem run = lineRuns[i]; TextStyle style = run.style; boolean hasAdorners = style != null && (style.underline || style.strikeout || style.borderStyle != SWT.NONE); if (run.length == 0) continue; if (drawX > clip.x + clip.width) break; if (drawX + run.width >= clip.x) { boolean skipTab = run.tab && !hasAdorners; if (!skipTab && (!run.lineBreak || run.softBreak) && !(style != null && style.metrics != null)) { OS.SetRect(rect, drawX, drawY, drawX + run.width, drawY + lineHeight); if (gdip) { int /*long*/ hFont = getItemFont(run); if (hFont != lastHFont) { lastHFont = hFont; if (gdipFont != 0) Gdip.Font_delete(gdipFont); int /*long*/ oldFont = OS.SelectObject(hdc, hFont); gdipFont = Gdip.Font_new(hdc, hFont); OS.SelectObject(hdc, oldFont); if (gdipFont == 0) SWT.error(SWT.ERROR_NO_HANDLES); if (!Gdip.Font_IsAvailable(gdipFont)) { Gdip.Font_delete(gdipFont); gdipFont = 0; } } int /*long*/ gdipFg = gdipForeground; if (style != null && style.underline && style.underlineStyle == SWT.UNDERLINE_LINK) { if (gdipLinkColor == 0) gdipLinkColor = createGdipBrush(linkColor, alpha); gdipFg = gdipLinkColor; } if (gdipFont != 0 && !run.analysis.fNoGlyphIndex) { pRect = drawRunTextGDIP(gdipGraphics, run, rect, gdipFont, baseline, gdipFg, gdipSelForeground, selectionStart, selectionEnd, alpha); } else { int fg = style != null && style.underline && style.underlineStyle == SWT.UNDERLINE_LINK ? linkColor : foreground; pRect = drawRunTextGDIPRaster(gdipGraphics, run, rect, baseline, fg, selForeground, selectionStart, selectionEnd); } underlineClip = drawUnderlineGDIP(gdipGraphics, x, drawY + baseline, lineUnderlinePos, drawY + lineHeight, lineRuns, i, gdipFg, gdipSelForeground, underlineClip, pRect, selectionStart, selectionEnd, alpha, clip); strikeoutClip = drawStrikeoutGDIP(gdipGraphics, x, drawY + baseline, lineRuns, i, gdipFg, gdipSelForeground, strikeoutClip, pRect, selectionStart, selectionEnd, alpha, clip); borderClip = drawBorderGDIP(gdipGraphics, x, drawY, lineHeight, lineRuns, i, gdipFg, gdipSelForeground, borderClip, pRect, selectionStart, selectionEnd, alpha, clip); } else { int fg = style != null && style.underline && style.underlineStyle == SWT.UNDERLINE_LINK ? linkColor : foreground; pRect = drawRunText(hdc, run, rect, baseline, fg, selForeground, selectionStart, selectionEnd); underlineClip = drawUnderline(hdc, x, drawY + baseline, lineUnderlinePos, drawY + lineHeight, lineRuns, i, fg, selForeground, underlineClip, pRect, selectionStart, selectionEnd, clip); strikeoutClip = drawStrikeout(hdc, x, drawY + baseline, lineRuns, i, fg, selForeground, strikeoutClip, pRect, selectionStart, selectionEnd, clip); borderClip = drawBorder(hdc, x, drawY, lineHeight, lineRuns, i, fg, selForeground, borderClip, pRect, selectionStart, selectionEnd, clip); } } } drawX += run.width; } } if (gdipSelBackground != 0) Gdip.SolidBrush_delete(gdipSelBackground); if (gdipSelForeground != 0) Gdip.SolidBrush_delete(gdipSelForeground); if (gdipLinkColor != 0) Gdip.SolidBrush_delete(gdipLinkColor); if (gdipFont != 0) Gdip.Font_delete(gdipFont); if (state != 0) OS.RestoreDC(hdc, state); if (selBackground != 0) OS.DeleteObject (selBackground); } RECT drawBorder(int /*long*/ hdc, int x, int y, int lineHeight, StyleItem[] line, int index, int color, int selectionColor, RECT clipRect, RECT pRect, int selectionStart, int selectionEnd, Rectangle drawClip) { StyleItem run = line[index]; TextStyle style = run.style; if (style == null) return null; if (style.borderStyle == SWT.NONE) return null; clipRect = addClipRect(run, clipRect, pRect, selectionStart, selectionEnd); boolean lastRunVisible = drawClip != null && (x + run.x + run.width) > (drawClip.x + drawClip.width); if (index + 1 >= line.length || lastRunVisible || !style.isAdherentBorder(line[index + 1].style)) { int left = run.x; int start = run.start; int end = run.start + run.length - 1; for (int i = index; i > 0 && style.isAdherentBorder(line[i - 1].style); i--) { left = line[i - 1].x; start = Math.min(start, line[i - 1].start); end = Math.max(end, line[i - 1].start + line[i - 1].length - 1); } boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1; boolean fullSelection = hasSelection && selectionStart <= start && end <= selectionEnd; if (style.borderColor != null) { color = style.borderColor.handle; clipRect = null; } else { if (fullSelection) { color = selectionColor; clipRect = null; } else { if (style.foreground != null) { color = style.foreground.handle; } } } int lineWidth = 1; int pattern = 1; int lineStyle = OS.PS_SOLID; switch (style.borderStyle) { case SWT.BORDER_SOLID: break; case SWT.BORDER_DASH: { lineStyle = OS.PS_DASH; pattern = 4; break; } case SWT.BORDER_DOT: { lineStyle = OS.PS_DOT; pattern = 2; break; } } int /*long*/ oldBrush = OS.SelectObject(hdc, OS.GetStockObject(OS.NULL_BRUSH)); LOGBRUSH logBrush = new LOGBRUSH(); logBrush.lbStyle = OS.BS_SOLID; logBrush.lbColor = /*64*/(int)color; int /*long*/ newPen = OS.ExtCreatePen(lineStyle | OS.PS_GEOMETRIC, lineWidth, logBrush, 0, null); int /*long*/ oldPen = OS.SelectObject(hdc, newPen); RECT drawRect = new RECT(); OS.SetRect(drawRect, x + left, y, x + run.x + run.width, y + lineHeight); if (drawClip != null) { if (drawRect.left < drawClip.x) { int remainder = drawRect.left % pattern; drawRect.left = drawClip.x / pattern * pattern + remainder - pattern; } if (drawRect.right > drawClip.x + drawClip.width) { int remainder = drawRect.right % pattern; drawRect.right = (drawClip.x + drawClip.width) / pattern * pattern + remainder + pattern; } } OS.Rectangle(hdc, drawRect.left,drawRect.top, drawRect.right, drawRect.bottom); OS.SelectObject(hdc, oldPen); OS.DeleteObject(newPen); if (clipRect != null) { int state = OS.SaveDC(hdc); if (clipRect.left == -1) clipRect.left = 0; if (clipRect.right == -1) clipRect.right = 0x7ffff; OS.IntersectClipRect(hdc, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom); logBrush.lbColor = /*64*/(int)selectionColor; int /*long*/ selPen = OS.ExtCreatePen (lineStyle | OS.PS_GEOMETRIC, lineWidth, logBrush, 0, null); oldPen = OS.SelectObject(hdc, selPen); OS.Rectangle(hdc, drawRect.left, drawRect.top, drawRect.right, drawRect.bottom); OS.RestoreDC(hdc, state); OS.SelectObject(hdc, oldPen); OS.DeleteObject(selPen); } OS.SelectObject(hdc, oldBrush); return null; } return clipRect; } RECT drawBorderGDIP(int /*long*/ graphics, int x, int y, int lineHeight, StyleItem[] line, int index, int /*long*/ color, int /*long*/ selectionColor, RECT clipRect, RECT pRect, int selectionStart, int selectionEnd, int alpha, Rectangle drawClip) { StyleItem run = line[index]; TextStyle style = run.style; if (style == null) return null; if (style.borderStyle == SWT.NONE) return null; clipRect = addClipRect(run, clipRect, pRect, selectionStart, selectionEnd); boolean lastRunVisible = drawClip != null && (x + run.x + run.width) > (drawClip.x + drawClip.width); if (index + 1 >= line.length || lastRunVisible || !style.isAdherentBorder(line[index + 1].style)) { int left = run.x; int start = run.start; int end = run.start + run.length - 1; for (int i = index; i > 0 && style.isAdherentBorder(line[i - 1].style); i--) { left = line[i - 1].x; start = Math.min(start, line[i - 1].start); end = Math.max(end, line[i - 1].start + line[i - 1].length - 1); } boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1; boolean fullSelection = hasSelection && selectionStart <= start && end <= selectionEnd; int /*long*/ brush = color; if (style.borderColor != null) { brush = createGdipBrush(style.borderColor, alpha); clipRect = null; } else { if (fullSelection) { brush = selectionColor; clipRect = null; } else { if (style.foreground != null) { brush = createGdipBrush(style.foreground, alpha); } } } int lineWidth = 1; int lineStyle = Gdip.DashStyleSolid; switch (style.borderStyle) { case SWT.BORDER_SOLID: break; case SWT.BORDER_DASH: lineStyle = Gdip.DashStyleDash; break; case SWT.BORDER_DOT: lineStyle = Gdip.DashStyleDot; break; } int /*long*/ pen = Gdip.Pen_new(brush, lineWidth); Gdip.Pen_SetDashStyle(pen, lineStyle); Gdip.Graphics_SetPixelOffsetMode(graphics, Gdip.PixelOffsetModeNone); int smoothingMode = Gdip.Graphics_GetSmoothingMode(graphics); Gdip.Graphics_SetSmoothingMode(graphics, Gdip.SmoothingModeNone); if (clipRect != null) { int gstate = Gdip.Graphics_Save(graphics); if (clipRect.left == -1) clipRect.left = 0; if (clipRect.right == -1) clipRect.right = 0x7ffff; Rect gdipRect = new Rect(); gdipRect.X = clipRect.left; gdipRect.Y = clipRect.top; gdipRect.Width = clipRect.right - clipRect.left; gdipRect.Height = clipRect.bottom - clipRect.top; Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeExclude); Gdip.Graphics_DrawRectangle(graphics, pen, x + left, y, run.x + run.width - left - 1, lineHeight - 1); Gdip.Graphics_Restore(graphics, gstate); gstate = Gdip.Graphics_Save(graphics); Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeIntersect); int /*long*/ selPen = Gdip.Pen_new(selectionColor, lineWidth); Gdip.Pen_SetDashStyle(selPen, lineStyle); Gdip.Graphics_DrawRectangle(graphics, selPen, x + left, y, run.x + run.width - left - 1, lineHeight - 1); Gdip.Pen_delete(selPen); Gdip.Graphics_Restore(graphics, gstate); } else { Gdip.Graphics_DrawRectangle(graphics, pen, x + left, y, run.x + run.width - left - 1, lineHeight - 1); } Gdip.Graphics_SetPixelOffsetMode(graphics, Gdip.PixelOffsetModeHalf); Gdip.Graphics_SetSmoothingMode(graphics, smoothingMode); Gdip.Pen_delete(pen); if (brush != selectionColor && brush != color) Gdip.SolidBrush_delete(brush); return null; } return clipRect; } void drawRunBackground(StyleItem run, int /*long*/ hdc, RECT rect, int selectionStart, int selectionEnd, int /*long*/ selBrush, boolean hasSelection) { int end = run.start + run.length - 1; boolean fullSelection = hasSelection && selectionStart <= run.start && selectionEnd >= end; if (fullSelection) { OS.SelectObject(hdc, selBrush); OS.PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, OS.PATCOPY); } else { if (run.style != null && run.style.background != null) { int bg = run.style.background.handle; int /*long*/ hBrush = OS.CreateSolidBrush (bg); int /*long*/ oldBrush = OS.SelectObject(hdc, hBrush); OS.PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, OS.PATCOPY); OS.SelectObject(hdc, oldBrush); OS.DeleteObject(hBrush); } boolean partialSelection = hasSelection && !(selectionStart > end || run.start > selectionEnd); if (partialSelection) { getPartialSelection(run, selectionStart, selectionEnd, rect); OS.SelectObject(hdc, selBrush); OS.PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, OS.PATCOPY); } } } void drawRunBackgroundGDIP(StyleItem run, int /*long*/ graphics, RECT rect, int selectionStart, int selectionEnd, int alpha, int /*long*/ selBrush, boolean hasSelection) { int end = run.start + run.length - 1; boolean fullSelection = hasSelection && selectionStart <= run.start && selectionEnd >= end; if (fullSelection) { Gdip.Graphics_FillRectangle(graphics, selBrush, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); } else { if (run.style != null && run.style.background != null) { int /*long*/ brush = createGdipBrush(run.style.background, alpha); Gdip.Graphics_FillRectangle(graphics, brush, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); Gdip.SolidBrush_delete(brush); } boolean partialSelection = hasSelection && !(selectionStart > end || run.start > selectionEnd); if (partialSelection) { getPartialSelection(run, selectionStart, selectionEnd, rect); if (rect.left > rect.right) { int tmp = rect.left; rect.left = rect.right; rect.right = tmp; } Gdip.Graphics_FillRectangle(graphics, selBrush, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); } } } RECT drawRunText(int /*long*/ hdc, StyleItem run, RECT rect, int baseline, int color, int selectionColor, int selectionStart, int selectionEnd) { int end = run.start + run.length - 1; boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1; boolean fullSelection = hasSelection && selectionStart <= run.start && selectionEnd >= end; boolean partialSelection = hasSelection && !fullSelection && !(selectionStart > end || run.start > selectionEnd); int offset = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? -1 : 0; int x = rect.left + offset; int y = rect.top + (baseline - run.ascent); int /*long*/ hFont = getItemFont(run); OS.SelectObject(hdc, hFont); if (fullSelection) { color = selectionColor; } else { if (run.style != null && run.style.foreground != null) { color = run.style.foreground.handle; } } OS.SetTextColor(hdc, color); OS.ScriptTextOut(hdc, run.psc, x, y, 0, null, run.analysis , 0, 0, run.glyphs, run.glyphCount, run.advances, run.justify, run.goffsets); if (partialSelection) { getPartialSelection(run, selectionStart, selectionEnd, rect); OS.SetTextColor(hdc, selectionColor); OS.ScriptTextOut(hdc, run.psc, x, y, OS.ETO_CLIPPED, rect, run.analysis , 0, 0, run.glyphs, run.glyphCount, run.advances, run.justify, run.goffsets); } return fullSelection || partialSelection ? rect : null; } RECT drawRunTextGDIP(int /*long*/ graphics, StyleItem run, RECT rect, int /*long*/ gdipFont, int baseline, int /*long*/ color, int /*long*/ selectionColor, int selectionStart, int selectionEnd, int alpha) { int end = run.start + run.length - 1; boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1; boolean fullSelection = hasSelection && selectionStart <= run.start && selectionEnd >= end; boolean partialSelection = hasSelection && !fullSelection && !(selectionStart > end || run.start > selectionEnd); int drawY = rect.top + baseline; if (run.style != null && run.style.rise != 0) drawY -= run.style.rise; int drawX = rect.left; int /*long*/ brush = color; if (fullSelection) { brush = selectionColor; } else { if (run.style != null && run.style.foreground != null) { brush = createGdipBrush(run.style.foreground, alpha); } } int gstate = 0; Rect gdipRect = null; if (partialSelection) { gdipRect = new Rect(); getPartialSelection(run, selectionStart, selectionEnd, rect); gdipRect.X = rect.left; gdipRect.Y = rect.top; gdipRect.Width = rect.right - rect.left; gdipRect.Height = rect.bottom - rect.top; gstate = Gdip.Graphics_Save(graphics); Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeExclude); } int gstateMirrored = 0; boolean isMirrored = (orientation & SWT.RIGHT_TO_LEFT) != 0; if (isMirrored) { switch (Gdip.Brush_GetType(brush)) { case Gdip.BrushTypeLinearGradient: Gdip.LinearGradientBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend); Gdip.LinearGradientBrush_TranslateTransform(brush, -2 * drawX - run.width, 0, Gdip.MatrixOrderPrepend); break; case Gdip.BrushTypeTextureFill: Gdip.TextureBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend); Gdip.TextureBrush_TranslateTransform(brush, -2 * drawX - run.width, 0, Gdip.MatrixOrderPrepend); break; } gstateMirrored = Gdip.Graphics_Save(graphics); Gdip.Graphics_ScaleTransform(graphics, -1, 1, Gdip.MatrixOrderPrepend); Gdip.Graphics_TranslateTransform(graphics, -2 * drawX - run.width, 0, Gdip.MatrixOrderPrepend); } int[] advances = new int[run.glyphCount]; float[] points = new float[run.glyphCount * 2]; OS.memmove(advances, run.justify != 0 ? run.justify : run.advances, run.glyphCount * 4); int glyphX = drawX; for (int h = 0, j = 0; h < advances.length; h++) { points[j++] = glyphX; points[j++] = drawY; glyphX += advances[h]; } Gdip.Graphics_DrawDriverString(graphics, run.glyphs, run.glyphCount, gdipFont, brush, points, 0, 0); if (partialSelection) { if (isMirrored) { Gdip.Graphics_Restore(graphics, gstateMirrored); } Gdip.Graphics_Restore(graphics, gstate); gstate = Gdip.Graphics_Save(graphics); Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeIntersect); if (isMirrored) { gstateMirrored = Gdip.Graphics_Save(graphics); Gdip.Graphics_ScaleTransform(graphics, -1, 1, Gdip.MatrixOrderPrepend); Gdip.Graphics_TranslateTransform(graphics, -2 * drawX - run.width, 0, Gdip.MatrixOrderPrepend); } Gdip.Graphics_DrawDriverString(graphics, run.glyphs, run.glyphCount, gdipFont, selectionColor, points, 0, 0); Gdip.Graphics_Restore(graphics, gstate); } if (isMirrored) { switch (Gdip.Brush_GetType(brush)) { case Gdip.BrushTypeLinearGradient: Gdip.LinearGradientBrush_ResetTransform(brush); break; case Gdip.BrushTypeTextureFill: Gdip.TextureBrush_ResetTransform(brush); break; } Gdip.Graphics_Restore(graphics, gstateMirrored); } if (brush != selectionColor && brush != color) Gdip.SolidBrush_delete(brush); return fullSelection || partialSelection ? rect : null; } RECT drawRunTextGDIPRaster(int /*long*/ graphics, StyleItem run, RECT rect, int baseline, int color, int selectionColor, int selectionStart, int selectionEnd) { int /*long*/ clipRgn = 0; Gdip.Graphics_SetPixelOffsetMode(graphics, Gdip.PixelOffsetModeNone); int /*long*/ rgn = Gdip.Region_new(); if (rgn == 0) SWT.error(SWT.ERROR_NO_HANDLES); Gdip.Graphics_GetClip(graphics, rgn); if (!Gdip.Region_IsInfinite(rgn, graphics)) { clipRgn = Gdip.Region_GetHRGN(rgn, graphics); } Gdip.Region_delete(rgn); Gdip.Graphics_SetPixelOffsetMode(graphics, Gdip.PixelOffsetModeHalf); float[] lpXform = null; int /*long*/ matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0); if (matrix == 0) SWT.error(SWT.ERROR_NO_HANDLES); Gdip.Graphics_GetTransform(graphics, matrix); if (!Gdip.Matrix_IsIdentity(matrix)) { lpXform = new float[6]; Gdip.Matrix_GetElements(matrix, lpXform); } Gdip.Matrix_delete(matrix); int /*long*/ hdc = Gdip.Graphics_GetHDC(graphics); int state = OS.SaveDC(hdc); if (lpXform != null) { OS.SetGraphicsMode(hdc, OS.GM_ADVANCED); OS.SetWorldTransform(hdc, lpXform); } if (clipRgn != 0) { OS.SelectClipRgn(hdc, clipRgn); OS.DeleteObject(clipRgn); } if ((orientation & SWT.RIGHT_TO_LEFT) != 0) { OS.SetLayout(hdc, OS.GetLayout(hdc) | OS.LAYOUT_RTL); } OS.SetBkMode(hdc, OS.TRANSPARENT); RECT pRect = drawRunText(hdc, run, rect, baseline, color, selectionColor, selectionStart, selectionEnd); OS.RestoreDC(hdc, state); Gdip.Graphics_ReleaseHDC(graphics, hdc); return pRect; } RECT drawStrikeout(int /*long*/ hdc, int x, int baseline, StyleItem[] line, int index, int color, int selectionColor, RECT clipRect, RECT pRect, int selectionStart, int selectionEnd, Rectangle drawClip) { StyleItem run = line[index]; TextStyle style = run.style; if (style == null) return null; if (!style.strikeout) return null; clipRect = addClipRect(run, clipRect, pRect, selectionStart, selectionEnd); boolean lastRunVisible = drawClip != null && (x + run.x + run.width) > (drawClip.x + drawClip.width); if (index + 1 >= line.length || lastRunVisible || !style.isAdherentStrikeout(line[index + 1].style)) { int left = run.x; int start = run.start; int end = run.start + run.length - 1; for (int i = index; i > 0 && style.isAdherentStrikeout(line[i - 1].style); i--) { left = line[i - 1].x; start = Math.min(start, line[i - 1].start); end = Math.max(end, line[i - 1].start + line[i - 1].length - 1); } boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1; boolean fullSelection = hasSelection && selectionStart <= start && end <= selectionEnd; if (style.strikeoutColor != null) { color = style.strikeoutColor.handle; clipRect = null; } else { if (fullSelection) { color = selectionColor; clipRect = null; } else { if (style.foreground != null) { color = style.foreground.handle; } } } RECT rect = new RECT(); OS.SetRect(rect, x + left, baseline - run.strikeoutPos - style.rise, x + run.x + run.width, baseline - run.strikeoutPos + run.strikeoutThickness - style.rise); int /*long*/ brush = OS.CreateSolidBrush(color); OS.FillRect(hdc, rect, brush); OS.DeleteObject(brush); if (clipRect != null) { int /*long*/ selBrush = OS.CreateSolidBrush(selectionColor); if (clipRect.left == -1) clipRect.left = 0; if (clipRect.right == -1) clipRect.right = 0x7ffff; OS.SetRect(clipRect, Math.max(rect.left, clipRect.left), rect.top, Math.min(rect.right, clipRect.right), rect.bottom); OS.FillRect(hdc, clipRect, selBrush); OS.DeleteObject(selBrush); } return null; } return clipRect; } RECT drawStrikeoutGDIP(int /*long*/ graphics, int x, int baseline, StyleItem[] line, int index, int /*long*/ color, int /*long*/ selectionColor, RECT clipRect, RECT pRect, int selectionStart, int selectionEnd, int alpha, Rectangle drawClip) { StyleItem run = line[index]; TextStyle style = run.style; if (style == null) return null; if (!style.strikeout) return null; clipRect = addClipRect(run, clipRect, pRect, selectionStart, selectionEnd); boolean lastRunVisible = drawClip != null && (x + run.x + run.width) > (drawClip.x + drawClip.width); if (index + 1 >= line.length || lastRunVisible || !style.isAdherentStrikeout(line[index + 1].style)) { int left = run.x; int start = run.start; int end = run.start + run.length - 1; for (int i = index; i > 0 && style.isAdherentStrikeout(line[i - 1].style); i--) { left = line[i - 1].x; start = Math.min(start, line[i - 1].start); end = Math.max(end, line[i - 1].start + line[i - 1].length - 1); } boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1; boolean fullSelection = hasSelection && selectionStart <= start && end <= selectionEnd; int /*long*/ brush = color; if (style.strikeoutColor != null) { brush = createGdipBrush(style.strikeoutColor, alpha); clipRect = null; } else { if (fullSelection) { brush = selectionColor; clipRect = null; } else { if (style.foreground != null) { brush = createGdipBrush(style.foreground, alpha); } } } if (clipRect != null) { int gstate = Gdip.Graphics_Save(graphics); if (clipRect.left == -1) clipRect.left = 0; if (clipRect.right == -1) clipRect.right = 0x7ffff; Rect gdipRect = new Rect(); gdipRect.X = clipRect.left; gdipRect.Y = clipRect.top; gdipRect.Width = clipRect.right - clipRect.left; gdipRect.Height = clipRect.bottom - clipRect.top; Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeExclude); Gdip.Graphics_FillRectangle(graphics, brush, x + left, baseline - run.strikeoutPos - style.rise, run.x + run.width - left, run.strikeoutThickness); Gdip.Graphics_Restore(graphics, gstate); gstate = Gdip.Graphics_Save(graphics); Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeIntersect); Gdip.Graphics_FillRectangle(graphics, selectionColor, x + left, baseline - run.strikeoutPos - style.rise, run.x + run.width - left, run.strikeoutThickness); Gdip.Graphics_Restore(graphics, gstate); } else { Gdip.Graphics_FillRectangle(graphics, brush, x + left, baseline - run.strikeoutPos - style.rise, run.x + run.width - left, run.strikeoutThickness); } if (brush != selectionColor && brush != color) Gdip.SolidBrush_delete(brush); return null; } return clipRect; } RECT drawUnderline(int /*long*/ hdc, int x, int baseline, int lineUnderlinePos, int lineBottom, StyleItem[] line, int index, int color, int selectionColor, RECT clipRect, RECT pRect, int selectionStart, int selectionEnd, Rectangle drawClip) { StyleItem run = line[index]; TextStyle style = run.style; if (style == null) return null; if (!style.underline) return null; clipRect = addClipRect(run, clipRect, pRect, selectionStart, selectionEnd); boolean lastRunVisible = drawClip != null && (x + run.x + run.width) > (drawClip.x + drawClip.width); if (index + 1 >= line.length || lastRunVisible || !style.isAdherentUnderline(line[index + 1].style)) { int left = run.x; int start = run.start; int end = run.start + run.length - 1; for (int i = index; i > 0 && style.isAdherentUnderline(line[i - 1].style); i--) { left = line[i - 1].x; start = Math.min(start, line[i - 1].start); end = Math.max(end, line[i - 1].start + line[i - 1].length - 1); } boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1; boolean fullSelection = hasSelection && selectionStart <= start && end <= selectionEnd; if (style.underlineColor != null) { color = style.underlineColor.handle; clipRect = null; } else { if (fullSelection) { color = selectionColor; clipRect = null; } else { if (style.foreground != null) { color = style.foreground.handle; } } } RECT rect = new RECT(); OS.SetRect(rect, x + left, baseline - lineUnderlinePos - style.rise, x + run.x + run.width, baseline - lineUnderlinePos + run.underlineThickness - style.rise); if (clipRect != null) { if (clipRect.left == -1) clipRect.left = 0; if (clipRect.right == -1) clipRect.right = 0x7ffff; OS.SetRect(clipRect, Math.max(rect.left, clipRect.left), rect.top, Math.min(rect.right, clipRect.right), rect.bottom); } switch (style.underlineStyle) { case SWT.UNDERLINE_SQUIGGLE: case SWT.UNDERLINE_ERROR: { int squigglyThickness = 1; int squigglyHeight = 2 * squigglyThickness; int squigglyY = Math.min(rect.top - squigglyHeight / 2, lineBottom - squigglyHeight - 1); int[] points = computePolyline(rect.left, squigglyY, rect.right, squigglyY + squigglyHeight); int /*long*/ pen = OS.CreatePen(OS.PS_SOLID, squigglyThickness, color); int /*long*/ oldPen = OS.SelectObject(hdc, pen); int state = OS.SaveDC(hdc); OS.IntersectClipRect(hdc, rect.left, squigglyY, rect.right + 1, squigglyY + squigglyHeight + 1); OS.Polyline(hdc, points, points.length / 2); int length = points.length; if (length >= 2 && squigglyThickness <= 1) { OS.SetPixel (hdc, points[length - 2], points[length - 1], color); } OS.SelectObject(hdc, oldPen); OS.DeleteObject(pen); OS.RestoreDC(hdc, state); if (clipRect != null) { pen = OS.CreatePen(OS.PS_SOLID, squigglyThickness, selectionColor); oldPen = OS.SelectObject(hdc, pen); state = OS.SaveDC(hdc); OS.IntersectClipRect(hdc, clipRect.left, squigglyY, clipRect.right + 1, squigglyY + squigglyHeight + 1); OS.Polyline(hdc, points, points.length / 2); if (length >= 2 && squigglyThickness <= 1) { OS.SetPixel (hdc, points[length - 2], points[length - 1], selectionColor); } OS.SelectObject(hdc, oldPen); OS.DeleteObject(pen); OS.RestoreDC(hdc, state); } break; } case SWT.UNDERLINE_SINGLE: case SWT.UNDERLINE_DOUBLE: case SWT.UNDERLINE_LINK: case UNDERLINE_IME_THICK: if (style.underlineStyle == UNDERLINE_IME_THICK) { rect.top -= run.underlineThickness; if (clipRect != null) clipRect.top -= run.underlineThickness; } int bottom = style.underlineStyle == SWT.UNDERLINE_DOUBLE ? rect.bottom + run.underlineThickness * 2 : rect.bottom; if (bottom > lineBottom) { OS.OffsetRect(rect, 0, lineBottom - bottom); if (clipRect != null) OS.OffsetRect(clipRect, 0, lineBottom - bottom); } int /*long*/ brush = OS.CreateSolidBrush(color); OS.FillRect(hdc, rect, brush); if (style.underlineStyle == SWT.UNDERLINE_DOUBLE) { OS.SetRect(rect, rect.left, rect.top + run.underlineThickness * 2, rect.right, rect.bottom + run.underlineThickness * 2); OS.FillRect(hdc, rect, brush); } OS.DeleteObject(brush); if (clipRect != null) { int /*long*/ selBrush = OS.CreateSolidBrush(selectionColor); OS.FillRect(hdc, clipRect, selBrush); if (style.underlineStyle == SWT.UNDERLINE_DOUBLE) { OS.SetRect(clipRect, clipRect.left, rect.top, clipRect.right, rect.bottom); OS.FillRect(hdc, clipRect, selBrush); } OS.DeleteObject(selBrush); } break; case UNDERLINE_IME_DASH: case UNDERLINE_IME_DOT: { int penStyle = style.underlineStyle == UNDERLINE_IME_DASH ? OS.PS_DASH : OS.PS_DOT; int /*long*/ pen = OS.CreatePen(penStyle, 1, color); int /*long*/ oldPen = OS.SelectObject(hdc, pen); OS.SetRect(rect, rect.left, baseline + run.descent, rect.right, baseline + run.descent + run.underlineThickness); OS.MoveToEx(hdc, rect.left, rect.top, 0); OS.LineTo(hdc, rect.right, rect.top); OS.SelectObject(hdc, oldPen); OS.DeleteObject(pen); if (clipRect != null) { pen = OS.CreatePen(penStyle, 1, selectionColor); oldPen = OS.SelectObject(hdc, pen); OS.SetRect(clipRect, clipRect.left, rect.top, clipRect.right, rect.bottom); OS.MoveToEx(hdc, clipRect.left, clipRect.top, 0); OS.LineTo(hdc, clipRect.right, clipRect.top); OS.SelectObject(hdc, oldPen); OS.DeleteObject(pen); } break; } } return null; } return clipRect; } RECT drawUnderlineGDIP (int /*long*/ graphics, int x, int baseline, int lineUnderlinePos, int lineBottom, StyleItem[] line, int index, int /*long*/ color, int /*long*/ selectionColor, RECT clipRect, RECT pRect, int selectionStart, int selectionEnd, int alpha, Rectangle drawClip) { StyleItem run = line[index]; TextStyle style = run.style; if (style == null) return null; if (!style.underline) return null; clipRect = addClipRect(run, clipRect, pRect, selectionStart, selectionEnd); boolean lastRunVisible = drawClip != null && (x + run.x + run.width) > (drawClip.x + drawClip.width); if (index + 1 >= line.length || lastRunVisible || !style.isAdherentUnderline(line[index + 1].style)) { int left = run.x; int start = run.start; int end = run.start + run.length - 1; for (int i = index; i > 0 && style.isAdherentUnderline(line[i - 1].style); i--) { left = line[i - 1].x; start = Math.min(start, line[i - 1].start); end = Math.max(end, line[i - 1].start + line[i - 1].length - 1); } boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1; boolean fullSelection = hasSelection && selectionStart <= start && end <= selectionEnd; int /*long*/ brush = color; if (style.underlineColor != null) { brush = createGdipBrush(style.underlineColor, alpha); clipRect = null; } else { if (fullSelection) { brush = selectionColor; clipRect = null; } else { if (style.foreground != null) { brush = createGdipBrush(style.foreground, alpha); } } } RECT rect = new RECT(); OS.SetRect(rect, x + left, baseline - lineUnderlinePos - style.rise, x + run.x + run.width, baseline - lineUnderlinePos + run.underlineThickness - style.rise); Rect gdipRect = null; if (clipRect != null) { if (clipRect.left == -1) clipRect.left = 0; if (clipRect.right == -1) clipRect.right = 0x7ffff; OS.SetRect(clipRect, Math.max(rect.left, clipRect.left), rect.top, Math.min(rect.right, clipRect.right), rect.bottom); gdipRect = new Rect(); gdipRect.X = clipRect.left; gdipRect.Y = clipRect.top; gdipRect.Width = clipRect.right - clipRect.left; gdipRect.Height = clipRect.bottom - clipRect.top; } int gstate = 0; Gdip.Graphics_SetPixelOffsetMode(graphics, Gdip.PixelOffsetModeNone); int smoothingMode = Gdip.Graphics_GetSmoothingMode(graphics); Gdip.Graphics_SetSmoothingMode(graphics, Gdip.SmoothingModeNone); switch (style.underlineStyle) { case SWT.UNDERLINE_SQUIGGLE: case SWT.UNDERLINE_ERROR: { int squigglyThickness = 1; int squigglyHeight = 2 * squigglyThickness; int squigglyY = Math.min(rect.top - squigglyHeight / 2, lineBottom - squigglyHeight - 1); int[] points = computePolyline(rect.left, squigglyY, rect.right, squigglyY + squigglyHeight); int /*long*/ pen = Gdip.Pen_new(brush, squigglyThickness); gstate = Gdip.Graphics_Save(graphics); if (gdipRect != null) { Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeExclude); } else { Rect r = new Rect(); r.X = rect.left; r.Y = squigglyY; r.Width = rect.right - rect.left; r.Height = squigglyHeight + 1; Gdip.Graphics_SetClip(graphics, r, Gdip.CombineModeIntersect); } Gdip.Graphics_DrawLines(graphics, pen, points, points.length / 2); if (gdipRect != null) { int /*long*/ selPen = Gdip.Pen_new(selectionColor, squigglyThickness); Gdip.Graphics_Restore(graphics, gstate); gstate = Gdip.Graphics_Save(graphics); Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeIntersect); Gdip.Graphics_DrawLines(graphics, selPen, points, points.length / 2); Gdip.Pen_delete(selPen); } Gdip.Graphics_Restore(graphics, gstate); Gdip.Pen_delete(pen); if (gstate != 0) Gdip.Graphics_Restore(graphics, gstate); break; } case SWT.UNDERLINE_SINGLE: case SWT.UNDERLINE_DOUBLE: case SWT.UNDERLINE_LINK: case UNDERLINE_IME_THICK: if (style.underlineStyle == UNDERLINE_IME_THICK) { rect.top -= run.underlineThickness; } int bottom = style.underlineStyle == SWT.UNDERLINE_DOUBLE ? rect.bottom + run.underlineThickness * 2 : rect.bottom; if (bottom > lineBottom) { OS.OffsetRect(rect, 0, lineBottom - bottom); } if (gdipRect != null) { gdipRect.Y = rect.top; if (style.underlineStyle == UNDERLINE_IME_THICK) { gdipRect.Height = run.underlineThickness * 2; } if (style.underlineStyle == SWT.UNDERLINE_DOUBLE) { gdipRect.Height = run.underlineThickness * 3; } gstate = Gdip.Graphics_Save(graphics); Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeExclude); } Gdip.Graphics_FillRectangle(graphics, brush, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); if (style.underlineStyle == SWT.UNDERLINE_DOUBLE) { Gdip.Graphics_FillRectangle(graphics, brush, rect.left, rect.top + run.underlineThickness * 2, rect.right - rect.left, rect.bottom - rect.top); } if (gdipRect != null) { Gdip.Graphics_Restore(graphics, gstate); gstate = Gdip.Graphics_Save(graphics); Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeIntersect); Gdip.Graphics_FillRectangle(graphics, selectionColor, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); if (style.underlineStyle == SWT.UNDERLINE_DOUBLE) { Gdip.Graphics_FillRectangle(graphics, selectionColor, rect.left, rect.top + run.underlineThickness * 2, rect.right - rect.left, rect.bottom - rect.top); } Gdip.Graphics_Restore(graphics, gstate); } break; case UNDERLINE_IME_DOT: case UNDERLINE_IME_DASH: { int /*long*/ pen = Gdip.Pen_new(brush, 1); int dashStyle = style.underlineStyle == UNDERLINE_IME_DOT ? Gdip.DashStyleDot : Gdip.DashStyleDash; Gdip.Pen_SetDashStyle(pen, dashStyle); if (gdipRect != null) { gstate = Gdip.Graphics_Save(graphics); Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeExclude); } Gdip.Graphics_DrawLine(graphics, pen, rect.left, baseline + run.descent, run.width - run.length, baseline + run.descent); if (gdipRect != null) { Gdip.Graphics_Restore(graphics, gstate); gstate = Gdip.Graphics_Save(graphics); Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeIntersect); int /*long*/ selPen = Gdip.Pen_new(brush, 1); Gdip.Pen_SetDashStyle(selPen, dashStyle); Gdip.Graphics_DrawLine(graphics, selPen, rect.left, baseline + run.descent, run.width - run.length, baseline + run.descent); Gdip.Graphics_Restore(graphics, gstate); Gdip.Pen_delete(selPen); } Gdip.Pen_delete(pen); break; } } if (brush != selectionColor && brush != color) Gdip.SolidBrush_delete(brush); Gdip.Graphics_SetPixelOffsetMode(graphics, Gdip.PixelOffsetModeHalf); Gdip.Graphics_SetSmoothingMode(graphics, smoothingMode); return null; } return clipRect; } void freeRuns () { if (allRuns == null) return; for (int i=0; i SWT.LEFT SWT.CENTER
or *SWT.RIGHT
. * * @return the alignment used to positioned text horizontally * * @exception SWTException
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_INVALID_ARGUMENT - if the character offset is out of range *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed */ public int getLevel (int offset) { checkLayout(); computeRuns(null); int length = text.length(); if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); offset = translateOffset(offset); for (int i=1; i
- ERROR_INVALID_ARGUMENT - if the line index is out of range *
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
- ERROR_INVALID_ARGUMENT - if the character offset is out of range *
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
- ERROR_INVALID_ARGUMENT - if the line index is out of range *
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
- ERROR_INVALID_ARGUMENT - if the offset is out of range *
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
- ERROR_INVALID_ARGUMENT - if the trailing length is less than
1
* - ERROR_NULL_ARGUMENT - if the point is null *
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
- ERROR_INVALID_ARGUMENT - if the trailing length is less than
1
* - ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
- ERROR_INVALID_ARGUMENT - if the offset is out of range *
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
-
*
-
*
-
*
-
*
-
*
-
*
-
*
trailing
argument indicates whether the offset
* corresponds to the leading or trailing edge of the cluster.
*
* @param offset the character offset
* @param trailing the trailing flag
* @return the location of the character offset
*
* @exception SWTException -
*
SWT.MOVEMENT_CHAR
,
* SWT.MOVEMENT_CLUSTER
, SWT.MOVEMENT_WORD
,
* SWT.MOVEMENT_WORD_END
or SWT.MOVEMENT_WORD_START
.
*
* @param offset the start offset
* @param movement the movement type
* @return the next offset
*
* @exception IllegalArgumentException -
*
-
*
-
*
-
*
-
*
-
*
-
*
SWT.MOVEMENT_CHAR
,
* SWT.MOVEMENT_CLUSTER
or SWT.MOVEMENT_WORD
,
* SWT.MOVEMENT_WORD_END
or SWT.MOVEMENT_WORD_START
.
*
* @param offset the start offset
* @param movement the movement type
* @return the previous offset
*
* @exception IllegalArgumentException -
*
-
*
TextStyle
.
*
* @return the ranges, an array of offsets representing the start and end of each
* text style.
*
* @exception SWTException -
*
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
null
if not set
*
* @exception IllegalArgumentException -
*
- ERROR_INVALID_ARGUMENT - if the character offset is out of range *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
true
if the text layout has been disposed,
* and false
otherwise.
* * This method gets the dispose state for the text layout. * When a text layout has been disposed, it is an error to * invoke any other method (except {@link #dispose()}) using the text layout. *
* * @returntrue
when the text layout is disposed and false
otherwise
*/
public boolean isDisposed () {
return device == null;
}
/*
* Itemize the receiver text
*/
StyleItem[] itemize () {
segmentsText = getSegmentsText();
int length = segmentsText.length();
SCRIPT_CONTROL scriptControl = new SCRIPT_CONTROL();
SCRIPT_STATE scriptState = new SCRIPT_STATE();
final int MAX_ITEM = length + 1;
if ((textDirection & SWT.RIGHT_TO_LEFT) != 0) {
scriptState.uBidiLevel = 1;
scriptState.fArabicNumContext = true;
}
/*
* In the version of Usp10.h that SWT is compiled the fReserved field is declared
* as a bitfield size 8. In newer versions of the Uniscribe, the first bit of fReserved
* was used to implement the fMergeNeutralItems feature which can be used to increase
* performance by reducing the number of SCRIPT_ITEM returned by ScriptItemize.
*
* Note: This code is wrong on a big endian machine.
*
* Note: This code is intentionally commented because it causes bug#377472.
*/
// if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
// scriptControl.fReserved = 0x1;
// }
OS.ScriptApplyDigitSubstitution(null, scriptControl, scriptState);
int /*long*/ hHeap = OS.GetProcessHeap();
int /*long*/ pItems = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, MAX_ITEM * SCRIPT_ITEM.sizeof);
if (pItems == 0) SWT.error(SWT.ERROR_NO_HANDLES);
int[] pcItems = new int[1];
char[] chars = new char[length];
segmentsText.getChars(0, length, chars, 0);
OS.ScriptItemize(chars, length, MAX_ITEM, scriptControl, scriptState, pItems, pcItems);
// if (hr == E_OUTOFMEMORY) //TODO handle it
StyleItem[] runs = merge(pItems, pcItems[0]);
OS.HeapFree(hHeap, 0, pItems);
return runs;
}
/*
* Merge styles ranges and script items
*/
StyleItem[] merge (int /*long*/ items, int itemCount) {
if (styles.length > stylesCount) {
StyleItem[] newStyles = new StyleItem[stylesCount];
System.arraycopy(styles, 0, newStyles, 0, stylesCount);
styles = newStyles;
}
int count = 0, start = 0, end = segmentsText.length(), itemIndex = 0, styleIndex = 0;
StyleItem[] runs = new StyleItem[itemCount + stylesCount];
SCRIPT_ITEM scriptItem = new SCRIPT_ITEM();
int itemLimit = -1;
int nextItemIndex = 0;
boolean linkBefore = false;
boolean merge = itemCount > TOO_MANY_RUNS;
SCRIPT_PROPERTIES sp = new SCRIPT_PROPERTIES();
while (start < end) {
StyleItem item = new StyleItem();
item.start = start;
item.style = styles[styleIndex].style;
runs[count++] = item;
OS.MoveMemory(scriptItem, items + itemIndex * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof);
item.analysis = scriptItem.a;
scriptItem.a = new SCRIPT_ANALYSIS();
if (linkBefore) {
item.analysis.fLinkBefore = true;
linkBefore = false;
}
char ch = segmentsText.charAt(start);
switch (ch) {
case '\r':
case '\n':
item.lineBreak = true;
break;
case '\t':
item.tab = true;
break;
}
if (itemLimit == -1) {
nextItemIndex = itemIndex + 1;
OS.MoveMemory(scriptItem, items + nextItemIndex * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof);
itemLimit = scriptItem.iCharPos;
if (nextItemIndex < itemCount && ch == '\r' && segmentsText.charAt(itemLimit) == '\n') {
nextItemIndex = itemIndex + 2;
OS.MoveMemory(scriptItem, items + nextItemIndex * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof);
itemLimit = scriptItem.iCharPos;
}
if (nextItemIndex < itemCount && merge) {
if (!item.lineBreak) {
OS.MoveMemory(sp, device.scripts[item.analysis.eScript], SCRIPT_PROPERTIES.sizeof);
if (!sp.fComplex || item.tab) {
for (int i = 0; i < MERGE_MAX; i++) {
if (nextItemIndex == itemCount) break;
char c = segmentsText.charAt(itemLimit);
if (c == '\n' || c == '\r') break;
if (c == '\t' != item.tab) break;
OS.MoveMemory(sp, device.scripts[scriptItem.a.eScript], SCRIPT_PROPERTIES.sizeof);
if (!item.tab && sp.fComplex) break;
nextItemIndex++;
OS.MoveMemory(scriptItem, items + nextItemIndex * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof);
itemLimit = scriptItem.iCharPos;
}
}
}
}
}
int styleLimit = translateOffset(styles[styleIndex + 1].start);
if (styleLimit <= itemLimit) {
styleIndex++;
start = styleLimit;
if (start < itemLimit && 0 < start && start < end) {
char pChar = segmentsText.charAt(start - 1);
char tChar = segmentsText.charAt(start);
if (Compatibility.isLetter(pChar) && Compatibility.isLetter(tChar)) {
item.analysis.fLinkAfter = true;
linkBefore = true;
}
}
}
if (itemLimit <= styleLimit) {
itemIndex = nextItemIndex;
start = itemLimit;
itemLimit = -1;
}
item.length = start - item.start;
}
StyleItem item = new StyleItem();
item.start = end;
OS.MoveMemory(scriptItem, items + itemCount * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof);
item.analysis = scriptItem.a;
runs[count++] = item;
if (runs.length != count) {
StyleItem[] result = new StyleItem[count];
System.arraycopy(runs, 0, result, 0, count);
return result;
}
return runs;
}
/*
* Reorder the run
*/
StyleItem[] reorder (StyleItem[] runs, boolean terminate) {
int length = runs.length;
if (length <= 1) return runs;
byte[] bidiLevels = new byte[length];
for (int i=0; iSWT.RIGHT
or SWT.CENTER
.
*
* The default alignment is SWT.LEFT
. Note that the receiver's
* width must be set in order to use SWT.RIGHT
or SWT.CENTER
* alignment.
*
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-1
which means that the
* ascent is calculated from the line fonts.
*
* @param ascent the new ascent
*
* @exception IllegalArgumentException -
*
- ERROR_INVALID_ARGUMENT - if the ascent is less than
-1
*
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-1
which means that the
* descent is calculated from the line fonts.
*
* @param descent the new descent
*
* @exception IllegalArgumentException -
*
- ERROR_INVALID_ARGUMENT - if the descent is less than
-1
*
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_INVALID_ARGUMENT - if the font has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
SWT.LEFT_TO_RIGHT
or SWT.RIGHT_TO_LEFT
.
*
* @param orientation new orientation style
*
* @exception SWTException -
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
* Each text segment is determined by two consecutive offsets in the
* segments
arrays. The first element of the array should
* always be zero and the last one should always be equals to length of
* the text.
*
* When segments characters are set, the segments are the offsets where * the characters are inserted in the text. *
* * @param segments the text segments offset * * @exception SWTException
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
TextLayout
.
*
* @param segmentsChars the segments characters
*
* @exception SWTException -
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_NULL_ARGUMENT - if the text is null *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
SWT.LEFT_TO_RIGHT
or SWT.RIGHT_TO_LEFT
.
*
* * Warning: This API is currently only implemented on Windows. * It doesn't set the base text direction on GTK and Cocoa. *
* * @param textDirection the new text direction * * @exception SWTException-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-1
which means wrapping is disabled.
*
* @param width the new width
*
* @exception IllegalArgumentException -
*
- ERROR_INVALID_ARGUMENT - if the width is
0
or less than-1
*
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *
-
*
- ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed *