|
@@ -47,6 +47,10 @@ class HtmlText extends Text {
|
|
|
return font;
|
|
|
}
|
|
|
|
|
|
+ function parseText( text : String ) {
|
|
|
+ return try Xml.parse(text) catch( e : Dynamic ) throw "Could not parse " + text + " (" + e +")";
|
|
|
+ }
|
|
|
+
|
|
|
override function initGlyphs( text : String, rebuild = true, handleAlign = true, ?lines : Array<Int> ) {
|
|
|
if( rebuild ) {
|
|
|
glyphs.clear();
|
|
@@ -77,13 +81,13 @@ class HtmlText extends Text {
|
|
|
sizePos = 0;
|
|
|
calcYMin = 0;
|
|
|
|
|
|
- var doc = try Xml.parse(text) catch( e : Dynamic ) throw "Could not parse " + text + " (" + e +")";
|
|
|
+ var doc = parseText(text);
|
|
|
|
|
|
var sizes = new Array<Float>();
|
|
|
prevChar = -1;
|
|
|
newLine = true;
|
|
|
for( e in doc )
|
|
|
- buildSizes(e, font, sizes);
|
|
|
+ buildSizes(e, font, sizes, false);
|
|
|
|
|
|
prevChar = -1;
|
|
|
newLine = true;
|
|
@@ -101,7 +105,7 @@ class HtmlText extends Text {
|
|
|
calcDone = true;
|
|
|
}
|
|
|
|
|
|
- function buildSizes( e : Xml, font : Font, sizes : Array<Float> ) {
|
|
|
+ function buildSizes( e : Xml, font : Font, sizes : Array<Float>, forSplit ) {
|
|
|
if( e.nodeType == Xml.Element ) {
|
|
|
var len = 0.;
|
|
|
var nodeName = e.nodeName.toLowerCase();
|
|
@@ -131,7 +135,7 @@ class HtmlText extends Text {
|
|
|
}
|
|
|
sizes.push(len);
|
|
|
for( child in e )
|
|
|
- buildSizes(child, font, sizes);
|
|
|
+ buildSizes(child, font, sizes, forSplit);
|
|
|
switch( nodeName ) {
|
|
|
case "p":
|
|
|
sizes.push( -1);// break
|
|
@@ -149,8 +153,15 @@ class HtmlText extends Text {
|
|
|
if( cc == "\n".code || font.charset.isBreakChar(cc) ) {
|
|
|
if( cc != "\n".code && !font.charset.isSpace(cc) )
|
|
|
xp += sz;
|
|
|
- sizes.push( -(xp + 1));
|
|
|
- return;
|
|
|
+ if( !forSplit ) {
|
|
|
+ sizes.push( -(xp + 1));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ sizes.push(xp);
|
|
|
+ if( font.charset.isSpace(cc) )
|
|
|
+ sizes.push(sz);
|
|
|
+ xp = 0;
|
|
|
+ continue;
|
|
|
}
|
|
|
xp += sz + letterSpacing;
|
|
|
}
|
|
@@ -178,6 +189,103 @@ class HtmlText extends Text {
|
|
|
return size;
|
|
|
}
|
|
|
|
|
|
+ override function splitText(text:String):String {
|
|
|
+ if( realMaxWidth < 0 )
|
|
|
+ return text;
|
|
|
+ yPos = 0;
|
|
|
+ xMax = 0;
|
|
|
+ sizePos = 0;
|
|
|
+ calcYMin = 0;
|
|
|
+
|
|
|
+ var doc = parseText(text);
|
|
|
+
|
|
|
+ /*
|
|
|
+ This might require a global refactoring at some point.
|
|
|
+ We would need a way to somehow build an AST from the XML representation
|
|
|
+ with all sizes and word breaks so analysis is much more easy.
|
|
|
+ */
|
|
|
+
|
|
|
+ var sizes = new Array<Float>();
|
|
|
+ prevChar = -1;
|
|
|
+ newLine = true;
|
|
|
+ for( e in doc )
|
|
|
+ buildSizes(e, font, sizes, true);
|
|
|
+ xMax = 0;
|
|
|
+ function addBreaks( e : Xml ) {
|
|
|
+ if( e.nodeType == Xml.Element ) {
|
|
|
+ var sz = sizes[sizePos++];
|
|
|
+ if( sz < 0 )
|
|
|
+ xMax = 0;
|
|
|
+ else
|
|
|
+ xMax += sz;
|
|
|
+ for( x in e )
|
|
|
+ addBreaks(x);
|
|
|
+ if( e.nodeName == "p" ) {
|
|
|
+ sizePos++;
|
|
|
+ xMax = 0;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ var text = htmlToText(e.nodeValue);
|
|
|
+ var startI = 0, prevI = 0;
|
|
|
+ for( i in 0...text.length ) {
|
|
|
+ var cc = text.charCodeAt(i);
|
|
|
+ if( cc == "\n".code || font.charset.isBreakChar(cc) ) {
|
|
|
+ var sz = sizes[sizePos++];
|
|
|
+ var sp = font.charset.isSpace(cc) ? sizes[sizePos++] : 0;
|
|
|
+ xMax += sz;
|
|
|
+ if( xMax > realMaxWidth ) {
|
|
|
+ var index = Lambda.indexOf(e.parent,e);
|
|
|
+ var pre = text.substr(startI,prevI - startI);
|
|
|
+ if( pre != "" )
|
|
|
+ e.parent.insertChild(Xml.createPCData(pre),index++);
|
|
|
+ e.parent.insertChild(Xml.createElement("br"),index);
|
|
|
+ e.nodeValue = text.substr(prevI+1);
|
|
|
+ startI = prevI+1;
|
|
|
+ xMax = sz;
|
|
|
+ }
|
|
|
+ xMax += sp + letterSpacing;
|
|
|
+ prevI = i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var sz = sizes[sizePos++];
|
|
|
+ xMax += sz;
|
|
|
+ if( xMax > realMaxWidth ) {
|
|
|
+ e.parent.insertChild(Xml.createElement("br"),Lambda.indexOf(e.parent,e));
|
|
|
+ xMax = sz;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for( d in doc )
|
|
|
+ addBreaks(d);
|
|
|
+ return doc.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ override function getTextProgress(text:String, progress:Float):String {
|
|
|
+ if( progress >= text.length )
|
|
|
+ return text;
|
|
|
+ var doc = parseText(text);
|
|
|
+ function progressRec(e:Xml) {
|
|
|
+ if( progress <= 0 ) {
|
|
|
+ e.parent.removeChild(e);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if( e.nodeType == Xml.Element ) {
|
|
|
+ for( x in [for( x in e ) x] )
|
|
|
+ progressRec(x);
|
|
|
+ } else {
|
|
|
+ var text = htmlToText(e.nodeValue);
|
|
|
+ if( text.length > progress ) {
|
|
|
+ text = text.substr(0, Std.int(progress));
|
|
|
+ e.nodeValue = text;
|
|
|
+ }
|
|
|
+ progress -= text.length;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for( x in [for( x in doc ) x] )
|
|
|
+ progressRec(x);
|
|
|
+ return doc.toString();
|
|
|
+ }
|
|
|
+
|
|
|
function addNode( e : Xml, font : Font, rebuild : Bool, handleAlign:Bool, sizes : Array<Float>, ?lines : Array<Int> = null ) {
|
|
|
sizePos++;
|
|
|
var calcLines = !handleAlign && !rebuild && lines != null;
|
|
@@ -286,6 +394,7 @@ class HtmlText extends Text {
|
|
|
addNode(child, font, rebuild, handleAlign, sizes, lines);
|
|
|
switch( nodeName ) {
|
|
|
case "p":
|
|
|
+ sizePos++;
|
|
|
makeLineBreak();
|
|
|
default:
|
|
|
}
|
|
@@ -295,7 +404,7 @@ class HtmlText extends Text {
|
|
|
@:privateAccess glyphs.curColor.load(prevColor);
|
|
|
} else {
|
|
|
newLine = false;
|
|
|
- var t = splitText(htmlToText(e.nodeValue), xPos, remainingSize(sizes));
|
|
|
+ var t = splitRawText(htmlToText(e.nodeValue), xPos, remainingSize(sizes));
|
|
|
var dy = this.font.baseLine - font.baseLine;
|
|
|
for( i in 0...t.length ) {
|
|
|
var cc = t.charCodeAt(i);
|