runs[line] = reorder(runs[line]);
runs[line] = reorder(runs[line], i == allRuns.length - 1);
void computeRuns (GC gc) {	if (runs != null) return;	int hDC = gc != null ? gc.handle : device.internal_new_GC(null);	int srcHdc = OS.CreateCompatibleDC(hDC);	allRuns = itemize();	for (int i=0; i<allRuns.length - 1; i++) {		StyleItem run = allRuns[i];		OS.SelectObject(srcHdc, getItemFont(run));		shape(srcHdc, run);	}	SCRIPT_LOGATTR logAttr = new SCRIPT_LOGATTR();	SCRIPT_PROPERTIES properties = new SCRIPT_PROPERTIES();	int lineWidth = indent, lineStart = 0, lineCount = 1;	for (int i=0; i<allRuns.length - 1; i++) {		StyleItem run = allRuns[i];		if (run.length == 1) {			char ch = segmentsText.charAt(run.start);			switch (ch) {				case '\t': {					run.tab = true;					if (tabs == null) break;					int tabsLength = tabs.length, j;					for (j = 0; j < tabsLength; j++) {						if (tabs[j] > 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;						}					}					break;				}				case '\n': {					run.lineBreak = true;					break;				}				case '\r': {					run.lineBreak = true;					StyleItem next = allRuns[i + 1];					if (next.length != 0 && segmentsText.charAt(next.start) == '\n') {						run.length += 1;						next.free();						i++;					}					break;				}			}		} 		if (wrapWidth != -1 && lineWidth + run.width > wrapWidth && !run.tab) {			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;			}			if (start == 0 && i != lineStart && !run.tab) {				run = allRuns[--i];			} else 	if (start <= 0 && i == lineStart) {				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 = run.analysis;				run.free();				run.length = start;				OS.SelectObject(srcHdc, getItemFont(run));				shape (srcHdc, run);				OS.SelectObject(srcHdc, getItemFont(newRun));				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 ?  0 : 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<allRuns.length; i++) {		StyleItem run = allRuns[i];		lineRuns[lineRunCount++] = run;		lineWidth += run.width;		ascent = Math.max(ascent, run.ascent);		descent = Math.max(descent, run.descent);		if (run.lineBreak || i == allRuns.length - 1) {			/* Update the run metrics if the last run is a hard break. */			if (lineRunCount == 1 && i == allRuns.length - 1) {				TEXTMETRIC lptm = OS.IsUnicode ? (TEXTMETRIC)new TEXTMETRICW() : new TEXTMETRICA();				OS.SelectObject(srcHdc, getItemFont(run));				OS.GetTextMetrics(srcHdc, lptm);				run.ascent = lptm.tmAscent;				run.descent = lptm.tmDescent;				ascent = Math.max(ascent, run.ascent);				descent = Math.max(descent, run.descent);			}			runs[line] = new StyleItem[lineRunCount];			System.arraycopy(lineRuns, 0, runs[line], 0, lineRunCount);						if (justify && wrapWidth != -1 && run.softBreak && lineWidth > 0) {				if (line == 0) {					lineWidth += indent;				} else {					StyleItem[] previousLine = runs[line - 1];					StyleItem previousRun = previousLine[previousLine.length - 1];					if (previousRun.lineBreak && !previousRun.softBreak) {						lineWidth += indent;					}				}				int 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);						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;						runs[line] = reorder(runs[line]);			StyleItem 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] = lastRun.start + lastRun.length;			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);	}