Skip to content

Commit 243cbc9

Browse files
author
John Messerly
committed
remove most string concat, fixes flutter#7
This fixes most of the egregious cases of string concat in the HTML tokenizer: * attribute names/values * data/comments * script/rawtext/rcdata It also fixes adjacent text nodes in TreeBuilder, which happens whenever space characters are adjacent to characters. There's still an issue of preserving char codes for longer, but this should get out of the O(N^2) at least. [email protected] Review URL: https://codereview.chromium.org//987433005
1 parent a58a092 commit 243cbc9

File tree

5 files changed

+142
-97
lines changed

5 files changed

+142
-97
lines changed

lib/dom.dart

+24-4
Original file line numberDiff line numberDiff line change
@@ -402,18 +402,32 @@ class DocumentType extends Node {
402402
}
403403

404404
class Text extends Node {
405-
String data;
405+
/// The text node's data, stored as either a String or StringBuffer.
406+
/// We support storing a StringBuffer here to support fast [appendData].
407+
/// It will flatten back to a String on read.
408+
var _data;
406409

407-
Text(this.data) : super._();
410+
Text(String data) : _data = data != null ? data : '', super._();
408411

409412
int get nodeType => Node.TEXT_NODE;
410413

414+
String get data => _data = _data.toString();
415+
set data(String value) {
416+
_data = value != null ? value : '';
417+
}
418+
411419
String toString() => '"$data"';
412420

413421
void _addOuterHtml(StringBuffer str) => writeTextNodeAsHtml(str, this);
414422

415423
Text clone(bool deep) => new Text(data);
416424

425+
void appendData(String data) {
426+
if (_data is! StringBuffer) _data = new StringBuffer(_data);
427+
StringBuffer sb = _data;
428+
sb.write(data);
429+
}
430+
417431
String get text => data;
418432
set text(String value) {
419433
data = value;
@@ -539,13 +553,19 @@ class Element extends Node with _ParentNode, _ElementAndDocument {
539553
void _addOuterHtml(StringBuffer str) {
540554
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#serializing-html-fragments
541555
// Element is the most complicated one.
542-
str.write('<${_getSerializationPrefix(namespaceUri)}$localName');
556+
str.write('<');
557+
str.write(_getSerializationPrefix(namespaceUri));
558+
str.write(localName);
543559

544560
if (attributes.length > 0) {
545561
attributes.forEach((key, v) {
546562
// Note: AttributeName.toString handles serialization of attribute
547563
// namespace, if needed.
548-
str.write(' $key="${htmlSerializeEscape(v, attributeMode: true)}"');
564+
str.write(' ');
565+
str.write(key);
566+
str.write('="');
567+
str.write(htmlSerializeEscape(v, attributeMode: true));
568+
str.write('"');
549569
});
550570
}
551571

lib/parser.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -3395,7 +3395,7 @@ class InForeignContentPhase extends Phase {
33953395

33963396
Token processCharacters(CharactersToken token) {
33973397
if (token.data == "\u0000") {
3398-
token.data = "\uFFFD";
3398+
token.replaceData("\uFFFD");
33993399
} else if (parser.framesetOK && !allWhitespace(token.data)) {
34003400
parser.framesetOK = false;
34013401
}

lib/src/token.dart

+27-3
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,25 @@ class EndTagToken extends TagToken {
4747
}
4848

4949
abstract class StringToken extends Token {
50-
String data;
51-
StringToken(this.data);
50+
StringBuffer _buffer;
51+
52+
String _string;
53+
String get data {
54+
if (_string == null) {
55+
_string = _buffer.toString();
56+
_buffer = null;
57+
}
58+
return _string;
59+
}
60+
61+
StringToken(string)
62+
: _string = string,
63+
_buffer = string == null ? new StringBuffer() : null;
64+
65+
StringToken add(String data) {
66+
_buffer.write(data);
67+
return this;
68+
}
5269
}
5370

5471
class ParseErrorToken extends StringToken {
@@ -64,6 +81,13 @@ class CharactersToken extends StringToken {
6481
CharactersToken([String data]) : super(data);
6582

6683
int get kind => TokenKind.characters;
84+
85+
/// Replaces the token's [data]. This should only be used to wholly replace
86+
/// data, not to append data.
87+
void replaceData(String newData) {
88+
_string = newData;
89+
_buffer = null;
90+
}
6791
}
6892

6993
class SpaceCharactersToken extends StringToken {
@@ -103,7 +127,7 @@ class TagAttribute {
103127
int startValue;
104128
int endValue;
105129

106-
TagAttribute(this.name, [this.value = '']);
130+
TagAttribute();
107131
}
108132

109133
class TokenKind {

0 commit comments

Comments
 (0)