@gjsify/dom-elements 0.3.21 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/_virtual/_rolldown/runtime.js +1 -1
- package/lib/esm/attr.js +1 -1
- package/lib/esm/character-data.js +1 -1
- package/lib/esm/comment.js +1 -1
- package/lib/esm/document-fragment.js +1 -1
- package/lib/esm/document.js +1 -1
- package/lib/esm/dom-matrix.js +1 -1
- package/lib/esm/dom-token-list.js +1 -1
- package/lib/esm/element.js +1 -1
- package/lib/esm/font-face.js +1 -1
- package/lib/esm/gst-time.js +1 -1
- package/lib/esm/html-canvas-element.js +1 -1
- package/lib/esm/html-element.js +1 -1
- package/lib/esm/html-image-element.js +1 -1
- package/lib/esm/html-media-element.js +1 -1
- package/lib/esm/html-video-element.js +1 -1
- package/lib/esm/image.js +1 -1
- package/lib/esm/intersection-observer.js +1 -1
- package/lib/esm/location-stub.js +1 -1
- package/lib/esm/match-media.js +1 -1
- package/lib/esm/mutation-observer.js +1 -1
- package/lib/esm/named-node-map.js +1 -1
- package/lib/esm/node-list.js +1 -1
- package/lib/esm/node.js +1 -1
- package/lib/esm/register/canvas.js +1 -1
- package/lib/esm/register/document.js +1 -1
- package/lib/esm/register/helpers.js +1 -1
- package/lib/esm/resize-observer.js +1 -1
- package/lib/esm/text.js +1 -1
- package/lib/types/location-stub.d.ts +1 -1
- package/package.json +78 -75
- package/src/attr.ts +0 -61
- package/src/character-data.ts +0 -79
- package/src/comment.ts +0 -31
- package/src/document-fragment.ts +0 -137
- package/src/document.ts +0 -103
- package/src/dom-matrix.ts +0 -109
- package/src/dom-token-list.ts +0 -140
- package/src/element.ts +0 -316
- package/src/font-face.ts +0 -97
- package/src/gst-time.ts +0 -26
- package/src/html-canvas-element.ts +0 -90
- package/src/html-element.ts +0 -502
- package/src/html-image-element.spec.ts +0 -285
- package/src/html-image-element.ts +0 -295
- package/src/html-media-element.ts +0 -123
- package/src/html-video-element.ts +0 -143
- package/src/image.ts +0 -31
- package/src/index.spec.ts +0 -914
- package/src/index.ts +0 -39
- package/src/intersection-observer.ts +0 -42
- package/src/location-stub.ts +0 -20
- package/src/match-media.ts +0 -32
- package/src/mutation-observer.ts +0 -39
- package/src/named-node-map.ts +0 -159
- package/src/namespace-uri.ts +0 -11
- package/src/node-list.ts +0 -52
- package/src/node-type.ts +0 -14
- package/src/node.ts +0 -280
- package/src/property-symbol.ts +0 -23
- package/src/register/canvas.ts +0 -23
- package/src/register/document.ts +0 -64
- package/src/register/font-face.ts +0 -18
- package/src/register/helpers.ts +0 -15
- package/src/register/image.ts +0 -8
- package/src/register/location.ts +0 -6
- package/src/register/match-media.ts +0 -6
- package/src/register/navigator.ts +0 -6
- package/src/register/observers.ts +0 -10
- package/src/register.spec.ts +0 -136
- package/src/register.ts +0 -13
- package/src/resize-observer.ts +0 -28
- package/src/stubs.spec.ts +0 -284
- package/src/test.browser.mts +0 -686
- package/src/test.mts +0 -9
- package/src/text.ts +0 -67
- package/src/types/i-html-image-element.ts +0 -44
- package/src/types/image-data.ts +0 -12
- package/src/types/index.ts +0 -3
- package/src/types/predefined-color-space.ts +0 -1
- package/tsconfig.json +0 -37
- package/tsconfig.tsbuildinfo +0 -1
package/src/element.ts
DELETED
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
// Adapted from happy-dom (refs/happy-dom/packages/happy-dom/src/nodes/element/Element.ts)
|
|
2
|
-
// Copyright (c) David Ortner (capricorn86). MIT license.
|
|
3
|
-
// Modifications: Simplified for gjsify — no innerHTML/outerHTML, no querySelector/CSS selectors,
|
|
4
|
-
// no Shadow DOM, no classList/DOMTokenList, no computed styles
|
|
5
|
-
|
|
6
|
-
import { Event } from '@gjsify/dom-events';
|
|
7
|
-
|
|
8
|
-
import { Node } from './node.js';
|
|
9
|
-
import { NodeType } from './node-type.js';
|
|
10
|
-
import { NamedNodeMap } from './named-node-map.js';
|
|
11
|
-
import { NamespaceURI } from './namespace-uri.js';
|
|
12
|
-
import * as PS from './property-symbol.js';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* DOM Element class.
|
|
16
|
-
*
|
|
17
|
-
* Reference: https://developer.mozilla.org/en-US/docs/Web/API/Element
|
|
18
|
-
*/
|
|
19
|
-
export class Element extends Node {
|
|
20
|
-
public [PS.tagName]: string = '';
|
|
21
|
-
public [PS.localName]: string = '';
|
|
22
|
-
public [PS.namespaceURI]: string | null = NamespaceURI.html;
|
|
23
|
-
public [PS.prefix]: string | null = null;
|
|
24
|
-
public [PS.attributes]: NamedNodeMap = new NamedNodeMap(this);
|
|
25
|
-
public [PS.propertyEventListeners]: Map<string, ((event: Event) => void) | null> = new Map();
|
|
26
|
-
|
|
27
|
-
constructor() {
|
|
28
|
-
super();
|
|
29
|
-
this[PS.nodeType] = NodeType.ELEMENT_NODE;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
get tagName(): string {
|
|
33
|
-
return this[PS.tagName];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
get localName(): string {
|
|
37
|
-
return this[PS.localName];
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
get namespaceURI(): string | null {
|
|
41
|
-
return this[PS.namespaceURI];
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
get prefix(): string | null {
|
|
45
|
-
return this[PS.prefix];
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
get nodeName(): string {
|
|
49
|
-
return this[PS.tagName];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
get attributes(): NamedNodeMap {
|
|
53
|
-
return this[PS.attributes];
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
get id(): string {
|
|
57
|
-
return this.getAttribute('id') ?? '';
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
set id(value: string) {
|
|
61
|
-
this.setAttribute('id', value);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
get className(): string {
|
|
65
|
-
return this.getAttribute('class') ?? '';
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
set className(value: string) {
|
|
69
|
-
this.setAttribute('class', value);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
get children(): Element[] {
|
|
73
|
-
return this[PS.elementChildren] as Element[];
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
get childElementCount(): number {
|
|
77
|
-
return this[PS.elementChildren].length;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
get firstElementChild(): Element | null {
|
|
81
|
-
return (this[PS.elementChildren][0] as Element) ?? null;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
get lastElementChild(): Element | null {
|
|
85
|
-
const children = this[PS.elementChildren];
|
|
86
|
-
return (children[children.length - 1] as Element) ?? null;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
get previousElementSibling(): Element | null {
|
|
90
|
-
const parent = this[PS.parentNode];
|
|
91
|
-
if (!parent) return null;
|
|
92
|
-
const siblings = parent[PS.elementChildren];
|
|
93
|
-
const idx = siblings.indexOf(this);
|
|
94
|
-
return idx > 0 ? (siblings[idx - 1] as Element) : null;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
get nextElementSibling(): Element | null {
|
|
98
|
-
const parent = this[PS.parentNode];
|
|
99
|
-
if (!parent) return null;
|
|
100
|
-
const siblings = parent[PS.elementChildren];
|
|
101
|
-
const idx = siblings.indexOf(this);
|
|
102
|
-
return idx !== -1 && idx < siblings.length - 1 ? (siblings[idx + 1] as Element) : null;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
get textContent(): string {
|
|
106
|
-
let text = '';
|
|
107
|
-
for (const child of this[PS.childNodesList]) {
|
|
108
|
-
if (child.textContent !== null) {
|
|
109
|
-
text += child.textContent;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return text;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
set textContent(_value: string | null) {
|
|
116
|
-
// Remove all children
|
|
117
|
-
const children = this[PS.childNodesList];
|
|
118
|
-
while (children.length > 0) {
|
|
119
|
-
this.removeChild(children[0]);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// -- Attribute methods --
|
|
124
|
-
|
|
125
|
-
getAttribute(qualifiedName: string): string | null {
|
|
126
|
-
const attr = this[PS.attributes].getNamedItem(qualifiedName);
|
|
127
|
-
return attr ? attr.value : null;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
getAttributeNS(namespace: string | null, localName: string): string | null {
|
|
131
|
-
const attr = this[PS.attributes].getNamedItemNS(namespace, localName);
|
|
132
|
-
return attr ? attr.value : null;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
setAttribute(qualifiedName: string, value: string): void {
|
|
136
|
-
this[PS.attributes]._setNamedItem(qualifiedName, String(value));
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
setAttributeNS(namespace: string | null, qualifiedName: string, value: string): void {
|
|
140
|
-
const ns = namespace === '' ? null : namespace;
|
|
141
|
-
const parts = qualifiedName.split(':');
|
|
142
|
-
const prefix = parts.length > 1 ? parts[0] : null;
|
|
143
|
-
this[PS.attributes]._setNamedItem(qualifiedName, String(value), ns, prefix);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
removeAttribute(qualifiedName: string): void {
|
|
147
|
-
this[PS.attributes]._removeNamedItem(qualifiedName);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
removeAttributeNS(namespace: string | null, localName: string): void {
|
|
151
|
-
const ns = namespace === '' ? null : namespace;
|
|
152
|
-
this[PS.attributes]._removeNamedItemNS(ns, localName);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
hasAttribute(qualifiedName: string): boolean {
|
|
156
|
-
return this[PS.attributes].getNamedItem(qualifiedName) !== null;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
hasAttributeNS(namespace: string | null, localName: string): boolean {
|
|
160
|
-
return this[PS.attributes].getNamedItemNS(namespace, localName) !== null;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
getAttributeNode(qualifiedName: string): unknown {
|
|
164
|
-
return this[PS.attributes].getNamedItem(qualifiedName);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
setAttributeNode(attr: unknown): unknown {
|
|
168
|
-
return this[PS.attributes].setNamedItem(attr as any);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
removeAttributeNode(attr: unknown): unknown {
|
|
172
|
-
const existing = this[PS.attributes].getNamedItem((attr as any).name);
|
|
173
|
-
if (!existing) {
|
|
174
|
-
throw new DOMException(
|
|
175
|
-
"Failed to execute 'removeAttributeNode' on 'Element': The attribute is not owned by this element.",
|
|
176
|
-
'NotFoundError',
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
this[PS.attributes].removeNamedItem(existing.name);
|
|
180
|
-
return existing;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
toggleAttribute(qualifiedName: string, force?: boolean): boolean {
|
|
184
|
-
if (force !== undefined) {
|
|
185
|
-
if (force) {
|
|
186
|
-
this.setAttribute(qualifiedName, '');
|
|
187
|
-
return true;
|
|
188
|
-
}
|
|
189
|
-
this.removeAttribute(qualifiedName);
|
|
190
|
-
return false;
|
|
191
|
-
}
|
|
192
|
-
if (this.hasAttribute(qualifiedName)) {
|
|
193
|
-
this.removeAttribute(qualifiedName);
|
|
194
|
-
return false;
|
|
195
|
-
}
|
|
196
|
-
this.setAttribute(qualifiedName, '');
|
|
197
|
-
return true;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
hasAttributes(): boolean {
|
|
201
|
-
return this[PS.attributes].length > 0;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// -- Override dispatchEvent to call on* property handlers --
|
|
205
|
-
|
|
206
|
-
dispatchEvent(event: Event): boolean {
|
|
207
|
-
const result = super.dispatchEvent(event);
|
|
208
|
-
|
|
209
|
-
// Call on<type> property handler if registered
|
|
210
|
-
const handler = this[PS.propertyEventListeners].get('on' + event.type);
|
|
211
|
-
if (typeof handler === 'function') {
|
|
212
|
-
handler.call(this, event);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
return result;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// -- Stubs for commonly expected methods --
|
|
219
|
-
|
|
220
|
-
querySelector(_selectors: string): Element | null {
|
|
221
|
-
return null;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
querySelectorAll(_selectors: string): Element[] {
|
|
225
|
-
return [];
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
matches(_selectors: string): boolean {
|
|
229
|
-
return false;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
closest(_selectors: string): Element | null {
|
|
233
|
-
return null;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
getElementsByTagName(tagName: string): Element[] {
|
|
237
|
-
const results: Element[] = [];
|
|
238
|
-
const upperTag = tagName.toUpperCase();
|
|
239
|
-
const walk = (node: Node): void => {
|
|
240
|
-
for (const child of node[PS.childNodesList]) {
|
|
241
|
-
if (child[PS.nodeType] === NodeType.ELEMENT_NODE) {
|
|
242
|
-
const el = child as Element;
|
|
243
|
-
if (tagName === '*' || el[PS.tagName] === upperTag) {
|
|
244
|
-
results.push(el);
|
|
245
|
-
}
|
|
246
|
-
walk(el);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
};
|
|
250
|
-
walk(this);
|
|
251
|
-
return results;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
getElementsByClassName(className: string): Element[] {
|
|
255
|
-
const results: Element[] = [];
|
|
256
|
-
const targetClasses = className.split(/\s+/).filter(Boolean);
|
|
257
|
-
const walk = (node: Node): void => {
|
|
258
|
-
for (const child of node[PS.childNodesList]) {
|
|
259
|
-
if (child[PS.nodeType] === NodeType.ELEMENT_NODE) {
|
|
260
|
-
const el = child as Element;
|
|
261
|
-
const elClasses = el.className.split(/\s+/);
|
|
262
|
-
if (targetClasses.every(c => elClasses.includes(c))) {
|
|
263
|
-
results.push(el);
|
|
264
|
-
}
|
|
265
|
-
walk(el);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
walk(this);
|
|
270
|
-
return results;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// -- Clone --
|
|
274
|
-
|
|
275
|
-
cloneNode(deep = false): Element {
|
|
276
|
-
const clone = super.cloneNode(false) as Element;
|
|
277
|
-
clone[PS.tagName] = this[PS.tagName];
|
|
278
|
-
clone[PS.localName] = this[PS.localName];
|
|
279
|
-
clone[PS.namespaceURI] = this[PS.namespaceURI];
|
|
280
|
-
clone[PS.prefix] = this[PS.prefix];
|
|
281
|
-
|
|
282
|
-
// Clone attributes
|
|
283
|
-
for (const attr of this[PS.attributes]) {
|
|
284
|
-
clone.setAttributeNS(attr.namespaceURI, attr.name, attr.value);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
if (deep) {
|
|
288
|
-
for (const child of this[PS.childNodesList]) {
|
|
289
|
-
clone.appendChild(child.cloneNode(true));
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
return clone;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// -- Pointer capture (no-op stubs, GTK tracks pointer implicitly) --
|
|
297
|
-
// Reference: refs/happy-dom/packages/happy-dom/src/nodes/element/Element.ts
|
|
298
|
-
|
|
299
|
-
private _pointerCaptures = new Set<number>();
|
|
300
|
-
|
|
301
|
-
setPointerCapture(pointerId: number): void {
|
|
302
|
-
this._pointerCaptures.add(pointerId);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
releasePointerCapture(pointerId: number): void {
|
|
306
|
-
this._pointerCaptures.delete(pointerId);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
hasPointerCapture(pointerId: number): boolean {
|
|
310
|
-
return this._pointerCaptures.has(pointerId);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
get [Symbol.toStringTag](): string {
|
|
314
|
-
return 'Element';
|
|
315
|
-
}
|
|
316
|
-
}
|
package/src/font-face.ts
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
// FontFace implementation for GJS — registers custom TTF fonts in PangoCairo
|
|
2
|
-
// so that Canvas2D fillText uses the correct font family.
|
|
3
|
-
//
|
|
4
|
-
// Flow (Excalibur): XHR(blob) → /tmp/gjsify-blob-N.ttf → createObjectURL →
|
|
5
|
-
// new FontFace(family, 'url(file:///tmp/gjsify-blob-N.ttf)') → face.load()
|
|
6
|
-
// The file is already on disk when load() is called; we just tell PangoCairo
|
|
7
|
-
// about it via font_map_get_default().add_font_file(path).
|
|
8
|
-
//
|
|
9
|
-
// Node.js: dynamic gi:// import fails gracefully → status='loaded' still set.
|
|
10
|
-
// Reference: https://developer.mozilla.org/en-US/docs/Web/API/FontFace
|
|
11
|
-
|
|
12
|
-
export class FontFace {
|
|
13
|
-
readonly family: string;
|
|
14
|
-
readonly source: string;
|
|
15
|
-
status: 'unloaded' | 'loading' | 'loaded' | 'error' = 'unloaded';
|
|
16
|
-
loaded: Promise<FontFace>;
|
|
17
|
-
display = 'auto';
|
|
18
|
-
style = 'normal';
|
|
19
|
-
weight = 'normal';
|
|
20
|
-
stretch = 'normal';
|
|
21
|
-
unicodeRange = 'U+0-10FFFF';
|
|
22
|
-
variant = 'normal';
|
|
23
|
-
featureSettings = 'normal';
|
|
24
|
-
|
|
25
|
-
constructor(family: string, source: string | ArrayBuffer | ArrayBufferView, _descriptors?: Record<string, string>) {
|
|
26
|
-
this.family = family;
|
|
27
|
-
this.source = typeof source === 'string' ? source : '[binary]';
|
|
28
|
-
this.loaded = Promise.resolve(this);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Parses: url(file:///path), url("file:///path"), url('file:///path')
|
|
32
|
-
private _extractFilePath(): string | null {
|
|
33
|
-
const m = this.source.match(/url\s*\(\s*["']?(file:\/\/\/[^"')]+)["']?\s*\)/i);
|
|
34
|
-
if (!m) return null;
|
|
35
|
-
// Strip file:// prefix → /path/to/file.ttf
|
|
36
|
-
return m[1].replace(/^file:\/\//, '');
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async load(): Promise<FontFace> {
|
|
40
|
-
this.status = 'loading';
|
|
41
|
-
const filePath = this._extractFilePath();
|
|
42
|
-
if (filePath) {
|
|
43
|
-
try {
|
|
44
|
-
// gi:// only available in GJS — fails gracefully on Node.js
|
|
45
|
-
// @ts-ignore
|
|
46
|
-
const { default: PangoCairo } = await import('gi://PangoCairo?version=1.0');
|
|
47
|
-
PangoCairo.font_map_get_default().add_font_file(filePath);
|
|
48
|
-
} catch {
|
|
49
|
-
// Not in GJS, or font file not found — fall through to loaded
|
|
50
|
-
// Canvas fillText will use system font fallback (acceptable)
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
this.status = 'loaded';
|
|
54
|
-
return this;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* FontFaceSet — tracks loaded FontFace objects and exposes them to consumers.
|
|
60
|
-
*
|
|
61
|
-
* Intentionally does NOT extend EventTarget. The dom-elements /register module
|
|
62
|
-
* runs before dom-events/register in the inject order, so EventTarget may not
|
|
63
|
-
* yet exist when this class is defined at module load time. All event methods
|
|
64
|
-
* are provided as no-ops; consumers that call addEventListener('loadingdone')
|
|
65
|
-
* etc. will silently receive nothing.
|
|
66
|
-
*/
|
|
67
|
-
export class FontFaceSet {
|
|
68
|
-
status: 'loading' | 'loaded' = 'loaded';
|
|
69
|
-
ready: Promise<FontFaceSet> = Promise.resolve(this);
|
|
70
|
-
|
|
71
|
-
private _faces = new Set<FontFace>();
|
|
72
|
-
|
|
73
|
-
addEventListener(_type: string, _listener: unknown): void {}
|
|
74
|
-
removeEventListener(_type: string, _listener: unknown): void {}
|
|
75
|
-
dispatchEvent(_event: unknown): boolean { return true; }
|
|
76
|
-
|
|
77
|
-
add(face: FontFace): FontFaceSet {
|
|
78
|
-
this._faces.add(face);
|
|
79
|
-
return this;
|
|
80
|
-
}
|
|
81
|
-
delete(face: FontFace): boolean { return this._faces.delete(face); }
|
|
82
|
-
clear(): void { this._faces.clear(); }
|
|
83
|
-
has(face: FontFace): boolean { return this._faces.has(face); }
|
|
84
|
-
check(_font: string, _text?: string): boolean { return false; }
|
|
85
|
-
load(_font: string, _text?: string): Promise<FontFace[]> { return Promise.resolve([]); }
|
|
86
|
-
forEach(callback: (value: FontFace, key: FontFace, parent: FontFaceSet) => void): void {
|
|
87
|
-
this._faces.forEach(f => callback(f, f, this));
|
|
88
|
-
}
|
|
89
|
-
values(): IterableIterator<FontFace> { return this._faces.values(); }
|
|
90
|
-
keys(): IterableIterator<FontFace> { return this._faces.values(); }
|
|
91
|
-
entries(): IterableIterator<[FontFace, FontFace]> {
|
|
92
|
-
const faces = Array.from(this._faces);
|
|
93
|
-
return faces.map(f => [f, f] as [FontFace, FontFace])[Symbol.iterator]() as IterableIterator<[FontFace, FontFace]>;
|
|
94
|
-
}
|
|
95
|
-
[Symbol.iterator](): Iterator<FontFace> { return this._faces[Symbol.iterator](); }
|
|
96
|
-
get size(): number { return this._faces.size; }
|
|
97
|
-
}
|
package/src/gst-time.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
// Conversions between seconds (Web video API) and GStreamer's nanosecond
|
|
2
|
-
// `BigInt` timebase (used by `Gst.Format.TIME` throughout GStreamer). Lives
|
|
3
|
-
// in @gjsify/dom-elements so HTMLVideoElement/HTMLAudioElement can use it
|
|
4
|
-
// directly; @gjsify/video re-exports these for consumers of the bridge
|
|
5
|
-
// package. Kept as pure number math — no runtime Gst import required.
|
|
6
|
-
|
|
7
|
-
const NS_PER_SECOND = 1_000_000_000;
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Convert seconds (number) to GStreamer nanoseconds (bigint).
|
|
11
|
-
* Rounds to the nearest nanosecond to avoid floating-point drift over
|
|
12
|
-
* repeated back-and-forth conversions.
|
|
13
|
-
*/
|
|
14
|
-
export function secondsToGstTime(seconds: number): bigint {
|
|
15
|
-
return BigInt(Math.round(seconds * NS_PER_SECOND));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Convert GStreamer nanoseconds to seconds (number).
|
|
20
|
-
* Accepts both `bigint` (the runtime type from GStreamer queries) and `number`
|
|
21
|
-
* (what the `@girs/gst-1.0` typings currently declare — a known GIR bug for
|
|
22
|
-
* `gint64` return values in `query_position` / `query_duration`).
|
|
23
|
-
*/
|
|
24
|
-
export function gstTimeToSeconds(nanoseconds: bigint | number): number {
|
|
25
|
-
return Number(nanoseconds) / NS_PER_SECOND;
|
|
26
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
// Adapted from happy-dom (refs/happy-dom/packages/happy-dom/src/nodes/html-canvas-element/HTMLCanvasElement.ts)
|
|
2
|
-
// Copyright (c) David Ortner (capricorn86). MIT license.
|
|
3
|
-
// Modifications: Simplified for gjsify — stubs only, no window reference, no MediaStream/OffscreenCanvas deps.
|
|
4
|
-
// getContext() overridden in @gjsify/webgl with GTK.GLArea-backed implementation.
|
|
5
|
-
|
|
6
|
-
import { HTMLElement } from './html-element.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* HTMLCanvasElement base class.
|
|
10
|
-
*
|
|
11
|
-
* This is a DOM-spec-compliant stub. The GTK-backed implementation lives in
|
|
12
|
-
* `@gjsify/webgl` and extends this class, overriding `getContext()`.
|
|
13
|
-
*
|
|
14
|
-
* Reference: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement
|
|
15
|
-
*/
|
|
16
|
-
export class HTMLCanvasElement extends HTMLElement {
|
|
17
|
-
// Context factory registry — packages register their context types here.
|
|
18
|
-
// e.g. @gjsify/canvas2d registers '2d', @gjsify/webgl registers 'webgl'.
|
|
19
|
-
private static _contextFactories = new Map<string, (canvas: HTMLCanvasElement, options?: any) => any>();
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Register a rendering context factory for a given context type.
|
|
23
|
-
* Called by packages like @gjsify/canvas2d and @gjsify/webgl to plug in their implementations.
|
|
24
|
-
*/
|
|
25
|
-
static registerContextFactory(contextId: string, factory: (canvas: HTMLCanvasElement, options?: any) => any): void {
|
|
26
|
-
HTMLCanvasElement._contextFactories.set(contextId, factory);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// WebGL context event handlers
|
|
30
|
-
oncontextlost: ((ev: Event) => any) | null = null;
|
|
31
|
-
oncontextrestored: ((ev: Event) => any) | null = null;
|
|
32
|
-
onwebglcontextcreationerror: ((ev: Event) => any) | null = null;
|
|
33
|
-
onwebglcontextlost: ((ev: Event) => any) | null = null;
|
|
34
|
-
onwebglcontextrestored: ((ev: Event) => any) | null = null;
|
|
35
|
-
|
|
36
|
-
/** Returns the width of the canvas element. Default: 300. */
|
|
37
|
-
get width(): number {
|
|
38
|
-
const w = this.getAttribute('width');
|
|
39
|
-
return w !== null ? Number(w) : 300;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
set width(value: number) {
|
|
43
|
-
this.setAttribute('width', String(value));
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** Returns the height of the canvas element. Default: 150. */
|
|
47
|
-
get height(): number {
|
|
48
|
-
const h = this.getAttribute('height');
|
|
49
|
-
return h !== null ? Number(h) : 150;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
set height(value: number) {
|
|
53
|
-
this.setAttribute('height', String(value));
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Returns a rendering context.
|
|
58
|
-
* Checks the static context factory registry for a matching factory.
|
|
59
|
-
* Subclasses (e.g. @gjsify/webgl) may override and fall through via super.getContext().
|
|
60
|
-
*/
|
|
61
|
-
getContext(contextId: string, options?: any): any {
|
|
62
|
-
const factory = HTMLCanvasElement._contextFactories.get(contextId);
|
|
63
|
-
if (factory) return factory(this, options);
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** Returns a data URL representing the canvas image. Delegates to the active 2D context if available. */
|
|
68
|
-
toDataURL(type?: string, quality?: any): string {
|
|
69
|
-
const ctx = this.getContext('2d') as any;
|
|
70
|
-
if (ctx && typeof ctx._toDataURL === 'function') return ctx._toDataURL(type, quality);
|
|
71
|
-
return '';
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/** Converts the canvas to a Blob and passes it to the callback. Delegates to the active 2D context if available. */
|
|
75
|
-
toBlob(callback: ((blob: Blob | null) => void), type?: string, quality?: any): void {
|
|
76
|
-
const dataUrl = this.toDataURL(type, quality);
|
|
77
|
-
if (!dataUrl) { callback(null); return; }
|
|
78
|
-
const [header, b64] = dataUrl.split(',');
|
|
79
|
-
const mime = header.split(':')[1].split(';')[0];
|
|
80
|
-
const bytes = atob(b64);
|
|
81
|
-
const arr = new Uint8Array(bytes.length);
|
|
82
|
-
for (let i = 0; i < bytes.length; i++) arr[i] = bytes.charCodeAt(i);
|
|
83
|
-
callback(new Blob([arr], { type: mime }));
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/** Returns a MediaStream capturing the canvas. Stub — returns empty object. */
|
|
87
|
-
captureStream(_frameRequestRate?: number): any {
|
|
88
|
-
return {};
|
|
89
|
-
}
|
|
90
|
-
}
|