浏览代码

Combine functions.

/main
Yuncong Zhang 5 年前
当前提交
ec3dbbd0
共有 2 个文件被更改,包括 239 次插入357 次删除
  1. 74
      Runtime/ui/txt/layout.cs
  2. 522
      Runtime/ui/txt/paragraph.cs

74
Runtime/ui/txt/layout.cs


static class Layout {
// Measure the length of the span of the text. Currently, this is only used to compute the length
// of ellipsis, assuming that the ellipsis does not contain any tab, tab is not considered for simplicity
public static float measureText(string text, int start, int count, TextStyle style) {
char startingChar = text[start];
public static float measureText(string text, TextStyle style) {
char startingChar = text[0];
for (int i = 0; i < count; i++) {
char ch = text[start + i];
for (int i = 0; i < text.Length; i++) {
char ch = text[i];
if (char.IsHighSurrogate(ch) || EmojiUtils.isSingleCharNonEmptyEmoji(ch)) {
totalWidth += advance;
}

Font font = FontManager.instance.getOrCreate(style.fontFamily, style.fontWeight, style.fontStyle).font;
font.RequestCharactersInTextureSafe(text.Substring(start, count), style.UnityFontSize, style.UnityFontStyle);
for (int i = 0; i < count; i++) {
char ch = text[start + i];
font.RequestCharactersInTextureSafe(text, style.UnityFontSize, style.UnityFontStyle);
for (int i = 0; i < text.Length; i++) {
char ch = text[i];
if (font.getGlyphInfo(ch, out var glyphInfo, style.UnityFontSize, style.UnityFontStyle)) {
totalWidth += glyphInfo.advance + style.letterSpacing;
}

return totalWidth;
}
public static int computeTruncateCount(float offset, string text, int start, int count, TextStyle style,
float advanceLimit, TabStops tabStops) {
char startingChar = text[start];

if (currentAdvance > advanceLimit) {
return count - i;
}
}
}
}
}
else {

currentAdvance += glyphInfo.advance + style.letterSpacing;
}
else {
currentAdvance = style.letterSpacing;
currentAdvance += style.letterSpacing;
if (currentAdvance > advanceLimit) {
return count - i;
}

return 0;
}
public static void computeCharWidths(string text, int start, int count, TextStyle style, float[] advances, int advanceOffset) {
public static void computeCharWidths(string text, int start, int count, TextStyle style, float[] advances,
int advanceOffset) {
char startingChar = text[start];
if (char.IsHighSurrogate(startingChar) || EmojiUtils.isSingleCharEmoji(startingChar)) {
float advance = style.fontSize + style.letterSpacing;

}
else {
Font font = FontManager.instance.getOrCreate(style.fontFamily, style.fontWeight, style.fontStyle).font;
font.RequestCharactersInTextureSafe(text.Substring(start, count), style.UnityFontSize, style.UnityFontStyle);
font.RequestCharactersInTextureSafe(text.Substring(start, count), style.UnityFontSize,
style.UnityFontStyle);
for (int i = 0; i < count; i++) {
char ch = text[start + i];
if (font.getGlyphInfo(ch, out var glyphInfo, style.UnityFontSize, style.UnityFontStyle)) {

}
public static float doLayout(float offset, string text, int start, int count, TextStyle style,
float[] advances, float[] positions, int advanceOffset, TabStops tabStops, out UnityEngine.Rect bounds) {
float[] advances, float[] positions, TabStops tabStops, out UnityEngine.Rect bounds) {
float advance = 0;
Font font = FontManager.instance.getOrCreate(style.fontFamily, style.fontWeight, style.fontStyle).font;

advance = _layoutEmoji(text, start, style, font, count, advances, positions, advanceOffset, advance, ref bounds);
advance = _layoutEmoji(text, start, count, style, font, advances, positions, ref bounds);
}
else {
// According to the logic of Paragraph.layout, it is assured that all the characters are requested

// font.RequestCharactersInTextureSafe(buff.text, style.UnityFontSize, style.UnityFontStyle);
// int wordstart = start == buff.size

for (int iter = start; iter < start + count; iter = wordend) {
wordend = LayoutUtils.getNextWordBreak(text, iter, start + count);
advance = _layoutWord(offset, iter - start, text, iter,
wordend - iter, style, font, advances, positions, advanceOffset, advance,
advance = _layoutWord(offset, iter - start, text, iter,
wordend - iter, style, font, advances, positions, advance,
tabStops, ref bounds);
}
}

static float _layoutWord(float offset, int layoutOffset,
string text, int start, int wordCount, TextStyle style, Font font, float[] advances,
float[] positions, int advanceOffset, float initAdvance, TabStops tabStops, ref UnityEngine.Rect bounds) {
float[] positions, float initAdvance, TabStops tabStops, ref UnityEngine.Rect bounds) {
float wordSpacing =
wordCount == 1 && LayoutUtils.isWordSpace(text[start]) ? style.wordSpacing : 0;

if (i == 0) {
x += letterSpaceHalfLeft + wordSpacing;
if (advances != null) {
advances[i + layoutOffset + advanceOffset] = letterSpaceHalfLeft + wordSpacing;
advances[i + layoutOffset] = letterSpaceHalfLeft + wordSpacing;
advances[i - 1 + layoutOffset + advanceOffset] += letterSpaceHalfRight;
advances[i + layoutOffset + advanceOffset] = letterSpaceHalfLeft;
advances[i - 1 + layoutOffset] += letterSpaceHalfRight;
advances[i + layoutOffset] = letterSpaceHalfLeft;
}
x += letterSpace;

positions[i + layoutOffset] = x;
}
float advance = glyphInfo.advance;
float advance;
else {
advance = glyphInfo.advance;
}
advances[i + layoutOffset + advanceOffset] += advance;
advances[i + layoutOffset] += advance;
advances[i + layoutOffset + advanceOffset] += letterSpaceHalfRight;
advances[i + layoutOffset] += letterSpaceHalfRight;
}
x += letterSpaceHalfRight;

return x;
}
static float _layoutEmoji(string text, int start, TextStyle style, Font font, int count, float[] advances,
float[] positions, int advanceOffset, float initAdvance, ref UnityEngine.Rect bounds) {
static float _layoutEmoji(string text, int start, int count, TextStyle style, Font font, float[] advances,
float[] positions, ref UnityEngine.Rect bounds) {
float x = initAdvance;
float x = 0;
for (int i = 0; i < count; i++) {
char c = text[start + i];
if (EmojiUtils.isSingleCharNonEmptyEmoji(c) || char.IsHighSurrogate(c)) {

x += letterSpaceHalfLeft;
if (advances != null) {
advances[i + advanceOffset] = letterSpaceHalfLeft;
advances[i] = letterSpaceHalfLeft;
}

x += advance;
if (advances != null) {
advances[i + advanceOffset] += advance;
advances[i + advanceOffset] += letterSpaceHalfRight;
advances[i] += advance;
advances[i] += letterSpaceHalfRight;
}
x += letterSpaceHalfRight;

advances[i + advanceOffset] = 0;
advances[i] = 0;
}
if (positions != null) {

bounds.yMax = maxY;
}
}
}
public static void requireEllipsisInTexture(string text, TextStyle style) {
Font font = FontManager.instance.getOrCreate(style.fontFamily, style.fontWeight, style.fontStyle).font;
font.RequestCharactersInTextureSafe(text, style.UnityFontSize, style.UnityFontStyle);
}
}
}

522
Runtime/ui/txt/paragraph.cs


public Range<float> xPos;
public readonly int start;
public readonly int count;
readonly GlyphPosition[] _positions;
public CodeUnitRun(GlyphPosition[] positions, Range<int> cu, Range<float> xPos, int line,

public readonly int start;
public readonly int count;
public readonly int totalCountUnits;
readonly GlyphPosition[] _positions;
public GlyphLine(GlyphPosition[] positions, int start, int count, int totalCountUnits) {

this._glyphLines.Clear();
this._computeLineBreak();
this._layout();
}
void _layout() {
int styleMaxLines = this._paragraphStyle.maxLines ?? int.MaxValue;
this._didExceedMaxLines = this._lineRanges.Count > styleMaxLines;

if (maxWordCount == 0) {
return;
}
Range<int>[] words = new Range<int>[maxWordCount];
float[] positions = null;
float[] advances = null;

this._computePaintRecordsFromLine(
lineNumber, ref lineLimit, ref styleRunIndex, ref maxWordWidth, ref yOffset, ref preMaxDescent,
builder, words, glyphPositions, ref pGlyphPositions, ref advances, ref positions
);
}
var lineRange = this._lineRanges[lineNumber];
int wordIndex = 0;
float runXOffset = 0;
float justifyXOffset = 0;
this._updateIntrinsicWidth(maxWordWidth);
}
void _computePaintRecordsFromLine(int lineNumber, ref int lineLimit, ref int styleRunIndex,
ref float maxWordWidth, ref float yOffset, ref float preMaxDescent, TextBlobBuilder builder,
Range<int>[] words, GlyphPosition[] glyphPositions, ref int pGlyphPositions, ref float[] advances, ref float[] positions) {
var lineRange = this._lineRanges[lineNumber];
int wordIndex = 0;
float runXOffset = 0;
float justifyXOffset = 0;
// Break the line into words if justification should be applied.
bool justifyLine = this._paragraphStyle.textAlign == TextAlign.justify &&
lineNumber != lineLimit - 1 && !lineRange.hardBreak;
// Break the line into words if justification should be applied.
bool justifyLine = this._paragraphStyle.textAlign == TextAlign.justify &&
lineNumber != lineLimit - 1 && !lineRange.hardBreak;
int wordCount = this._findWords(lineRange.start, lineRange.end, words);
float wordGapWidth = !(justifyLine && wordCount > 1)
? 0
: (this._width - this._lineWidths[lineNumber]) / (wordCount - 1);
int wordCount = this._findWords(lineRange.start, lineRange.end, words);
float wordGapWidth = !(justifyLine && wordCount > 1)
? 0
: (this._width - this._lineWidths[lineNumber]) / (wordCount - 1);
int lineStyleRunCount = this._countLineStyleRuns(lineRange, styleRunIndex, out int maxTextCount);
int lineStyleRunCount = this._countLineStyleRuns(lineRange, styleRunIndex, out int maxTextCount);
if (advances == null || advances.Length < maxTextCount) {
advances = new float[maxTextCount];
}
if (positions == null || positions.Length < maxTextCount) {
positions = new float[maxTextCount];
}
int glyphPositionStart = pGlyphPositions;
if (lineStyleRunCount != 0) {
int tLineLimit = lineLimit;
float tMaxWordWidth = maxWordWidth;
// Exclude trailing whitespace from right-justified lines so the last
// visible character in the line will be flush with the right margin.
int lineEndIndex = this._paragraphStyle.textAlign == TextAlign.right ||
this._paragraphStyle.textAlign == TextAlign.center
? lineRange.endExcludingWhitespace
: lineRange.end;
int lineStyleRunIndex = 0;
while (styleRunIndex < this._runs.size) {
var styleRun = this._runs.getRun(styleRunIndex);
if (styleRun.start < lineEndIndex && styleRun.end > lineRange.start) {
int start = Mathf.Max(styleRun.start, lineRange.start);
int end = Mathf.Min(styleRun.end, lineEndIndex);
// Make sure that each line is not empty
if (start < end) {
var isLastLineStyleRun = lineStyleRunIndex == lineStyleRunCount - 1;
this._paintRecords.Add(this._generatePaintRecordFromLineStyleRun(
new LineStyleRun(start, end, styleRun.style),
builder,
isLastLineStyleRun,
lineNumber,
justifyLine,
wordGapWidth,
wordCount,
ref tLineLimit,
ref wordIndex,
ref runXOffset,
ref justifyXOffset,
ref tMaxWordWidth,
words,
glyphPositions,
ref pGlyphPositions,
ref advances,
ref positions));
}
}
if (styleRun.end >= lineEndIndex) {
break;
}
styleRunIndex++;
if (advances == null || advances.Length < maxTextCount) {
advances = new float[maxTextCount];
lineLimit = tLineLimit;
maxWordWidth = tMaxWordWidth;
}
this._computeLineOffset(lineNumber, lineStyleRunCount, ref yOffset, ref preMaxDescent);
float lineXOffset = this.getLineXOffset(runXOffset);
this._shiftByLineXOffset(runXOffset, glyphPositions, pGlyphPositions - glyphPositionStart);
this._populateGlyphLines(lineNumber, glyphPositions, glyphPositionStart, pGlyphPositions - glyphPositionStart);
this._shiftPaintRecords(lineStyleRunCount, lineXOffset, yOffset);
}
int _countLineStyleRuns(LineRange lineRange, int styleRunIndex, out int maxTextCount) {
// Exclude trailing whitespace from right-justified lines so the last
// visible character in the line will be flush with the right margin.
int lineEndIndex = this._paragraphStyle.textAlign == TextAlign.right ||
this._paragraphStyle.textAlign == TextAlign.center
? lineRange.endExcludingWhitespace
: lineRange.end;
maxTextCount = 0;
int lineStyleRunCount = 0;
for (int i = styleRunIndex; i < this._runs.size; i++) {
var styleRun = this._runs.getRun(i);
if (styleRun.start < lineEndIndex && styleRun.end > lineRange.start) {
int start = Mathf.Max(styleRun.start, lineRange.start);
int end = Mathf.Min(styleRun.end, lineEndIndex);
// Make sure that each line is not empty
if (start < end) {
lineStyleRunCount++;
maxTextCount = Math.Max(end - start, maxTextCount);
}
if (positions == null || positions.Length < maxTextCount) {
positions = new float[maxTextCount];
if (styleRun.end >= lineEndIndex) {
break;
}
}
int glyphPositionStart = pGlyphPositions;
return lineStyleRunCount;
}
if (lineStyleRunCount != 0) {
int tLineLimit = lineLimit;
float tMaxWordWidth = maxWordWidth;
// Exclude trailing whitespace from right-justified lines so the last
// visible character in the line will be flush with the right margin.
int lineEndIndex = this._paragraphStyle.textAlign == TextAlign.right ||
this._paragraphStyle.textAlign == TextAlign.center
? lineRange.endExcludingWhitespace
: lineRange.end;
int lineStyleRunIndex = 0;
PaintRecord _generatePaintRecordFromLineStyleRun(
LineStyleRun run,
TextBlobBuilder builder,
bool isLastLineStyleRun,
int lineNumber,
bool justifyLine,
float wordGapWidth,
int wordCount,
ref int lineLimit,
ref int wordIndex,
ref float runXOffset,
ref float justifyXOffset,
ref float maxWordWidth,
Range<int>[] words,
GlyphPosition[] glyphPositions,
ref int pLineGlyphPositions,
ref float[] advances,
ref float[] positions) {
string text = this._text;
int textStart = run.start;
int textEnd = run.end;
int textCount = textEnd - textStart;
while (styleRunIndex < this._runs.size) {
var styleRun = this._runs.getRun(styleRunIndex);
if (styleRun.start < lineEndIndex && styleRun.end > lineRange.start) {
int start = Mathf.Max(styleRun.start, lineRange.start);
int end = Mathf.Min(styleRun.end, lineEndIndex);
// Make sure that each run is not empty
if (start < end) {
var run = new LineStyleRun(start, end, styleRun.style);
string text = this._text;
int textStart = run.start;
int textEnd = run.end;
int textCount = textEnd - textStart;
// It is assured in the _computeLineStyleRuns that run is not empty
D.assert(textCount != 0);
// It is assured in the _computeLineStyleRuns that run is not empty
D.assert(textCount != 0);
bool hardBreak = this._lineRanges[lineNumber].hardBreak;
if (this._shouldConsiderEllipsis(hardBreak, isLastLineStyleRun, lineNumber, lineLimit)) {
this._handleOverflowEllipsis(ref text, textStart, ref textCount, run.style, runXOffset);
if (this._paragraphStyle.maxLines == null) {
lineLimit = lineNumber + 1;
this._didExceedMaxLines = true;
}
}
bool hardBreak = this._lineRanges[lineNumber].hardBreak;
if (!string.IsNullOrEmpty(this._paragraphStyle.ellipsis) && !hardBreak &&
!this._width.isInfinite() && lineStyleRunIndex == lineStyleRunCount - 1 &&
(lineNumber == lineLimit - 1 || this._paragraphStyle.maxLines == null)) {
string ellipsis = this._paragraphStyle.ellipsis;
float ellipsisWidth = Layout.measureText(ellipsis, run.style);
if (advances == null || advances.Length < textCount) {
advances = new float[textCount];
}
if (positions == null || positions.Length < textCount) {
positions = new float[textCount];
}
float advance = Layout.doLayout(runXOffset, text, textStart, textCount, run.style, advances, positions,
0, this._tabStops, out var bounds);
// Find the minimum number of characters to truncate, so that the truncated text
// appended with ellipsis is within the constraints of line width
int truncateCount = Layout.computeTruncateCount(runXOffset, text, textStart,
textCount, run.style, this._width - ellipsisWidth, this._tabStops);
builder.allocRunPos(run.style, text, textStart, textCount);
// bounds relative to first character
bounds.x -= positions[0];
builder.setBounds(bounds);
text = text.Substring(0, textStart + textCount - truncateCount) + ellipsis;
textCount = text.Length - textStart;
D.assert(textCount != 0);
if (this._paragraphStyle.maxLines == null) {
lineLimit = lineNumber + 1;
this._didExceedMaxLines = true;
}
}
this._populateGlyphPositions(
textStart, textCount,
builder,
words,
glyphPositions,
advances,
positions,
run.start,
runXOffset,
wordGapWidth,
justifyLine,
wordCount,
ref pLineGlyphPositions,
ref wordIndex,
ref justifyXOffset,
ref maxWordWidth);
if (advances == null || advances.Length < textCount) {
advances = new float[textCount];
}
TextBlob textBlob = builder.make();
PaintRecord paintRecord = this._generatePaintRecord(run.style, textBlob, runXOffset, advance);
runXOffset += advance;
this._codeUnitRuns.Add(this._generateCodeUnitRun(run, lineNumber, glyphPositions,
pLineGlyphPositions - textCount, textCount));
if (positions == null || positions.Length < textCount) {
positions = new float[textCount];
}
return paintRecord;
}
float advance = Layout.doLayout(runXOffset, text, textStart, textCount, run.style,
advances, positions, this._tabStops, out var bounds);
bool _shouldConsiderEllipsis(bool hardBreak, bool isLastLineStyleRun, int lineNumber, int lineLimit) {
return !string.IsNullOrEmpty(this._paragraphStyle.ellipsis) && !this._width.isInfinite() && !hardBreak
&& isLastLineStyleRun && (lineNumber == lineLimit - 1 || this._paragraphStyle.maxLines == null);
}
builder.allocRunPos(run.style, text, textStart, textCount);
// bounds relative to first character
bounds.x -= positions[0];
builder.setBounds(bounds);
void _handleOverflowEllipsis(ref string text, int textStart, ref int textCount, TextStyle style,
float runXOffset) {
// By now, all characters have been "RequestCharactersInTexture"d by computeLineBreaks
// except the ellipsis, so Layout.doLayout skips calling RequestCharactersInTexture for
// performance, and the ellipsis is handled here
string ellipsis = this._paragraphStyle.ellipsis;
Layout.requireEllipsisInTexture(ellipsis, style);
float wordStartPosition = float.NaN;
for (int glyphIndex = 0; glyphIndex < textCount; ++glyphIndex) {
float glyphXOffset = positions[glyphIndex] + justifyXOffset;
float glyphAdvance = advances[glyphIndex];
builder.setPosition(glyphIndex, glyphXOffset);
glyphPositions[pGlyphPositions++] = new GlyphPosition(runXOffset + glyphXOffset,
glyphAdvance,
new Range<int>(textStart + glyphIndex, textStart + glyphIndex + 1));
if (words != null && wordIndex < wordCount) {
Range<int> word = words[wordIndex];
if (word.start == run.start + glyphIndex) {
wordStartPosition = runXOffset + glyphXOffset;
}
float ellipsisWidth = Layout.measureText(ellipsis, 0, ellipsis.Length, style);
if (word.end == run.start + glyphIndex + 1) {
if (justifyLine) {
justifyXOffset += wordGapWidth;
}
// Find the minimum number of characters to truncate, so that the truncated text appended with ellipsis
// is within the constraints of line width
int truncateCount = Layout.computeTruncateCount(runXOffset, text, textStart, textCount, style,
this._width - ellipsisWidth, this._tabStops);
wordIndex++;
if (!float.IsNaN(wordStartPosition)) {
maxWordWidth = Mathf.Max(maxWordWidth,
glyphPositions[pGlyphPositions - 1].xPos.end - wordStartPosition);
wordStartPosition = float.NaN;
}
}
}
}
text = text.Substring(0, textStart + textCount - truncateCount) + ellipsis;
textCount = text.Length - textStart;
}
TextBlob textBlob = builder.make();
var font = FontManager.instance.getOrCreate(run.style.fontFamily,
run.style.fontWeight, run.style.fontStyle).font;
var metrics = FontMetrics.fromFont(font, run.style.UnityFontSize);
PaintRecord paintRecord = new PaintRecord(run.style, runXOffset, 0, textBlob, metrics,
advance);
void _populateGlyphPositions(int textStart, int textCount,
TextBlobBuilder builder,
Range<int>[] words,
GlyphPosition[] glyphPositions,
float[] advances,
float[] positions,
int runStart,
float runXOffset,
float wordGapWidth,
bool justifyLine,
int wordCount,
ref int pLineGlyphPositions,
ref int wordIndex,
ref float justifyXOffset,
ref float maxWordWidth) {
D.assert(textCount != 0);
float wordStartPosition = float.NaN;
for (int glyphIndex = 0; glyphIndex < textCount; ++glyphIndex) {
float glyphXOffset = positions[glyphIndex] + justifyXOffset;
float glyphAdvance = advances[glyphIndex];
builder.setPosition(glyphIndex, glyphXOffset);
glyphPositions[pLineGlyphPositions++] = new GlyphPosition(runXOffset + glyphXOffset,
glyphAdvance, new Range<int>(textStart + glyphIndex, textStart + glyphIndex + 1));
if (words != null && wordIndex < wordCount) {
Range<int> word = words[wordIndex];
if (word.start == runStart + glyphIndex) {
wordStartPosition = runXOffset + glyphXOffset;
}
runXOffset += advance;
this._codeUnitRuns.Add(new CodeUnitRun(
glyphPositions,
new Range<int>(run.start, run.end),
new Range<float>(glyphPositions[0].xPos.start, glyphPositions.last().xPos.end),
lineNumber, TextDirection.ltr, pGlyphPositions - textCount, textCount));
if (word.end == runStart + glyphIndex + 1) {
if (justifyLine) {
justifyXOffset += wordGapWidth;
this._paintRecords.Add(paintRecord);
}
wordIndex++;
if (!float.IsNaN(wordStartPosition)) {
float wordWidth = glyphPositions[pLineGlyphPositions-1].xPos.end - wordStartPosition;
maxWordWidth = Mathf.Max(wordWidth, maxWordWidth);
wordStartPosition = float.NaN;
if (styleRun.end >= lineEndIndex) {
break;
styleRunIndex++;
lineLimit = tLineLimit;
maxWordWidth = tMaxWordWidth;
}
}
PaintRecord _generatePaintRecord(TextStyle style, TextBlob textBlob, float runXOffset, float advance) {
var font = FontManager.instance.getOrCreate(style.fontFamily,
style.fontWeight, style.fontStyle).font;
var metrics = FontMetrics.fromFont(font, style.UnityFontSize);
return new PaintRecord(style, runXOffset, 0, textBlob, metrics, advance);
}
float maxLineSpacing = 0;
float maxDescent = 0;
CodeUnitRun _generateCodeUnitRun(LineStyleRun run, int lineNumber, GlyphPosition[] glyphPositions, int start, int count) {
return new CodeUnitRun(glyphPositions,
new Range<int>(run.start, run.end),
new Range<float>(glyphPositions[0].xPos.start, glyphPositions.last().xPos.end),
lineNumber, TextDirection.ltr, start, count);
}
void updateLineMetrics(FontMetrics metrics, float styleHeight) {
float lineSpacing = lineNumber == 0
? -metrics.ascent * styleHeight
: (-metrics.ascent + metrics.leading) * styleHeight;
if (lineSpacing > maxLineSpacing) {
maxLineSpacing = lineSpacing;
if (lineNumber == 0) {
this._alphabeticBaseline = lineSpacing;
this._ideographicBaseline =
(metrics.underlinePosition ?? 0.0f - metrics.ascent) * styleHeight;
}
}
void _shiftByLineXOffset(float lineXOffset, GlyphPosition[] glyphPositions, int count) {
if (lineXOffset != 0 && glyphPositions != null) {
for (int i = 0; i < count; ++i) {
glyphPositions[glyphPositions.Length - i - 1].shiftSelf(lineXOffset);
float descent = metrics.descent * styleHeight;
maxDescent = Mathf.Max(descent, maxDescent);
}
}
void _populateGlyphLines(int lineNumber, GlyphPosition[] glyphPositions, int start, int count) {
int lineStart = this._lineRanges[lineNumber].start;
int nextLineStart = lineNumber < this._lineRanges.Count - 1
? this._lineRanges[lineNumber + 1].start
: this._text.Length;
this._glyphLines.Add(new GlyphLine(glyphPositions, start, count, nextLineStart - lineStart));
}
if (lineStyleRunCount != 0) {
for (int i = 0; i < lineStyleRunCount; i++) {
var paintRecord = this._paintRecords[this._paintRecords.Count - i - 1];
updateLineMetrics(paintRecord.metrics, paintRecord.style.height);
}
}
else {
var defaultFont = FontManager.instance.getOrCreate(
this._paragraphStyle.fontFamily ?? TextStyle.kDefaultFontFamily,
this._paragraphStyle.fontWeight ?? TextStyle.kDefaultFontWeight,
this._paragraphStyle.fontStyle ?? TextStyle.kDefaultfontStyle).font;
var metrics = FontMetrics.fromFont(defaultFont,
(int) (this._paragraphStyle.fontSize ?? TextStyle.kDefaultFontSize));
updateLineMetrics(metrics, this._paragraphStyle.lineHeight ?? TextStyle.kDefaultHeight);
}
void _computeLineOffset(int lineNumber, int lineStyleRunCount, ref float yOffset, ref float preMaxDescent) {
float maxLineSpacing = 0;
float maxDescent = 0;
void updateLineMetrics(FontMetrics metrics, float styleHeight) {
float lineSpacing = lineNumber == 0
? -metrics.ascent * styleHeight
: (-metrics.ascent + metrics.leading) * styleHeight;
if (lineSpacing > maxLineSpacing) {
maxLineSpacing = lineSpacing;
if (lineNumber == 0) {
this._alphabeticBaseline = lineSpacing;
this._ideographicBaseline =
(metrics.underlinePosition ?? 0.0f - metrics.ascent) * styleHeight;
this._lineHeights.Add((this._lineHeights.Count == 0 ? 0 : this._lineHeights.last())
+ Mathf.Round(maxLineSpacing + maxDescent));
this._lineBaseLines.Add(this._lineHeights.last() - maxDescent);
yOffset += Mathf.Round(maxLineSpacing + preMaxDescent);
preMaxDescent = maxDescent;
float lineXOffset = this.getLineXOffset(runXOffset);
int count = pGlyphPositions - glyphPositionStart;
if (lineXOffset != 0 && glyphPositions != null) {
for (int i = 0; i < count; ++i) {
glyphPositions[glyphPositions.Length - i - 1].shiftSelf(lineXOffset);
float descent = metrics.descent * styleHeight;
maxDescent = Mathf.Max(descent, maxDescent);
}
if (lineStyleRunCount != 0) {
int lineStart = this._lineRanges[lineNumber].start;
int nextLineStart = lineNumber < this._lineRanges.Count - 1
? this._lineRanges[lineNumber + 1].start
: this._text.Length;
this._glyphLines.Add(
new GlyphLine(glyphPositions, glyphPositionStart, count, nextLineStart - lineStart));
var paintRecord = this._paintRecords[this._paintRecords.Count - i - 1];
updateLineMetrics(paintRecord.metrics, paintRecord.style.height);
var paintRecord = this._paintRecords[this._paintRecords.Count - 1 - i];
paintRecord.shift(lineXOffset, yOffset);
this._paintRecords[this._paintRecords.Count - 1 - i] = paintRecord;
} else {
// TODO: the default values are filled in directly, to avoid the cost of creating a new TextStyle
// However this may become inconsistent with the default values in TextStyle (text.cs)
// A better way is to define some global constants used in both places.
var defaultFont = FontManager.instance.getOrCreate(
this._paragraphStyle.fontFamily ?? TextStyle.kDefaultFontFamily,
this._paragraphStyle.fontWeight ?? TextStyle.kDefaultFontWeight,
this._paragraphStyle.fontStyle ?? TextStyle.kDefaultfontStyle).font;
var metrics = FontMetrics.fromFont(defaultFont, (int) (this._paragraphStyle.fontSize ?? TextStyle.kDefaultFontSize));
updateLineMetrics(metrics, this._paragraphStyle.lineHeight ?? TextStyle.kDefaultHeight);
this._lineHeights.Add(
(this._lineHeights.Count == 0 ? 0 : this._lineHeights.last())
+ Mathf.Round(maxLineSpacing + maxDescent));
this._lineBaseLines.Add(this._lineHeights.last() - maxDescent);
yOffset += Mathf.Round(maxLineSpacing + preMaxDescent);
preMaxDescent = maxDescent;
}
void _shiftPaintRecords(int paintRecordsCount, float lineXOffset, float yOffset) {
for (int i = 0; i < paintRecordsCount; i++) {
var paintRecord = this._paintRecords[this._paintRecords.Count - 1 - i];
paintRecord.shift(lineXOffset, yOffset);
this._paintRecords[this._paintRecords.Count - 1 - i] = paintRecord;
}
}
void _updateIntrinsicWidth(float maxWordWidth) {
this._maxIntrinsicWidth = 0;
float lineBlockWidth = 0;
for (int i = 0; i < this._lineWidths.Count; ++i) {

else {
this._minIntrinsicWidth = Mathf.Min(maxWordWidth, this.maxIntrinsicWidth);
}
}
int _countLineStyleRuns(LineRange lineRange, int styleRunIndex, out int maxTextCount) {
// Exclude trailing whitespace from right-justified lines so the last
// visible character in the line will be flush with the right margin.
int lineEndIndex = this._paragraphStyle.textAlign == TextAlign.right ||
this._paragraphStyle.textAlign == TextAlign.center
? lineRange.endExcludingWhitespace
: lineRange.end;
maxTextCount = 0;
int lineStyleRunCount = 0;
for (int i = styleRunIndex; i < this._runs.size; i++) {
var styleRun = this._runs.getRun(i);
if (styleRun.start < lineEndIndex && styleRun.end > lineRange.start) {
int start = Mathf.Max(styleRun.start, lineRange.start);
int end = Mathf.Min(styleRun.end, lineEndIndex);
// Make sure that each line is not empty
if (start < end) {
lineStyleRunCount++;
maxTextCount = Math.Max(end - start, maxTextCount);
}
}
if (styleRun.end >= lineEndIndex) {
break;
}
}
return lineStyleRunCount;
}
internal void setText(string text, StyledRuns runs) {

var inWord = false;
int wordCount = 0;
int wordStart = 0;
for (int i = start; i < end; ++i) {
bool isSpace = LayoutUtils.isWordSpace(this._text[i]);
if (!inWord && !isSpace) {

正在加载...
取消
保存