Sciter Architecture Details of implementation Sciter UI layer

  • Slides: 40
Download presentation
Sciter Architecture. Details of implementation.

Sciter Architecture. Details of implementation.

Sciter – UI layer of the application • Separation of concerns principle, UI: –

Sciter – UI layer of the application • Separation of concerns principle, UI: – Objects lifecycle: complex ownership graph with loops. – Tend to change in lifetime of the application. – Subject of style changes and customization. • Must be isolated from backend. • UI <-> backend API shall be compact and stable.

Sciter Architecture • Major Sciter modules: 1. 2. 3. 4. 5. HTML: parser/compiler and

Sciter Architecture • Major Sciter modules: 1. 2. 3. 4. 5. HTML: parser/compiler and DOM tree; CSS: parser/compiler and CSS OM; Layout module; Script: source-to-bytecode compiler, VM, runtime classes: Array, Object, String, … Graphics, Windowing/Desktop and system back ends;

Source code sturcture • • • batch engine gtk – linux/gtk osx – Mac.

Source code sturcture • • • batch engine gtk – linux/gtk osx – Mac. OS xgl – win, lin, mac – Skia incl. Open. GL • sdk • engine – tool – gool – html – tiscript – xdom – d 2 d, gdi+ – external • jpeg, png, webp, zlib • uv – lib. UV - async I/O – win – api – res

Sciter. Threading model • Sciter is mostly single threaded – UI code and scripts

