@gjsify/canvas2d-core 0.3.21 → 0.4.0
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 -0
- package/lib/esm/cairo-types.js +1 -0
- package/lib/esm/cairo-utils.js +1 -1
- package/lib/esm/canvas-gradient.js +1 -1
- package/lib/esm/canvas-path.js +1 -1
- package/lib/esm/canvas-pattern.js +1 -1
- package/lib/esm/canvas-rendering-context-2d.js +1 -1
- package/lib/esm/canvas-state.js +1 -1
- package/lib/esm/color.js +1 -1
- package/lib/esm/dom-types.js +1 -0
- package/lib/esm/image-data.js +1 -1
- package/lib/types/cairo-types.d.ts +20 -0
- package/lib/types/canvas-pattern.d.ts +1 -1
- package/lib/types/canvas-rendering-context-2d.d.ts +18 -6
- package/lib/types/dom-types.d.ts +88 -0
- package/package.json +10 -10
- package/src/cairo-types.ts +44 -0
- package/src/canvas-pattern.ts +20 -11
- package/src/canvas-rendering-context-2d.ts +79 -58
- package/src/dom-types.ts +96 -0
- package/tmp/.tsbuildinfo +1 -1
|
@@ -10,6 +10,14 @@ import PangoCairo from 'gi://PangoCairo';
|
|
|
10
10
|
// HTMLCanvasElement type is provided by the DOM lib.
|
|
11
11
|
// Our @gjsify/dom-elements HTMLCanvasElement satisfies this interface.
|
|
12
12
|
|
|
13
|
+
import { asCairoPattern } from './cairo-types.js';
|
|
14
|
+
import {
|
|
15
|
+
type CanvasLike,
|
|
16
|
+
type CanvasGlobalThis,
|
|
17
|
+
type DOMMatrix2DLike,
|
|
18
|
+
isPixbufImageSource,
|
|
19
|
+
isCanvasImageSource,
|
|
20
|
+
} from './dom-types.js';
|
|
13
21
|
import { parseColor } from './color.js';
|
|
14
22
|
import {
|
|
15
23
|
quadraticToCubic,
|
|
@@ -26,12 +34,24 @@ import { CanvasGradient as OurCanvasGradient } from './canvas-gradient.js';
|
|
|
26
34
|
import { CanvasPattern as OurCanvasPattern } from './canvas-pattern.js';
|
|
27
35
|
import { Path2D } from './canvas-path.js';
|
|
28
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Options bag passed through the `getContext('2d', options)` factory. Mirrors
|
|
39
|
+
* the WHATWG `CanvasRenderingContext2DSettings` dictionary; fields are
|
|
40
|
+
* accepted but not yet honored by this implementation.
|
|
41
|
+
*/
|
|
42
|
+
export interface CanvasRenderingContext2DInit {
|
|
43
|
+
alpha?: boolean;
|
|
44
|
+
desynchronized?: boolean;
|
|
45
|
+
colorSpace?: PredefinedColorSpace;
|
|
46
|
+
willReadFrequently?: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
29
49
|
/**
|
|
30
50
|
* CanvasRenderingContext2D backed by Cairo.ImageSurface.
|
|
31
51
|
* Implements the Canvas 2D API for GJS.
|
|
32
52
|
*/
|
|
33
53
|
export class CanvasRenderingContext2D {
|
|
34
|
-
readonly canvas:
|
|
54
|
+
readonly canvas: CanvasLike;
|
|
35
55
|
|
|
36
56
|
private _surface: Cairo.ImageSurface;
|
|
37
57
|
private _ctx: Cairo.Context;
|
|
@@ -40,7 +60,7 @@ export class CanvasRenderingContext2D {
|
|
|
40
60
|
private _surfaceWidth: number;
|
|
41
61
|
private _surfaceHeight: number;
|
|
42
62
|
|
|
43
|
-
constructor(canvas:
|
|
63
|
+
constructor(canvas: CanvasLike, _options?: CanvasRenderingContext2DInit) {
|
|
44
64
|
this.canvas = canvas;
|
|
45
65
|
this._surfaceWidth = canvas.width || 300;
|
|
46
66
|
this._surfaceHeight = canvas.height || 150;
|
|
@@ -115,18 +135,17 @@ export class CanvasRenderingContext2D {
|
|
|
115
135
|
* creation — so we re-apply it on every fill/stroke.
|
|
116
136
|
*/
|
|
117
137
|
private _applyPatternFilter(): void {
|
|
118
|
-
const pat = (this._ctx
|
|
119
|
-
if (pat
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
pat.setFilter(filter);
|
|
138
|
+
const pat = asCairoPattern(this._ctx.getSource?.());
|
|
139
|
+
if (!pat) return;
|
|
140
|
+
let filter: Cairo.Filter;
|
|
141
|
+
if (!this._state.imageSmoothingEnabled) {
|
|
142
|
+
filter = Cairo.Filter.NEAREST;
|
|
143
|
+
} else if (this._state.imageSmoothingQuality === 'high') {
|
|
144
|
+
filter = Cairo.Filter.BEST;
|
|
145
|
+
} else {
|
|
146
|
+
filter = Cairo.Filter.BILINEAR;
|
|
129
147
|
}
|
|
148
|
+
pat.setFilter(filter);
|
|
130
149
|
}
|
|
131
150
|
|
|
132
151
|
/** Apply line properties to the Cairo context. */
|
|
@@ -170,9 +189,9 @@ export class CanvasRenderingContext2D {
|
|
|
170
189
|
* regardless of any ctx.scale() or ctx.rotate() in effect.
|
|
171
190
|
*/
|
|
172
191
|
private _deviceToUserDistance(dx: number, dy: number): [number, number] {
|
|
173
|
-
const origin =
|
|
174
|
-
const xAxis =
|
|
175
|
-
const yAxis =
|
|
192
|
+
const origin = this._ctx.userToDevice(0, 0);
|
|
193
|
+
const xAxis = this._ctx.userToDevice(1, 0);
|
|
194
|
+
const yAxis = this._ctx.userToDevice(0, 1);
|
|
176
195
|
const a = (xAxis[0] ?? 0) - (origin[0] ?? 0);
|
|
177
196
|
const b = (xAxis[1] ?? 0) - (origin[1] ?? 0);
|
|
178
197
|
const c = (yAxis[0] ?? 0) - (origin[0] ?? 0);
|
|
@@ -304,9 +323,9 @@ export class CanvasRenderingContext2D {
|
|
|
304
323
|
// userToDevice(0, 0) = (e, f) — translation
|
|
305
324
|
// userToDevice(1, 0) = (a + e, b + f) — first basis vector
|
|
306
325
|
// userToDevice(0, 1) = (c + e, d + f) — second basis vector
|
|
307
|
-
const origin =
|
|
308
|
-
const xAxis =
|
|
309
|
-
const yAxis =
|
|
326
|
+
const origin = this._ctx.userToDevice(0, 0);
|
|
327
|
+
const xAxis = this._ctx.userToDevice(1, 0);
|
|
328
|
+
const yAxis = this._ctx.userToDevice(0, 1);
|
|
310
329
|
const e = origin[0] ?? 0;
|
|
311
330
|
const f = origin[1] ?? 0;
|
|
312
331
|
const a = (xAxis[0] ?? 0) - e;
|
|
@@ -314,11 +333,11 @@ export class CanvasRenderingContext2D {
|
|
|
314
333
|
const c = (yAxis[0] ?? 0) - e;
|
|
315
334
|
const d = (yAxis[1] ?? 0) - f;
|
|
316
335
|
|
|
317
|
-
const DOMMatrixCtor = (globalThis as
|
|
336
|
+
const DOMMatrixCtor = (globalThis as CanvasGlobalThis).DOMMatrix;
|
|
318
337
|
if (typeof DOMMatrixCtor === 'function') {
|
|
319
338
|
return new DOMMatrixCtor([a, b, c, d, e, f]);
|
|
320
339
|
}
|
|
321
|
-
|
|
340
|
+
const fallback: DOMMatrix2DLike = {
|
|
322
341
|
a, b, c, d, e, f,
|
|
323
342
|
m11: a, m12: b, m13: 0, m14: 0,
|
|
324
343
|
m21: c, m22: d, m23: 0, m24: 0,
|
|
@@ -326,7 +345,8 @@ export class CanvasRenderingContext2D {
|
|
|
326
345
|
m41: e, m42: f, m43: 0, m44: 1,
|
|
327
346
|
is2D: true,
|
|
328
347
|
isIdentity: (a === 1 && b === 0 && c === 0 && d === 1 && e === 0 && f === 0),
|
|
329
|
-
}
|
|
348
|
+
};
|
|
349
|
+
return fallback as unknown as DOMMatrix;
|
|
330
350
|
}
|
|
331
351
|
|
|
332
352
|
resetTransform(): void {
|
|
@@ -693,15 +713,15 @@ export class CanvasRenderingContext2D {
|
|
|
693
713
|
// ---- Gradient / Pattern factories ----
|
|
694
714
|
|
|
695
715
|
createLinearGradient(x0: number, y0: number, x1: number, y1: number): CanvasGradient {
|
|
696
|
-
return new OurCanvasGradient('linear', x0, y0, x1, y1) as
|
|
716
|
+
return new OurCanvasGradient('linear', x0, y0, x1, y1) as unknown as CanvasGradient;
|
|
697
717
|
}
|
|
698
718
|
|
|
699
719
|
createRadialGradient(x0: number, y0: number, r0: number, x1: number, y1: number, r1: number): CanvasGradient {
|
|
700
|
-
return new OurCanvasGradient('radial', x0, y0, x1, y1, r0, r1) as
|
|
720
|
+
return new OurCanvasGradient('radial', x0, y0, x1, y1, r0, r1) as unknown as CanvasGradient;
|
|
701
721
|
}
|
|
702
722
|
|
|
703
|
-
createPattern(image:
|
|
704
|
-
return OurCanvasPattern.create(image, repetition) as
|
|
723
|
+
createPattern(image: unknown, repetition: string | null): CanvasPattern | null {
|
|
724
|
+
return OurCanvasPattern.create(image, repetition) as unknown as CanvasPattern | null;
|
|
705
725
|
}
|
|
706
726
|
|
|
707
727
|
// ---- Image data methods ----
|
|
@@ -710,9 +730,9 @@ export class CanvasRenderingContext2D {
|
|
|
710
730
|
createImageData(imagedata: ImageData): ImageData;
|
|
711
731
|
createImageData(swOrImageData: number | ImageData, sh?: number): ImageData {
|
|
712
732
|
if (typeof swOrImageData === 'number') {
|
|
713
|
-
return new OurImageData(Math.abs(swOrImageData), Math.abs(sh!)) as
|
|
733
|
+
return new OurImageData(Math.abs(swOrImageData), Math.abs(sh!)) as unknown as ImageData;
|
|
714
734
|
}
|
|
715
|
-
return new OurImageData(swOrImageData.width, swOrImageData.height) as
|
|
735
|
+
return new OurImageData(swOrImageData.width, swOrImageData.height) as unknown as ImageData;
|
|
716
736
|
}
|
|
717
737
|
|
|
718
738
|
getImageData(sx: number, sy: number, sw: number, sh: number): ImageData {
|
|
@@ -722,7 +742,7 @@ export class CanvasRenderingContext2D {
|
|
|
722
742
|
// Use Gdk.pixbuf_get_from_surface to read pixels
|
|
723
743
|
const pixbuf = Gdk.pixbuf_get_from_surface(this._surface, sx, sy, sw, sh);
|
|
724
744
|
if (!pixbuf) {
|
|
725
|
-
return new OurImageData(sw, sh) as
|
|
745
|
+
return new OurImageData(sw, sh) as unknown as ImageData;
|
|
726
746
|
}
|
|
727
747
|
|
|
728
748
|
const pixels = pixbuf.get_pixels();
|
|
@@ -742,7 +762,7 @@ export class CanvasRenderingContext2D {
|
|
|
742
762
|
}
|
|
743
763
|
}
|
|
744
764
|
|
|
745
|
-
return new OurImageData(out, sw, sh) as
|
|
765
|
+
return new OurImageData(out, sw, sh) as unknown as ImageData;
|
|
746
766
|
}
|
|
747
767
|
|
|
748
768
|
putImageData(imageData: ImageData, dx: number, dy: number, dirtyX?: number, dirtyY?: number, dirtyWidth?: number, dirtyHeight?: number): void {
|
|
@@ -784,7 +804,7 @@ export class CanvasRenderingContext2D {
|
|
|
784
804
|
// putImageData per spec ignores compositing — always uses SOURCE operator
|
|
785
805
|
this._ctx.save();
|
|
786
806
|
this._ctx.setOperator(Cairo.Operator.SOURCE);
|
|
787
|
-
Gdk.cairo_set_source_pixbuf(this._ctx
|
|
807
|
+
Gdk.cairo_set_source_pixbuf(this._ctx, pixbuf, dx + sx, dy + sy);
|
|
788
808
|
this._ctx.rectangle(dx + sx, dy + sy, sw, sh);
|
|
789
809
|
this._ctx.fill();
|
|
790
810
|
this._ctx.restore();
|
|
@@ -792,11 +812,11 @@ export class CanvasRenderingContext2D {
|
|
|
792
812
|
|
|
793
813
|
// ---- drawImage ----
|
|
794
814
|
|
|
795
|
-
drawImage(image:
|
|
796
|
-
drawImage(image:
|
|
797
|
-
drawImage(image:
|
|
815
|
+
drawImage(image: unknown, dx: number, dy: number): void;
|
|
816
|
+
drawImage(image: unknown, dx: number, dy: number, dw: number, dh: number): void;
|
|
817
|
+
drawImage(image: unknown, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void;
|
|
798
818
|
drawImage(
|
|
799
|
-
image:
|
|
819
|
+
image: unknown,
|
|
800
820
|
a1: number, a2: number,
|
|
801
821
|
a3?: number, a4?: number,
|
|
802
822
|
a5?: number, a6?: number,
|
|
@@ -860,7 +880,7 @@ export class CanvasRenderingContext2D {
|
|
|
860
880
|
this._ctx.scale(dw / sw, dh / sh);
|
|
861
881
|
this._ctx.translate(-sx, -sy);
|
|
862
882
|
|
|
863
|
-
Gdk.cairo_set_source_pixbuf(this._ctx
|
|
883
|
+
Gdk.cairo_set_source_pixbuf(this._ctx, pixbuf, 0, 0);
|
|
864
884
|
|
|
865
885
|
// Apply Cairo interpolation filter based on imageSmoothingEnabled +
|
|
866
886
|
// imageSmoothingQuality. setSource installs a fresh SurfacePattern and
|
|
@@ -871,16 +891,17 @@ export class CanvasRenderingContext2D {
|
|
|
871
891
|
//
|
|
872
892
|
// Cairo.Filter values (verified runtime in GJS 1.86):
|
|
873
893
|
// FAST=0 GOOD=1 BEST=2 NEAREST=3 BILINEAR=4 GAUSSIAN=5
|
|
874
|
-
// GIR typings are
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
894
|
+
// GIR typings are missing setFilter on Pattern — `asCairoPattern`
|
|
895
|
+
// narrows to the augmented shape (see cairo-types.ts).
|
|
896
|
+
const pat = asCairoPattern(this._ctx.getSource?.());
|
|
897
|
+
if (pat) {
|
|
898
|
+
let filter: Cairo.Filter;
|
|
878
899
|
if (!this._state.imageSmoothingEnabled) {
|
|
879
|
-
filter = Cairo.Filter.NEAREST
|
|
900
|
+
filter = Cairo.Filter.NEAREST;
|
|
880
901
|
} else if (this._state.imageSmoothingQuality === 'high') {
|
|
881
|
-
filter = Cairo.Filter.BEST
|
|
902
|
+
filter = Cairo.Filter.BEST;
|
|
882
903
|
} else {
|
|
883
|
-
filter = Cairo.Filter.BILINEAR
|
|
904
|
+
filter = Cairo.Filter.BILINEAR;
|
|
884
905
|
}
|
|
885
906
|
pat.setFilter(filter);
|
|
886
907
|
}
|
|
@@ -891,24 +912,24 @@ export class CanvasRenderingContext2D {
|
|
|
891
912
|
// doesn't support per-draw alpha, so paint() is the spec-correct
|
|
892
913
|
// choice for drawImage. The clip above confines the paint to dx,dy,dw,dh.
|
|
893
914
|
if (this._state.globalAlpha < 1) {
|
|
894
|
-
|
|
915
|
+
this._ctx.paintWithAlpha(this._state.globalAlpha);
|
|
895
916
|
} else {
|
|
896
917
|
this._ctx.paint();
|
|
897
918
|
}
|
|
898
919
|
this._ctx.restore();
|
|
899
920
|
}
|
|
900
921
|
|
|
901
|
-
private _getDrawImageSource(image:
|
|
922
|
+
private _getDrawImageSource(image: unknown): { pixbuf: GdkPixbuf.Pixbuf; imgWidth: number; imgHeight: number } | null {
|
|
902
923
|
// HTMLImageElement (GdkPixbuf-backed)
|
|
903
|
-
if (
|
|
904
|
-
const pixbuf = image._pixbuf
|
|
924
|
+
if (isPixbufImageSource(image)) {
|
|
925
|
+
const pixbuf = image._pixbuf;
|
|
905
926
|
return { pixbuf, imgWidth: pixbuf.get_width(), imgHeight: pixbuf.get_height() };
|
|
906
927
|
}
|
|
907
928
|
|
|
908
929
|
// HTMLCanvasElement with a 2D context
|
|
909
|
-
if (
|
|
910
|
-
const w = image.width;
|
|
911
|
-
const h = image.height;
|
|
930
|
+
if (isCanvasImageSource(image)) {
|
|
931
|
+
const w = image.width ?? 0;
|
|
932
|
+
const h = image.height ?? 0;
|
|
912
933
|
// Reject non-positive / non-finite dimensions before they reach
|
|
913
934
|
// GdkPixbuf — `pixbuf_get_from_surface` logs a GLib-CRITICAL on
|
|
914
935
|
// `width > 0 && height > 0` assertion failure for NaN/0 inputs.
|
|
@@ -917,7 +938,7 @@ export class CanvasRenderingContext2D {
|
|
|
917
938
|
}
|
|
918
939
|
const ctx2d = image.getContext('2d');
|
|
919
940
|
if (ctx2d && typeof ctx2d._getSurface === 'function') {
|
|
920
|
-
const surface = ctx2d._getSurface()
|
|
941
|
+
const surface = ctx2d._getSurface();
|
|
921
942
|
surface.flush();
|
|
922
943
|
const pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0, w, h);
|
|
923
944
|
if (pixbuf) {
|
|
@@ -933,7 +954,7 @@ export class CanvasRenderingContext2D {
|
|
|
933
954
|
|
|
934
955
|
/** Create a PangoCairo layout configured with current font/text settings. */
|
|
935
956
|
private _createTextLayout(text: string): Pango.Layout {
|
|
936
|
-
const layout = PangoCairo.create_layout(this._ctx
|
|
957
|
+
const layout = PangoCairo.create_layout(this._ctx);
|
|
937
958
|
layout.set_text(text, -1);
|
|
938
959
|
|
|
939
960
|
// Force LTR base direction so text is never rendered mirrored
|
|
@@ -1077,10 +1098,10 @@ export class CanvasRenderingContext2D {
|
|
|
1077
1098
|
const aa = this._state.imageSmoothingEnabled ? Cairo.Antialias.DEFAULT : Cairo.Antialias.NONE;
|
|
1078
1099
|
for (const [tx, ty, ta] of taps) {
|
|
1079
1100
|
this._ctx.save();
|
|
1080
|
-
|
|
1101
|
+
this._ctx.setAntialias(aa);
|
|
1081
1102
|
this._ctx.setSourceRGBA(sc.r, sc.g, sc.b, ta);
|
|
1082
1103
|
this._ctx.moveTo(x + xOff + tx, y + yOff + ty);
|
|
1083
|
-
PangoCairo.show_layout(this._ctx
|
|
1104
|
+
PangoCairo.show_layout(this._ctx, layout);
|
|
1084
1105
|
this._ctx.restore();
|
|
1085
1106
|
}
|
|
1086
1107
|
}
|
|
@@ -1090,9 +1111,9 @@ export class CanvasRenderingContext2D {
|
|
|
1090
1111
|
this._ctx.save();
|
|
1091
1112
|
// Disable anti-aliasing so pixel/bitmap fonts render crisp (matching browser
|
|
1092
1113
|
// behaviour for fonts with no outline hints). cairo_save/restore covers antialias.
|
|
1093
|
-
|
|
1114
|
+
this._ctx.setAntialias(this._state.imageSmoothingEnabled ? Cairo.Antialias.DEFAULT : Cairo.Antialias.NONE);
|
|
1094
1115
|
this._ctx.moveTo(x + xOff, y + yOff);
|
|
1095
|
-
PangoCairo.show_layout(this._ctx
|
|
1116
|
+
PangoCairo.show_layout(this._ctx, layout);
|
|
1096
1117
|
this._ctx.restore();
|
|
1097
1118
|
}
|
|
1098
1119
|
|
|
@@ -1107,9 +1128,9 @@ export class CanvasRenderingContext2D {
|
|
|
1107
1128
|
const yOff = this._getTextBaselineOffset(layout);
|
|
1108
1129
|
|
|
1109
1130
|
this._ctx.save();
|
|
1110
|
-
|
|
1131
|
+
this._ctx.setAntialias(this._state.imageSmoothingEnabled ? Cairo.Antialias.DEFAULT : Cairo.Antialias.NONE);
|
|
1111
1132
|
this._ctx.moveTo(x + xOff, y + yOff);
|
|
1112
|
-
PangoCairo.layout_path(this._ctx
|
|
1133
|
+
PangoCairo.layout_path(this._ctx, layout);
|
|
1113
1134
|
this._ctx.stroke();
|
|
1114
1135
|
this._ctx.restore();
|
|
1115
1136
|
}
|
package/src/dom-types.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Internal interface declarations for the DOM-shaped objects that
|
|
2
|
+
// CanvasRenderingContext2D consumes.
|
|
3
|
+
//
|
|
4
|
+
// canvas2d-core deliberately has *no* dependency on @gjsify/dom-elements (that
|
|
5
|
+
// would create a cycle: dom-elements → canvas2d-core → dom-elements). Instead
|
|
6
|
+
// it accepts duck-typed inputs that match the relevant slice of the WHATWG
|
|
7
|
+
// Canvas 2D API. These interfaces document those slices and let the rest of
|
|
8
|
+
// the package work against concrete types instead of `any`.
|
|
9
|
+
|
|
10
|
+
import type Cairo from 'cairo';
|
|
11
|
+
import type GdkPixbuf from 'gi://GdkPixbuf';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The HTMLCanvasElement-shaped object passed into the
|
|
15
|
+
* `CanvasRenderingContext2D` constructor by the registered context factory.
|
|
16
|
+
*
|
|
17
|
+
* `@gjsify/dom-elements`' `HTMLCanvasElement` satisfies this — but so does any
|
|
18
|
+
* lightweight `{ width, height }` mock used by unit tests. Width/height
|
|
19
|
+
* default to the WHATWG canvas defaults (300×150) when missing.
|
|
20
|
+
*/
|
|
21
|
+
export interface CanvasLike {
|
|
22
|
+
width?: number;
|
|
23
|
+
height?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* GdkPixbuf-backed image source produced by `@gjsify/dom-elements`'
|
|
28
|
+
* `HTMLImageElement` (and other pixbuf-bearing wrappers).
|
|
29
|
+
*
|
|
30
|
+
* The `isPixbuf()` brand keeps us decoupled from the concrete class while
|
|
31
|
+
* preventing accidental matches against unrelated objects.
|
|
32
|
+
*/
|
|
33
|
+
export interface PixbufImageSource {
|
|
34
|
+
isPixbuf(): boolean;
|
|
35
|
+
/** @internal — populated by HTMLImageElement once decoding completes. */
|
|
36
|
+
_pixbuf: GdkPixbuf.Pixbuf;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Canvas-like image source carrying a 2D context whose backing surface can be
|
|
41
|
+
* sampled (used for `drawImage(canvas, …)` and `createPattern(canvas, …)`).
|
|
42
|
+
*/
|
|
43
|
+
export interface CanvasImageSource extends CanvasLike {
|
|
44
|
+
getContext(contextId: '2d', options?: unknown): CanvasContext2DLike | null;
|
|
45
|
+
getContext(contextId: string, options?: unknown): unknown;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The minimal slice of `CanvasRenderingContext2D` required to extract pixel
|
|
50
|
+
* data for `drawImage` / `createPattern`. Our own context naturally satisfies
|
|
51
|
+
* this through `_getSurface()`.
|
|
52
|
+
*/
|
|
53
|
+
export interface CanvasContext2DLike {
|
|
54
|
+
/** @internal — exposes the Cairo backing surface. */
|
|
55
|
+
_getSurface?(): Cairo.ImageSurface;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Type guard for {@link PixbufImageSource}. */
|
|
59
|
+
export function isPixbufImageSource(value: unknown): value is PixbufImageSource {
|
|
60
|
+
if (value === null || typeof value !== 'object') return false;
|
|
61
|
+
const candidate = value as { isPixbuf?: unknown };
|
|
62
|
+
return typeof candidate.isPixbuf === 'function' && (value as PixbufImageSource).isPixbuf();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Type guard for {@link CanvasImageSource}. */
|
|
66
|
+
export function isCanvasImageSource(value: unknown): value is CanvasImageSource {
|
|
67
|
+
if (value === null || typeof value !== 'object') return false;
|
|
68
|
+
return typeof (value as { getContext?: unknown }).getContext === 'function';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Minimal `DOMMatrix` shape returned by `CanvasRenderingContext2D.getTransform()`
|
|
73
|
+
* when no native `DOMMatrix` constructor is registered. Mirrors the
|
|
74
|
+
* `is2D`-only subset of the WHATWG matrix interface.
|
|
75
|
+
*/
|
|
76
|
+
export interface DOMMatrix2DLike {
|
|
77
|
+
a: number; b: number; c: number; d: number; e: number; f: number;
|
|
78
|
+
m11: number; m12: number; m13: number; m14: number;
|
|
79
|
+
m21: number; m22: number; m23: number; m24: number;
|
|
80
|
+
m31: number; m32: number; m33: number; m34: number;
|
|
81
|
+
m41: number; m42: number; m43: number; m44: number;
|
|
82
|
+
is2D: boolean;
|
|
83
|
+
isIdentity: boolean;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Constructor signature for the platform `DOMMatrix`. Lets us reach the
|
|
88
|
+
* runtime constructor through `globalThis` without an `any` cast when an
|
|
89
|
+
* embedder (e.g. `@gjsify/dom-elements`) has registered one.
|
|
90
|
+
*/
|
|
91
|
+
export type DOMMatrixConstructor = new (init?: number[] | string) => DOMMatrix;
|
|
92
|
+
|
|
93
|
+
/** Subset of `globalThis` we touch inside this package. */
|
|
94
|
+
export interface CanvasGlobalThis {
|
|
95
|
+
DOMMatrix?: DOMMatrixConstructor;
|
|
96
|
+
}
|