5 /// { document: Document, tag_name: &'static str }
8 /// { document: Document, tag_name: &'static str }
11 /// { document: Document, data: &str }
14 /// { document: Document, data: &str }
17 #ifdef WITH_DOCUMENT_FRAGMENT
18 /// { document: Document }
19 CreateDocumentFragment = 4,
21 /// { node: CharacterData, data: &str }
23 /// { element: Element, name: &'static str, value: &str }
25 /// { element: Element, name: &'static str }
27 /// { parent: Element, new_child: Node }
29 /// { parent: Element, reference_child: Node, new_child: Node }
31 /// { reference: Node }
36 #ifdef WITH_REALLOCATOR
38 private nodes: (Node | u32)[];
39 # define PUSH_NODE push_node
41 private nodes: Node[];
42 # define PUSH_NODE nodes.push
44 private textDecoder: TextDecoder;
47 // FIXME: is 0 document or what? (Perhaps I should define a “document” opcode rather than prefilling it?)
48 #ifdef WITH_REALLOCATOR
52 this.textDecoder = new TextDecoder();
55 #ifdef WITH_REALLOCATOR
56 private push_node(node: Node) {
57 if (this.next_id === this.nodes.length) {
58 this.nodes.push(this.next_id + 1);
60 const id = this.next_id;
61 this.next_id = this.nodes[id] as u32;
62 this.nodes[id] = node;
66 execute(instructions: Uint8Array) {
67 const length = instructions.byteLength;
68 let offset: Offset = 0;
69 while (offset < length) {
70 // Variable-width instruction set. First byte is the opcode.
71 const opcode = instructions[offset++];
73 case Opcode.CreateElement:
75 case Opcode.CreateSvgElement:
78 const [document, offset1] = this.readNode(instructions, offset) as [Document, Offset];
79 const [tagName, offset2] = this.readString(
85 const element = (opcode == Opcode.CreateElement) ?
86 document.createElement(tagName) :
87 document.createElementNS('http://www.w3.org/2000/svg', tagName);
89 const element = document.createElement(tagName);
91 this.PUSH_NODE(element);
94 case Opcode.CreateTextNode: {
95 const [document, offset1] = this.readNode(instructions, offset) as [Document, Offset];
96 const [data, offset2] = this.readString(instructions, offset1);
98 this.PUSH_NODE(document.createTextNode(data));
102 case Opcode.CreateComment: {
103 const [document, offset1] = this.readNode(instructions, offset) as [Document, Offset];
104 const [data, offset2] = this.readString(instructions, offset1);
106 this.PUSH_NODE(document.createComment(data));
110 #ifdef WITH_DOCUMENT_FRAGMENT
111 case Opcode.CreateDocumentFragment: {
112 const [document, offset1] = this.readNode(instructions, offset) as [Document, Offset];
114 this.PUSH_NODE(document.createDocumentFragment());
118 case Opcode.SetData: {
119 const [characterData, offset1] = this.readNode(instructions, offset) as [CharacterData, Offset];
120 const [data, offset2] = this.readString(instructions, offset1);
122 characterData.data = data;
125 case Opcode.SetAttribute: {
126 const [element, offset1] = this.readNode(instructions, offset) as [Element, Offset];
127 const [name, offset2] = this.readString(instructions, offset1);
128 const [value, offset3] = this.readString(instructions, offset2);
130 element.setAttribute(name, value);
133 case Opcode.RemoveAttribute: {
134 const [element, offset1] = this.readNode(instructions, offset) as [Element, Offset];
135 const [attributeName, offset2] = this.readString(instructions, offset1);
137 element.removeAttribute(attributeName);
140 case Opcode.AppendChild: {
141 const [parentNode, offset1] = this.readNode(instructions, offset) as [Document, Offset];
142 const [newChild, offset2] = this.readNode(instructions, offset1);
144 parentNode.appendChild(newChild);
147 case Opcode.InsertBefore: {
148 const [parentNode, offset1] = this.readNode(instructions, offset) as [Document, Offset];
149 const [referenceChild, offset2] = this.readNode(instructions, offset1);
150 const [newChild, offset3] = this.readNode(instructions, offset2);
152 parentNode.insertBefore(newChild, referenceChild);
156 const [node, offset1] = this.readU32(instructions, offset);
158 #ifdef WITH_REALLOCATOR
159 this.nodes[node] = this.next_id;
162 delete this.nodes[node];
167 const error = new Error('Unknown opcode ');
168 error.name = 'VmError';
175 private readStringWithDictionary(instructions: Uint8Array, offset: Offset, dictionary: string[]): [string, Offset] {
176 const index = instructions[offset++];
178 return this.readString(instructions, offset);
180 return [dictionary[index], offset];
184 private readString(instructions: Uint8Array, offset: Offset): [string, Offset] {
185 const [length, offset1] = this.readU32(instructions, offset);
186 const string = this.textDecoder.decode(new Uint8Array(instructions.buffer, instructions.byteOffset + offset1, length));
187 return [string, offset1 + length];
190 private readU32(instructions: Uint8Array, offset: Offset): [u32, Offset] {
193 (instructions[offset++] << 24) |
194 (instructions[offset++] << 16) |
195 (instructions[offset++] << 8) |
196 (instructions[offset++] << 0)
202 private readNode(instructions: Uint8Array, offset: Offset): [Node, Offset] {
203 const [node, offset1] = this.readU32(instructions, offset);
204 return [this.nodes[node], offset1];