using System ;
using System.Collections.Generic ;
using System.Text ;
using JetBrains.Annotations ;
using UnityEngine.Assertions ;
using UnityEngine.Experimental.UIElements ;
public struct Vector2d
{
public double x ;
public double y ;
public Vector2d ( double x = 0.0 , double y = 0.0 )
{
this . x = x ;
this . y = y ;
}
public static Vector2d operator + ( Vector2d a , Vector2d b )
{
return new Vector2d ( a . x + b . x , a . y + b . y ) ;
}
public static Vector2d operator - ( Vector2d a , Vector2d b )
{
return new Vector2d ( a . x - b . x , a . y - b . y ) ;
}
}
public class Paragraph
{
struct Range < T > : IEquatable < Range < T > >
public readonly int endIncludingNewLine ;
public readonly bool hardBreak ;
}
class LayoutContext
{
public int width ;
public int index ;
public Vector2 offset ;
public TextStyle style ;
public Font font ;
public int wordStart ;
public int lineStart ;
public int prevWordEnd ;
}
private static readonly Shader textShader ;
private ParagraphStyle _paragraphStyle ;
private List < LineRange > _lineRanges = new List < LineRange > ( ) ;
private List < double > _lineWidths = new List < double > ( ) ;
private Vector2 [ ] _characterPositions ;
private Vector2d [ ] _characterPositions ;
private float [ ] _characterWidths ;
private double [ ] _characterWidths ;
private LayoutContext context ;
private bool _didExceedMaxLines ;
// private double _characterWidth;
return ch = = ' ' | | ch = = CHAR_NBSP ;
}
// This function determines whether a character is a space that disappears at end of line.
// It is the Unicode set: [[:General_Category=Space_Separator:]-[:Line_Break=Glue:]],
// plus '\n'.
// Note: all such characters are in the BMP, so it's ok to use code units for this.
static bool isLineEndSpace ( char c ) {
return c = = '\n' | | c = = ' ' | | c = = 0 x1680 | | ( 0 x2000 < = c & & c < = 0 x200A & & c ! = 0 x2007 ) | |
c = = 0 x205F | | c = = 0 x3000 ;
}
public double height
{
get { return _lineHeights . Count = = 0 ? 0 : _lineHeights [ _lineHeights . Count - 1 ] ; }
public double alphabeticBaseline
{
get { return 0.0 ; }
get { return _alphabeticBaseline ; }
get { return 0.0 ; }
get { return _ideographicBaseline ; }
}
public bool didExceedMaxLines
{
maxWordWidth = wordWidth ;
}
} ) ;
} ) ;
if ( _paragraphStyle . TextAlign = = TextAlign . justify & & ! _lineRanges [ lineNumber ] . hardBreak
& & lineNumber ! = lineLimits - 1 )
{
justifyLine ( lineNumber , words ) ;
} else if ( line . endExcludingWhitespace > line . start )
{
Debug . Assert ( ! isLineEndSpace ( _text [ line . endExcludingWhitespace - 1 ] ) ) ;
var lineTotalAdvance = _characterPositions [ line . endExcludingWhitespace - 1 ] . x +
_characterWidths [ line . endExcludingWhitespace - 1 ] ;
double xOffset = getLineXOffset ( lineTotalAdvance ) ;
if ( xOffset > 0 | | xOffset < 0 )
{
offsetCharacters ( new Vector2d ( xOffset , 0 ) ,
_characterPositions , line . start , line . endExcludingWhitespace ) ;
}
}
}
_styleRunFonts = null ;
}
public static void offsetCharacters ( Vector2 offset , Vector2 [ ] characterPos , int start , int end )
public static void offsetCharacters ( Vector2d offset , Vector2d [ ] characterPos , int start , int end )
{
if ( characterPos ! = null )
{
private void setup ( )
{
_characterPositions = new Vector2 [ _text . Length ] ;
if ( _characterPositions = = null | | _characterPositions . Length < _text . Length )
{
_characterPositions = new Vector2d [ _text . Length ] ;
}
_characterWidths = new float [ _text . Length ] ;
_characterWidths = new double [ _text . Length ] ;
if ( _styleRunFonts = = null )
{
_styleRunFonts = new Font [ _runs . size ] ;
_ideographicBaseline = maxAscent ; // todo Properly implement ideographic_baseline
}
lastDescent = maxDescent ;
yOffset + = maxAscent + lastDescent ;
yOffset = Utils . PixelCorrectRound ( yOffset + maxAscent + lastDescent ) ;
_characterPositions [ charIndex ] . y = ( float ) yOffset ;
_characterPositions [ charIndex ] . y = yOffset ;
}
_lineHeights . Add ( ( _lineHeights . Count = = 0 ? 0 : _lineHeights [ _lineHeights . Count - 1 ] ) +
}
newLinePositions . Add ( _text . Length ) ;
int runIndex = 0 ;
StyledRuns . Run lastRun = null ;
lineBreaker . setup ( _text , _runs , _styleRunFonts , ( float ) _width , _characterPositions , _characterWidths ) ;
lineBreaker . setup ( _text , _runs , _styleRunFonts , _width , _characterPositions , _characterWidths ) ;
for ( var newlineIndex = 0 ; newlineIndex < newLinePositions . Count ; + + newlineIndex )
{
var line = lines [ i ] ;
var end = i + 1 < lines . Count ? lines [ i + 1 ] . start : blockEnd ;
var nonWhite Space = end - 1 ;
while ( nonWhite Space > = line . start & & _text [ nonWhiteSpace ] = = ' ' | | _text [ nonWhiteSpace ] = = '\t' )
var nonSpaceEnd = end ;
while ( nonSpaceEnd > line . start & & isLineEndSpace ( _text [ nonSpaceEnd - 1 ] ) )
nonWhite Space - - ;
nonSpaceEnd - - ;
_lineRanges . Add ( new LineRange ( line . start , end , nonWhite Space , end + 1 , end = = blockEnd ) ) ;
_lineRanges . Add ( new LineRange ( line . start , end , nonSpaceEnd , end + 1 , end = = blockEnd ) ) ;
_lineWidths . Add ( line . width ) ;
}
}
var vertices = new Vector3 [ _text . Length * 4 ] ;
var triangles = new int [ _text . Length * 6 ] ;
var uv = new Vector2 [ _text . Length * 4 ] ;
Vector3 offset = new Vector3 ( ( float ) x , ( float ) y , 0 ) ;
Vector3 offset = new Vector3 ( ( float ) Utils . PixelCorrectRound ( x ) , ( float ) Utils . PixelCorrectRound ( y ) , 0 ) ;
CharacterInfo charInfo ;
var result = font . GetCharacterInfo ( _text [ charIndex ] , out charInfo , run . style . UnityFontSize , run . style . UnityFontStyle ) ;
var position = _characterPositions [ charIndex ] ;
vertices [ 4 * charIndex + 0 ] = offset + new Vector3 ( position . x + charInfo . minX , position . y - charInfo . maxY , 0 ) ;
vertices [ 4 * charIndex + 1 ] = offset + new Vector3 ( position . x + charInfo . maxX , position . y - charInfo . maxY , 0 ) ;
vertices [ 4 * charIndex + 2 ] = offset + new Vector3 ( position . x + charInfo . maxX , position . y - charInfo . minY , 0 ) ;
vertices [ 4 * charIndex + 3 ] = offset + new Vector3 ( position . x + charInfo . minX , position . y - charInfo . minY , 0 ) ;
if ( _text [ charIndex ] ! = ' ' & & _text [ charIndex ] ! = '\t' & & _text [ charIndex ] ! = '\n' )
CharacterInfo charInfo = new CharacterInfo ( ) ;
if ( _text [ charIndex ] ! = '\n' & & _text [ charIndex ] ! = '\t' )
uv [ 4 * charIndex + 0 ] = charInfo . uvTopLeft ;
uv [ 4 * charIndex + 1 ] = charInfo . uvTopRight ;
uv [ 4 * charIndex + 2 ] = charInfo . uvBottomRight ;
uv [ 4 * charIndex + 3 ] = charInfo . uvBottomLeft ;
font . GetCharacterInfo ( _text [ charIndex ] , out charInfo , run . style . UnityFontSize , run . style . UnityFontStyle ) ;
var position = _characterPositions [ charIndex ] ;
vertices [ 4 * charIndex + 0 ] = offset + new Vector3 ( ( float ) ( position . x + charInfo . minX ) ,
( float ) ( position . y - charInfo . maxY ) , 0 ) ;
vertices [ 4 * charIndex + 1 ] = offset + new Vector3 ( ( float ) ( position . x + charInfo . maxX ) ,
( float ) ( position . y - charInfo . maxY ) , 0 ) ;
vertices [ 4 * charIndex + 2 ] = offset + new Vector3 (
( float ) ( position . x + charInfo . maxX ) , ( float ) ( position . y - charInfo . minY ) , 0 ) ;
vertices [ 4 * charIndex + 3 ] = offset + new Vector3 (
( float ) ( position . x + charInfo . minX ) , ( float ) ( position . y - charInfo . minY ) , 0 ) ;
vertices [ 4 * charIndex + 0 ] = vertices [ 4 * charIndex + 1 ] =
vertices [ 4 * charIndex + 2 ] = vertices [ 4 * charIndex + 3 ] = offset ;
}
if ( isWordSpace ( _text [ charIndex ] ) | | isLineEndSpace ( _text [ charIndex ] ) | | _text [ charIndex ] = = '\t' )
{
} else
{
uv [ 4 * charIndex + 0 ] = charInfo . uvTopLeft ;
uv [ 4 * charIndex + 1 ] = charInfo . uvTopRight ;
uv [ 4 * charIndex + 2 ] = charInfo . uvBottomRight ;
uv [ 4 * charIndex + 3 ] = charInfo . uvBottomLeft ;
}
triangles [ 6 * charIndex + 0 ] = 4 * charIndex + 0 ;
triangles [ 6 * charIndex + 5 ] = 4 * charIndex + 3 ;
}
// for (var i = 0; i < vertices.Length; i++)
// {
// vertices[i].x = (float)Math.Round(vertices[i].x);
// vertices[i].y = (float)Math.Round(vertices[i].y);
// }
var mesh = new Mesh ( )
{
vertices = vertices ,
return mesh ;
}
private double getLineXOffset ( double lineTotalAdvance ) {
if ( double . IsInfinity ( _width ) )
{
return 0 ;
}
var align = _paragraphStyle . TextAlign ;
if ( align = = TextAlign . right ) {
return _width - lineTotalAdvance ;
} else if ( align = = TextAlign . center ) {
return Utils . PixelCorrectRound ( ( _width - lineTotalAdvance ) / 2 ) ;
} else {
return 0 ;
}
}
private void justifyLine ( int lineNumber , List < Range < int > > words )
{
if ( words . Count < = 1 )
{
return ;
}
var line = _lineRanges [ lineNumber ] ;
Debug . Assert ( ! isLineEndSpace ( _text [ line . endExcludingWhitespace - 1 ] ) ) ;
var lineTotalAdvance = _characterPositions [ line . endExcludingWhitespace - 1 ] . x +
_characterWidths [ line . endExcludingWhitespace - 1 ] ;
double gapWidth = ( _width - lineTotalAdvance ) / ( words . Count - 1 ) ;
double justifyOffset = 0.0 ;
foreach ( var word in words )
{
offsetCharacters ( new Vector2d ( justifyOffset ) ,
_characterPositions , word . start , word . end ) ;
justifyOffset + = gapWidth ;
justifyOffset = Utils . PixelCorrectRound ( justifyOffset ) ;
}
}
private List < Range < int > > findWords ( int start , int end )
{
var inWord = false ;