Sciter. Threading model • Sciter is mostly single threaded – UI code and scripts run solely in GUI thread; – Multiple GUI threads supported but a) not required and b) not recommended. • Sciter may use worker (non-GUI) threads internally: – HTTP communication; – lib. UV: Sockets, Pipes, File I/O (threads or completion ports). • Sciter API is thread safe but involves marshalling of call parameters into GUI thread. • Call of long-running native methods: function find. Threats() { function when. Found(data) { //. . . update UI by data. . . } // starts worker thread and returns immediately view. long. Running(when. Found); }

HTML DOM tree HTML source: <html> <head> <script>…</script> <style>…</style> </head> <body> <header>…</header> <main> Hello

HTML DOM tree HTML source: <html> <head> <script>…</script> <style>…</style> </head> <body> <header>…</header> <main> Hello World </main> <footer>…</footer> </body> </html>

Document loading sequence • Parse input HTML – elements created and pushed into DOM

Document loading sequence • Parse input HTML – elements created and pushed into DOM tree; – <style> elements are parsed as they inserted into DOM tree; – At the end: DOM tree is compete, style tables are there. • Compile and run scripts in <script> elements – Handle include "other. tis"; while running. • Resolve styles of all elements – Load images for background-image: url(…); – Handle behavior: ”…” and prototype: ”…” – behaviors assignment. May involve running script code of attached() methods. • Do layout of visible elements in the window – May involve running script code of element. on. Size() methods. • Render all visible elements

HTML DOM • List of classes – Node – Text: Node – Comment: Node

HTML DOM • List of classes – Node – Text: Node – Comment: Node – Element: Node – Document: Element – View (a. k. a. window) • DOM tree: – View contains single root document element. – Document contains tree of its children.

HTML DOM. Node and Element namespace html { struct node : resource { weak_handle<element>

HTML DOM. Node and Element namespace html { struct node : resource { weak_handle<element> parent; // DOM parent weak_handle<element> owner; // rendering parent uint node_index; uint 64 obj; // script object }; struct text : node {. . . }; struct comment : node {. . . }; struct element : node { uint tag; attribute_bag atts; ui_state; // <img> // <img src="url"> // : active, : focus, : hover array<handle<node>> nodes; // children handle<style> handle<ctl> handle<animation> handle<layout_data> }; } c_style, p_style; behavior; animator; ldata;

HTML DOM. Document • Document is <html> element – root of the DOM tree.

HTML DOM. Document • Document is <html> element – root of the DOM tree. It also contains resource and style collections. namespace html { struct document : element { weak_handle<view> view; image_bag style_bag images; styles; handle<application> app; uint 64 ns; // script namespace object }; }

CSS • CSS is parsed into: – Flat table of • selector/struct style pairs

CSS • CSS is parsed into: – Flat table of • selector/struct style pairs • ordered by the selector specificity

namespace html { struct style : resource { enum_v display; enum_v visibility; string font_name;

namespace html { struct style : resource { enum_v display; enum_v visibility; string font_name; size_v font_size; . . . }; struct style_def selector handle<style> uint }; CSS internals { selector; style; specicity() const; // of selector struct style_bag { tool: : pool<hstyle> resolved_pool; // interned styles tool: : array<hstyle_def>> defs; // ordered in specificity() order }; }

CSS. Style resolution. • To find styles of DOM elements: • • Each DOM

CSS. Style resolution. • To find styles of DOM elements: • • Each DOM element is tested against each style selector. If selector matches the style then properties of the style rule are applied. • The complexity of style resolution is O(N*S) where: • • N – number of DOM elements; S – number of style rules; for each (var element in document) { style_to_find; for each ( var style_def in document. styles ) if (element. match(style_def. selector)) { style_to_find. update(style_def. style); } element. current_style = document. intern(style_to_find); }

CSS. Style resolution. Optimization • Engine does sibling style optimization: – Previous sibling with

CSS. Style resolution. Optimization • Engine does sibling style optimization: – Previous sibling with resolved style is tested against “similarity”: • Has same set of attributes and state flags • Has same number of children, etc. – If previous sibling matches then its resolved style is used for the element. – Note: use of : nth-child() selector breaks this optimization.

Layout Step I • Compute min/max intrinsic sizes Hello world Hello universe Hello Symantec

Layout Step I • Compute min/max intrinsic sizes Hello world Hello universe Hello Symantec Hello Los Angeles

Layout Step II • Compute min/max intrinsic sizes • Setup widths – will give

Layout Step II • Compute min/max intrinsic sizes • Setup widths – will give us heights Hello world Hello universe Hello Symantec Hello Los Angeles

Layout Step III • Compute min/max intrinsic sizes • Setup widths – will give

Layout Step III • Compute min/max intrinsic sizes • Setup widths – will give us heights • Adjust vertical alignment and positions. Hello world Hello universe Hello Symantec Hello Los Angeles

Complexity of layout computation • At least O(N) complex, N is a number of

Complexity of layout computation • At least O(N) complex, N is a number of DOM elements involved. • Dynamic updates and property animations: small change of the DOM may lead to deep tree layout computation. – Solutions: • Minimize number of elements involved, or: • CSS transform animations – no relayout; • Opacity animations – no relayout.

DOM Population, Complexity • Parsing (performed as a single transaction): Element. html = "html

DOM Population, Complexity • Parsing (performed as a single transaction): Element. html = "html string"; Element. content("html string"); • Batch (array) population (single transaction) Element. content([el 1, el 2, …]); //. append()/. prepend • Single element insertion/deletion (worst case – O(n 2) if it is done in a loop) Element. append(el); //. insert()/. prepend After each external mutation, the DOM must be in consistent state. Check for consistency can be expensive. Possible solution: Reactor/SSX*

Events. Dispatching • Two phases of event delivering: – “Sinking” – from parent to

Events. Dispatching • Two phases of event delivering: – “Sinking” – from parent to child – “Bubbling” – from child to parent • Events can be “consumed” in any phase – return true; from an event handler; • Container can: – intercept events of children – postprocess events of children

DOM. Behavior • Behavior is a named event handler attached to DOM element. –

DOM. Behavior • Behavior is a named event handler attached to DOM element. – Can be native – Or in script as a class • Native behaviors attachment is defined by CSS property “behavior”: toolbar > button { behavior: clickable; } • The behavior CSS property assigns native event handlers that are declared in engine core or in code of host application. • Close analogy: HWND == HELEMENT, behavior == Win. Proc + struct • Supports concept of value: element. value = 2;

DOM. Native behavior • Attached to an element. Responsible for event handling, value, can

DOM. Native behavior • Attached to an element. Responsible for event handling, value, can perform custom drawing and provide “methods” for script: struct ctl: event_handler { virtual bool on(view &v, virtual bool on(view &v, element element *self, *self, event_mouse &evt); event_key &evt); event_focus &evt); event_command &evt); event_scroll &evt); event_behavior &evt); event_exchange &evt); event_gesture &evt); virtual bool set_value(view &v, element *self, const value &val); virtual bool get_value(view &v, element *self, value &val); virtual bool draw_foreground(view &v, element *self, graphics *sf, point pos); draw_background(view &v, element *self, graphics *sf, point pos); draw_content(view &v, element *self, graphics *sf, point pos); draw_outline(view &v, element *self, graphics *sf, point pos); virtual bool on_x_method_call(view &v, element *self, const char *name, const value *argv, size_t argc, value &retval); };

DOM. Built-in behaviors Basic buttons Edits clickable button checkbox radio & switch edit password

DOM. Built-in behaviors Basic buttons Edits clickable button checkbox radio & switch edit password masked-edit numeric integer decimal textarea richtext Selects dropdown-select dropdown-multi-select-multiple select-checkmarks tree-view tree-checkmarks Date/time calendar date time Output/indicators output • text • integer • decimal • currency • date-local • time-local progress scrollbar slider image shellicon filethumbnail style-bag HTML behaviors Auxiliary frame history frame-set form hyperlink htmlarea expandable-list collapsible-list swipe marquee column-resizer Menu menu-bar menu popup-selector

Scripting behaviors & event handlers • Classes: CSS (declarative) assignment: class My. Button :

Scripting behaviors & event handlers • Classes: CSS (declarative) assignment: class My. Button : Element { event click(event) { … } event keyup(event) { … } } • Aspects: function My. Button() { this << event click { … }; } • Explicit event handlers: var some. El = …; some. El << event click { … }; span. my-button { prototype: My. Button url(buttons. tis); } span. my-button { aspect: My. Button url(buttons. tis); }

Sciter Script: TIScript • Mostly Java. Script and has: – Compiler, producing bytecodes. –

Sciter Script: TIScript • Mostly Java. Script and has: – Compiler, producing bytecodes. – Virtual machine executing those bytecodes – Heap manager that uses compacting copying GC. • Extended by: – Classes, namespaces, decorators, persistent storage, streams and “UI types”. • Integrated with DOM, GC.

Sciter script: data types • • • Numeric: integer, float Collections: array, map (object)

Sciter script: data types • • • Numeric: integer, float Collections: array, map (object) String and Symbol Boolean: true and false Tuple (tagged array) Stream (file, in-memory string buffer) Bytes – vector of bytes. Persistent data: Storage and Index Length: 1 dip, 2 px, 1 em (CSS support type) Angle: 1 grad, 3 rad, 1 turn (CSS support type) Duration: 1 s, 400 ms (CSS support type)

Script: namespaces • Namespaces are declared by using the namespace keyword. They can contain

Script: namespaces • Namespaces are declared by using the namespace keyword. They can contain classes, functions, variables, and constants: namespace Threats { var threat. List = []; function add(threat) { threat. List. push(threat); } } Threats. add(found. Threat); // calling function in namespace Message { // enum like namespace const WARNING = 1; const ERROR = 2; const CRITICAL_ERROR = 3; } var msg. Type = Message. ERROR;

Script: Classes, constructors, and properties

Script: Classes, constructors, and properties

namespace tis { class VM { value array<value> value* Script VM val; stack; sp;

namespace tis { class VM { value array<value> value* Script VM val; stack; sp; // current value register // execution stack // stack top pointer // script heap, two "halves" Cs. Memory. Space *old. Space; // old memory space Cs. Memory. Space *new. Space; // new memory space value* value value. . . }; } bytecodes; pc; ns; method. Object; vector. Object; string. Object; integer. Object; // // // bytecodes of current function // current bytecode position // namespace of current function obj obj for for the the Method type Vector type String type Integer type

Script VM: value namespace tis { typedef uint 64 value; } • tis: :

Script VM: value namespace tis { typedef uint 64 value; } • tis: : value can store inplace: – float number ( a. k. a. cpp: : double – 64 bit ); – integer number – 32 bit signed integer; – symbols including true|false|undefined|null; • reference types (as 32 bit or 48 bit pointer): – Objects, classes and namespaces; – Arrays; – Strings;

Script VM: value packaging • IEEE 754 double-precision floating-point number. double type is 64

Script VM: value packaging • IEEE 754 double-precision floating-point number. double type is 64 -bit, comprised of 1 sign bit, 11 exponent bits and 52 mantissa bits: 7 6 5 4 3 2 1 0 seeeeeee | eeeemmmm | mmmmmmmm | mmmmmmmm • “Not-a-number” double value is when exponent is 111111. So all other values are: 7 6 5 4 3 2 1 0 1111 | 1111 tttt | vvvvvvvv | vvvvvvvv Na. N marker |type | 48 -bit placeholder for values: pointers, strings

Script VM. Object struct object { value prototype; // a. k. a. class value

Script VM. Object struct object { value prototype; // a. k. a. class value properties; // list of properties or hash map int property. Count; value observer; // list of observers unsigned flags; }; Calling object methods: obj. zap(); // found locally, // this === obj. clear(); // found in prototype chain // this === obj

Script VM: bytecodes • Bytecode: value in range 0. . 255 • Instruction for

Script VM: bytecodes • Bytecode: value in range 0. . 255 • Instruction for VM - similar to code instruction fro i 386 processor “machine”. #define #define #define #define BC_NOP 0 x 00 BC_BRT 0 x 01 BC_BRF 0 x 02 BC_BR 0 x 03 BC_T 0 x 04 BC_NULL 0 x 05 BC_PUSH 0 x 06 BC_NOT 0 x 07 BC_ADD 0 x 08 BC_SUB 0 x 09 BC_MUL 0 x 0 a BC_DIV 0 x 0 b BC_REM 0 x 0 c BC_BAND 0 x 0 d. . . /* /* /* /* NOP */ branch on true */ branch on false */ branch unconditionally */ load val with true */ load val with null */ push val onto stack */ logical negate top of stack */ add two numeric expressions */ subtract two numeric expressions */ multiply two numeric expressions */ divide two numeric expressions */ remainder of two numeric expressions */ bitwise and of top two stack entries */

Script compiler • Translates sequence of tokens into sequence of bytecodes: var a =

Script compiler • Translates sequence of tokens into sequence of bytecodes: var a = 1 + 2; BC_LITERAL 1 BC_PUSH BC_LITERAL 2 BC_ADD BC_STORE A // // // vm. val <- integer(1) vm. stack. push(vm. val) vm. val <- integer(2) vm. val <- vm. stack. pop() + vm. val heap_variable('A') <- vm. val • Bytecodes are stored in function objects: struct method : public object /* method is an Object! */ { value code; // bytecodes value ns; // namespace };

Script VM: execution • To run a function: a) setup VM by function bytecodes

Script VM: execution • To run a function: a) setup VM by function bytecodes and b) execute them: bool Exec: : run(VM *c, …) /* Execute - execute bytecodes */ { while (c->pc < c->bytecodes. end()) { switch (*c->pc++) { case BC_NOP: break; case BC_RETURN: if (last) return true; break; case BC_BRT: . . . ; break; case BC_BRF: . . . ; break; case BC_BR: . . . ; break; case BC_NULL: c->val = NULL_VALUE; break; case BC_PUSH: Cs. Push(c, c->val); break; case BC_NOT: c->val = Cs. To. Boolean(c, c->val) ? FALSE_VALUE : TRUE_VALUE; break; case BC_ADD: c->val = Binary. Op(c, BC_ADD, Cs. Pop(c), c->val); break; . . . } } }

Script VM: heap and GC Copying GC: • Contains two equal “halves”; • On

Script VM: heap and GC Copying GC: • Contains two equal “halves”; • On heap overflow copies content of one half into another; • Compacts memory while copying.

Window/View • Wraps HWINDOW – platform specific window; • Holds root document; • Holds

Window/View • Wraps HWINDOW – platform specific window; • Holds root document; • Holds reference to VM that is shared among all windows in the thread class view : public virtual resource, public iwindow, public event_handler, public pump { virtual HWINDOW get_hwnd() = 0; virtual graphics* surface() = 0; } // HWND, NSWindow, Gtk. Window // provides surface graphics handle<document> pdoc; // root document array<posted_event> array<handle<functor>> array<timer_def> posted_events; // element. post. Event(. . . ) posted_functors; // element. post( function(){. . . }) element_timers; array<handle<iwindow>> windows; // popup, tool and child windows // scripting handle<tis: : vm> tis: : value vm; view_obj; // holds script VM // 'view' object in script

Graphics • Supported backends: – Windows: • • Direct 2 D with GDI+ fallback

Graphics • Supported backends: – Windows: • • Direct 2 D with GDI+ fallback (Windows XP) Direct 2 D with Skia/CPU fallback * Skia/Open. GL with Skia/CPU fallback Direct 2 D backends: – – Direct 2 D/Warp (on Windows 7) Direct 2 D/HW (on W 8 and above and on high-DPI) Direct. Composition Direct. X surfaces – Mac. OS • Core. Graphics • Skia/Open. GL with Skia/CPU fallback * – Linux • GTK/Cairo * • Skia/Open. GL with Skia/CPU fallback

“Acrylic” Windows • Direct. Composition windows – rendered directly on desktop • WS_EX_NOREDIRECTIONBITMAP style

“Acrylic” Windows • Direct. Composition windows – rendered directly on desktop • WS_EX_NOREDIRECTIONBITMAP style • Alternative to WS_EX_LAYERED (but not exact)

The end • Questions?

The end • Questions?