Chromium Code Reviews| Index: sdk/lib/js/dartium/js_dartium.dart |
| diff --git a/sdk/lib/js/dartium/js_dartium.dart b/sdk/lib/js/dartium/js_dartium.dart |
| index f184cfb04a7ef1fe21235c74eed2b8eb9b42d1d2..5f03fe1ac29bc52f58302b5c45146755b1f82280 100644 |
| --- a/sdk/lib/js/dartium/js_dartium.dart |
| +++ b/sdk/lib/js/dartium/js_dartium.dart |
| @@ -138,6 +138,112 @@ final _jsInterfaceTypes = new Set<mirrors.ClassMirror>(); |
| @Deprecated("Internal Use Only") |
| Iterable<mirrors.ClassMirror> get jsInterfaceTypes => _jsInterfaceTypes; |
| +class _StringLiteralEscape { |
| + // Character code constants. |
| + static const int BACKSPACE = 0x08; |
| + static const int TAB = 0x09; |
| + static const int NEWLINE = 0x0a; |
| + static const int CARRIAGE_RETURN = 0x0d; |
| + static const int FORM_FEED = 0x0c; |
| + static const int QUOTE = 0x22; |
| + static const int CHAR_$ = 0x24; |
| + static const int CHAR_0 = 0x30; |
| + static const int BACKSLASH = 0x5c; |
| + static const int CHAR_b = 0x62; |
| + static const int CHAR_f = 0x66; |
| + static const int CHAR_n = 0x6e; |
| + static const int CHAR_r = 0x72; |
| + static const int CHAR_t = 0x74; |
| + static const int CHAR_u = 0x75; |
| + |
| + final StringSink _sink; |
| + |
| + _StringLiteralEscape(this._sink); |
| + |
| + void writeString(String string) { |
| + _sink.write(string); |
| + } |
| + |
| + void writeStringSlice(String string, int start, int end) { |
| + _sink.write(string.substring(start, end)); |
| + } |
| + |
| + void writeCharCode(int charCode) { |
| + _sink.writeCharCode(charCode); |
| + } |
| + |
| + /// ('0' + x) or ('a' + x - 10) |
| + static int hexDigit(int x) => x < 10 ? 48 + x : 87 + x; |
| + |
| + /// Write, and suitably escape, a string's content as a JSON string literal. |
| + void writeStringContent(String s) { |
| + // Identical to JSON string lieral escaping except that we also escape $. |
|
sra1
2016/07/22 20:16:32
lieral?
Jacob
2016/07/25 16:31:58
Done.
|
| + int offset = 0; |
| + final int length = s.length; |
| + for (int i = 0; i < length; i++) { |
| + int charCode = s.codeUnitAt(i); |
| + if (charCode > BACKSLASH) continue; |
| + if (charCode < 32) { |
| + if (i > offset) writeStringSlice(s, offset, i); |
| + offset = i + 1; |
| + writeCharCode(BACKSLASH); |
| + switch (charCode) { |
| + case BACKSPACE: |
| + writeCharCode(CHAR_b); |
| + break; |
| + case TAB: |
| + writeCharCode(CHAR_t); |
| + break; |
| + case NEWLINE: |
| + writeCharCode(CHAR_n); |
| + break; |
| + case FORM_FEED: |
| + writeCharCode(CHAR_f); |
| + break; |
| + case CARRIAGE_RETURN: |
| + writeCharCode(CHAR_r); |
| + break; |
| + default: |
| + writeCharCode(CHAR_u); |
| + writeCharCode(CHAR_0); |
| + writeCharCode(CHAR_0); |
| + writeCharCode(hexDigit((charCode >> 4) & 0xf)); |
| + writeCharCode(hexDigit(charCode & 0xf)); |
| + break; |
| + } |
| + } else if (charCode == QUOTE || charCode == BACKSLASH || charCode == CHAR_$) { |
|
sra1
2016/07/22 20:16:32
line length
Jacob
2016/07/25 16:31:58
done. ran dartfmt
|
| + if (i > offset) writeStringSlice(s, offset, i); |
| + offset = i + 1; |
| + writeCharCode(BACKSLASH); |
| + writeCharCode(charCode); |
| + } |
| + } |
| + if (offset == 0) { |
| + writeString(s); |
| + } else if (offset < length) { |
| + writeStringSlice(s, offset, length); |
| + } |
| + } |
| + |
| + /** |
| + * Serialize a [num], [String], [bool], [Null], [List] or [Map] value. |
| + * |
| + * Returns true if the value is one of these types, and false if not. |
| + * If a value is both a [List] and a [Map], it's serialized as a [List]. |
|
sra1
2016/07/22 20:16:32
This comment is wrong.
|
| + */ |
| + bool writeStringLiteral(String str) { |
|
sra1
2016/07/22 20:16:32
Doesn't return anything.
Jacob
2016/07/25 16:31:58
Done.
|
| + writeString('"'); |
| + writeStringContent(str); |
| + writeString('"'); |
| + } |
| +} |
| + |
| +String _escapeString(String str) { |
| + StringBuffer output = new StringBuffer(); |
| + new _StringLiteralEscape(output)..writeStringLiteral(str); |
| + return output.toString(); |
|
sra1
2016/07/22 20:16:32
Could you use the JSON codec rather than copy & pa
Jacob
2016/07/25 16:31:58
Can't easily because of $
JSON doesn't need to esc
|
| +} |
| + |
| /// A collection of methods where all methods have the same name. |
| /// This class is intended to optimize whether a specific invocation is |
| /// appropritate for at least some of the methods in the collection. |
| @@ -369,7 +475,7 @@ String _accessJsPathHelper(Iterable<String> parts) { |
| ..write('${_JS_LIBRARY_PREFIX}.JsNative.getProperty(' * parts.length) |
| ..write("${_JS_LIBRARY_PREFIX}.context"); |
| for (var p in parts) { |
| - sb.write(", '$p')"); |
| + sb.write(", ${_escapeString(p)})"); |
| } |
| return sb.toString(); |
| } |
| @@ -380,13 +486,13 @@ String _accessJsPathHelper(Iterable<String> parts) { |
| String _accessJsPathSetter(String path) { |
| var parts = path.split("."); |
| return "${_JS_LIBRARY_PREFIX}.JsNative.setProperty(${_accessJsPathHelper(parts.getRange(0, parts.length - 1)) |
| - }, '${parts.last}', v)"; |
| + }, ${_escapeString(parts.last)}, v)"; |
| } |
| String _accessJsPathCallMethodHelper(String path) { |
| var parts = path.split("."); |
| return "${_JS_LIBRARY_PREFIX}.JsNative.callMethod(${_accessJsPathHelper(parts.getRange(0, parts.length - 1)) |
| - }, '${parts.last}',"; |
| + }, ${_escapeString(parts.last)},"; |
| } |
| @Deprecated("Internal Use Only") |
| @@ -566,7 +672,7 @@ _generateLibraryCodegen(uri, library, staticCodegen) { |
| mirrors.MirrorSystem.getName(p.simpleName)); |
| sbPatch.write(" if($name != ${_UNDEFINED_VAR}) {\n" |
| " ${_JS_LIBRARY_PREFIX}.safeForTypedInterop($name);\n" |
| - " ${_JS_LIBRARY_PREFIX}.JsNative.setProperty(ret, '$jsName', $name);\n" |
| + " ${_JS_LIBRARY_PREFIX}.JsNative.setProperty(ret, ${_escapeString(jsName)}, $name);\n" |
| " }\n"); |
| i++; |
| } |
| @@ -1344,42 +1450,6 @@ class JsNative { |
| static JSFunction withThis(Function f) native "JsFunction_withThisNoWrap"; |
| } |
| -/// Utility methods to efficiently manipulate typed JSInterop objects in cases |
| -/// where the name to call is not known at runtime. You should only use these |
| -/// methods when the same effect cannot be achieved with @JS annotations. |
| -/// These methods would be extension methods on JSObject if Dart supported |
| -/// extension methods. |
| -class JSNative { |
| - /** |
| - * WARNING: performance of this method is much worse than other methods |
| - * in JSNative. Only use this method as a last resort. |
| - * |
| - * Recursively converts a JSON-like collection of Dart objects to a |
| - * collection of JavaScript objects and returns a [JsObject] proxy to it. |
| - * |
| - * [object] must be a [Map] or [Iterable], the contents of which are also |
| - * converted. Maps and Iterables are copied to a new JavaScript object. |
| - * Primitives and other transferrable values are directly converted to their |
| - * JavaScript type, and all other objects are proxied. |
| - */ |
| - static jsify(object) { |
| - if ((object is! Map) && (object is! Iterable)) { |
| - throw new ArgumentError("object must be a Map or Iterable"); |
| - } |
| - return _jsify(object); |
| - } |
| - |
| - static _jsify(object) native "JSObject_jsify"; |
| - static JSObject newObject() native "JSObject_newObject"; |
| - |
| - static hasProperty(JSObject o, name) => o._hasProperty(name); |
| - static getProperty(JSObject o, name) => o._operator_getter(name); |
| - static setProperty(JSObject o, name, value) => o._operator_setter(name, value); |
| - static callMethod(JSObject o, String method, List args) => o._callMethod(method, args); |
| - static instanceof(JSObject o, Function type) => o._instanceof(type); |
| - static callConstructor(JSObject constructor, List args) native "JSNative_callConstructor"; |
| -} |
| - |
| /** |
| * Proxies a JavaScript Function object. |
| */ |