Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library android_extension; | 5 library android_extension; |
| 6 import 'dart:async'; | 6 import 'dart:async'; |
| 7 | 7 |
| 8 // A VERY simplified DOM. | 8 // A VERY simplified DOM. |
| 9 | 9 |
| 10 class BodyElement { | 10 class BodyElement { |
| 11 List _nodes; | 11 List _nodes; |
| 12 get nodes => _nodes; | 12 get nodes => _nodes; |
| 13 BodyElement() : _nodes = new List(); | 13 BodyElement() : _nodes = new List(); |
| 14 } | 14 } |
| 15 | 15 |
| 16 // The OpenGLUI "equivalent" of Window. | 16 // The OpenGLUI "equivalent" of Window. |
| 17 | 17 |
| 18 typedef void RequestAnimationFrameCallback(num highResTime); | 18 typedef void RequestAnimationFrameCallback(num highResTime); |
| 19 | 19 |
| 20 class Window { | 20 class Window { |
| 21 static int _nextId = 0; | 21 static int _nextId = 0; |
| 22 Map<int, RequestAnimationFrameCallback> _callbacks; | 22 List _callbacks; |
| 23 List _arguments; | |
| 23 | 24 |
| 24 Window._internal() : _callbacks = new Map(); | 25 Window._internal() : _callbacks = [], _arguments = []; |
| 26 | |
| 27 int scheduleCallback(callback, [argument]) { | |
|
vsm
2013/03/27 22:27:06
Make this private? It's not a public Window api.
| |
| 28 _callbacks.add(callback); | |
| 29 _arguments.add(argument); | |
| 30 return _callbacks.length - 1; | |
| 31 } | |
| 25 | 32 |
| 26 int requestAnimationFrame(RequestAnimationFrameCallback callback) { | 33 int requestAnimationFrame(RequestAnimationFrameCallback callback) { |
| 27 _callbacks[_nextId++] = callback; | 34 return scheduleCallback(callback, |
| 35 (new DateTime.now()).millisecondsSinceEpoch); | |
| 28 } | 36 } |
| 37 | |
| 29 void cancelAnimationFrame(id) { | 38 void cancelAnimationFrame(id) { |
| 30 if (_callbacks.containsKey(id)) { | 39 _callbacks[id] = null; |
| 31 _callbacks.remove(id); | 40 _arguments[id] = null; |
| 32 } | |
| 33 } | 41 } |
| 42 | |
| 34 get animationFrame { | 43 get animationFrame { |
| 35 // TODO(gram) | 44 // TODO(gram) |
| 36 return null; | 45 return null; |
| 37 } | 46 } |
| 38 | 47 |
| 39 void _dispatch() { | 48 void _dispatch() { |
| 40 var when = (new DateTime.now()).millisecondsSinceEpoch; | |
| 41 // We clear out the callbacks map before calling any callbacks, | 49 // We clear out the callbacks map before calling any callbacks, |
| 42 // as they may schedule new callbacks. | 50 // as they may schedule new callbacks. |
| 43 var oldcallbacks = _callbacks; | 51 var oldcallbacks = _callbacks; |
| 44 _callbacks = new Map(); | 52 var oldarguments = _arguments; |
| 45 for (var c in oldcallbacks.values) { | 53 _callbacks = []; |
| 46 c(when); | 54 _arguments = []; |
| 55 for (var i = 0; i < oldcallbacks.length; i++) { | |
| 56 if (oldcallbacks[i] != null) { | |
| 57 oldcallbacks[i](oldarguments[i]); | |
| 58 } | |
| 47 } | 59 } |
| 60 // We could loop around here to handle any callbacks | |
| 61 // scheduled in processing the prior ones, but then we | |
| 62 // need some other mechanism for trying to get requestAnimationFrame | |
| 63 // callbacks at 60fps. | |
| 48 } | 64 } |
| 65 | |
| 66 Map localStorage = {}; | |
|
vsm
2013/03/27 22:27:06
Should this be persistent somehow? (Not in this C
| |
| 49 } | 67 } |
| 50 | 68 |
| 51 Window window = new Window._internal(); | 69 Window window = new Window._internal(); |
| 52 | 70 |
| 53 // The OpenGLUI "equivalent" of HtmlDocument. | 71 // The OpenGLUI "equivalent" of HtmlDocument. |
| 54 class Document { | 72 class Document extends Node { |
| 55 BodyElement _body; | 73 BodyElement _body; |
| 56 get body => _body; | 74 get body => _body; |
| 57 Document._internal() : _body = new BodyElement(); | 75 Document._internal() : _body = new BodyElement(); |
| 58 } | 76 } |
| 59 | 77 |
| 60 Document document = new Document._internal(); | 78 Document document = new Document._internal(); |
| 61 | 79 |
| 62 // TODO(gram): make private and call from within library context. | 80 // TODO(gram): make private and call from within library context. |
| 63 update_() { | 81 update_() { |
| 82 log("in update"); | |
| 64 window._dispatch(); | 83 window._dispatch(); |
| 65 } | 84 } |
| 66 | 85 |
| 67 // Event handling. This is very kludgy for now, especially the | 86 // Event handling. This is very kludgy for now, especially the |
| 68 // bare-bones Stream stuff! | 87 // bare-bones Stream stuff! |
| 69 | 88 |
| 70 typedef void EventListener(Event event); | 89 typedef void EventListener(Event event); |
| 71 | 90 |
| 72 class EventTarget { | 91 class EventTarget { |
| 73 static Map<EventTarget, Map<String, List<EventListener>>> | 92 static Map<EventTarget, Map<String, List<EventListener>>> |
| 74 _listeners = new Map(); | 93 _listeners = new Map(); |
| 75 | 94 |
| 76 static get listeners => _listeners; | 95 static get listeners => _listeners; |
| 77 | 96 |
| 78 bool dispatchEvent(Event event) { | 97 bool dispatchEvent(Event event) { |
| 98 var rtn = false; | |
| 79 if (!_listeners.containsKey(this)) return false; | 99 if (!_listeners.containsKey(this)) return false; |
| 80 var listeners = _listeners[this]; | 100 var listeners = _listeners[this]; |
| 81 if (!listeners.containsKey(event.type)) return false; | 101 if (!listeners.containsKey(event.type)) return false; |
| 82 var eventListeners = listeners[event.type]; | 102 var eventListeners = listeners[event.type]; |
| 83 for (var eventListener in eventListeners) { | 103 for (var eventListener in eventListeners) { |
| 84 if (eventListener != null) { | 104 if (eventListener != null) { |
| 85 eventListener(event); | 105 eventListener(event); |
| 106 rtn = true; | |
| 86 } | 107 } |
| 87 } | 108 } |
| 88 return true; | 109 return rtn; |
| 89 } | 110 } |
| 90 | 111 |
| 91 void addListener(String eventType, EventListener handler) { | 112 void addListener(String eventType, EventListener handler) { |
| 92 if (!_listeners.containsKey(this)) { | 113 if (!_listeners.containsKey(this)) { |
| 93 _listeners[this] = new Map(); | 114 _listeners[this] = new Map(); |
| 94 } | 115 } |
| 95 var listeners = _listeners[this]; | 116 var listeners = _listeners[this]; |
| 96 if (!listeners.containsKey(eventType)) { | 117 if (!listeners.containsKey(eventType)) { |
| 97 listeners[eventType] = new List(); | 118 listeners[eventType] = new List(); |
| 98 } | 119 } |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 119 } | 140 } |
| 120 } | 141 } |
| 121 } | 142 } |
| 122 } | 143 } |
| 123 } | 144 } |
| 124 | 145 |
| 125 class Event { | 146 class Event { |
| 126 final String type; | 147 final String type; |
| 127 EventTarget target; | 148 EventTarget target; |
| 128 Event(String type) : this.type = type; | 149 Event(String type) : this.type = type; |
| 150 preventDefault() {} | |
| 151 stopPropagation() {} | |
| 129 } | 152 } |
| 130 | 153 |
| 131 class KeyEvent extends Event { | 154 class KeyboardEvent extends Event { |
| 132 final bool altKey; | 155 final bool altKey; |
| 133 final bool ctrlKey; | 156 final bool ctrlKey; |
| 134 final bool shiftKey; | 157 final bool shiftKey; |
| 135 final int keyCode; | 158 final int keyCode; |
| 136 | 159 |
| 137 KeyEvent(String type, int keycode, bool alt, bool ctrl, bool shift) | 160 KeyboardEvent(String type, int keycode, bool alt, bool ctrl, bool shift) |
| 138 : super(type), | 161 : super(type), |
| 139 keyCode = keycode, | 162 keyCode = keycode, |
| 140 altKey = alt, | 163 altKey = alt, |
| 141 ctrlKey = ctrl, | 164 ctrlKey = ctrl, |
| 142 shiftKey = shift { | 165 shiftKey = shift { |
| 143 } | 166 } |
| 144 } | 167 } |
| 145 | 168 |
| 146 class MouseEvent extends Event { | 169 class MouseEvent extends Event { |
| 147 final int screenX, screenY; | 170 final int screenX, screenY; |
| 148 final int clientX, clientY; | 171 final int clientX, clientY; |
| 149 | 172 |
| 150 MouseEvent(String type, int x, int y) | 173 MouseEvent(String type, int x, int y) |
| 151 : super(type), | 174 : super(type), |
| 152 screenX = x, | 175 screenX = x, |
| 153 screenY = y, | 176 screenY = y, |
| 154 clientX = x, | 177 clientX = x, |
| 155 clientY = y { | 178 clientY = y { |
| 156 } | 179 } |
| 157 } | 180 } |
| 158 | 181 |
| 159 | |
| 160 class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> { | 182 class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> { |
| 161 int _pauseCount = 0; | 183 int _pauseCount = 0; |
| 162 EventTarget _target; | 184 EventTarget _target; |
| 163 final String _eventType; | 185 final String _eventType; |
| 164 var _onData; | 186 var _onData; |
| 165 | 187 |
| 166 _EventStreamSubscription(this._target, this._eventType, this._onData) { | 188 _EventStreamSubscription(this._target, this._eventType, this._onData) { |
| 167 _tryResume(); | 189 _tryResume(); |
| 168 } | 190 } |
| 169 | 191 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 249 { void onError(AsyncError error), | 271 { void onError(AsyncError error), |
| 250 void onDone(), | 272 void onDone(), |
| 251 bool unsubscribeOnError}) { | 273 bool unsubscribeOnError}) { |
| 252 | 274 |
| 253 return new _EventStreamSubscription<T>( | 275 return new _EventStreamSubscription<T>( |
| 254 this._target, this._eventType, onData); | 276 this._target, this._eventType, onData); |
| 255 } | 277 } |
| 256 } | 278 } |
| 257 | 279 |
| 258 class Node extends EventTarget { | 280 class Node extends EventTarget { |
| 259 Stream<KeyEvent> get onKeyDown => new _EventStream(this, 'keydown'); | 281 Stream<KeyboardEvent> get onKeyDown => new _EventStream(this, 'keydown'); |
| 260 Stream<KeyEvent> get onKeyUp => new _EventStream(this, 'keyup'); | 282 Stream<KeyboardEvent> get onKeyUp => new _EventStream(this, 'keyup'); |
| 261 Stream<MouseEvent> get onMouseDown => new _EventStream(this, 'mousedown'); | 283 Stream<MouseEvent> get onMouseDown => new _EventStream(this, 'mousedown'); |
| 262 Stream<MouseEvent> get onMouseMove => new _EventStream(this, 'mousemove'); | 284 Stream<MouseEvent> get onMouseMove => new _EventStream(this, 'mousemove'); |
| 263 Stream<MouseEvent> get onMouseUp => new _EventStream(this, 'mouseup'); | 285 Stream<MouseEvent> get onMouseUp => new _EventStream(this, 'mouseup'); |
| 264 } | 286 } |
| 265 | 287 |
| 266 // TODO(gram): If we support more than one on-screen canvas, we will | 288 // TODO(gram): If we support more than one on-screen canvas, we will |
| 267 // need to filter dispatched mouse and key events by the target Node | 289 // need to filter dispatched mouse and key events by the target Node |
| 268 // with more granularity; right now we just iterate through DOM nodes | 290 // with more granularity; right now we just iterate through DOM nodes |
| 269 // until we find one that handles the event. | 291 // until we find one that handles the event. |
| 270 _dispatchEvent(Event event) { | 292 _dispatchEvent(Event event) { |
| 271 assert(document.body.nodes.length <= 1); | 293 assert(document.body.nodes.length <= 1); |
| 272 for (var target in document.body.nodes) { | 294 for (var target in document.body.nodes) { |
| 273 event.target = target; | 295 event.target = target; |
| 274 if (target.dispatchEvent(event)) { | 296 if (target.dispatchEvent(event)) { |
| 275 break; | 297 return; |
| 276 } | 298 } |
| 277 } | 299 } |
| 300 document.dispatchEvent(event); | |
| 278 } | 301 } |
| 279 | 302 |
| 280 _dispatchKeyEvent(String type, int keyCode, bool alt, bool ctrl, bool shift) { | 303 _dispatchKeyEvent(String type, int keyCode, bool alt, bool ctrl, bool shift) { |
| 281 _dispatchEvent(new KeyEvent(type, keyCode, alt, ctrl, shift)); | 304 _dispatchEvent(new KeyboardEvent(type, keyCode, alt, ctrl, shift)); |
| 282 } | 305 } |
| 283 | 306 |
| 284 _dispatchMouseEvent(String type, double x, double y) { | 307 _dispatchMouseEvent(String type, double x, double y) { |
| 285 _dispatchEvent(new MouseEvent(type, x.toInt(), y.toInt())); | 308 _dispatchEvent(new MouseEvent(type, x.toInt(), y.toInt())); |
| 286 } | 309 } |
| 287 | 310 |
| 288 // These next few are called by vmglue.cc. | 311 // These next few are called by vmglue.cc. |
| 289 onKeyDown_(int when, int keyCode, bool alt, bool ctrl, bool shift, int repeat) | 312 onKeyDown_(int when, int keyCode, bool alt, bool ctrl, bool shift, int repeat) |
| 290 => _dispatchKeyEvent('keydown', keyCode, alt, ctrl, shift); | 313 => _dispatchKeyEvent('keydown', keyCode, alt, ctrl, shift); |
| 291 | 314 |
| 292 onKeyUp_(int when, int keyCode, bool alt, bool ctrl, bool shift, int repeat) => | 315 onKeyUp_(int when, int keyCode, bool alt, bool ctrl, bool shift, int repeat) => |
| 293 _dispatchKeyEvent('keyup', keyCode, alt, ctrl, shift); | 316 _dispatchKeyEvent('keyup', keyCode, alt, ctrl, shift); |
| 294 | 317 |
| 295 onMouseDown_(int when, double x, double y) => | 318 onMouseDown_(int when, double x, double y) => |
| 296 _dispatchMouseEvent('mousedown', x, y); | 319 _dispatchMouseEvent('mousedown', x, y); |
| 297 | 320 |
| 298 onMouseMove_(int when, double x, double y) => | 321 onMouseMove_(int when, double x, double y) => |
| 299 _dispatchMouseEvent('mousemove', x, y); | 322 _dispatchMouseEvent('mousemove', x, y); |
| 300 | 323 |
| 301 onMouseUp_(int when, double x, double y) => | 324 onMouseUp_(int when, double x, double y) => |
| 302 _dispatchMouseEvent('mouseup', x, y); | 325 _dispatchMouseEvent('mouseup', x, y); |
| 303 | 326 |
| 304 class CanvasElement extends Node { | 327 class CanvasElement extends Node { |
| 305 int _height; | 328 int height; |
| 306 int _width; | 329 int width; |
| 307 | |
| 308 get height => _height; | |
| 309 get width => _width; | |
| 310 | 330 |
| 311 CanvasRenderingContext2D _context2d; | 331 CanvasRenderingContext2D _context2d; |
| 312 WebGLRenderingContext _context3d; | 332 WebGLRenderingContext _context3d; |
| 313 | 333 |
| 314 // For use with drawImage, we want to support a src property | 334 // For use with drawImage, we want to support a src property |
| 315 // like ImageElement, which maps to the context handle in native | 335 // like ImageElement, which maps to the context handle in native |
| 316 // code. | 336 // code. |
| 317 get src => "context2d://${_context2d.handle}"; | 337 get src => "context2d://${_context2d.handle}"; |
| 318 | 338 |
| 319 CanvasElement({int width, int height}) | 339 CanvasElement({int width, int height}) |
| 320 : super() { | 340 : super() { |
| 321 _width = (width == null) ? getDeviceScreenWidth() : width; | 341 this.width = (width == null) ? getDeviceScreenWidth() : width; |
| 322 _height = (height == null) ? getDeviceScreenHeight() : height; | 342 this.height = (height == null) ? getDeviceScreenHeight() : height; |
| 343 getContext('2d'); | |
| 323 } | 344 } |
| 324 | 345 |
| 325 CanvasRenderingContext getContext(String contextId) { | 346 CanvasRenderingContext getContext(String contextId) { |
| 326 if (contextId == "2d") { | 347 if (contextId == "2d") { |
| 327 if (_context2d == null) { | 348 if (_context2d == null) { |
| 328 _context2d = new CanvasRenderingContext2D(this, _width, _height); | 349 _context2d = new CanvasRenderingContext2D(this, width, height); |
| 329 } | 350 } |
| 330 return _context2d; | 351 return _context2d; |
| 331 } else if (contextId == "webgl" || | 352 } else if (contextId == "webgl" || |
| 332 contextId == "experimental-webgl") { | 353 contextId == "experimental-webgl") { |
| 333 if (_context3d == null) { | 354 if (_context3d == null) { |
| 334 _context3d = new WebGLRenderingContext(this); | 355 _context3d = new WebGLRenderingContext(this); |
| 335 } | 356 } |
| 336 return _context3d; | 357 return _context3d; |
| 337 } | 358 } |
| 338 } | 359 } |
| 360 | |
| 361 String toDataUrl(String type) { | |
| 362 // This needs to take the contents of the underlying | |
| 363 // canvas painted by the 2d context, give that a unique | |
| 364 // URL, and return that. The canvas element should be | |
| 365 // reuable afterwards without destroying the previously | |
| 366 // rendered data associated with this URL. | |
| 367 assert(_context2d != null); | |
| 368 var rtn = src; | |
| 369 _context2d = null; | |
| 370 return rtn; | |
| 371 } | |
| 339 } | 372 } |
| 340 | 373 |
| 341 class CanvasRenderingContext { | 374 class CanvasRenderingContext { |
| 342 final CanvasElement canvas; | 375 final CanvasElement canvas; |
| 343 | 376 |
| 344 CanvasRenderingContext(this.canvas); | 377 CanvasRenderingContext(this.canvas); |
| 345 } | 378 } |
| 346 | 379 |
| 380 class AudioElement { | |
| 381 double volume; | |
| 382 String _src; | |
| 383 get src => _src; | |
| 384 set src(String v) { | |
| 385 _src = v; | |
| 386 loadSample(v); | |
| 387 } | |
| 388 | |
| 389 AudioElement([this._src]); | |
| 390 void play() { | |
| 391 playSample(_src); | |
| 392 } | |
| 393 } | |
| 394 | |
| 347 // The simplest way to call native code: top-level functions. | 395 // The simplest way to call native code: top-level functions. |
| 348 int systemRand() native "SystemRand"; | 396 int systemRand() native "SystemRand"; |
| 349 void systemSrand(int seed) native "SystemSrand"; | 397 void systemSrand(int seed) native "SystemSrand"; |
| 350 void log(String what) native "Log"; | 398 void log(String what) native "Log"; |
| 351 | 399 |
| 352 int getDeviceScreenWidth() native "GetDeviceScreenWidth"; | 400 int getDeviceScreenWidth() native "GetDeviceScreenWidth"; |
| 353 int getDeviceScreenHeight() native "GetDeviceScreenHeight"; | 401 int getDeviceScreenHeight() native "GetDeviceScreenHeight"; |
| 354 | 402 |
| 355 // EGL functions. | 403 // EGL functions. |
| 356 void glSwapBuffers() native "SwapBuffers"; | 404 void glSwapBuffers() native "SwapBuffers"; |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 639 native "C2DStrokeText"; | 687 native "C2DStrokeText"; |
| 640 void C2DTransform(int handle, double m11, double m12, | 688 void C2DTransform(int handle, double m11, double m12, |
| 641 double m21, double m22, double dx, double dy) | 689 double m21, double m22, double dx, double dy) |
| 642 native "C2DTransform"; | 690 native "C2DTransform"; |
| 643 void C2DTranslate(int handle, double x, double y) | 691 void C2DTranslate(int handle, double x, double y) |
| 644 native "C2DTranslate"; | 692 native "C2DTranslate"; |
| 645 | 693 |
| 646 void C2DCreateNativeContext(int handle, int width, int height) | 694 void C2DCreateNativeContext(int handle, int width, int height) |
| 647 native "C2DCreateNativeContext"; | 695 native "C2DCreateNativeContext"; |
| 648 | 696 |
| 697 void C2DSetFillGradient(int handle, bool isRadial, | |
|
vsm
2013/03/27 22:27:06
Should these C2D functions be private?
| |
| 698 double x0, double y0, double r0, | |
| 699 double x1, double y1, double r1, | |
| 700 List<double> positions, List<String> colors) | |
| 701 native "C2DSetFillGradient"; | |
| 702 | |
| 703 void C2DSetStrokeGradient(int handle, bool isRadial, | |
| 704 double x0, double y0, double r0, | |
| 705 double x1, double y1, double r1, | |
| 706 List<double> positions, List<String> colors) | |
| 707 native "C2DSetStrokeGradient"; | |
| 708 | |
| 709 int C2DGetImageWidth(String url) | |
| 710 native "C2DGetImageWidth"; | |
| 711 | |
| 712 int C2DGetImageHeight(String url) | |
| 713 native "C2DGetImageHeight"; | |
| 714 | |
| 715 class CanvasGradient { | |
| 716 num _x0, _y0, _r0 = 0, _x1, _y1, _r1 = 0; | |
| 717 bool _isRadial; | |
| 718 List<double> _colorStopPositions = []; | |
| 719 List<String> _colorStopColors = []; | |
| 720 | |
| 721 void addColorStop(num offset, String color) { | |
| 722 _colorStopPositions.add(offset.toDouble()); | |
| 723 _colorStopColors.add(color); | |
| 724 } | |
| 725 | |
| 726 CanvasGradient.linear(this._x0, this._y0, this._x1, this._y1) | |
| 727 : _isRadial = false; | |
| 728 | |
| 729 CanvasGradient.radial(this._x0, this._y0, this._r0, | |
| 730 this._x1, this._y1, this._r1) | |
| 731 : _isRadial = true; | |
| 732 | |
| 733 void setAsFillStyle(_handle) { | |
| 734 C2DSetFillGradient(_handle, _isRadial, | |
| 735 _x0.toDouble(), _y0.toDouble(), _r0.toDouble(), | |
| 736 _x1.toDouble(), _y1.toDouble(), _r1.toDouble(), | |
| 737 _colorStopPositions, _colorStopColors); | |
| 738 } | |
| 739 | |
| 740 void setAsStrokeStyle(_handle) { | |
| 741 C2DSetStrokeGradient(_handle, _isRadial, | |
| 742 _x0.toDouble(), _y0.toDouble(), _r0.toDouble(), | |
| 743 _x1.toDouble(), _y1.toDouble(), _r1.toDouble(), | |
| 744 _colorStopPositions, _colorStopColors); | |
| 745 } | |
| 746 } | |
| 747 | |
| 649 class ImageElement extends Node { | 748 class ImageElement extends Node { |
| 650 Stream<Event> get onLoad => new _EventStream(this, 'load'); | 749 Stream<Event> get onLoad => new _EventStream(this, 'load'); |
| 651 | 750 |
| 652 String _src; | 751 String _src; |
| 653 int _width; | 752 int _width; |
| 654 int _height; | 753 int _height; |
| 655 | 754 |
| 656 get src => _src; | 755 get src => _src; |
| 756 | |
| 657 set src(String v) { | 757 set src(String v) { |
| 758 log("Set ImageElement src to $v"); | |
| 658 _src = v; | 759 _src = v; |
| 659 var e = new Event('load'); | |
| 660 e.target = this; | |
| 661 dispatchEvent(e); | |
| 662 } | 760 } |
| 663 | 761 |
| 664 get width => _width; | 762 // The onLoad handler may be set after the src, so |
| 763 // we hook into that here... | |
| 764 void addListener(String eventType, EventListener handler) { | |
| 765 super.addListener(eventType, handler); | |
| 766 if (eventType == 'load') { | |
| 767 var e = new Event('load'); | |
| 768 e.target = this; | |
| 769 window.scheduleCallback(handler, e); | |
| 770 } | |
| 771 } | |
| 772 | |
| 773 get width => _width == null ? _width = C2DGetImageWidth(_src) : _width; | |
| 774 get height => _height == null ? _height = C2DGetImageHeight(_src) : _height; | |
| 665 set width(int widthp) => _width = widthp; | 775 set width(int widthp) => _width = widthp; |
| 666 | |
| 667 get height => _height; | |
| 668 set height(int heightp) => _height = heightp; | 776 set height(int heightp) => _height = heightp; |
| 669 | 777 |
| 670 ImageElement({String srcp, int widthp, int heightp}) | 778 ImageElement({String srcp, int widthp, int heightp}) |
| 671 : _src = srcp, | 779 : _src = srcp, |
| 672 _width = widthp, | 780 _width = widthp, |
| 673 _height = heightp { | 781 _height = heightp { |
| 782 if (_src != null) { | |
| 783 if (_width == null) _width = C2DGetImageWidth(_src); | |
| 784 if (_height == null) _height = C2DGetImageHeight(_src); | |
| 785 } | |
| 674 } | 786 } |
| 675 } | 787 } |
| 676 | 788 |
| 677 class ImageData { | 789 class ImageData { |
| 678 final Uint8ClampedArray data; | 790 final Uint8ClampedArray data; |
| 679 final int height; | 791 final int height; |
| 680 final int width; | 792 final int width; |
| 681 ImageData(this.height, this.width, this.data); | 793 ImageData(this.height, this.width, this.data); |
| 682 } | 794 } |
| 683 | 795 |
| 684 class TextMetrics { | 796 class TextMetrics { |
| 685 final num width; | 797 final num width; |
| 686 TextMetrics(this.width); | 798 TextMetrics(this.width); |
| 687 } | 799 } |
| 688 | 800 |
| 689 void shutdown() { | 801 void shutdown() { |
| 690 CanvasRenderingContext2D.next_handle = 0; | 802 CanvasRenderingContext2D.next_handle = 0; |
| 691 } | 803 } |
| 692 | 804 |
| 805 class Rect { | |
| 806 final num top, left, width, height; | |
| 807 const Rect(this.left, this.top, this.width, this.height); | |
| 808 } | |
| 809 | |
| 693 class CanvasRenderingContext2D extends CanvasRenderingContext { | 810 class CanvasRenderingContext2D extends CanvasRenderingContext { |
| 694 // TODO(gram): We need to support multiple contexts, for cached content | 811 // TODO(gram): We need to support multiple contexts, for cached content |
| 695 // prerendered to an offscreen buffer. For this we will use handles, with | 812 // prerendered to an offscreen buffer. For this we will use handles, with |
| 696 // handle 0 being the physical display. | 813 // handle 0 being the physical display. |
| 697 static int next_handle = 0; | 814 static int next_handle = 0; |
| 698 int _handle = 0; | 815 int _handle = 0; |
| 699 get handle => _handle; | 816 get handle => _handle; |
| 700 | 817 |
| 701 int _width, _height; | 818 int _width, _height; |
| 702 set width(int w) { _width = C2DSetWidth(_handle, w); } | 819 set width(int w) { _width = C2DSetWidth(_handle, w); } |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 713 double _alpha = 1.0; | 830 double _alpha = 1.0; |
| 714 set globalAlpha(num a) { | 831 set globalAlpha(num a) { |
| 715 _alpha = C2DSetGlobalAlpha(_handle, a.toDouble()); | 832 _alpha = C2DSetGlobalAlpha(_handle, a.toDouble()); |
| 716 } | 833 } |
| 717 get globalAlpha => _alpha; | 834 get globalAlpha => _alpha; |
| 718 | 835 |
| 719 // TODO(gram): make sure we support compound assignments like: | 836 // TODO(gram): make sure we support compound assignments like: |
| 720 // fillStyle = strokeStyle = "red" | 837 // fillStyle = strokeStyle = "red" |
| 721 var _fillStyle = "#000"; | 838 var _fillStyle = "#000"; |
| 722 set fillStyle(fs) { | 839 set fillStyle(fs) { |
| 723 C2DSetFillStyle(_handle, _fillStyle = fs); | 840 _fillStyle = fs; |
| 841 // TODO(gram): Support for CanvasPattern. | |
| 842 if (fs is CanvasGradient) { | |
| 843 fs.setAsFillStyle(_handle); | |
| 844 } else { | |
| 845 C2DSetFillStyle(_handle, fs); | |
| 846 } | |
| 724 } | 847 } |
| 725 get fillStyle => _fillStyle; | 848 get fillStyle => _fillStyle; |
| 726 | 849 |
| 727 String _font = "10px sans-serif"; | 850 String _font = "10px sans-serif"; |
| 728 set font(String f) { _font = C2DSetFont(_handle, f); } | 851 set font(String f) { _font = C2DSetFont(_handle, f); } |
| 729 get font => _font; | 852 get font => _font; |
| 730 | 853 |
| 731 String _globalCompositeOperation = "source-over"; | 854 String _globalCompositeOperation = "source-over"; |
| 732 set globalCompositeOperation(String o) => | 855 set globalCompositeOperation(String o) => |
| 733 C2DSetGlobalCompositeOperation(_handle, _globalCompositeOperation = o); | 856 C2DSetGlobalCompositeOperation(_handle, _globalCompositeOperation = o); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 784 num _shadowOffsetY; | 907 num _shadowOffsetY; |
| 785 get shadowOffsetY => _shadowOffsetY; | 908 get shadowOffsetY => _shadowOffsetY; |
| 786 set shadowOffsetY(num offset) { | 909 set shadowOffsetY(num offset) { |
| 787 _shadowOffsetY = offset; | 910 _shadowOffsetY = offset; |
| 788 C2DSetShadowOffsetY(_handle, offset.toDouble()); | 911 C2DSetShadowOffsetY(_handle, offset.toDouble()); |
| 789 } | 912 } |
| 790 | 913 |
| 791 var _strokeStyle = "#000"; | 914 var _strokeStyle = "#000"; |
| 792 get strokeStyle => _strokeStyle; | 915 get strokeStyle => _strokeStyle; |
| 793 set strokeStyle(ss) { | 916 set strokeStyle(ss) { |
| 794 C2DSetStrokeStyle(_handle, _strokeStyle = ss); | 917 _strokeStyle = ss; |
| 918 // TODO(gram): Support for CanvasPattern. | |
| 919 if (ss is CanvasGradient) { | |
| 920 ss.setAsStrokeStyle(_handle); | |
| 921 } else { | |
| 922 C2DSetStrokeStyle(_handle, ss); | |
| 923 } | |
| 795 } | 924 } |
| 796 | 925 |
| 797 String _textAlign = "start"; | 926 String _textAlign = "start"; |
| 798 get textAlign => _textAlign; | 927 get textAlign => _textAlign; |
| 799 set textAlign(String a) { _textAlign = C2DSetTextAlign(_handle, a); } | 928 set textAlign(String a) { _textAlign = C2DSetTextAlign(_handle, a); } |
| 800 | 929 |
| 801 String _textBaseline = "alphabetic"; | 930 String _textBaseline = "alphabetic"; |
| 802 get textBaseline => _textBaseline; | 931 get textBaseline => _textBaseline; |
| 803 set textBaseline(String b) { _textBaseline = C2DSetTextBaseline(_handle, b); } | 932 set textBaseline(String b) { _textBaseline = C2DSetTextBaseline(_handle, b); } |
| 804 | 933 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 857 | 986 |
| 858 ImageData createImageData(var imagedata_OR_sw, [num sh = null]) { | 987 ImageData createImageData(var imagedata_OR_sw, [num sh = null]) { |
| 859 if (sh == null) { | 988 if (sh == null) { |
| 860 throw new Exception('Unimplemented createImageData(imagedata)'); | 989 throw new Exception('Unimplemented createImageData(imagedata)'); |
| 861 } else { | 990 } else { |
| 862 return C2DCreateImageDataFromDimensions(_handle, imagedata_OR_sw, sh); | 991 return C2DCreateImageDataFromDimensions(_handle, imagedata_OR_sw, sh); |
| 863 } | 992 } |
| 864 } | 993 } |
| 865 | 994 |
| 866 CanvasGradient createLinearGradient(num x0, num y0, num x1, num y1) { | 995 CanvasGradient createLinearGradient(num x0, num y0, num x1, num y1) { |
| 867 throw new Exception('Unimplemented createLinearGradient'); | 996 return new CanvasGradient.linear(x0, y0, x1, y1); |
| 868 } | 997 } |
| 869 | 998 |
| 870 CanvasPattern createPattern(canvas_OR_image, String repetitionType) { | 999 CanvasPattern createPattern(canvas_OR_image, String repetitionType) { |
| 871 throw new Exception('Unimplemented createPattern'); | 1000 throw new Exception('Unimplemented createPattern'); |
| 872 } | 1001 } |
| 873 | 1002 |
| 874 CanvasGradient createRadialGradient(num x0, num y0, num x1, num y1, num r1) { | 1003 CanvasGradient createRadialGradient(num x0, num y0, num r0, |
| 875 throw new Exception('Unimplemented createRadialGradient'); | 1004 num x1, num y1, num r1) { |
| 1005 return new CanvasGradient.radial(x0, y0, r0, x1, y1, r1); | |
| 876 } | 1006 } |
| 877 | 1007 |
| 878 void drawImage(element, num x1, num y1, | 1008 void drawImage(element, num x1, num y1, |
| 879 [num w1, num h1, num x2, num y2, num w2, num h2]) { | 1009 [num w1, num h1, num x2, num y2, num w2, num h2]) { |
| 1010 if (element == null || element.src == null || element.src.length == 0) { | |
| 1011 throw "drawImage called with no valid src"; | |
| 1012 } else { | |
| 1013 log("drawImage ${element.src}"); | |
| 1014 } | |
| 880 var w = (element.width == null) ? 0 : element.width; | 1015 var w = (element.width == null) ? 0 : element.width; |
| 881 var h = (element.height == null) ? 0 : element.height; | 1016 var h = (element.height == null) ? 0 : element.height; |
| 882 if (!?w1) { // drawImage(element, dx, dy) | 1017 if (!?w1) { // drawImage(element, dx, dy) |
| 883 C2DDrawImage(_handle, element.src, 0, 0, false, w, h, | 1018 C2DDrawImage(_handle, element.src, 0, 0, false, w, h, |
| 884 x1.toInt(), y1.toInt(), false, 0, 0); | 1019 x1.toInt(), y1.toInt(), false, 0, 0); |
| 885 } else if (!?x2) { // drawImage(element, dx, dy, dw, dh) | 1020 } else if (!?x2) { // drawImage(element, dx, dy, dw, dh) |
| 886 C2DDrawImage(_handle, element.src, 0, 0, false, w, h, | 1021 C2DDrawImage(_handle, element.src, 0, 0, false, w, h, |
| 887 x1.toInt(), y1.toInt(), true, w1.toInt(), h1.toInt()); | 1022 x1.toInt(), y1.toInt(), true, w1.toInt(), h1.toInt()); |
| 888 } else { // drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) | 1023 } else { // drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) |
| 889 C2DDrawImage(_handle, element.src, | 1024 C2DDrawImage(_handle, element.src, |
| 890 x1.toInt(), y1.toInt(), true, w1.toInt(), h1.toInt(), | 1025 x1.toInt(), y1.toInt(), true, w1.toInt(), h1.toInt(), |
| 891 x2.toInt(), y2.toInt(), true, w2.toInt(), h2.toInt()); | 1026 x2.toInt(), y2.toInt(), true, w2.toInt(), h2.toInt()); |
| 892 } | 1027 } |
| 893 } | 1028 } |
| 894 | 1029 |
| 1030 void drawImageAtScale(element, Rect dest, {Rect sourceRect}) { | |
| 1031 if (sourceRect == null) { | |
| 1032 drawImage(element, dest.left, dest.top, dest.width, dest.height); | |
| 1033 } else { | |
| 1034 drawImage(element, | |
| 1035 sourceRect.left, sourceRect.top, sourceRect.width, sourceRect.height, | |
| 1036 dest.left, dest.top, dest.width, dest.height); | |
| 1037 } | |
| 1038 } | |
| 1039 | |
| 895 void fill() => C2DFill(_handle); | 1040 void fill() => C2DFill(_handle); |
| 896 | 1041 |
| 897 void fillRect(num x, num y, num w, num h) => | 1042 void fillRect(num x, num y, num w, num h) => |
| 898 C2DFillRect(_handle, x.toDouble(), y.toDouble(), | 1043 C2DFillRect(_handle, x.toDouble(), y.toDouble(), |
| 899 w.toDouble(), h.toDouble()); | 1044 w.toDouble(), h.toDouble()); |
| 900 | 1045 |
| 901 void fillText(String text, num x, num y, [num maxWidth = -1]) => | 1046 void fillText(String text, num x, num y, [num maxWidth = -1]) => |
| 902 C2DFillText(_handle, text, x.toDouble(), y.toDouble(), | 1047 C2DFillText(_handle, text, x.toDouble(), y.toDouble(), |
| 903 maxWidth.toDouble()); | 1048 maxWidth.toDouble()); |
| 904 | 1049 |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1027 num dirtyWidth, num dirtyHeight]) { | 1172 num dirtyWidth, num dirtyHeight]) { |
| 1028 throw new Exception('Unimplemented webkitGetImageDataHD'); | 1173 throw new Exception('Unimplemented webkitGetImageDataHD'); |
| 1029 } | 1174 } |
| 1030 | 1175 |
| 1031 // TODO(vsm): Kill. | 1176 // TODO(vsm): Kill. |
| 1032 noSuchMethod(invocation) { | 1177 noSuchMethod(invocation) { |
| 1033 throw new Exception('Unimplemented/unknown ${invocation.memberName}'); | 1178 throw new Exception('Unimplemented/unknown ${invocation.memberName}'); |
| 1034 } | 1179 } |
| 1035 } | 1180 } |
| 1036 | 1181 |
| 1182 int loadSample(String s) native "LoadSample"; | |
|
vsm
2013/03/27 22:27:06
Make these private?
| |
| 1183 int playSample(String s) native "PlaySample"; | |
| OLD | NEW |