blob: 89f139410824c907f28b772ff438896480913901 [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of html;
class _Utils {
static double dateTimeToDouble(DateTime dateTime) =>
dateTime.millisecondsSinceEpoch.toDouble();
static DateTime doubleToDateTime(double dateTime) {
try {
return new DateTime.fromMillisecondsSinceEpoch(dateTime.toInt());
} catch(_) {
// TODO(antonnm): treat exceptions properly in bindings and
// find out how to treat NaNs.
return null;
}
}
static List convertToList(List list) {
// FIXME: [possible optimization]: do not copy the array if Dart_IsArray is fine w/ it.
final length = list.length;
List result = new List(length);
result.setRange(0, length, list);
return result;
}
static List convertMapToList(Map map) {
List result = [];
map.forEach((k, v) => result.addAll([k, v]));
return result;
}
static int convertCanvasElementGetContextMap(Map map) {
int result = 0;
if (map['alpha'] == true) result |= 0x01;
if (map['depth'] == true) result |= 0x02;
if (map['stencil'] == true) result |= 0x4;
if (map['antialias'] == true) result |= 0x08;
if (map['premultipliedAlpha'] == true) result |= 0x10;
if (map['preserveDrawingBuffer'] == true) result |= 0x20;
return result;
}
static List parseStackTrace(StackTrace stackTrace) {
final regExp = new RegExp(r'#\d\s+(.*) \((.*):(\d+):(\d+)\)');
List result = [];
for (var match in regExp.allMatches(stackTrace.toString())) {
result.add([match.group(1), match.group(2), int.parse(match.group(3)), int.parse(match.group(4))]);
}
return result;
}
static void populateMap(Map result, List list) {
for (int i = 0; i < list.length; i += 2) {
result[list[i]] = list[i + 1];
}
}
static bool isMap(obj) => obj is Map;
static Map createMap() => {};
static makeUnimplementedError(String fileName, int lineNo) {
return new UnsupportedError('[info: $fileName:$lineNo]');
}
static window() native "Utils_window";
static forwardingPrint(String message) native "Utils_forwardingPrint";
static void spawnDomFunction(Function f, int replyTo) native "Utils_spawnDomFunction";
static void spawnDomUri(String uri, int replyTo) native "Utils_spawnDomUri";
static int _getNewIsolateId() native "Utils_getNewIsolateId";
}
class _NPObject extends NativeFieldWrapperClass1 {
_NPObject.internal();
static _NPObject retrieve(String key) native "NPObject_retrieve";
property(String propertyName) native "NPObject_property";
invoke(String methodName, [List args = null]) native "NPObject_invoke";
}
class _DOMWindowCrossFrame extends NativeFieldWrapperClass1 implements
WindowBase {
_DOMWindowCrossFrame.internal();
// Fields.
HistoryBase get history native "DOMWindow_history_cross_frame_Getter";
LocationBase get location native "DOMWindow_location_cross_frame_Getter";
bool get closed native "DOMWindow_closed_Getter";
int get length native "DOMWindow_length_Getter";
WindowBase get opener native "DOMWindow_opener_Getter";
WindowBase get parent native "DOMWindow_parent_Getter";
WindowBase get top native "DOMWindow_top_Getter";
// Methods.
void close() native "DOMWindow_close_Callback";
void postMessage(/*SerializedScriptValue*/ message, String targetOrigin, [List messagePorts]) native "DOMWindow_postMessage_Callback";
// Implementation support.
String get typeName => "DOMWindow";
}
class _HistoryCrossFrame extends NativeFieldWrapperClass1 implements HistoryBase {
_HistoryCrossFrame.internal();
// Methods.
void back() native "History_back_Callback";
void forward() native "History_forward_Callback";
void go(int distance) native "History_go_Callback";
// Implementation support.
String get typeName => "History";
}
class _LocationCrossFrame extends NativeFieldWrapperClass1 implements LocationBase {
_LocationCrossFrame.internal();
// Fields.
void set href(String) native "Location_href_Setter";
// Implementation support.
String get typeName => "Location";
}
class _DOMStringMap extends NativeFieldWrapperClass1 implements Map<String, String> {
_DOMStringMap.internal();
bool containsValue(String value) => Maps.containsValue(this, value);
bool containsKey(String key) native "DOMStringMap_containsKey_Callback";
String operator [](String key) native "DOMStringMap_item_Callback";
void operator []=(String key, String value) native "DOMStringMap_setItem_Callback";
String putIfAbsent(String key, String ifAbsent()) => Maps.putIfAbsent(this, key, ifAbsent);
String remove(String key) native "DOMStringMap_remove_Callback";
void clear() => Maps.clear(this);
void forEach(void f(String key, String value)) => Maps.forEach(this, f);
Iterable<String> get keys native "DOMStringMap_getKeys_Callback";
Iterable<String> get values => Maps.getValues(this);
int get length => Maps.length(this);
bool get isEmpty => Maps.isEmpty(this);
bool get isNotEmpty => Maps.isNotEmpty(this);
}
final Future<SendPort> __HELPER_ISOLATE_PORT =
spawnDomFunction(_helperIsolateMain);
// Tricky part.
// Once __HELPER_ISOLATE_PORT gets resolved, it will still delay in .then
// and to delay Timer.run is used. However, Timer.run will try to register
// another Timer and here we got stuck: event cannot be posted as then
// callback is not executed because it's delayed with timer.
// Therefore once future is resolved, it's unsafe to call .then on it
// in Timer code.
SendPort __SEND_PORT;
_sendToHelperIsolate(msg, SendPort replyTo) {
if (__SEND_PORT != null) {
__SEND_PORT.send(msg, replyTo);
} else {
__HELPER_ISOLATE_PORT.then((port) {
__SEND_PORT = port;
__SEND_PORT.send(msg, replyTo);
});
}
}
final _TIMER_REGISTRY = new Map<SendPort, Timer>();
const _NEW_TIMER = 'NEW_TIMER';
const _CANCEL_TIMER = 'CANCEL_TIMER';
const _TIMER_PING = 'TIMER_PING';
const _PRINT = 'PRINT';
_helperIsolateMain() {
port.receive((msg, replyTo) {
final cmd = msg[0];
if (cmd == _NEW_TIMER) {
final duration = new Duration(milliseconds: msg[1]);
bool periodic = msg[2];
ping() { replyTo.send(_TIMER_PING); };
_TIMER_REGISTRY[replyTo] = periodic ?
new Timer.periodic(duration, (_) { ping(); }) :
new Timer(duration, ping);
} else if (cmd == _CANCEL_TIMER) {
_TIMER_REGISTRY.remove(replyTo).cancel();
} else if (cmd == _PRINT) {
final message = msg[1];
// TODO(antonm): we need somehow identify those isolates.
print('[From isolate] $message');
}
});
}
final _printClosure = window.console.log;
final _pureIsolatePrintClosure = (s) {
_sendToHelperIsolate([_PRINT, s], null);
};
final _forwardingPrintClosure = _Utils.forwardingPrint;
class _Timer implements Timer {
final canceller;
_Timer(this.canceller);
void cancel() { canceller(); }
}
get _timerFactoryClosure => (int milliSeconds, void callback(Timer timer), bool repeating) {
var maker;
var canceller;
if (repeating) {
maker = window._setInterval;
canceller = window._clearInterval;
} else {
maker = window._setTimeout;
canceller = window._clearTimeout;
}
Timer timer;
final int id = maker(() { callback(timer); }, milliSeconds);
timer = new _Timer(() { canceller(id); });
return timer;
};
class _PureIsolateTimer implements Timer {
final ReceivePort _port = new ReceivePort();
SendPort _sendPort; // Effectively final.
static SendPort _SEND_PORT;
_PureIsolateTimer(int milliSeconds, callback, repeating) {
_sendPort = _port.toSendPort();
_port.receive((msg, replyTo) {
assert(msg == _TIMER_PING);
callback(this);
if (!repeating) _cancel();
});
_send([_NEW_TIMER, milliSeconds, repeating]);
}
void cancel() {
_cancel();
_send([_CANCEL_TIMER]);
}
void _cancel() {
_port.close();
}
_send(msg) {
_sendToHelperIsolate(msg, _sendPort);
}
}
get _pureIsolateTimerFactoryClosure =>
((int milliSeconds, void callback(Timer time), bool repeating) =>
new _PureIsolateTimer(milliSeconds, callback, repeating));