Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/TextLayout.java')
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/TextLayout.java495
1 files changed, 296 insertions, 199 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/TextLayout.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/TextLayout.java
index 663d970214..1c71538df3 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/TextLayout.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/TextLayout.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -18,6 +18,7 @@ import java.util.*;
import org.eclipse.swt.*;
import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.gdip.*;
+import org.eclipse.swt.internal.ole.win32.*;
import org.eclipse.swt.internal.win32.*;
/**
@@ -60,21 +61,40 @@ public final class TextLayout extends Resource {
StyleItem[] allRuns;
StyleItem[][] runs;
int[] lineOffset, lineY, lineWidth;
- long /*int*/ mLangFontLink2;
+ IMLangFontLink2 mLangFontLink2;
int verticalIndentInPoints;
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;
+ /**
+ * Runs over a certain length (32000 characters / 65536 Glyphs / 32768 pixels -
+ * these numbers come from WinAPI docs + analysis done in Bug 23406 Comment 31)
+ * will fail to render in ScriptTextOut, ScriptShape, ScriptPlace so such
+ * long runs need to be split into shorter runs. Because it is expensive to
+ * keep testing (with Script*) to maximize the length we use this heuristic
+ * to minimize the length. However splitting the runs into too short pieces
+ * affects performance, so this is a balance.
+ */
+ static final int MAX_RUN_LENGTH = 32000;
+ /**
+ * When splitting a run (see {@link #MAX_RUN_LENGTH}) the run needs to split
+ * in a way that does not affect the display of the glyphs, so it is important
+ * to not split the run in the middle of a glyph. We use the same info to find
+ * where we can wrap text to find where we can break the runs (ScriptBreak's info).
+ * This setting limits how far back from {@link #MAX_RUN_LENGTH} the code
+ * will search for a break before forcing a break at {@link #MAX_RUN_LENGTH}.
+ */
+ static final int MAX_SEARCH_RUN_BREAK = 1000;
+ {
+ // While developing the splitting long runs it can be useful to
+ // make these constants smaller, but these invariants must
+ // preserved even in such cases.
+ assert MAX_RUN_LENGTH > 1;
+ assert MAX_SEARCH_RUN_BREAK < MAX_RUN_LENGTH;
+ }
/* IME has a copy of these constants */
static final int UNDERLINE_IME_DOT = 1 << 16;
@@ -88,17 +108,17 @@ public final class TextLayout extends Resource {
/*Script cache and analysis */
SCRIPT_ANALYSIS analysis;
- long /*int*/ psc = 0;
+ long psc = 0;
/*Shape info (malloc when the run is shaped) */
- long /*int*/ glyphs;
+ long glyphs;
int glyphCount;
- long /*int*/ clusters;
- long /*int*/ visAttrs;
+ long clusters;
+ long visAttrs;
/*Place info (malloc when the run is placed) */
- long /*int*/ advances;
- long /*int*/ goffsets;
+ long advances;
+ long goffsets;
int width;
int ascentInPoints;
int descentInPoints;
@@ -108,15 +128,16 @@ public final class TextLayout extends Resource {
int strikeoutPos, strikeoutThickness;
/* Justify info (malloc during computeRuns) */
- long /*int*/ justify;
+ long justify;
/* ScriptBreak */
- long /*int*/ psla;
+ int pslaAllocSize;
+ long psla;
- long /*int*/ fallbackFont;
+ long fallbackFont;
void free() {
- long /*int*/ hHeap = OS.GetProcessHeap();
+ long hHeap = OS.GetProcessHeap();
if (psc != 0) {
OS.ScriptFreeCache (psc);
OS.HeapFree(hHeap, 0, psc);
@@ -190,10 +211,10 @@ public TextLayout (Device device) {
styles[1] = new StyleItem();
stylesCount = 2;
text = ""; //$NON-NLS-1$
- long /*int*/[] ppv = new long /*int*/[1];
+ long[] ppv = new long[1];
OS.OleInitialize(0);
- if (OS.CoCreateInstance(CLSID_CMultiLanguage, 0, OS.CLSCTX_INPROC_SERVER, IID_IMLangFontLink2, ppv) == OS.S_OK) {
- mLangFontLink2 = ppv[0];
+ if (COM.CoCreateInstance(COM.CLSID_CMultiLanguage, 0, COM.CLSCTX_INPROC_SERVER, COM.IID_IMLangFontLink2, ppv) == OS.S_OK) {
+ mLangFontLink2 = new IMLangFontLink2(ppv[0]);
}
init();
}
@@ -227,7 +248,8 @@ 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);
- long /*int*/ hHeap = OS.GetProcessHeap();
+ long hHeap = OS.GetProcessHeap();
+ run.pslaAllocSize = SCRIPT_LOGATTR.sizeof * chars.length;
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);
@@ -243,8 +265,8 @@ void checkLayout () {
*/
void computeRuns (GC gc) {
if (runs != null) return;
- long /*int*/ hDC = gc != null ? gc.handle : device.internal_new_GC(null);
- long /*int*/ srcHdc = OS.CreateCompatibleDC(hDC);
+ long hDC = gc != null ? gc.handle : device.internal_new_GC(null);
+ long srcHdc = OS.CreateCompatibleDC(hDC);
allRuns = itemize();
for (int i=0; i<allRuns.length - 1; i++) {
StyleItem run = allRuns[i];
@@ -272,6 +294,11 @@ void computeRuns (GC gc) {
run.width = tabX - lineWidth;
}
}
+
+ /*
+ * This block adjusts the indentation after merged tabs stops.
+ * The extra tabs are removed in merge.
+ */
int length = run.length;
if (length > 1) {
int stop = j + length - 1;
@@ -434,10 +461,9 @@ void computeRuns (GC gc) {
}
}
lineWidth += lineIndent;
- long /*int*/ hHeap = OS.GetProcessHeap();
+ long hHeap = OS.GetProcessHeap();
int newLineWidth = 0;
- for (int j = 0; j < runs[line].length; j++) {
- StyleItem item = runs[line][j];
+ for (StyleItem item : runs[line]) {
int iDx = item.width * wrapWidth / lineWidth;
if (iDx != item.width) {
item.justify = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, item.glyphCount * 4);
@@ -461,9 +487,9 @@ void computeRuns (GC gc) {
}
lineWidth = getLineIndent(line);
- for (int j = 0; j < runs[line].length; j++) {
- runs[line][j].x = lineWidth;
- lineWidth += runs[line][j].width;
+ for (StyleItem run1 : runs[line]) {
+ run1.x = lineWidth;
+ lineWidth += run1.width;
}
line++;
lineY[line] = lineY[line - 1] + ascentInPoints + descentInPoints + lineSpacingInPoints;
@@ -491,10 +517,9 @@ void destroy () {
lineWidth = null;
segments = null;
segmentsChars = null;
- if (mLangFontLink2 != 0) {
- /* Release() */
- OS.VtblCall(2, mLangFontLink2);
- mLangFontLink2 = 0;
+ if (mLangFontLink2 != null) {
+ mLangFontLink2.Release();
+ mLangFontLink2 = null;
}
OS.OleUninitialize();
}
@@ -546,12 +571,12 @@ int[] computePolyline(int left, int top, int right, int bottom) {
return coordinates;
}
-long /*int*/ createGdipBrush(int pixel, int alpha) {
+long createGdipBrush(int pixel, int alpha) {
int argb = ((alpha & 0xFF) << 24) | ((pixel >> 16) & 0xFF) | (pixel & 0xFF00) | ((pixel & 0xFF) << 16);
return Gdip.SolidBrush_new(argb);
}
-long /*int*/ createGdipBrush(Color color, int alpha) {
+long createGdipBrush(Color color, int alpha) {
return createGdipBrush(color.handle, alpha);
}
@@ -648,16 +673,16 @@ void drawInPixels (GC gc, int x, int y, int selectionStart, int selectionEnd, Co
int length = text.length();
if (length == 0 && flags == 0) return;
y += getScaledVerticalIndent();
- long /*int*/ hdc = gc.handle;
+ long hdc = gc.handle;
Rectangle clip = gc.getClippingInPixels();
GCData data = gc.data;
- long /*int*/ gdipGraphics = data.gdipGraphics;
+ long gdipGraphics = data.gdipGraphics;
int foreground = data.foreground;
int linkColor = OS.GetSysColor (OS.COLOR_HOTLIGHT);
int alpha = data.alpha;
boolean gdip = gdipGraphics != 0;
- long /*int*/ gdipForeground = 0;
- long /*int*/ gdipLinkColor = 0;
+ long gdipForeground = 0;
+ long gdipLinkColor = 0;
int state = 0;
if (gdip) {
gc.checkGC(GC.FOREGROUND);
@@ -669,8 +694,8 @@ void drawInPixels (GC gc, int x, int y, int selectionStart, int selectionEnd, Co
}
}
boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1;
- long /*int*/ gdipSelBackground = 0, gdipSelForeground = 0, gdipFont = 0, lastHFont = 0;
- long /*int*/ selBackground = 0;
+ long gdipSelBackground = 0, gdipSelForeground = 0, gdipFont = 0, lastHFont = 0;
+ 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);
@@ -731,8 +756,7 @@ void drawInPixels (GC gc, int x, int y, int selectionStart, int selectionEnd, Co
//Draw the background of the runs in the line
int alignmentX = drawX;
- for (int i = 0; i < lineRuns.length; i++) {
- StyleItem run = lineRuns[i];
+ for (StyleItem run : lineRuns) {
if (run.length == 0) continue;
if (drawX > clip.x + clip.width) break;
if (drawX + run.width >= clip.x) {
@@ -751,9 +775,9 @@ void drawInPixels (GC gc, int x, int y, int selectionStart, int selectionEnd, Co
//Draw the text, underline, strikeout, and border of the runs in the line
int baselineInPixels = Math.max(0, this.ascentInPixels);
int lineUnderlinePos = 0;
- for (int i = 0; i < lineRuns.length; i++) {
- baselineInPixels = Math.max(baselineInPixels, DPIUtil.autoScaleUp(getDevice(), lineRuns[i].ascentInPoints));
- lineUnderlinePos = Math.min(lineUnderlinePos, lineRuns[i].underlinePos);
+ for (StyleItem run : lineRuns) {
+ baselineInPixels = Math.max(baselineInPixels, DPIUtil.autoScaleUp(getDevice(), run.ascentInPoints));
+ lineUnderlinePos = Math.min(lineUnderlinePos, run.underlinePos);
}
RECT borderClip = null, underlineClip = null, strikeoutClip = null, pRect = null;
drawX = alignmentX;
@@ -768,11 +792,11 @@ void drawInPixels (GC gc, int x, int y, int selectionStart, int selectionEnd, Co
if (!skipTab && (!run.lineBreak || run.softBreak) && !(style != null && style.metrics != null)) {
OS.SetRect(rect, drawX, drawY, drawX + run.width, drawY + lineHeight);
if (gdip) {
- long /*int*/ hFont = getItemFont(run);
+ long hFont = getItemFont(run);
if (hFont != lastHFont) {
lastHFont = hFont;
if (gdipFont != 0) Gdip.Font_delete(gdipFont);
- long /*int*/ oldFont = OS.SelectObject(hdc, hFont);
+ 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);
@@ -781,7 +805,7 @@ void drawInPixels (GC gc, int x, int y, int selectionStart, int selectionEnd, Co
gdipFont = 0;
}
}
- long /*int*/ gdipFg = gdipForeground;
+ long gdipFg = gdipForeground;
if (style != null && style.underline && style.underlineStyle == SWT.UNDERLINE_LINK) {
if (gdipLinkColor == 0) gdipLinkColor = createGdipBrush(linkColor, alpha);
gdipFg = gdipLinkColor;
@@ -815,14 +839,14 @@ void drawInPixels (GC gc, int x, int y, int selectionStart, int selectionEnd, Co
if (selBackground != 0) OS.DeleteObject (selBackground);
}
-RECT drawBorder(long /*int*/ 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) {
+RECT drawBorder(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)) {
+ if (index + 1 >= line.length || lastRunVisible || line[index + 1].lineBreak || !style.isAdherentBorder(line[index + 1].style)) {
int left = run.x;
int start = run.start;
int end = run.start + run.length - 1;
@@ -862,12 +886,12 @@ RECT drawBorder(long /*int*/ hdc, int x, int y, int lineHeight, StyleItem[] line
break;
}
}
- long /*int*/ oldBrush = OS.SelectObject(hdc, OS.GetStockObject(OS.NULL_BRUSH));
+ long oldBrush = OS.SelectObject(hdc, OS.GetStockObject(OS.NULL_BRUSH));
LOGBRUSH logBrush = new LOGBRUSH();
logBrush.lbStyle = OS.BS_SOLID;
- logBrush.lbColor = /*64*/(int)color;
- long /*int*/ newPen = OS.ExtCreatePen(lineStyle | OS.PS_GEOMETRIC, lineWidth, logBrush, 0, null);
- long /*int*/ oldPen = OS.SelectObject(hdc, newPen);
+ logBrush.lbColor = color;
+ long newPen = OS.ExtCreatePen(lineStyle | OS.PS_GEOMETRIC, lineWidth, logBrush, 0, null);
+ 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) {
@@ -888,8 +912,8 @@ RECT drawBorder(long /*int*/ hdc, int x, int y, int lineHeight, StyleItem[] line
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;
- long /*int*/ selPen = OS.ExtCreatePen (lineStyle | OS.PS_GEOMETRIC, lineWidth, logBrush, 0, null);
+ logBrush.lbColor = selectionColor;
+ 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);
@@ -902,14 +926,14 @@ RECT drawBorder(long /*int*/ hdc, int x, int y, int lineHeight, StyleItem[] line
return clipRect;
}
-RECT drawBorderGDIP(long /*int*/ graphics, int x, int y, int lineHeight, StyleItem[] line, int index, long /*int*/ color, long /*int*/ selectionColor, RECT clipRect, RECT pRect, int selectionStart, int selectionEnd, int alpha, Rectangle drawClip) {
+RECT drawBorderGDIP(long graphics, int x, int y, int lineHeight, StyleItem[] line, int index, long color, 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)) {
+ if (index + 1 >= line.length || lastRunVisible || line[index + 1].lineBreak || !style.isAdherentBorder(line[index + 1].style)) {
int left = run.x;
int start = run.start;
int end = run.start + run.length - 1;
@@ -920,7 +944,7 @@ RECT drawBorderGDIP(long /*int*/ graphics, int x, int y, int lineHeight, StyleIt
}
boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1;
boolean fullSelection = hasSelection && selectionStart <= start && end <= selectionEnd;
- long /*int*/ brush = color;
+ long brush = color;
if (style.borderColor != null) {
brush = createGdipBrush(style.borderColor, alpha);
clipRect = null;
@@ -941,7 +965,7 @@ RECT drawBorderGDIP(long /*int*/ graphics, int x, int y, int lineHeight, StyleIt
case SWT.BORDER_DASH: lineStyle = Gdip.DashStyleDash; break;
case SWT.BORDER_DOT: lineStyle = Gdip.DashStyleDot; break;
}
- long /*int*/ pen = Gdip.Pen_new(brush, lineWidth);
+ long pen = Gdip.Pen_new(brush, lineWidth);
Gdip.Pen_SetDashStyle(pen, lineStyle);
Gdip.Graphics_SetPixelOffsetMode(graphics, Gdip.PixelOffsetModeNone);
int smoothingMode = Gdip.Graphics_GetSmoothingMode(graphics);
@@ -960,7 +984,7 @@ RECT drawBorderGDIP(long /*int*/ graphics, int x, int y, int lineHeight, StyleIt
Gdip.Graphics_Restore(graphics, gstate);
gstate = Gdip.Graphics_Save(graphics);
Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeIntersect);
- long /*int*/ selPen = Gdip.Pen_new(selectionColor, lineWidth);
+ 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);
@@ -977,7 +1001,7 @@ RECT drawBorderGDIP(long /*int*/ graphics, int x, int y, int lineHeight, StyleIt
return clipRect;
}
-void drawRunBackground(StyleItem run, long /*int*/ hdc, RECT rect, int selectionStart, int selectionEnd, long /*int*/ selBrush, boolean hasSelection) {
+void drawRunBackground(StyleItem run, long hdc, RECT rect, int selectionStart, int selectionEnd, long selBrush, boolean hasSelection) {
int end = run.start + run.length - 1;
boolean fullSelection = hasSelection && selectionStart <= run.start && selectionEnd >= end;
if (fullSelection) {
@@ -986,8 +1010,8 @@ void drawRunBackground(StyleItem run, long /*int*/ hdc, RECT rect, int selection
} else {
if (run.style != null && run.style.background != null) {
int bg = run.style.background.handle;
- long /*int*/ hBrush = OS.CreateSolidBrush (bg);
- long /*int*/ oldBrush = OS.SelectObject(hdc, hBrush);
+ long hBrush = OS.CreateSolidBrush (bg);
+ 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);
@@ -1001,14 +1025,14 @@ void drawRunBackground(StyleItem run, long /*int*/ hdc, RECT rect, int selection
}
}
-void drawRunBackgroundGDIP(StyleItem run, long /*int*/ graphics, RECT rect, int selectionStart, int selectionEnd, int alpha, long /*int*/ selBrush, boolean hasSelection) {
+void drawRunBackgroundGDIP(StyleItem run, long graphics, RECT rect, int selectionStart, int selectionEnd, int alpha, 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) {
- long /*int*/ brush = createGdipBrush(run.style.background, alpha);
+ 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);
}
@@ -1025,7 +1049,7 @@ void drawRunBackgroundGDIP(StyleItem run, long /*int*/ graphics, RECT rect, int
}
}
-RECT drawRunText(long /*int*/ hdc, StyleItem run, RECT rect, int baselineInPixels, int color, int selectionColor, int selectionStart, int selectionEnd) {
+RECT drawRunText(long hdc, StyleItem run, RECT rect, int baselineInPixels, 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;
@@ -1033,7 +1057,7 @@ RECT drawRunText(long /*int*/ hdc, StyleItem run, RECT rect, int baselineInPixel
int offset = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? -1 : 0;
int x = rect.left + offset;
int y = rect.top + (baselineInPixels - DPIUtil.autoScaleUp(getDevice(), run.ascentInPoints));
- long /*int*/ hFont = getItemFont(run);
+ long hFont = getItemFont(run);
OS.SelectObject(hdc, hFont);
if (fullSelection) {
color = selectionColor;
@@ -1052,7 +1076,7 @@ RECT drawRunText(long /*int*/ hdc, StyleItem run, RECT rect, int baselineInPixel
return fullSelection || partialSelection ? rect : null;
}
-RECT drawRunTextGDIP(long /*int*/ graphics, StyleItem run, RECT rect, long /*int*/ gdipFont, int baselineInPixels, long /*int*/ color, long /*int*/ selectionColor, int selectionStart, int selectionEnd, int alpha) {
+RECT drawRunTextGDIP(long graphics, StyleItem run, RECT rect, long gdipFont, int baselineInPixels, long color, 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;
@@ -1060,7 +1084,7 @@ RECT drawRunTextGDIP(long /*int*/ graphics, StyleItem run, RECT rect, long /*int
int drawY = rect.top + baselineInPixels;
if (run.style != null && run.style.rise != 0) drawY -= DPIUtil.autoScaleUp(getDevice(), run.style.rise);
int drawX = rect.left;
- long /*int*/ brush = color;
+ long brush = color;
if (fullSelection) {
brush = selectionColor;
} else {
@@ -1137,10 +1161,10 @@ RECT drawRunTextGDIP(long /*int*/ graphics, StyleItem run, RECT rect, long /*int
return fullSelection || partialSelection ? rect : null;
}
-RECT drawRunTextGDIPRaster(long /*int*/ graphics, StyleItem run, RECT rect, int baselineInPixels, int color, int selectionColor, int selectionStart, int selectionEnd) {
- long /*int*/ clipRgn = 0;
+RECT drawRunTextGDIPRaster(long graphics, StyleItem run, RECT rect, int baselineInPixels, int color, int selectionColor, int selectionStart, int selectionEnd) {
+ long clipRgn = 0;
Gdip.Graphics_SetPixelOffsetMode(graphics, Gdip.PixelOffsetModeNone);
- long /*int*/ rgn = Gdip.Region_new();
+ 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)) {
@@ -1149,7 +1173,7 @@ RECT drawRunTextGDIPRaster(long /*int*/ graphics, StyleItem run, RECT rect, int
Gdip.Region_delete(rgn);
Gdip.Graphics_SetPixelOffsetMode(graphics, Gdip.PixelOffsetModeHalf);
float[] lpXform = null;
- long /*int*/ matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0);
+ 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)) {
@@ -1157,7 +1181,7 @@ RECT drawRunTextGDIPRaster(long /*int*/ graphics, StyleItem run, RECT rect, int
Gdip.Matrix_GetElements(matrix, lpXform);
}
Gdip.Matrix_delete(matrix);
- long /*int*/ hdc = Gdip.Graphics_GetHDC(graphics);
+ long hdc = Gdip.Graphics_GetHDC(graphics);
int state = OS.SaveDC(hdc);
if (lpXform != null) {
OS.SetGraphicsMode(hdc, OS.GM_ADVANCED);
@@ -1177,14 +1201,14 @@ RECT drawRunTextGDIPRaster(long /*int*/ graphics, StyleItem run, RECT rect, int
return pRect;
}
-RECT drawStrikeout(long /*int*/ hdc, int x, int baselineInPixels, StyleItem[] line, int index, int color, int selectionColor, RECT clipRect, RECT pRect, int selectionStart, int selectionEnd, Rectangle drawClip) {
+RECT drawStrikeout(long hdc, int x, int baselineInPixels, 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)) {
+ if (index + 1 >= line.length || lastRunVisible || line[index + 1].lineBreak || !style.isAdherentStrikeout(line[index + 1].style)) {
int left = run.x;
int start = run.start;
int end = run.start + run.length - 1;
@@ -1211,11 +1235,11 @@ RECT drawStrikeout(long /*int*/ hdc, int x, int baselineInPixels, StyleItem[] li
RECT rect = new RECT();
int riseInPixels = DPIUtil.autoScaleUp(getDevice(), style.rise);
OS.SetRect(rect, x + left, baselineInPixels - run.strikeoutPos - riseInPixels, x + run.x + run.width, baselineInPixels - run.strikeoutPos + run.strikeoutThickness - riseInPixels);
- long /*int*/ brush = OS.CreateSolidBrush(color);
+ long brush = OS.CreateSolidBrush(color);
OS.FillRect(hdc, rect, brush);
OS.DeleteObject(brush);
if (clipRect != null) {
- long /*int*/ selBrush = OS.CreateSolidBrush(selectionColor);
+ 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);
@@ -1227,14 +1251,14 @@ RECT drawStrikeout(long /*int*/ hdc, int x, int baselineInPixels, StyleItem[] li
return clipRect;
}
-RECT drawStrikeoutGDIP(long /*int*/ graphics, int x, int baselineInPixels, StyleItem[] line, int index, long /*int*/ color, long /*int*/ selectionColor, RECT clipRect, RECT pRect, int selectionStart, int selectionEnd, int alpha, Rectangle drawClip) {
+RECT drawStrikeoutGDIP(long graphics, int x, int baselineInPixels, StyleItem[] line, int index, long color, 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)) {
+ if (index + 1 >= line.length || lastRunVisible || line[index + 1].lineBreak || !style.isAdherentStrikeout(line[index + 1].style)) {
int left = run.x;
int start = run.start;
int end = run.start + run.length - 1;
@@ -1245,7 +1269,7 @@ RECT drawStrikeoutGDIP(long /*int*/ graphics, int x, int baselineInPixels, Style
}
boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1;
boolean fullSelection = hasSelection && selectionStart <= start && end <= selectionEnd;
- long /*int*/ brush = color;
+ long brush = color;
if (style.strikeoutColor != null) {
brush = createGdipBrush(style.strikeoutColor, alpha);
clipRect = null;
@@ -1285,14 +1309,14 @@ RECT drawStrikeoutGDIP(long /*int*/ graphics, int x, int baselineInPixels, Style
return clipRect;
}
-RECT drawUnderline(long /*int*/ hdc, int x, int baselineInPixels, int lineUnderlinePos, int lineBottom, StyleItem[] line, int index, int color, int selectionColor, RECT clipRect, RECT pRect, int selectionStart, int selectionEnd, Rectangle drawClip) {
+RECT drawUnderline(long hdc, int x, int baselineInPixels, 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)) {
+ if (index + 1 >= line.length || lastRunVisible || line[index + 1].lineBreak || !style.isAdherentUnderline(line[index + 1].style)) {
int left = run.x;
int start = run.start;
int end = run.start + run.length - 1;
@@ -1331,8 +1355,8 @@ RECT drawUnderline(long /*int*/ hdc, int x, int baselineInPixels, int lineUnderl
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);
- long /*int*/ pen = OS.CreatePen(OS.PS_SOLID, squigglyThickness, color);
- long /*int*/ oldPen = OS.SelectObject(hdc, pen);
+ long pen = OS.CreatePen(OS.PS_SOLID, squigglyThickness, color);
+ 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);
@@ -1371,7 +1395,7 @@ RECT drawUnderline(long /*int*/ hdc, int x, int baselineInPixels, int lineUnderl
OS.OffsetRect(rect, 0, lineBottom - bottom);
if (clipRect != null) OS.OffsetRect(clipRect, 0, lineBottom - bottom);
}
- long /*int*/ brush = OS.CreateSolidBrush(color);
+ 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);
@@ -1379,7 +1403,7 @@ RECT drawUnderline(long /*int*/ hdc, int x, int baselineInPixels, int lineUnderl
}
OS.DeleteObject(brush);
if (clipRect != null) {
- long /*int*/ selBrush = OS.CreateSolidBrush(selectionColor);
+ 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);
@@ -1391,8 +1415,8 @@ RECT drawUnderline(long /*int*/ hdc, int x, int baselineInPixels, int lineUnderl
case UNDERLINE_IME_DASH:
case UNDERLINE_IME_DOT: {
int penStyle = style.underlineStyle == UNDERLINE_IME_DASH ? OS.PS_DASH : OS.PS_DOT;
- long /*int*/ pen = OS.CreatePen(penStyle, 1, color);
- long /*int*/ oldPen = OS.SelectObject(hdc, pen);
+ long pen = OS.CreatePen(penStyle, 1, color);
+ long oldPen = OS.SelectObject(hdc, pen);
int descentInPixels = DPIUtil.autoScaleUp(getDevice(), run.descentInPoints);
OS.SetRect(rect, rect.left, baselineInPixels + descentInPixels, rect.right, baselineInPixels + descentInPixels + run.underlineThickness);
OS.MoveToEx(hdc, rect.left, rect.top, 0);
@@ -1416,14 +1440,14 @@ RECT drawUnderline(long /*int*/ hdc, int x, int baselineInPixels, int lineUnderl
return clipRect;
}
-RECT drawUnderlineGDIP (long /*int*/ graphics, int x, int baselineInPixels, int lineUnderlinePos, int lineBottom, StyleItem[] line, int index, long /*int*/ color, long /*int*/ selectionColor, RECT clipRect, RECT pRect, int selectionStart, int selectionEnd, int alpha, Rectangle drawClip) {
+RECT drawUnderlineGDIP (long graphics, int x, int baselineInPixels, int lineUnderlinePos, int lineBottom, StyleItem[] line, int index, long color, 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)) {
+ if (index + 1 >= line.length || lastRunVisible || line[index + 1].lineBreak || !style.isAdherentUnderline(line[index + 1].style)) {
int left = run.x;
int start = run.start;
int end = run.start + run.length - 1;
@@ -1434,7 +1458,7 @@ RECT drawUnderlineGDIP (long /*int*/ graphics, int x, int baselineInPixels, int
}
boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1;
boolean fullSelection = hasSelection && selectionStart <= start && end <= selectionEnd;
- long /*int*/ brush = color;
+ long brush = color;
if (style.underlineColor != null) {
brush = createGdipBrush(style.underlineColor, alpha);
clipRect = null;
@@ -1473,7 +1497,7 @@ RECT drawUnderlineGDIP (long /*int*/ graphics, int x, int baselineInPixels, int
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);
- long /*int*/ pen = Gdip.Pen_new(brush, squigglyThickness);
+ long pen = Gdip.Pen_new(brush, squigglyThickness);
gstate = Gdip.Graphics_Save(graphics);
if (gdipRect != null) {
Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeExclude);
@@ -1487,7 +1511,7 @@ RECT drawUnderlineGDIP (long /*int*/ graphics, int x, int baselineInPixels, int
}
Gdip.Graphics_DrawLines(graphics, pen, points, points.length / 2);
if (gdipRect != null) {
- long /*int*/ selPen = Gdip.Pen_new(selectionColor, squigglyThickness);
+ long selPen = Gdip.Pen_new(selectionColor, squigglyThickness);
Gdip.Graphics_Restore(graphics, gstate);
gstate = Gdip.Graphics_Save(graphics);
Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeIntersect);
@@ -1538,7 +1562,7 @@ RECT drawUnderlineGDIP (long /*int*/ graphics, int x, int baselineInPixels, int
break;
case UNDERLINE_IME_DOT:
case UNDERLINE_IME_DASH: {
- long /*int*/ pen = Gdip.Pen_new(brush, 1);
+ 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) {
@@ -1551,7 +1575,7 @@ RECT drawUnderlineGDIP (long /*int*/ graphics, int x, int baselineInPixels, int
Gdip.Graphics_Restore(graphics, gstate);
gstate = Gdip.Graphics_Save(graphics);
Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeIntersect);
- long /*int*/ selPen = Gdip.Pen_new(brush, 1);
+ long selPen = Gdip.Pen_new(brush, 1);
Gdip.Pen_SetDashStyle(selPen, dashStyle);
Gdip.Graphics_DrawLine(graphics, selPen, rect.left, baselineInPixels + descentInPixels, run.width - run.length, baselineInPixels + descentInPixels);
Gdip.Graphics_Restore(graphics, gstate);
@@ -1571,8 +1595,7 @@ RECT drawUnderlineGDIP (long /*int*/ graphics, int x, int baselineInPixels, int
void freeRuns () {
if (allRuns == null) return;
- for (int i=0; i<allRuns.length; i++) {
- StyleItem run = allRuns[i];
+ for (StyleItem run : allRuns) {
run.free();
}
allRuns = null;
@@ -1707,10 +1730,8 @@ Rectangle getBoundsInPixels (int start, int end) {
GlyphMetrics metrics = run.style.metrics;
cx = metrics.getWidthInPixels() * (start - run.start);
} else if (!run.tab) {
- int[] piX = new int[1];
- long /*int*/ advances = run.justify != 0 ? run.justify : run.advances;
- OS.ScriptCPtoX(start - run.start, false, run.length, run.glyphCount, run.clusters, run.visAttrs, advances, run.analysis, piX);
- cx = isRTL ? run.width - piX[0] : piX[0];
+ int iX = ScriptCPtoX(start - run.start, false, run);
+ cx = isRTL ? run.width - iX : iX;
}
if (run.analysis.fRTL ^ isRTL) {
runTrail = run.x + cx;
@@ -1724,10 +1745,8 @@ Rectangle getBoundsInPixels (int start, int end) {
GlyphMetrics metrics = run.style.metrics;
cx = metrics.getWidthInPixels() * (end - run.start + 1);
} else if (!run.tab) {
- int[] piX = new int[1];
- long /*int*/ advances = run.justify != 0 ? run.justify : run.advances;
- OS.ScriptCPtoX(end - run.start, true, run.length, run.glyphCount, run.clusters, run.visAttrs, advances, run.analysis, piX);
- cx = isRTL ? run.width - piX[0] : piX[0];
+ int iX = ScriptCPtoX(end - run.start, true, run);
+ cx = isRTL ? run.width - iX : iX;
}
if (run.analysis.fRTL ^ isRTL) {
runLead = run.x + cx;
@@ -1817,7 +1836,7 @@ public boolean getJustify () {
return justify;
}
-long /*int*/ getItemFont (StyleItem item) {
+long getItemFont (StyleItem item) {
if (item.fallbackFont != 0) return item.fallbackFont;
if (item.style != null && item.style.font != null) {
return item.style.font.handle;
@@ -1975,8 +1994,8 @@ public FontMetrics getLineMetrics (int lineIndex) {
checkLayout();
computeRuns(null);
if (!(0 <= lineIndex && lineIndex < runs.length)) SWT.error(SWT.ERROR_INVALID_RANGE);
- long /*int*/ hDC = device.internal_new_GC(null);
- long /*int*/ srcHdc = OS.CreateCompatibleDC(hDC);
+ long hDC = device.internal_new_GC(null);
+ long srcHdc = OS.CreateCompatibleDC(hDC);
TEXTMETRIC lptm = new TEXTMETRIC();
OS.SelectObject(srcHdc, font != null ? font.handle : device.systemFont.handle);
OS.GetTextMetrics(srcHdc, lptm);
@@ -1987,9 +2006,7 @@ public FontMetrics getLineMetrics (int lineIndex) {
int descentInPoints = DPIUtil.autoScaleDown(getDevice(), Math.max(lptm.tmDescent, this.descentInPixels));
int leadingInPoints = DPIUtil.autoScaleDown(getDevice(), lptm.tmInternalLeading);
if (text.length() != 0) {
- StyleItem[] lineRuns = runs[lineIndex];
- for (int i = 0; i<lineRuns.length; i++) {
- StyleItem run = lineRuns[i];
+ for (StyleItem run : runs[lineIndex]) {
if (run.ascentInPoints > ascentInPoints) {
ascentInPoints = run.ascentInPoints;
leadingInPoints = run.leadingInPoints;
@@ -2100,12 +2117,8 @@ Point getLocationInPixels (int offset, boolean trailing) {
width = (trailing || (offset == length)) ? run.width : 0;
} else {
int runOffset = offset - run.start;
- int cChars = run.length;
- int gGlyphs = run.glyphCount;
- int[] piX = new int[1];
- long /*int*/ advances = run.justify != 0 ? run.justify : run.advances;
- OS.ScriptCPtoX(runOffset, trailing, cChars, gGlyphs, run.clusters, run.visAttrs, advances, run.analysis, piX);
- width = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? run.width - piX[0] : piX[0];
+ final int iX = ScriptCPtoX(runOffset, trailing, run);
+ width = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? run.width - iX : iX;
}
return new Point(run.x + width, DPIUtil.autoScaleUp(getDevice(), lineY[line]) + getScaledVerticalIndent());
}
@@ -2114,6 +2127,24 @@ Point getLocationInPixels (int offset, boolean trailing) {
}
/**
+ * Wrapper around
+ * {@link OS#ScriptCPtoX(int, boolean, int, int, long, long, long, SCRIPT_ANALYSIS, int[])}
+ * to handle common arguments consistently.
+ *
+ * @param characterPosition the first argument of OS.ScriptCPtoX
+ * @param trailing the first argument of OS.ScriptCPtoX
+ * @param run used to define remaining arguments of OS.ScriptCPtoX
+ * @return x position of the caret.
+ */
+private int ScriptCPtoX(int characterPosition, boolean trailing, StyleItem run) {
+ int[] piX = new int[1];
+ long advances = run.justify != 0 ? run.justify : run.advances;
+ OS.ScriptCPtoX(characterPosition, trailing, run.length, run.glyphCount, run.clusters, run.visAttrs, advances,
+ run.analysis, piX);
+ return piX[0];
+}
+
+/**
* Returns the next offset for the specified offset and movement
* type. The movement is one of <code>SWT.MOVEMENT_CHAR</code>,
* <code>SWT.MOVEMENT_CLUSTER</code>, <code>SWT.MOVEMENT_WORD</code>,
@@ -2320,7 +2351,7 @@ int getOffsetInPixels (int x, int y, int[] trailing) {
if ((orientation & SWT.RIGHT_TO_LEFT) != 0) {
xRun = run.width - xRun;
}
- long /*int*/ advances = run.justify != 0 ? run.justify : run.advances;
+ long advances = run.justify != 0 ? run.justify : run.advances;
OS.ScriptXtoCP(xRun, cChars, cGlyphs, run.clusters, run.visAttrs, advances, run.analysis, piCP, piTrailing);
int offset = run.start + piCP[0];
int length = segmentsText.length();
@@ -2372,16 +2403,12 @@ void getPartialSelection(StyleItem run, int selectionStart, int selectionEnd, RE
int end = run.start + run.length - 1;
int selStart = Math.max(selectionStart, run.start) - run.start;
int selEnd = Math.min(selectionEnd, end) - run.start;
- int cChars = run.length;
- int gGlyphs = run.glyphCount;
- int[] piX = new int[1];
int x = rect.left;
- long /*int*/ advances = run.justify != 0 ? run.justify : run.advances;
- OS.ScriptCPtoX(selStart, false, cChars, gGlyphs, run.clusters, run.visAttrs, advances, run.analysis, piX);
- int runX = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? run.width - piX[0] : piX[0];
+ int iX = ScriptCPtoX(selStart, false, run);
+ int runX = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? run.width - iX : iX;
rect.left = x + runX;
- OS.ScriptCPtoX(selEnd, true, cChars, gGlyphs, run.clusters, run.visAttrs, advances, run.analysis, piX);
- runX = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? run.width - piX[0] : piX[0];
+ iX = ScriptCPtoX(selEnd, true, run);
+ runX = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? run.width - iX : iX;
rect.right = x + runX;
}
@@ -2718,27 +2745,45 @@ StyleItem[] itemize () {
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.
- */
-// scriptControl.fReserved = 0x1;
-
- OS.ScriptApplyDigitSubstitution(null, scriptControl, scriptState);
+ OS.ScriptApplyDigitSubstitution(0, scriptControl, scriptState);
- long /*int*/ hHeap = OS.GetProcessHeap();
- long /*int*/ pItems = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, MAX_ITEM * SCRIPT_ITEM.sizeof);
+ long hHeap = OS.GetProcessHeap();
+ // This buffer needs to be one entry bigger than the cMaxItems param to ScriptItemize
+ // see https://docs.microsoft.com/en-us/windows/win32/api/usp10/nf-usp10-scriptitemize
+ // and https://bugzilla.mozilla.org/show_bug.cgi?id=366643 which was a similar bug
+ // in Mozilla. The MSDN docs have been updated since the Mozilla bug to make this clear
+ long pItems = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, (1 + 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);
+ // enable font ligatures
+ scriptControl.fMergeNeutralItems = true;
+ /*
+ * With font ligatures enabled: CJK characters are not rendered properly when
+ * used in Java comments, workaround is to avoid ligatures between ascii and
+ * non-ascii chars. For more details refer bug 565526
+ */
+ for (int i = 0, latestNeutralIndex = -2, latestUnicodeIndex = -2; i < length; i++) {
+ char c = chars[i];
+
+ if (c >= ' ' && c <= '~' && !Character.isAlphabetic(c)) {
+ latestNeutralIndex = i;
+ } else if (c > 255) {
+ latestUnicodeIndex = i;
+ } else {
+ continue;
+ }
+
+ // If the latest neutral and unicode characters are adjacent
+ if (Math.abs(latestNeutralIndex - latestUnicodeIndex) == 1) {
+ // Change the neutral into a non-neutral alphabet character
+ chars[latestNeutralIndex] = 'A';
+ }
+ }
+
OS.ScriptItemize(chars, length, MAX_ITEM, scriptControl, scriptState, pItems, pcItems);
+
// if (hr == E_OUTOFMEMORY) //TODO handle it
StyleItem[] runs = merge(pItems, pcItems[0]);
@@ -2749,14 +2794,19 @@ StyleItem[] itemize () {
/*
* Merge styles ranges and script items
*/
-StyleItem[] merge (long /*int*/ items, int itemCount) {
+StyleItem[] merge (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];
+ final int end = segmentsText.length();
+ int start = 0, itemIndex = 0, styleIndex = 0;
+ /*
+ * Maximum size of runs is each itemized item + each style needing its own run +
+ * enough space for splitting runs that are too long.
+ */
+ List<StyleItem> runs = new ArrayList<>(itemCount + stylesCount + (end + MAX_RUN_LENGTH - 1) / MAX_RUN_LENGTH);
SCRIPT_ITEM scriptItem = new SCRIPT_ITEM();
int itemLimit = -1;
int nextItemIndex = 0;
@@ -2767,7 +2817,7 @@ StyleItem[] merge (long /*int*/ items, int itemCount) {
StyleItem item = new StyleItem();
item.start = start;
item.style = styles[styleIndex].style;
- runs[count++] = item;
+ runs.add(item);
OS.MoveMemory(scriptItem, items + itemIndex * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof);
item.analysis = scriptItem.a;
scriptItem.a = new SCRIPT_ANALYSIS();
@@ -2794,6 +2844,13 @@ StyleItem[] merge (long /*int*/ items, int itemCount) {
OS.MoveMemory(scriptItem, items + nextItemIndex * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof);
itemLimit = scriptItem.iCharPos;
}
+
+ /*
+ * This block merges a bunch of tabs or non-complex scripts into a single item
+ * run. This is done so that less item runs are needed and is used when there
+ * could be a performance penalty because of too many runs.
+ * The tabs need to be "restored", see computeRuns
+ */
if (nextItemIndex < itemCount && merge) {
if (!item.lineBreak) {
OS.MoveMemory(sp, device.scripts[item.analysis.eScript], SCRIPT_PROPERTIES.sizeof);
@@ -2814,20 +2871,28 @@ StyleItem[] merge (long /*int*/ items, int itemCount) {
}
}
+ boolean mayNeedSplit = true;
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 (Character.isLetter(pChar) && Character.isLetter(tChar)) {
- item.analysis.fLinkAfter = true;
- linkBefore = true;
+ int runLen = styleLimit - start;
+ if (runLen < MAX_RUN_LENGTH) {
+ mayNeedSplit = false;
+ styleIndex++;
+ start = styleLimit;
+ if (start < itemLimit && 0 < start && start < end) {
+ char pChar = segmentsText.charAt(start - 1);
+ char tChar = segmentsText.charAt(start);
+ if (Character.isLetter(pChar) && Character.isLetter(tChar)) {
+ item.analysis.fLinkAfter = true;
+ linkBefore = true;
+ }
}
}
}
- if (itemLimit <= styleLimit) {
+ int runLen = itemLimit - start;
+ if (mayNeedSplit && runLen > MAX_RUN_LENGTH) {
+ start += splitLongRun(item);
+ } else if (itemLimit <= styleLimit) {
itemIndex = nextItemIndex;
start = itemLimit;
itemLimit = -1;
@@ -2838,13 +2903,43 @@ StyleItem[] merge (long /*int*/ items, int itemCount) {
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;
+ runs.add(item);
+ return runs.toArray(StyleItem[]::new);
+}
+
+/**
+ * Use OS.ScriptBreak to identify where in the run it is safe to split a character.
+ * @param run the run to split
+ * @return how many characters into the run is the best place to split
+ */
+int splitLongRun(StyleItem run) {
+ run.length = MAX_RUN_LENGTH;
+ breakRun(run);
+ SCRIPT_LOGATTR logAttr = new SCRIPT_LOGATTR();
+ int best = MAX_RUN_LENGTH;
+ for (int i = MAX_RUN_LENGTH - 1; i >= MAX_RUN_LENGTH - MAX_SEARCH_RUN_BREAK; i--) {
+ int memoryIndex = i * SCRIPT_LOGATTR.sizeof;
+ if (memoryIndex + SCRIPT_LOGATTR.sizeof > run.pslaAllocSize) {
+ throw new IndexOutOfBoundsException();
+ }
+ OS.MoveMemory(logAttr, run.psla + memoryIndex, SCRIPT_LOGATTR.sizeof);
+ if (logAttr.fSoftBreak || logAttr.fWhiteSpace || logAttr.fWordStop) {
+ best = i;
+ break;
+ }
}
- return runs;
+
+ /*
+ * In the improbable case that the entire run has nowhere to split we need to
+ * make sure that at least we don't split a surrogate pair. This can happen
+ * if ScriptBreak above identifies nowhere that can be split, and the last
+ * character is the first part of a surrogate pair.
+ */
+ if (Character.isHighSurrogate(segmentsText.charAt(run.start + best - 1))) {
+ best--;
+ }
+
+ return best;
}
/*
@@ -3414,7 +3509,7 @@ void setWrapIndentInPixels (int wrapIndent) {
this.wrapIndent = wrapIndent;
}
-boolean shape (long /*int*/ hdc, StyleItem run, char[] chars, int[] glyphCount, int maxGlyphs, SCRIPT_PROPERTIES sp) {
+boolean shape (long hdc, StyleItem run, char[] chars, int[] glyphCount, int maxGlyphs, SCRIPT_PROPERTIES sp) {
boolean useCMAPcheck = !sp.fComplex && !run.analysis.fNoGlyphIndex;
if (useCMAPcheck) {
short[] glyphs = new short[chars.length];
@@ -3422,16 +3517,23 @@ boolean shape (long /*int*/ hdc, StyleItem run, char[] chars, int[] glyphCount,
if (run.psc != 0) {
OS.ScriptFreeCache(run.psc);
glyphCount[0] = 0;
- OS.MoveMemory(run.psc, new long /*int*/ [1], C.PTR_SIZEOF);
+ OS.MoveMemory(run.psc, new long [1], C.PTR_SIZEOF);
}
return false;
}
}
- int hr = OS.ScriptShape(hdc, run.psc, chars, chars.length, maxGlyphs, run.analysis, run.glyphs, run.clusters, run.visAttrs, glyphCount);
- run.glyphCount = glyphCount[0];
- if (useCMAPcheck) return true;
+ int scriptShaprHr = OS.ScriptShape(hdc, run.psc, chars, chars.length, maxGlyphs, run.analysis, run.glyphs,
+ run.clusters, run.visAttrs, glyphCount);
+ if (scriptShaprHr == OS.S_OK) {
+ run.glyphCount = glyphCount[0];
+ if (useCMAPcheck) return true;
- if (hr != OS.USP_E_SCRIPT_NOT_IN_FONT) {
+ /*
+ * scriptShapeHr could have been OS.USP_E_SCRIPT_NOT_IN_FONT which indicates
+ * the whole run doesn't work with the font. The rest of this method verifies that
+ * none of the individual glyphs are missing an entry in the font.
+ * The fallback is to try other fonts (See caller)
+ */
if (run.analysis.fNoGlyphIndex) return true;
SCRIPT_FONTPROPERTIES fp = new SCRIPT_FONTPROPERTIES ();
fp.cBytes = SCRIPT_FONTPROPERTIES.sizeof;
@@ -3447,14 +3549,14 @@ boolean shape (long /*int*/ hdc, StyleItem run, char[] chars, int[] glyphCount,
if (run.psc != 0) {
OS.ScriptFreeCache(run.psc);
glyphCount[0] = 0;
- OS.MoveMemory(run.psc, new long /*int*/ [1], C.PTR_SIZEOF);
+ OS.MoveMemory(run.psc, new long [1], C.PTR_SIZEOF);
}
run.glyphCount = 0;
return false;
}
-long /*int*/ createMetafileWithChars(long /*int*/ hdc, long /*int*/ hFont, char[] chars, int charCount) {
- long /*int*/ hHeap = OS.GetProcessHeap();
+long createMetafileWithChars(long hdc, long hFont, char[] chars, int charCount) {
+ long hHeap = OS.GetProcessHeap();
/*
* The native string must remain unchanged between ScriptStringAnalyse and ScriptStringOut.
@@ -3466,12 +3568,12 @@ long /*int*/ createMetafileWithChars(long /*int*/ hdc, long /*int*/ hFont, char[
* temporary native string which will be deallocated upon return from ScriptStringAnalyse.
*/
int nativeStringSize = charCount * Character.BYTES;
- long /*int*/ nativeString = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, nativeStringSize);
+ long nativeString = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, nativeStringSize);
OS.MoveMemory (nativeString, chars, nativeStringSize);
- long /*int*/ ssa = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, OS.SCRIPT_STRING_ANALYSIS_sizeof());
- long /*int*/ metaFileDc = OS.CreateEnhMetaFile(hdc, null, null, null);
- long /*int*/ oldMetaFont = OS.SelectObject(metaFileDc, hFont);
+ long ssa = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, OS.SCRIPT_STRING_ANALYSIS_sizeof());
+ long metaFileDc = OS.CreateEnhMetaFile(hdc, null, null, null);
+ long oldMetaFont = OS.SelectObject(metaFileDc, hFont);
int flags = OS.SSA_METAFILE | OS.SSA_FALLBACK | OS.SSA_GLYPHS | OS.SSA_LINK;
if (OS.ScriptStringAnalyse(metaFileDc, nativeString, charCount, 0, -1, flags, 0, null, null, 0, 0, 0, ssa) == OS.S_OK) {
OS.ScriptStringOut(ssa, 0, 0, 0, null, 0, 0, false);
@@ -3486,7 +3588,7 @@ long /*int*/ createMetafileWithChars(long /*int*/ hdc, long /*int*/ hFont, char[
/*
* Generate glyphs for one Run.
*/
-void shape (final long /*int*/ hdc, final StyleItem run) {
+void shape (final long hdc, final StyleItem run) {
if (run.lineBreak) return;
if (run.glyphs != 0) return;
final int[] buffer = new int[1];
@@ -3494,7 +3596,7 @@ void shape (final long /*int*/ hdc, final StyleItem run) {
segmentsText.getChars(run.start, run.start + run.length, chars, 0);
final int maxGlyphs = (chars.length * 3 / 2) + 16;
- long /*int*/ hHeap = OS.GetProcessHeap();
+ long hHeap = OS.GetProcessHeap();
run.glyphs = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, maxGlyphs * 2);
if (run.glyphs == 0) SWT.error(SWT.ERROR_NO_HANDLES);
run.clusters = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, maxGlyphs * 2);
@@ -3514,8 +3616,8 @@ void shape (final long /*int*/ hdc, final StyleItem run) {
}
}
if (!shapeSucceed) {
- long /*int*/ hFont = OS.GetCurrentObject(hdc, OS.OBJ_FONT);
- long /*int*/ newFont = 0;
+ long hFont = OS.GetCurrentObject(hdc, OS.OBJ_FONT);
+ long newFont = 0;
/*
* Bug in Uniscribe. In some version of Uniscribe, ScriptStringAnalyse crashes
* when the character array is too long. The fix is to limit the size of character
@@ -3534,10 +3636,10 @@ void shape (final long /*int*/ hdc, final StyleItem run) {
}
}
if (count > 0) {
- long /*int*/ metaFile = createMetafileWithChars(hdc, hFont, sampleChars, count);
+ long metaFile = createMetafileWithChars(hdc, hFont, sampleChars, count);
final EMREXTCREATEFONTINDIRECTW emr = new EMREXTCREATEFONTINDIRECTW();
class MetaFileEnumProc {
- long /*int*/ metaFileEnumProc (long /*int*/ hDC, long /*int*/ table, long /*int*/ record, long /*int*/ nObj, long /*int*/ lpData) {
+ long metaFileEnumProc (long hDC, long table, long record, long nObj, long lpData) {
OS.MoveMemory(emr.emr, record, EMR.sizeof);
switch (emr.emr.iType) {
case OS.EMR_EXTCREATEFONTINDIRECTW:
@@ -3554,9 +3656,7 @@ void shape (final long /*int*/ hdc, final StyleItem run) {
boolean compilerWarningWorkaround = false;
if (compilerWarningWorkaround) object.metaFileEnumProc(0, 0, 0, 0, 0);
Callback callback = new Callback(object, "metaFileEnumProc", 5);
- long /*int*/ address = callback.getAddress();
- if (address == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
- OS.EnumEnhMetaFile(0, metaFile, address, 0, null);
+ OS.EnumEnhMetaFile(0, metaFile, callback.getAddress(), 0, null);
OS.DeleteEnhMetaFile(metaFile);
callback.dispose();
newFont = OS.CreateFontIndirect(emr.elfw.elfLogFont);
@@ -3573,7 +3673,7 @@ void shape (final long /*int*/ hdc, final StyleItem run) {
if (index > 0) {
StyleItem pRun = allRuns[index - 1];
if (pRun.analysis.eScript == run.analysis.eScript) {
- long /*int*/ pFont = getItemFont(pRun);
+ long pFont = getItemFont(pRun);
LOGFONT logFont = new LOGFONT ();
OS.GetObject(pFont, LOGFONT.sizeof, logFont);
newFont = OS.CreateFontIndirect(logFont);
@@ -3585,7 +3685,7 @@ void shape (final long /*int*/ hdc, final StyleItem run) {
if (nRun.analysis.eScript == run.analysis.eScript) {
OS.SelectObject(hdc, getItemFont(nRun));
shape(hdc, nRun);
- long /*int*/ nFont = getItemFont(nRun);
+ long nFont = getItemFont(nRun);
LOGFONT logFont = new LOGFONT ();
OS.GetObject(nFont, LOGFONT.sizeof, logFont);
newFont = OS.CreateFontIndirect(logFont);
@@ -3614,19 +3714,16 @@ void shape (final long /*int*/ hdc, final StyleItem run) {
}
}
if (!shapeSucceed) {
- if (mLangFontLink2 != 0) {
- long /*int*/[] hNewFont = new long /*int*/[1];
+ if (mLangFontLink2 != null) {
+ long [] hNewFont = new long [1];
int[] dwCodePages = new int[1], cchCodePages = new int[1];
- /* GetStrCodePages() */
- OS.VtblCall(4, mLangFontLink2, chars, chars.length, 0, dwCodePages, cchCodePages);
- /* MapFont() */
- if (OS.VtblCall(10, mLangFontLink2, hdc, dwCodePages[0], chars[0], hNewFont) == OS.S_OK) {
+ mLangFontLink2.GetStrCodePages(chars, chars.length, 0, dwCodePages, cchCodePages);
+ if (mLangFontLink2.MapFont(hdc, dwCodePages[0], chars[0], hNewFont) == OS.S_OK) {
LOGFONT logFont = new LOGFONT ();
OS.GetObject(hNewFont[0], LOGFONT.sizeof, logFont);
- /* ReleaseFont() */
- OS.VtblCall(8, mLangFontLink2, hNewFont[0]);
- long /*int*/ mLangFont = OS.CreateFontIndirect(logFont);
- long /*int*/ oldFont = OS.SelectObject(hdc, mLangFont);
+ mLangFontLink2.ReleaseFont(hNewFont[0]);
+ long mLangFont = OS.CreateFontIndirect(logFont);
+ long oldFont = OS.SelectObject(hdc, mLangFont);
if (shapeSucceed = shape(hdc, run, chars, buffer, maxGlyphs, sp)) {
run.fallbackFont = mLangFont;
} else {

Back to the top