浏览代码

Optimize layout.

/main
Yuncong Zhang 6 年前
当前提交
822731d2
共有 9 个文件被更改,包括 389 次插入341 次删除
  1. 4
      Runtime/painting/text_painter.cs
  2. 14
      Runtime/rendering/editable.cs
  3. 2
      Runtime/ui/text.cs
  4. 543
      Runtime/ui/txt/layout.cs
  5. 37
      Runtime/ui/txt/linebreaker.cs
  6. 2
      Runtime/ui/txt/paint_record.cs
  7. 109
      Runtime/ui/txt/paragraph.cs
  8. 7
      Runtime/ui/txt/word_separate.cs
  9. 12
      Runtime/ui/txt/wordbreaker.cs

4
Runtime/painting/text_painter.cs


var prevCodeUnit = this._text.codeUnitAt(offset);
if (prevCodeUnit == null) // out of upper bounds
{
var rectNextLine = this._paragraph.getNextLineStartRect();
TextBox? rectNextLine = this._paragraph.getNextLineStartRect();
return new Offset(rectNextLine.start, rectNextLine.top);
return new Offset(((TextBox) rectNextLine).start, ((TextBox) rectNextLine).top);
}
}
}

14
Runtime/rendering/editable.cs


public TextPosition getParagraphForward(TextPosition position, TextAffinity? affinity = null) {
var lineCount = this._textPainter.getLineCount();
Paragraph.LineRange line = null;
Paragraph.LineRange? line = null;
if (!line.hardBreak) {
if (!((Paragraph.LineRange) line).hardBreak) {
if (line.end > position.offset) {
if (((Paragraph.LineRange) line).end > position.offset) {
break;
}
}

}
return new TextPosition(line.end, affinity ?? position.affinity);
return new TextPosition(((Paragraph.LineRange) line).end, affinity ?? position.affinity);
}

Paragraph.LineRange line = null;
Paragraph.LineRange? line = null;
for (int i = lineCount - 1; i >= 0; --i) {
line = this._textPainter.getLineRange(i);
if (i != 0 && !this._textPainter.getLineRange(i - 1).hardBreak) {

if (line.start < position.offset) {
if (((Paragraph.LineRange) line).start < position.offset) {
break;
}
}

}
return new TextPosition(line.start, affinity ?? position.affinity);
return new TextPosition(((Paragraph.LineRange) line).start, affinity ?? position.affinity);
}
protected override float computeMinIntrinsicWidth(float height) {

2
Runtime/ui/text.cs


}
}
public class TextBox : IEquatable<TextBox> {
public struct TextBox : IEquatable<TextBox> {
public readonly float left;
public readonly float top;

543
Runtime/ui/txt/layout.cs


using System.Collections.Generic;
using Unity.UIWidgets.foundation;
using UnityEngine;
namespace Unity.UIWidgets.ui {
class Layout {
int _start;
int _count;
List<float> _advances = new List<float>();
List<float> _positions = new List<float>();
float _advance;
UnityEngine.Rect _bounds;
TabStops _tabStops;
static UnityEngine.Rect _innerBounds; // Used to pass bounds from static to non-static doLayout
public static float measureText(float offset, TextBuff buff, int start, int count, TextStyle style,
List<float> advances, int advanceOffset, TabStops tabStops) {
return _doLayout(offset, buff, start, count, style, advances, null, advanceOffset, tabStops);
}
public void doLayout(float offset, TextBuff buff, int start, int count, TextStyle style) {
this._start = start;
this._count = count;
this._advances.reset(count);
this._positions.reset(count);
_innerBounds = default;
this._advance = _doLayout(offset, buff, start, count, style, this._advances, this._positions, 0,
this._tabStops);
this._bounds = _innerBounds;
this._count = count;
}
static float _doLayout(float offset, TextBuff buff, int start, int count, TextStyle style,
List<float> advances, List<float> positions, int advanceOffset, TabStops tabStops) {
float advance = 0;
Font font = FontManager.instance.getOrCreate(style.fontFamily, style.fontWeight, style.fontStyle).font;
char startingChar = buff.text[buff.offset + start];
if (char.IsHighSurrogate(startingChar) || EmojiUtils.isSingleCharEmoji(startingChar)) {
advance = _layoutEmoji(buff.text.Substring(buff.offset + start, count), style, font, count,
advances, positions, advanceOffset, advance);
}
else {
font.RequestCharactersInTextureSafe(buff.text, style.UnityFontSize, style.UnityFontStyle);
int wordstart = start == buff.size
? start
: LayoutUtils.getPrevWordBreakForCache(buff, start + 1);
int wordend;
for (int iter = start; iter < start + count; iter = wordend) {
wordend = LayoutUtils.getNextWordBreakForCache(buff, iter);
int wordCount = Mathf.Min(start + count, wordend) - iter;
advance = _layoutWord(offset, iter - start, buff.subBuff(wordstart, wordend - wordstart),
iter - wordstart, wordCount, style, font, advances, positions,
advanceOffset, advance, tabStops);
wordstart = wordend;
}
}
return advance;
}
static float _layoutWord(float offset, int layoutOffset,
TextBuff buff, int start, int wordCount, TextStyle style, Font font, List<float> advances,
List<float> positions, int advanceOffset, float initAdvance, TabStops tabStops) {
float wordSpacing =
wordCount == 1 && LayoutUtils.isWordSpace(buff.charAt(start)) ? style.wordSpacing : 0;
float x = initAdvance;
float letterSpace = style.letterSpacing;
float letterSpaceHalfLeft = letterSpace * 0.5f;
float letterSpaceHalfRight = letterSpace - letterSpaceHalfLeft;
for (int i = 0; i < wordCount; i++) {
var ch = buff.charAt(start + i);
if (i == 0) {
x += letterSpaceHalfLeft + wordSpacing;
if (advances != null) {
advances[i + layoutOffset + advanceOffset] = letterSpaceHalfLeft + wordSpacing;
}
}
else {
if (advances != null) {
advances[i - 1 + layoutOffset + advanceOffset] += letterSpaceHalfRight;
advances[i + layoutOffset + advanceOffset] = letterSpaceHalfLeft;
}
x += letterSpace;
}
if (font.getGlyphInfo(ch, out var glyphInfo, style.UnityFontSize, style.UnityFontStyle)) {
var minX = glyphInfo.minX + x;
var maxX = glyphInfo.maxX + x;
var minY = -glyphInfo.maxY;
var maxY = -glyphInfo.minY;
if (_innerBounds.width <= 0 || _innerBounds.height <= 0) {
_innerBounds.x = minX;
_innerBounds.y = minY;
_innerBounds.xMax = maxX;
_innerBounds.yMax = maxY;
}
else {
if (minX < _innerBounds.x) {
_innerBounds.x = minX;
}
if (minY < _innerBounds.y) {
_innerBounds.y = minY;
}
if (maxX > _innerBounds.xMax) {
_innerBounds.xMax = maxX;
}
if (maxY > _innerBounds.yMax) {
_innerBounds.yMax = maxY;
}
}
}
if (positions != null) {
positions[i + layoutOffset] = x;
}
float advance = glyphInfo.advance;
if (ch == '\t') {
advance = tabStops.nextTab((initAdvance + offset)) - initAdvance;
}
x += advance;
if (advances != null) {
advances[i + layoutOffset + advanceOffset] += advance;
}
if (i + 1 == wordCount) {
if (advances != null) {
advances[i + layoutOffset + advanceOffset] += letterSpaceHalfRight;
}
x += letterSpaceHalfRight;
}
}
return x;
}
static float _layoutEmoji(string text, TextStyle style, Font font, int count, List<float> advances,
List<float> positions, int advanceOffset, float initAdvance) {
var metrics = FontMetrics.fromFont(font, style.UnityFontSize);
float x = initAdvance;
for (int i = 0; i < count; i++) {
char c = text[i];
if (EmojiUtils.isSingleCharNonEmptyEmoji(c) || char.IsHighSurrogate(c)) {
float letterSpace = style.letterSpacing;
float letterSpaceHalfLeft = letterSpace * 0.5f;
float letterSpaceHalfRight = letterSpace - letterSpaceHalfLeft;
x += letterSpaceHalfLeft;
if (advances != null) {
advances[i + advanceOffset] = letterSpaceHalfLeft;
}
var minX = x;
var maxX = metrics.descent - metrics.ascent + x;
var minY = metrics.ascent;
var maxY = metrics.descent;
if (_innerBounds.width <= 0 || _innerBounds.height <= 0) {
_innerBounds.x = minX;
_innerBounds.y = minY;
_innerBounds.xMax = maxX;
_innerBounds.yMax = maxY;
}
else {
if (minX < _innerBounds.x) {
_innerBounds.x = minX;
}
if (minY < _innerBounds.y) {
_innerBounds.y = minY;
}
if (maxX > _innerBounds.xMax) {
_innerBounds.xMax = maxX;
}
if (maxY > _innerBounds.yMax) {
_innerBounds.yMax = maxY;
}
}
if (positions != null) {
positions[i] = x;
}
float advance = style.fontSize;
x += advance;
if (advances != null) {
advances[i + advanceOffset] += advance;
advances[i + advanceOffset] += letterSpaceHalfRight;
}
x += letterSpaceHalfRight;
}
else {
if (advances != null) {
advances[i + advanceOffset] = 0;
}
if (positions != null) {
positions[i] = x;
}
}
}
return x;
}
public void setTabStops(TabStops tabStops) {
this._tabStops = tabStops;
}
public int nGlyphs() {
return this._count;
}
public List<float> getAdvances() {
return this._advances;
}
public float getAdvance() {
return this._advance;
}
public float getX(int index) {
return this._positions[index];
}
public float getY(int index) {
return 0;
}
public float getCharAdvance(int index) {
return this._advances[index];
}
public Rect getBounds() {
return Rect.fromLTWH(this._bounds.x, this._bounds.y, this._bounds.width, this._bounds.height);
}
}
using System.Collections.Generic;
using Unity.UIWidgets.foundation;
using UnityEngine;
namespace Unity.UIWidgets.ui {
class Layout {
int _start;
int _count;
List<float> _advances = new List<float>();
List<float> _positions = new List<float>();
float _advance;
UnityEngine.Rect _bounds;
TabStops _tabStops;
static UnityEngine.Rect _innerBounds; // Used to pass bounds from static to non-static doLayout
public static float measureText(float offset, TextBuff buff, int start, int count, TextStyle style,
List<float> advances, int advanceOffset, TabStops tabStops) {
return _doLayout(offset, buff, start, count, style, advances, null, advanceOffset, tabStops);
}
public void doLayout(float offset, TextBuff buff, int start, int count, TextStyle style) {
this._start = start;
this._count = count;
this._advances.reset(count);
this._positions.reset(count);
_innerBounds = default;
this._advance = _doLayout(offset, buff, start, count, style, this._advances, this._positions, 0,
this._tabStops);
this._bounds = _innerBounds;
this._count = count;
}
public static void computeCharWidths(TextBuff buff, int start, int count, TextStyle style, List<float> advances, int advanceOffset) {
char startingChar = buff.charAt(start);
if (char.IsHighSurrogate(startingChar) || EmojiUtils.isSingleCharEmoji(startingChar)) {
float advance = style.fontSize + style.letterSpacing;
for (int i = 0; i < count; i++) {
char ch = buff.charAt(start + i);
if (char.IsHighSurrogate(ch) || EmojiUtils.isSingleCharNonEmptyEmoji(ch)) {
advances[i + advanceOffset] = advance;
}
else {
advances[i + advanceOffset] = 0;
}
}
}
else {
Font font = FontManager.instance.getOrCreate(style.fontFamily, style.fontWeight, style.fontStyle).font;
font.RequestCharactersInTextureSafe(buff.text, style.UnityFontSize, style.UnityFontStyle);
for (int i = 0; i < count; i++) {
char ch = buff.charAt(start + i);
if (font.getGlyphInfo(ch, out var glyphInfo, style.UnityFontSize, style.UnityFontStyle)) {
advances[i + advanceOffset] = glyphInfo.advance + style.letterSpacing;
}
else {
advances[i + advanceOffset] = style.letterSpacing;
}
if (LayoutUtils.isWordSpace(ch)) advances[i + advanceOffset] += style.wordSpacing;
}
}
}
static float _doLayout(float offset, TextBuff buff, int start, int count, TextStyle style,
List<float> advances, List<float> positions, int advanceOffset, TabStops tabStops) {
float advance = 0;
Font font = FontManager.instance.getOrCreate(style.fontFamily, style.fontWeight, style.fontStyle).font;
char startingChar = buff.charAt(start);
if (char.IsHighSurrogate(startingChar) || EmojiUtils.isSingleCharEmoji(startingChar)) {
advance = _layoutEmoji(buff.text.Substring(buff.offset + start, count), style, font, count,
advances, positions, advanceOffset, advance);
}
else {
font.RequestCharactersInTextureSafe(buff.text, style.UnityFontSize, style.UnityFontStyle);
int wordstart = start == buff.size
? start
: LayoutUtils.getPrevWordBreakForCache(buff, start + 1);
int wordend;
for (int iter = start; iter < start + count; iter = wordend) {
wordend = LayoutUtils.getNextWordBreakForCache(buff, iter);
int wordCount = Mathf.Min(start + count, wordend) - iter;
advance = _layoutWord(offset, iter - start, buff.subBuff(wordstart, wordend - wordstart),
iter - wordstart, wordCount, style, font, advances, positions,
advanceOffset, advance, tabStops);
wordstart = wordend;
}
}
return advance;
}
static float _layoutWord(float offset, int layoutOffset,
TextBuff buff, int start, int wordCount, TextStyle style, Font font, List<float> advances,
List<float> positions, int advanceOffset, float initAdvance, TabStops tabStops) {
float wordSpacing =
wordCount == 1 && LayoutUtils.isWordSpace(buff.charAt(start)) ? style.wordSpacing : 0;
float x = initAdvance;
float letterSpace = style.letterSpacing;
float letterSpaceHalfLeft = letterSpace * 0.5f;
float letterSpaceHalfRight = letterSpace - letterSpaceHalfLeft;
for (int i = 0; i < wordCount; i++) {
var ch = buff.charAt(start + i);
if (i == 0) {
x += letterSpaceHalfLeft + wordSpacing;
if (advances != null) {
advances[i + layoutOffset + advanceOffset] = letterSpaceHalfLeft + wordSpacing;
}
}
else {
if (advances != null) {
advances[i - 1 + layoutOffset + advanceOffset] += letterSpaceHalfRight;
advances[i + layoutOffset + advanceOffset] = letterSpaceHalfLeft;
}
x += letterSpace;
}
if (font.getGlyphInfo(ch, out var glyphInfo, style.UnityFontSize, style.UnityFontStyle)) {
var minX = glyphInfo.minX + x;
var maxX = glyphInfo.maxX + x;
var minY = -glyphInfo.maxY;
var maxY = -glyphInfo.minY;
if (_innerBounds.width <= 0 || _innerBounds.height <= 0) {
_innerBounds.x = minX;
_innerBounds.y = minY;
_innerBounds.xMax = maxX;
_innerBounds.yMax = maxY;
}
else {
if (minX < _innerBounds.x) {
_innerBounds.x = minX;
}
if (minY < _innerBounds.y) {
_innerBounds.y = minY;
}
if (maxX > _innerBounds.xMax) {
_innerBounds.xMax = maxX;
}
if (maxY > _innerBounds.yMax) {
_innerBounds.yMax = maxY;
}
}
}
if (positions != null) {
positions[i + layoutOffset] = x;
}
float advance = glyphInfo.advance;
if (ch == '\t') {
advance = tabStops.nextTab((initAdvance + offset)) - initAdvance;
}
x += advance;
if (advances != null) {
advances[i + layoutOffset + advanceOffset] += advance;
}
if (i + 1 == wordCount) {
if (advances != null) {
advances[i + layoutOffset + advanceOffset] += letterSpaceHalfRight;
}
x += letterSpaceHalfRight;
}
}
return x;
}
static float _layoutEmoji(string text, TextStyle style, Font font, int count, List<float> advances,
List<float> positions, int advanceOffset, float initAdvance) {
var metrics = FontMetrics.fromFont(font, style.UnityFontSize);
float x = initAdvance;
for (int i = 0; i < count; i++) {
char c = text[i];
if (EmojiUtils.isSingleCharNonEmptyEmoji(c) || char.IsHighSurrogate(c)) {
float letterSpace = style.letterSpacing;
float letterSpaceHalfLeft = letterSpace * 0.5f;
float letterSpaceHalfRight = letterSpace - letterSpaceHalfLeft;
x += letterSpaceHalfLeft;
if (advances != null) {
advances[i + advanceOffset] = letterSpaceHalfLeft;
}
var minX = x;
var maxX = metrics.descent - metrics.ascent + x;
var minY = metrics.ascent;
var maxY = metrics.descent;
if (_innerBounds.width <= 0 || _innerBounds.height <= 0) {
_innerBounds.x = minX;
_innerBounds.y = minY;
_innerBounds.xMax = maxX;
_innerBounds.yMax = maxY;
}
else {
if (minX < _innerBounds.x) {
_innerBounds.x = minX;
}
if (minY < _innerBounds.y) {
_innerBounds.y = minY;
}
if (maxX > _innerBounds.xMax) {
_innerBounds.xMax = maxX;
}
if (maxY > _innerBounds.yMax) {
_innerBounds.yMax = maxY;
}
}
if (positions != null) {
positions[i] = x;
}
float advance = style.fontSize;
x += advance;
if (advances != null) {
advances[i + advanceOffset] += advance;
advances[i + advanceOffset] += letterSpaceHalfRight;
}
x += letterSpaceHalfRight;
}
else {
if (advances != null) {
advances[i + advanceOffset] = 0;
}
if (positions != null) {
positions[i] = x;
}
}
}
return x;
}
public void setTabStops(TabStops tabStops) {
this._tabStops = tabStops;
}
public int nGlyphs() {
return this._count;
}
public List<float> getAdvances() {
return this._advances;
}
public float getAdvance() {
return this._advance;
}
public float getX(int index) {
return this._positions[index];
}
public float getY(int index) {
return 0;
}
public float getCharAdvance(int index) {
return this._advances[index];
}
public Rect getBounds() {
return Rect.fromLTWH(this._bounds.x, this._bounds.y, this._bounds.width, this._bounds.height);
}
}
}

37
Runtime/ui/txt/linebreaker.cs


using System.Collections.Generic;
using Unity.UIWidgets.InternalBridge;
using UnityEditorInternal;
using UnityEngine;
namespace Unity.UIWidgets.ui {

}
}
class Candidate {
struct Candidate {
public int offset;
public int pre;
public float preBreak;

const float ScoreInfty = float.MaxValue;
const float ScoreDesperate = 1e10f;
public static LineBreaker instance {
get {
if(_instance == null)
_instance = new LineBreaker();
return _instance;
}
}
static LineBreaker _instance;
public static List<int> newLinePositions {
get {
if (_newLinePositions == null)
_newLinePositions = new List<int>();
return _newLinePositions;
}
}
static List<int> _newLinePositions;
TextBuff _textBuf;
List<float> _charWidths = new List<float>();
List<int> _breaks = new List<int>();

this._lineWidth = lineWidth;
}
public float addStyleRun(TextStyle style, int start, int end) {
float width = 0.0f;
public void addStyleRun(TextStyle style, int start, int end) {
width = Layout.measureText(this._width - this._preBreak, this._textBuf,
start, end - start, style,
this._charWidths, start, this._tabStops);
// Layout.measureText(this._width - this._preBreak, this._textBuf,
// start, end - start, style,
// this._charWidths, start, this._tabStops);
Layout.computeCharWidths(this._textBuf, start, end - start, style, this._charWidths, start);
}
int current = this._wordBreaker.current();

for (int i = start; i < end; i++) {
char c = this._textBuf.charAt(i);
if (c == '\t') {
this._width = this._preBreak + this._tabStops.nextTab((this._width - this._preBreak));
this._width = this._preBreak + this._tabStops.nextTab(this._width - this._preBreak);
if (this.mFirstTabIndex == int.MaxValue) {
this.mFirstTabIndex = i;
}

current = this._wordBreaker.next();
}
}
return width;
}
public void finish() {

2
Runtime/ui/txt/paint_record.cs


namespace Unity.UIWidgets.ui {
class PaintRecord {
struct PaintRecord {
public PaintRecord(TextStyle style, Offset offset, TextBlob text,
FontMetrics metrics,
int line, float runWidth) {

109
Runtime/ui/txt/paragraph.cs


}
}
class GlyphPosition {
struct GlyphPosition {
public readonly Range<float> xPos;
public readonly Range<int> codeUnits;

public class Paragraph {
public class LineRange {
public struct LineRange {
public LineRange(int start, int end, int endExcludingWhitespace, int endIncludingNewLine, bool hardBreak) {
this.start = start;
this.end = end;

const float kFloatDecorationSpacing = 3.0f;
public float height {
get { return this._lineHeights.Count == 0 ? 0 : this._lineHeights[this._lineHeights.Count - 1]; }
get { return this._lineHeights.Count == 0 ? 0 : this._lineHeights.last(); }
}
public float minIntrinsicWidth {

}
public void paint(Canvas canvas, Offset offset) {
foreach (var paintRecord in this._paintRecords) {
this.paintBackground(canvas, paintRecord, offset);
}

}
var textStyle = this._paragraphStyle.getTextStyle();
this._tabStops.setFont(FontManager.instance.getOrCreate(textStyle.fontFamily,
this._tabStops.setFont(FontManager.instance.getOrCreate(textStyle.fontFamily,
textStyle.fontWeight, textStyle.fontStyle).font,
textStyle.UnityFontSize);

List<CodeUnitRun> lineCodeUnitRuns = new List<CodeUnitRun>();
List<GlyphPosition> glyphPositions = new List<GlyphPosition>();
List<LineStyleRun> lineRuns = new List<LineStyleRun>();
List<GlyphPosition> lineGlyphPositions = new List<GlyphPosition>();
List<PaintRecord> paintRecords = new List<PaintRecord>();
List<Range<int>> words = new List<Range<int>>();
List<float> textAdvances = new List<float>();
string ellipsis = this._paragraphStyle.ellipsis;
TextBuff ellipsisTextBuff = new TextBuff(ellipsis);
for (int lineNumber = 0; lineNumber < lineLimit; ++lineNumber) {
var lineRange = this._lineRanges[lineNumber];
float wordGapWidth = 0;

bool justifyLine = this._paragraphStyle.textAlign == TextAlign.justify &&
lineNumber != lineLimit - 1 &&
!lineRange.hardBreak;
var words = this.findWords(lineRange.start, lineRange.end);
words.Clear();
this.findWords(lineRange.start, lineRange.end, words);
if (justifyLine) {
if (words.Count > 1) {
wordGapWidth = (this._width - this._lineWidths[lineNumber]) / (words.Count - 1);

: lineRange.end;
List<LineStyleRun> lineRuns = new List<LineStyleRun>();
lineRuns.Clear();
while (styleRunIndex < this._runs.size) {
var styleRun = this._runs.getRun(styleRunIndex);
if (styleRun.start < lineEndIndex && styleRun.end > lineRange.start) {

float runXOffset = 0;
float justifyXOffset = 0;
lineCodeUnitRuns.Clear();
List<GlyphPosition> lineGlyphPositions = new List<GlyphPosition>();
List<PaintRecord> paintRecords = new List<PaintRecord>();
lineGlyphPositions.Clear();
paintRecords.Clear();
int textStart = Mathf.Max(run.start, lineRange.start);
int textEnd = Mathf.Min(run.end, lineEndIndex);
int textStart = run.start;
int textEnd = run.end;
string ellipsis = this._paragraphStyle.ellipsis;
&& i == lineRuns.Count - 1 && (lineNumber == lineLimit - 1 || this._paragraphStyle.maxLines == null)) {
float ellipsisWidth = Layout.measureText(runXOffset, new TextBuff(ellipsis), 0,
&& i == lineRuns.Count - 1 &&
(lineNumber == lineLimit - 1 || this._paragraphStyle.maxLines == null)) {
float ellipsisWidth = Layout.measureText(runXOffset, ellipsisTextBuff, 0,
List<float> textAdvances = new List<float>(textCount);
for (int index = 0; index < textCount;++index) {
textAdvances.Add(0);
}
textAdvances.reset(textCount);
int truncateCount = 0;
while (truncateCount < textCount &&
runXOffset + textWidth + ellipsisWidth > this._width) {

float wordStartPosition = float.NaN;
builder.allocRunPos(run.style, text, textStart, textCount);
builder.setBounds(layout.getBounds().translate(-layout.getX(0), 0)); // bounds relative to first character
builder.setBounds(layout.getBounds()
.translate(-layout.getX(0), 0)); // bounds relative to first character
glyphPositions.Clear();
for (int glyphIndex = 0; glyphIndex < textCount; ++glyphIndex) {

wordIndex++;
if (!float.IsNaN(wordStartPosition)) {
float wordWidth =
glyphPositions[glyphPositions.Count - 1].xPos.end - wordStartPosition;
float wordWidth = glyphPositions.last().xPos.end - wordStartPosition;
maxWordWidth = Mathf.Max(wordWidth, maxWordWidth);
wordStartPosition = float.NaN;
}

continue;
}
var font = FontManager.instance.getOrCreate(run.style.fontFamily,
var font = FontManager.instance.getOrCreate(run.style.fontFamily,
run.style.fontWeight, run.style.fontStyle).font;
var metrics = FontMetrics.fromFont(font, run.style.UnityFontSize);
paintRecords.Add(new PaintRecord(run.style, new Offset(runXOffset, 0),

var codeUnitPositions = new List<GlyphPosition>(glyphPositions);
lineCodeUnitRuns.Add(new CodeUnitRun(codeUnitPositions, new Range<int>(run.start, run.end),
lineNumber,
new Range<float>(glyphPositions[0].xPos.start,
glyphPositions[glyphPositions.Count - 1].xPos.end),
lineCodeUnitRuns.Add(new CodeUnitRun(codeUnitPositions,
new Range<int>(run.start, run.end), lineNumber,
new Range<float>(glyphPositions[0].xPos.start, glyphPositions.last().xPos.end),
metrics, TextDirection.ltr));
runXOffset += layout.getAdvance();
}

float maxDescent = 0;
int line = lineNumber; // Resolve "accessing modified closure" problem
var updateLineMetrics = new Action<FontMetrics, TextStyle>((metrics, style) => {
void updateLineMetrics(FontMetrics metrics, TextStyle style) {
float lineSpacing = ((line == 0)
? -metrics.ascent * style.height
: (-metrics.ascent + metrics.leading) * (style.height));

float descent = metrics.descent * style.height;
maxDescent = Mathf.Max(descent, maxDescent);
});
}
foreach (var paintRecord in paintRecords) {
updateLineMetrics(paintRecord.metrics, paintRecord.style);

var defaultStyle = this._paragraphStyle.getTextStyle();
var defaultFont = FontManager.instance.getOrCreate(defaultStyle.fontFamily,
var defaultFont = FontManager.instance.getOrCreate(defaultStyle.fontFamily,
defaultStyle.fontWeight, defaultStyle.fontStyle).font;
var metrics = FontMetrics.fromFont(defaultFont, defaultStyle.UnityFontSize);
updateLineMetrics(metrics, defaultStyle);

(this._lineHeights.Count == 0 ? 0 : this._lineHeights[this._lineHeights.Count - 1])
(this._lineHeights.Count == 0 ? 0 : this._lineHeights.last())
this._lineBaseLines.Add(this._lineHeights[this._lineHeights.Count - 1] - maxDescent);
this._lineBaseLines.Add(this._lineHeights.last() - maxDescent);
foreach (var paintRecord in paintRecords) {
for (int i = 0; i < paintRecords.Count; i++) {
PaintRecord paintRecord = paintRecords[i];
paintRecord.offset = new Offset(paintRecord.offset.dx + lineXOffset, yOffset);
this._paintRecords.Add(paintRecord);
}

var x = this._lineWidths[lineNumber];
var top = (lineNumber > 0) ? this._lineHeights[lineNumber - 1] : 0;
var bottom = this._lineHeights[lineNumber];
lineBoxes.Add(lineNumber, new List<TextBox>() {
lineBoxes.Add(lineNumber, new List<TextBox> {
TextBox.fromLTBD(
x, top, x, bottom, TextDirection.ltr)
});

return result;
}
public TextBox getNextLineStartRect() {
public TextBox? getNextLineStartRect() {
if (this._text.Length == 0 || this._text[this._text.Length - 1] != '\n') {
return null;
}

}
GlyphPosition gp = null;
GlyphPosition gp = new GlyphPosition();
bool gpSet = false;
for (int xIndex = 0; xIndex < lineGlyphPosition.Count; ++xIndex) {
float glyphEnd = xIndex < lineGlyphPosition.Count - 1
? lineGlyphPosition[xIndex + 1].xPos.start

gpSet = true;
if (gp == null) {
GlyphPosition lastGlyph = lineGlyphPosition[lineGlyphPosition.Count - 1];
if (!gpSet) {
GlyphPosition lastGlyph = lineGlyphPosition.last();
return new PositionWithAffinity(lastGlyph.codeUnits.end, TextAffinity.upstream);
}

(direction == TextDirection.rtl && dx >= glyphCenter)) {
return new PositionWithAffinity(gp.codeUnits.start, TextAffinity.downstream);
}
else {
return new PositionWithAffinity(gp.codeUnits.end, TextAffinity.upstream);
}
return new PositionWithAffinity(gp.codeUnits.end, TextAffinity.upstream);
}
public int getLine(TextPosition position) {

this._lineWidths.Clear();
this._maxIntrinsicWidth = 0;
var newLinePositions = new List<int>();
var newLinePositions = LineBreaker.newLinePositions;
newLinePositions.Clear();
for (var i = 0; i < this._text.Length; i++) {
if (this._text[i] == '\n') {
newLinePositions.Add(i);

newLinePositions.Add(this._text.Length);
var lineBreaker = new LineBreaker();
var lineBreaker = LineBreaker.instance;
int runIndex = 0;
for (var newlineIndex = 0; newlineIndex < newLinePositions.Count; ++newlineIndex) {
var blockStart = newlineIndex > 0 ? newLinePositions[newlineIndex - 1] + 1 : 0;

}
}
List<Range<int>> findWords(int start, int end) {
void findWords(int start, int end, List<Range<int>> words) {
List<Range<int>> words = new List<Range<int>>();
for (int i = start; i < end; ++i) {
bool isSpace = LayoutUtils.isWordSpace(this._text[i]);
if (!inWord && !isSpace) {

if (inWord) {
words.Add(new Range<int>(wordStart, end));
}
return words;
}
void paintDecorations(Canvas canvas, PaintRecord record, Offset baseOffset) {

if (this._paragraphStyle.textAlign == TextAlign.right) {
return this._width - lineTotalAdvance;
}
else if (this._paragraphStyle.textAlign == TextAlign.center) {
if (this._paragraphStyle.textAlign == TextAlign.center) {
else {
return 0;
}
return 0;
}
static bool _isUtf16Surrogate(int value) {

7
Runtime/ui/txt/word_separate.cs


namespace Unity.UIWidgets.ui {
class WordSeparate {
enum Direction {
Forward,
Backward,
}
struct WordSeparate {
internal enum characterType {
LetterLike,
Symbol,

12
Runtime/ui/txt/wordbreaker.cs


if (this._current == this._text.size) {
return -1;
}
WordSeparate.characterType preType = WordSeparate.classifyChar(this._text.charAt(this._current));
bool preBoundaryChar = isBoundaryChar(this._text.charAt(this._current));
char c = this._text.charAt(this._current);
WordSeparate.characterType preType = WordSeparate.classifyChar(c);
bool preBoundaryChar = isBoundaryChar(c);
this._current++;
if (preBoundaryChar) {
return this._current;

c = this._text.charAt(this._current);
if (isBoundaryChar(this._text.charAt(this._current))) {
if (isBoundaryChar(c)) {
var currentType = WordSeparate.classifyChar(this._text.charAt(this._current));
var currentType = WordSeparate.classifyChar(c);
if ((currentType == WordSeparate.characterType.WhiteSpace)
!= (preType == WordSeparate.characterType.WhiteSpace)) {
break;

正在加载...
取消
保存