@gtkx/cairo 1.2.2
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/dist/context.d.ts +229 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +646 -0
- package/dist/context.js.map +1 -0
- package/dist/device.d.ts +21 -0
- package/dist/device.d.ts.map +1 -0
- package/dist/device.js +39 -0
- package/dist/device.js.map +1 -0
- package/dist/enums.d.ts +526 -0
- package/dist/enums.d.ts.map +1 -0
- package/dist/enums.js +482 -0
- package/dist/enums.js.map +1 -0
- package/dist/font-face.d.ts +55 -0
- package/dist/font-face.d.ts.map +1 -0
- package/dist/font-face.js +103 -0
- package/dist/font-face.js.map +1 -0
- package/dist/font-options.d.ts +43 -0
- package/dist/font-options.d.ts.map +1 -0
- package/dist/font-options.js +95 -0
- package/dist/font-options.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/lib.d.ts +36 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +120 -0
- package/dist/lib.js.map +1 -0
- package/dist/matrix.d.ts +40 -0
- package/dist/matrix.d.ts.map +1 -0
- package/dist/matrix.js +93 -0
- package/dist/matrix.js.map +1 -0
- package/dist/path.d.ts +14 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +67 -0
- package/dist/path.js.map +1 -0
- package/dist/pattern.d.ts +95 -0
- package/dist/pattern.d.ts.map +1 -0
- package/dist/pattern.js +250 -0
- package/dist/pattern.js.map +1 -0
- package/dist/region.d.ts +59 -0
- package/dist/region.d.ts.map +1 -0
- package/dist/region.js +154 -0
- package/dist/region.js.map +1 -0
- package/dist/scaled-font.d.ts +43 -0
- package/dist/scaled-font.d.ts.map +1 -0
- package/dist/scaled-font.js +156 -0
- package/dist/scaled-font.js.map +1 -0
- package/dist/structs.d.ts +120 -0
- package/dist/structs.d.ts.map +1 -0
- package/dist/structs.js +185 -0
- package/dist/structs.js.map +1 -0
- package/dist/surface.d.ts +98 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +274 -0
- package/dist/surface.js.map +1 -0
- package/dist/text.d.ts +10 -0
- package/dist/text.d.ts.map +1 -0
- package/dist/text.js +45 -0
- package/dist/text.js.map +1 -0
- package/dist/types.d.ts +245 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +9 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +13 -0
- package/dist/version.js.map +1 -0
- package/package.json +64 -0
- package/src/context.ts +899 -0
- package/src/device.ts +50 -0
- package/src/enums.ts +571 -0
- package/src/font-face.ts +157 -0
- package/src/font-options.ts +142 -0
- package/src/index.ts +28 -0
- package/src/lib.ts +186 -0
- package/src/matrix.ts +135 -0
- package/src/path.ts +87 -0
- package/src/pattern.ts +423 -0
- package/src/region.ts +216 -0
- package/src/scaled-font.ts +268 -0
- package/src/structs.ts +306 -0
- package/src/surface.ts +411 -0
- package/src/text.ts +56 -0
- package/src/types.ts +290 -0
- package/src/version.ts +16 -0
package/src/surface.ts
ADDED
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
import {
|
|
2
|
+
alloc,
|
|
3
|
+
type ExternalObject,
|
|
4
|
+
getHandle,
|
|
5
|
+
type Handle,
|
|
6
|
+
read,
|
|
7
|
+
registerWrapperClass,
|
|
8
|
+
registerWrapperClassResolver,
|
|
9
|
+
setHandle,
|
|
10
|
+
t,
|
|
11
|
+
wrapHandle,
|
|
12
|
+
type WrapperClassResolver,
|
|
13
|
+
write,
|
|
14
|
+
} from "@gtkx/runtime";
|
|
15
|
+
import type { RectangleInt } from "./structs.js";
|
|
16
|
+
import type { DeviceOffset, DeviceScale, FallbackResolution, InkExtents, RectangleData } from "./types.js";
|
|
17
|
+
import { type Content, type Format, type Status, SurfaceType } from "./enums.js";
|
|
18
|
+
import { FontOptions } from "./font-options.js";
|
|
19
|
+
import {
|
|
20
|
+
bindCairo,
|
|
21
|
+
type BoundFunction,
|
|
22
|
+
cairoGType,
|
|
23
|
+
DEVICE_T,
|
|
24
|
+
FONT_OPTIONS_T,
|
|
25
|
+
RECTANGLE_INT_T,
|
|
26
|
+
RECTANGLE_T,
|
|
27
|
+
SURFACE_FULL_T,
|
|
28
|
+
SURFACE_T,
|
|
29
|
+
} from "./lib.js";
|
|
30
|
+
|
|
31
|
+
const SURFACE_TYPE = cairoGType("cairo_gobject_surface_get_type");
|
|
32
|
+
const RECTANGLE_SIZE = 32;
|
|
33
|
+
const DEVICE_PAIR_ARGS = [SURFACE_T, t.float64, t.float64];
|
|
34
|
+
const DEVICE_PAIR_OUT_ARGS = [SURFACE_T, t.ref(t.float64), t.ref(t.float64)];
|
|
35
|
+
const SIMILAR_ARGS = [SURFACE_T, t.int32, t.int32, t.int32];
|
|
36
|
+
const cairoSurfaceCreateSimilar = bindCairo("cairo_surface_create_similar", SIMILAR_ARGS, SURFACE_FULL_T);
|
|
37
|
+
const cairoSurfaceCreateSimilarImage = bindCairo("cairo_surface_create_similar_image", SIMILAR_ARGS, SURFACE_FULL_T);
|
|
38
|
+
|
|
39
|
+
const cairoSurfaceCreateForRectangle = bindCairo(
|
|
40
|
+
"cairo_surface_create_for_rectangle",
|
|
41
|
+
[SURFACE_T, t.float64, t.float64, t.float64, t.float64],
|
|
42
|
+
SURFACE_FULL_T,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const cairoSurfaceWriteToPng = bindCairo("cairo_surface_write_to_png", [SURFACE_T, t.string("full")], t.int32);
|
|
46
|
+
const cairoSurfaceStatus = bindCairo("cairo_surface_status", [SURFACE_T], t.int32);
|
|
47
|
+
const cairoSurfaceFinish = bindCairo("cairo_surface_finish", [SURFACE_T], t.void);
|
|
48
|
+
const cairoSurfaceFlush = bindCairo("cairo_surface_flush", [SURFACE_T], t.void);
|
|
49
|
+
const cairoSurfaceGetDevice = bindCairo("cairo_surface_get_device", [SURFACE_T], DEVICE_T);
|
|
50
|
+
const cairoSurfaceGetFontOptions = bindCairo("cairo_surface_get_font_options", [SURFACE_T, FONT_OPTIONS_T], t.void);
|
|
51
|
+
const cairoSurfaceGetContent = bindCairo("cairo_surface_get_content", [SURFACE_T], t.int32);
|
|
52
|
+
const cairoSurfaceMarkDirty = bindCairo("cairo_surface_mark_dirty", [SURFACE_T], t.void);
|
|
53
|
+
|
|
54
|
+
const cairoSurfaceMarkDirtyRectangle = bindCairo(
|
|
55
|
+
"cairo_surface_mark_dirty_rectangle",
|
|
56
|
+
[SURFACE_T, t.int32, t.int32, t.int32, t.int32],
|
|
57
|
+
t.void,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const cairoSurfaceSetDeviceOffset = bindCairo("cairo_surface_set_device_offset", DEVICE_PAIR_ARGS, t.void);
|
|
61
|
+
const cairoSurfaceGetDeviceOffset = bindCairo("cairo_surface_get_device_offset", DEVICE_PAIR_OUT_ARGS, t.void);
|
|
62
|
+
const cairoSurfaceGetDeviceScale = bindCairo("cairo_surface_get_device_scale", DEVICE_PAIR_OUT_ARGS, t.void);
|
|
63
|
+
const cairoSurfaceSetDeviceScale = bindCairo("cairo_surface_set_device_scale", DEVICE_PAIR_ARGS, t.void);
|
|
64
|
+
const cairoSurfaceSetFallbackResolution = bindCairo("cairo_surface_set_fallback_resolution", DEVICE_PAIR_ARGS, t.void);
|
|
65
|
+
|
|
66
|
+
const cairoSurfaceGetFallbackResolution = bindCairo(
|
|
67
|
+
"cairo_surface_get_fallback_resolution",
|
|
68
|
+
DEVICE_PAIR_OUT_ARGS,
|
|
69
|
+
t.void,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const cairoSurfaceGetType = bindCairo("cairo_surface_get_type", [SURFACE_T], t.int32);
|
|
73
|
+
const cairoSurfaceGetReferenceCount = bindCairo("cairo_surface_get_reference_count", [SURFACE_T], t.int32);
|
|
74
|
+
const cairoSurfaceCopyPage = bindCairo("cairo_surface_copy_page", [SURFACE_T], t.void);
|
|
75
|
+
const cairoSurfaceShowPage = bindCairo("cairo_surface_show_page", [SURFACE_T], t.void);
|
|
76
|
+
const cairoSurfaceHasShowTextGlyphs = bindCairo("cairo_surface_has_show_text_glyphs", [SURFACE_T], t.boolean);
|
|
77
|
+
|
|
78
|
+
const cairoSurfaceSupportsMimeType = bindCairo(
|
|
79
|
+
"cairo_surface_supports_mime_type",
|
|
80
|
+
[SURFACE_T, t.string("full")],
|
|
81
|
+
t.boolean,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const cairoSurfaceMapToImage = bindCairo("cairo_surface_map_to_image", [SURFACE_T, RECTANGLE_INT_T], SURFACE_T);
|
|
85
|
+
const cairoSurfaceUnmapImage = bindCairo("cairo_surface_unmap_image", [SURFACE_T, SURFACE_T], t.void);
|
|
86
|
+
const cairoImageSurfaceCreate = bindCairo("cairo_image_surface_create", [t.int32, t.int32, t.int32], SURFACE_FULL_T);
|
|
87
|
+
|
|
88
|
+
const cairoImageSurfaceCreateFromPng = bindCairo(
|
|
89
|
+
"cairo_image_surface_create_from_png",
|
|
90
|
+
[t.string("full")],
|
|
91
|
+
SURFACE_FULL_T,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const cairoImageSurfaceGetWidth = bindCairo("cairo_image_surface_get_width", [SURFACE_T], t.int32);
|
|
95
|
+
const cairoImageSurfaceGetHeight = bindCairo("cairo_image_surface_get_height", [SURFACE_T], t.int32);
|
|
96
|
+
const cairoImageSurfaceGetFormat = bindCairo("cairo_image_surface_get_format", [SURFACE_T], t.int32);
|
|
97
|
+
const cairoImageSurfaceGetStride = bindCairo("cairo_image_surface_get_stride", [SURFACE_T], t.int32);
|
|
98
|
+
const cairoRecordingSurfaceCreate = bindCairo("cairo_recording_surface_create", [t.int32, RECTANGLE_T], SURFACE_FULL_T);
|
|
99
|
+
|
|
100
|
+
const cairoRecordingSurfaceCreateUnbounded = bindCairo(
|
|
101
|
+
"cairo_recording_surface_create",
|
|
102
|
+
[t.int32, t.uint64],
|
|
103
|
+
SURFACE_FULL_T,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const cairoRecordingSurfaceInkExtents = bindCairo(
|
|
107
|
+
"cairo_recording_surface_ink_extents",
|
|
108
|
+
[SURFACE_T, t.ref(t.float64), t.ref(t.float64), t.ref(t.float64), t.ref(t.float64)],
|
|
109
|
+
t.void,
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
const cairoRecordingSurfaceGetExtents = bindCairo(
|
|
113
|
+
"cairo_recording_surface_get_extents",
|
|
114
|
+
[SURFACE_T, RECTANGLE_T],
|
|
115
|
+
t.boolean,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const wrapSurface = (handle: unknown): Surface => wrapHandle(handle as ExternalObject<Handle>, Surface);
|
|
119
|
+
|
|
120
|
+
const readPair = <T>(boundFn: BoundFunction, self: object, build: (first: number, second: number) => T): T => {
|
|
121
|
+
const first = { value: 0 };
|
|
122
|
+
const second = { value: 0 };
|
|
123
|
+
boundFn(getHandle(self), first, second);
|
|
124
|
+
|
|
125
|
+
return build(first.value, second.value);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const allocRectangle = (rect: RectangleData): ExternalObject<Handle> => {
|
|
129
|
+
const buffer = alloc(RECTANGLE_SIZE);
|
|
130
|
+
write(buffer, t.float64, 0, rect.x);
|
|
131
|
+
write(buffer, t.float64, 8, rect.y);
|
|
132
|
+
write(buffer, t.float64, 16, rect.width);
|
|
133
|
+
write(buffer, t.float64, 24, rect.height);
|
|
134
|
+
|
|
135
|
+
return buffer;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const readRectangle = (buffer: ExternalObject<Handle>): RectangleData => ({
|
|
139
|
+
x: read(buffer, t.float64, 0) as number,
|
|
140
|
+
y: read(buffer, t.float64, 8) as number,
|
|
141
|
+
width: read(buffer, t.float64, 16) as number,
|
|
142
|
+
height: read(buffer, t.float64, 24) as number,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const createRecordingSurface = (content: Content, extents?: RectangleData): ExternalObject<Handle> =>
|
|
146
|
+
(extents === undefined
|
|
147
|
+
? cairoRecordingSurfaceCreateUnbounded(content, 0)
|
|
148
|
+
: cairoRecordingSurfaceCreate(content, allocRectangle(extents))) as ExternalObject<Handle>;
|
|
149
|
+
|
|
150
|
+
const surfaceClassFor: WrapperClassResolver = (handle) => {
|
|
151
|
+
const type = cairoSurfaceGetType(handle) as SurfaceType;
|
|
152
|
+
|
|
153
|
+
if (type === SurfaceType.IMAGE) {
|
|
154
|
+
return ImageSurface;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (type === SurfaceType.RECORDING) {
|
|
158
|
+
return RecordingSurface;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return Surface;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* A cairo surface (`cairo_surface_t`): the target a context draws onto. Surfaces come from the `create*`
|
|
166
|
+
* statics, from `ImageSurface` and `RecordingSurface`, or from GTK, and wrap as the concrete class their
|
|
167
|
+
* backend reports (`instanceof ImageSurface` for an image surface).
|
|
168
|
+
*/
|
|
169
|
+
abstract class Surface {
|
|
170
|
+
static {
|
|
171
|
+
registerWrapperClass(this, SURFACE_TYPE);
|
|
172
|
+
registerWrapperClassResolver(this, surfaceClassFor);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Creates a surface of the given `content` and size as compatible as possible with `other`. */
|
|
176
|
+
static createSimilar(other: Surface, content: Content, width: number, height: number): Surface {
|
|
177
|
+
return wrapSurface(cairoSurfaceCreateSimilar(getHandle(other), content, width, height));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Creates an image surface of the given `format` and size as compatible as possible with `other`. */
|
|
181
|
+
static createSimilarImage(other: Surface, format: Format, width: number, height: number): Surface {
|
|
182
|
+
return wrapSurface(cairoSurfaceCreateSimilarImage(getHandle(other), format, width, height));
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Creates a surface that draws onto the given rectangle of `target`. */
|
|
186
|
+
static createForRectangle(target: Surface, x: number, y: number, width: number, height: number): Surface {
|
|
187
|
+
return wrapSurface(cairoSurfaceCreateForRectangle(getHandle(target), x, y, width, height));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** GType of `CairoSurface`, the boxed type this class is registered under. */
|
|
191
|
+
declare __type__: bigint;
|
|
192
|
+
|
|
193
|
+
/** Writes the surface to a PNG file at `filename` and returns the resulting status. */
|
|
194
|
+
writeToPng(filename: string): Status {
|
|
195
|
+
return cairoSurfaceWriteToPng(getHandle(this), filename) as Status;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Returns the error status of the surface, `Status.SUCCESS` when it is usable. */
|
|
199
|
+
status(): Status {
|
|
200
|
+
return cairoSurfaceStatus(getHandle(this)) as Status;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Finishes the surface and drops its backend resources; further drawing reports an error. */
|
|
204
|
+
finish(): void {
|
|
205
|
+
cairoSurfaceFinish(getHandle(this));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Performs any pending drawing so the backend storage is up to date. */
|
|
209
|
+
flush(): void {
|
|
210
|
+
cairoSurfaceFlush(getHandle(this));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** Returns the raw handle of the device behind the surface, or null when it has none. */
|
|
214
|
+
getDevice(): ExternalObject<Handle> | null {
|
|
215
|
+
return cairoSurfaceGetDevice(getHandle(this)) as ExternalObject<Handle> | null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** Returns the font options the surface's backend prefers for rendering text. */
|
|
219
|
+
getFontOptions(): FontOptions {
|
|
220
|
+
const options = FontOptions.create();
|
|
221
|
+
cairoSurfaceGetFontOptions(getHandle(this), getHandle(options));
|
|
222
|
+
|
|
223
|
+
return options;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** Returns whether the surface holds color, alpha or both. */
|
|
227
|
+
getContent(): Content {
|
|
228
|
+
return cairoSurfaceGetContent(getHandle(this)) as Content;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Tells cairo the surface's storage was modified outside of cairo. */
|
|
232
|
+
markDirty(): void {
|
|
233
|
+
cairoSurfaceMarkDirty(getHandle(this));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** Tells cairo the given rectangle of the surface's storage was modified outside of cairo. */
|
|
237
|
+
markDirtyRectangle(x: number, y: number, width: number, height: number): void {
|
|
238
|
+
cairoSurfaceMarkDirtyRectangle(getHandle(this), x, y, width, height);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** Sets the offset added to device coordinates when drawing onto the surface. */
|
|
242
|
+
setDeviceOffset(xOffset: number, yOffset: number): void {
|
|
243
|
+
cairoSurfaceSetDeviceOffset(getHandle(this), xOffset, yOffset);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** Returns the offset added to device coordinates when drawing onto the surface. */
|
|
247
|
+
getDeviceOffset(): DeviceOffset {
|
|
248
|
+
return readPair(cairoSurfaceGetDeviceOffset, this, (xOffset, yOffset) => ({ xOffset, yOffset }));
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Returns the scale applied between user and device units. */
|
|
252
|
+
getDeviceScale(): DeviceScale {
|
|
253
|
+
return readPair(cairoSurfaceGetDeviceScale, this, (xScale, yScale) => ({ xScale, yScale }));
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Sets the scale applied between user and device units. */
|
|
257
|
+
setDeviceScale(xScale: number, yScale: number): void {
|
|
258
|
+
cairoSurfaceSetDeviceScale(getHandle(this), xScale, yScale);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/** Sets the resolution used when vector content has to be rasterized. */
|
|
262
|
+
setFallbackResolution(xPixelsPerInch: number, yPixelsPerInch: number): void {
|
|
263
|
+
cairoSurfaceSetFallbackResolution(getHandle(this), xPixelsPerInch, yPixelsPerInch);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** Returns the resolution used when vector content has to be rasterized. */
|
|
267
|
+
getFallbackResolution(): FallbackResolution {
|
|
268
|
+
return readPair(cairoSurfaceGetFallbackResolution, this, (xPixelsPerInch, yPixelsPerInch) => ({
|
|
269
|
+
xPixelsPerInch,
|
|
270
|
+
yPixelsPerInch,
|
|
271
|
+
}));
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/** Returns the backend type of the surface. */
|
|
275
|
+
getType(): SurfaceType {
|
|
276
|
+
return cairoSurfaceGetType(getHandle(this)) as SurfaceType;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/** Returns the reference count of the surface. */
|
|
280
|
+
getReferenceCount(): number {
|
|
281
|
+
return cairoSurfaceGetReferenceCount(getHandle(this)) as number;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** Emits the current page and keeps its content for the next one, on paged backends. */
|
|
285
|
+
copyPage(): void {
|
|
286
|
+
cairoSurfaceCopyPage(getHandle(this));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** Emits the current page and starts a blank one, on paged backends. */
|
|
290
|
+
showPage(): void {
|
|
291
|
+
cairoSurfaceShowPage(getHandle(this));
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/** Returns whether the surface supports `Context.showTextGlyphs` natively. */
|
|
295
|
+
hasShowTextGlyphs(): boolean {
|
|
296
|
+
return cairoSurfaceHasShowTextGlyphs(getHandle(this)) as boolean;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/** Returns whether the surface can embed data of the given MIME type. */
|
|
300
|
+
supportsMimeType(mimeType: string): boolean {
|
|
301
|
+
return cairoSurfaceSupportsMimeType(getHandle(this), mimeType) as boolean;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** Returns an image surface giving direct access to the pixels of `extents`; release it with `unmapImage`. */
|
|
305
|
+
mapToImage(extents: RectangleInt): Surface {
|
|
306
|
+
return wrapSurface(cairoSurfaceMapToImage(getHandle(this), getHandle(extents)));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** Uploads the pixels of `image`, obtained from `mapToImage`, back to the surface and releases it. */
|
|
310
|
+
unmapImage(image: Surface): void {
|
|
311
|
+
cairoSurfaceUnmapImage(getHandle(this), getHandle(image));
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/** A surface backed by an in-memory pixel buffer, the usual target for offscreen drawing. */
|
|
316
|
+
class ImageSurface extends Surface {
|
|
317
|
+
/** Creates an image surface of the given pixel `format` and size, the same as `new ImageSurface(...)`. */
|
|
318
|
+
static create(format: Format, width: number, height: number): ImageSurface {
|
|
319
|
+
return wrapHandle(cairoImageSurfaceCreate(format, width, height) as ExternalObject<Handle>, this);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** Loads a PNG file into a new image surface; a missing or invalid file yields a surface in an error status. */
|
|
323
|
+
static createFromPng(filename: string): ImageSurface {
|
|
324
|
+
return wrapHandle(cairoImageSurfaceCreateFromPng(filename) as ExternalObject<Handle>, this);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/** Creates an image surface of the given pixel `format` and size. */
|
|
328
|
+
constructor(format: Format, width: number, height: number) {
|
|
329
|
+
super();
|
|
330
|
+
setHandle(this, cairoImageSurfaceCreate(format, width, height) as ExternalObject<Handle>);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/** Returns the width of the surface in pixels. */
|
|
334
|
+
getWidth(): number {
|
|
335
|
+
return cairoImageSurfaceGetWidth(getHandle(this)) as number;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/** Returns the height of the surface in pixels. */
|
|
339
|
+
getHeight(): number {
|
|
340
|
+
return cairoImageSurfaceGetHeight(getHandle(this)) as number;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/** Returns the pixel format of the surface. */
|
|
344
|
+
getFormat(): Format {
|
|
345
|
+
return cairoImageSurfaceGetFormat(getHandle(this)) as Format;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/** Returns the number of bytes between the starts of consecutive rows. */
|
|
349
|
+
getStride(): number {
|
|
350
|
+
return cairoImageSurfaceGetStride(getHandle(this)) as number;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/** Returns a copy of the pixel data, `getStride() * getHeight()` bytes in the surface's format. */
|
|
354
|
+
getData(): Uint8Array {
|
|
355
|
+
this.flush();
|
|
356
|
+
const totalBytes = this.getStride() * this.getHeight();
|
|
357
|
+
|
|
358
|
+
if (totalBytes === 0) {
|
|
359
|
+
return new Uint8Array(0);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const getImageData = bindCairo(
|
|
363
|
+
"cairo_image_surface_get_data",
|
|
364
|
+
[SURFACE_T],
|
|
365
|
+
t.struct("borrowed", { size: totalBytes }),
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
const data = getImageData(getHandle(this)) as ExternalObject<Handle> | null;
|
|
369
|
+
|
|
370
|
+
if (data === null) {
|
|
371
|
+
return new Uint8Array(0);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return Uint8Array.from({ length: totalBytes }, (_, index) => read(data, t.uint8, index) as number);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/** A surface that records the drawing operations applied to it, for replaying them onto other surfaces. */
|
|
379
|
+
class RecordingSurface extends Surface {
|
|
380
|
+
/** Creates a recording surface, the same as `new RecordingSurface(...)`. */
|
|
381
|
+
static create(content: Content, extents?: RectangleData): RecordingSurface {
|
|
382
|
+
return new RecordingSurface(content, extents);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/** Creates a recording surface of the given `content`, bounded to `extents` or unbounded when omitted. */
|
|
386
|
+
constructor(content: Content, extents?: RectangleData) {
|
|
387
|
+
super();
|
|
388
|
+
setHandle(this, createRecordingSurface(content, extents));
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/** Returns the area that has been drawn on so far. */
|
|
392
|
+
inkExtents(): InkExtents {
|
|
393
|
+
const x0 = { value: 0 };
|
|
394
|
+
const y0 = { value: 0 };
|
|
395
|
+
const width = { value: 0 };
|
|
396
|
+
const height = { value: 0 };
|
|
397
|
+
cairoRecordingSurfaceInkExtents(getHandle(this), x0, y0, width, height);
|
|
398
|
+
|
|
399
|
+
return { x0: x0.value, y0: y0.value, width: width.value, height: height.value };
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/** Returns the extents the surface was created with, or null for an unbounded surface. */
|
|
403
|
+
getExtents(): RectangleData | null {
|
|
404
|
+
const buffer = alloc(RECTANGLE_SIZE);
|
|
405
|
+
const isBounded = cairoRecordingSurfaceGetExtents(getHandle(this), buffer) as boolean;
|
|
406
|
+
|
|
407
|
+
return isBounded ? readRectangle(buffer) : null;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export { ImageSurface, RecordingSurface, Surface };
|
package/src/text.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { alloc, type ExternalObject, type Handle, read, t, write } from "@gtkx/runtime";
|
|
2
|
+
import type { CairoGlyph, CairoTextCluster, FontExtents, TextExtents } from "./types.js";
|
|
3
|
+
|
|
4
|
+
const GLYPH_SIZE = 24;
|
|
5
|
+
const CLUSTER_SIZE = 8;
|
|
6
|
+
const TEXT_EXTENTS_SIZE = 48;
|
|
7
|
+
const FONT_EXTENTS_SIZE = 40;
|
|
8
|
+
|
|
9
|
+
const allocGlyphBuffer = (glyphs: CairoGlyph[]): ExternalObject<Handle> => {
|
|
10
|
+
const buffer = alloc(glyphs.length * GLYPH_SIZE);
|
|
11
|
+
let offset = 0;
|
|
12
|
+
|
|
13
|
+
for (const glyph of glyphs) {
|
|
14
|
+
write(buffer, t.uint64, offset, glyph.index);
|
|
15
|
+
write(buffer, t.float64, offset + 8, glyph.x);
|
|
16
|
+
write(buffer, t.float64, offset + 16, glyph.y);
|
|
17
|
+
offset += GLYPH_SIZE;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return buffer;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const allocClusterBuffer = (clusters: CairoTextCluster[]): ExternalObject<Handle> => {
|
|
24
|
+
const buffer = alloc(clusters.length * CLUSTER_SIZE);
|
|
25
|
+
let offset = 0;
|
|
26
|
+
|
|
27
|
+
for (const cluster of clusters) {
|
|
28
|
+
write(buffer, t.int32, offset, cluster.numBytes);
|
|
29
|
+
write(buffer, t.int32, offset + 4, cluster.numGlyphs);
|
|
30
|
+
offset += CLUSTER_SIZE;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return buffer;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const allocTextExtents = (): ExternalObject<Handle> => alloc(TEXT_EXTENTS_SIZE);
|
|
37
|
+
const allocFontExtents = (): ExternalObject<Handle> => alloc(FONT_EXTENTS_SIZE);
|
|
38
|
+
|
|
39
|
+
const readTextExtents = (handle: ExternalObject<Handle>): TextExtents => ({
|
|
40
|
+
xBearing: read(handle, t.float64, 0) as number,
|
|
41
|
+
yBearing: read(handle, t.float64, 8) as number,
|
|
42
|
+
width: read(handle, t.float64, 16) as number,
|
|
43
|
+
height: read(handle, t.float64, 24) as number,
|
|
44
|
+
xAdvance: read(handle, t.float64, 32) as number,
|
|
45
|
+
yAdvance: read(handle, t.float64, 40) as number,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const readFontExtents = (handle: ExternalObject<Handle>): FontExtents => ({
|
|
49
|
+
ascent: read(handle, t.float64, 0) as number,
|
|
50
|
+
descent: read(handle, t.float64, 8) as number,
|
|
51
|
+
height: read(handle, t.float64, 16) as number,
|
|
52
|
+
maxXAdvance: read(handle, t.float64, 24) as number,
|
|
53
|
+
maxYAdvance: read(handle, t.float64, 32) as number,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export { allocClusterBuffer, allocFontExtents, allocGlyphBuffer, allocTextExtents, readFontExtents, readTextExtents };
|