Skip to content

Commit 284f469

Browse files
committed
chore: updates
1 parent 0b4d95d commit 284f469

File tree

8 files changed

+536
-55
lines changed

8 files changed

+536
-55
lines changed

crates/canvas-2d/src/context/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,14 @@ impl Context {
560560
};
561561
}
562562

563+
pub fn reset(&mut self) {
564+
self.reset_state();
565+
self.reset_transform();
566+
self.with_canvas_dirty(|canvas| {
567+
canvas.clear(Color::TRANSPARENT);
568+
});
569+
}
570+
563571
pub fn reset_state(&mut self) {
564572
let direction = self.state.direction;
565573
self.state = State::default();

crates/canvas-c/src/c2d/context.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2457,6 +2457,14 @@ pub extern "C" fn canvas_native_context_rect(
24572457
context.context.rect(x, y, width, height)
24582458
}
24592459

2460+
#[no_mangle]
2461+
pub extern "C" fn canvas_native_context_reset(
2462+
context: *mut CanvasRenderingContext2D
2463+
) {
2464+
let context = unsafe { &mut *context };
2465+
context.context.reset()
2466+
}
2467+
24602468
#[no_mangle]
24612469
pub extern "C" fn canvas_native_context_round_rect(
24622470
context: *mut CanvasRenderingContext2D,

napi/canvas-napi/index.d.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,28 @@ export declare class ImageData {
4141
get height(): number;
4242
get data(): Buffer;
4343
}
44+
export declare class TextMetrics {
45+
get width(): number;
46+
get actualBoundingBoxLeft(): number;
47+
get actualBoundingBoxRight(): number;
48+
get actualBoundingBoxAscent(): number;
49+
get actualBoundingBoxDescent(): number;
50+
get fontBoundingBoxAscent(): number;
51+
get fontBoundingBoxDescent(): number;
52+
get emHeightAscent(): number;
53+
get emHeightDescent(): number;
54+
get hangingBaseline(): number;
55+
get alphabeticBaseline(): number;
56+
get ideographicBaseline(): number;
57+
}
4458
export declare class CanvasRenderingContext2D {
4559
static withView(view: number, width: number, height: number, density: number, alpha: boolean, fontColor: number, ppi: number, direction: number): CanvasRenderingContext2D;
60+
static withMtlViewDeviceQueue(view: number, device: number, queue: number, alpha: boolean, density: number, samples: number, fontColor: number, ppi: number, direction: number): CanvasRenderingContext2D;
61+
present(): void;
62+
flush(): void;
63+
render(): void;
4664
static withCpu(width: number, height: number, density: number, alpha: boolean, fontColor: number, ppi: number, direction: number): CanvasRenderingContext2D;
65+
toDataURL(format: string, encoderOptions?: number | undefined | null): string;
4766
get direction(): string;
4867
set direction(direction: string);
4968
get fillStyle(): unknown;
@@ -109,19 +128,25 @@ export declare class CanvasRenderingContext2D {
109128
createPattern(image: ImageAsset, repetition?: string | undefined | null): CanvasPattern;
110129
createRadialGradient(x0: number, y0: number, r0: number, x1: number, y1: number, r1: number): CanvasGradient;
111130
drawFocusIfNeeded(elementPath: object | Path2D, element?: object | undefined | null): void;
131+
drawImage(image: ImageAsset, sx?: number | undefined | null, sy?: number | undefined | null, sWidth?: number | undefined | null, sHeight?: number | undefined | null, dx?: number | undefined | null, dy?: number | undefined | null, dWidth?: number | undefined | null, dHeight?: number | undefined | null): void;
112132
ellipse(x: number, y: number, radiusX: number, radiusY: number, rotation: number, startAngle: number, endAngle: number, anticlockwise?: boolean | undefined | null): void;
113133
fill(path?: Path2D | undefined | null, rule?: string | undefined | null): void;
114134
fillRect(x: number, y: number, width: number, height: number): void;
115135
fillText(text: string, x: number, y: number, maxWidth?: number | undefined | null): void;
116136
getImageData(x: number, y: number, width: number, height: number): ImageData;
117137
getLineDash(): Array<number>;
118138
getTransform(): DOMMatrix;
139+
isContextLost(): boolean;
140+
isPointInPath(xOrPath: number | Path2D, y?: number | undefined | null, ruleOrY?: number | string | undefined | null, rule?: string | undefined | null): boolean;
141+
isPointInStroke(xOrPath: number | Path2D, xOrY?: number | undefined | null, y?: number | undefined | null): boolean;
119142
lineTo(x: number, y: number): void;
143+
measureText(text: string): TextMetrics;
120144
moveTo(x: number, y: number): void;
121-
render(): void;
122-
toDataURL(format: string, encoderOptions?: number | undefined | null): string;
123-
drawImage(image: ImageAsset, sx?: number | undefined | null, sy?: number | undefined | null, sWidth?: number | undefined | null, sHeight?: number | undefined | null, dx?: number | undefined | null, dy?: number | undefined | null, dWidth?: number | undefined | null, dHeight?: number | undefined | null): void;
145+
putImageData(imageData: ImageData, dx: number, dy: number, dirtyX?: number | undefined | null, dirtyY?: number | undefined | null, dirtyWidth?: number | undefined | null, dirtyHeight?: number | undefined | null): void;
146+
quadraticCurveTo(cpx: number, cpy: number, x: number, y: number): void;
124147
rect(x: number, y: number, width: number, height: number): void;
148+
reset(): void;
149+
resetTransform(): void;
125150
restore(): void;
126151
rotate(angle: number): void;
127152
roundRect(x: number, y: number, width: number, height: number, radii: number | Array<number>): void;

napi/canvas-napi/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,13 +284,14 @@ if (!nativeBinding) {
284284
throw new Error(`Failed to load native binding`);
285285
}
286286

287-
const { WebGLRenderingContext, Path2D, CanvasPattern, CanvasGradient, ImageData, CanvasRenderingContext2D, ImageAsset, DomMatrix } = nativeBinding;
287+
const { WebGLRenderingContext, Path2D, CanvasPattern, CanvasGradient, ImageData, TextMetrics, CanvasRenderingContext2D, ImageAsset, DomMatrix } = nativeBinding;
288288

289289
module.exports.WebGLRenderingContext = WebGLRenderingContext;
290290
module.exports.Path2D = Path2D;
291291
module.exports.CanvasPattern = CanvasPattern;
292292
module.exports.CanvasGradient = CanvasGradient;
293293
module.exports.ImageData = ImageData;
294+
module.exports.TextMetrics = TextMetrics;
294295
module.exports.CanvasRenderingContext2D = CanvasRenderingContext2D;
295296
module.exports.ImageAsset = ImageAsset;
296297
module.exports.DomMatrix = DomMatrix;

napi/canvas-napi/main.mjs

Lines changed: 144 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,58 @@ export class NSCMTLView extends NSView {
5555
static {
5656
NativeClass(this);
5757
}
58+
_device;
59+
_queue;
60+
_canvas;
61+
62+
get queue() {
63+
return this._queue;
64+
}
65+
66+
get device() {
67+
return this._device;
68+
}
69+
70+
initWithFrame(frameRect) {
71+
super.initWithFrame(frameRect);
72+
this.wantsLayer = true;
73+
const layer = CAMetalLayer.layer();
74+
this._device = MTLCreateSystemDefaultDevice();
75+
this._queue = this._device.newCommandQueue();
76+
layer.device = this._device;
77+
layer.presentsWithTransaction = false;
78+
layer.framebufferOnly = false;
79+
layer.pixelFormat = MTLPixelFormat.BGRA8Unorm;
80+
81+
this.layer = layer;
82+
return this;
83+
}
84+
85+
86+
/**
87+
* @return {CGSize}
88+
*/
89+
get drawableSize() {
90+
return this.layer.drawableSize;
91+
}
92+
93+
/**
94+
* @param {CGSize} value
95+
*/
96+
set drawableSize(value) {
97+
this.layer.drawableSize = value;
98+
}
99+
100+
101+
present() {
102+
this._canvas?.getContext('2d').flush();
103+
this._canvas?.getContext('2d').present();
104+
}
105+
106+
static ObjCExposedMethods = {
107+
present: { returns: interop.types.void, params: [] }
108+
};
109+
58110
}
59111

60112
export class NSCCanvas extends NSView {
@@ -89,6 +141,7 @@ export class CanvasGLView extends NSOpenGLView {
89141
}
90142
}
91143

144+
92145
export class ViewController extends NSViewController {
93146
static {
94147
NativeClass(this);
@@ -105,15 +158,25 @@ export class ViewController extends NSViewController {
105158
this.view.addSubview(this.canvas);
106159

107160
glview.frame = this.view.frame;
161+
mtlview.frame = this.view.frame;
162+
mtlview.drawableSize = new CGSize({
163+
width: this.view.frame.size.width * NSScreen.mainScreen.backingScaleFactor,
164+
height: this.view.frame.size.height * NSScreen.mainScreen.backingScaleFactor
165+
});
166+
167+
this.canvas.addSubview(mtlview);
108168

109-
this.canvas.addSubview(glview);
169+
//this.canvas.addSubview(glview);
110170

111-
glview.wantsLayer = true;
171+
// glview.wantsLayer = true;
112172
}
113173
}
114174

115175
const glview = CanvasGLView.alloc().initWithFrame({ x: 0, y: 0, width: 0, height: 0 });
116176

177+
const mtlview = NSCMTLView.alloc().initWithFrame({ x: 0, y: 0, width: 0, height: 0 });
178+
179+
117180
let isDoingOrDone = false;
118181

119182
function mdnShadowColor(ctx) {
@@ -399,8 +462,8 @@ function flappyBird(canvas) {
399462
}
400463

401464
function main() {
402-
width = canvas.clientWidth * window.devicePixelRatio;
403-
height = canvas.clientHeight * window.devicePixelRatio;
465+
width = canvas.clientWidth //* window.devicePixelRatio;
466+
height = canvas.clientHeight // * window.devicePixelRatio;
404467

405468
canvas.addEventListener('touchstart', onpress);
406469

@@ -981,6 +1044,47 @@ function mdnPattern(canvas) {
9811044
ctx.fillRect(0, 0, canvas.width, canvas.height);
9821045
}
9831046

1047+
function mdnPutImageData(canvas) {
1048+
const ctx = canvas.getContext('2d');
1049+
1050+
function putImageData(
1051+
ctx,
1052+
imageData,
1053+
dx,
1054+
dy,
1055+
dirtyX,
1056+
dirtyY,
1057+
dirtyWidth,
1058+
dirtyHeight
1059+
) {
1060+
const data = imageData.data;
1061+
const height = imageData.height;
1062+
const width = imageData.width;
1063+
dirtyX = dirtyX || 0;
1064+
dirtyY = dirtyY || 0;
1065+
dirtyWidth = dirtyWidth !== undefined ? dirtyWidth : width;
1066+
dirtyHeight = dirtyHeight !== undefined ? dirtyHeight : height;
1067+
const limitBottom = dirtyY + dirtyHeight;
1068+
const limitRight = dirtyX + dirtyWidth;
1069+
for (let y = dirtyY; y < limitBottom; y++) {
1070+
for (let x = dirtyX; x < limitRight; x++) {
1071+
const pos = y * width + x;
1072+
ctx.fillStyle = `rgb(${data[pos * 4 + 0]} ${data[pos * 4 + 1]}
1073+
${data[pos * 4 + 2]} / ${data[pos * 4 + 3] / 255})`;
1074+
ctx.fillRect(x + dx, y + dy, 1, 1);
1075+
}
1076+
}
1077+
}
1078+
1079+
// Draw content onto the canvas
1080+
ctx.fillRect(0, 0, 100, 100);
1081+
// Create an ImageData object from it
1082+
const imagedata = ctx.getImageData(0, 0, 100, 100);
1083+
// use the putImageData function that illustrates how putImageData works
1084+
putImageData(ctx, imagedata, 150, 0, 50, 50, 25, 25);
1085+
ctx.render();
1086+
}
1087+
9841088
function mdnRadialGradient(canvas) {
9851089
const ctx = canvas.getContext('2d');
9861090

@@ -1028,7 +1132,31 @@ function doTheThing() {
10281132
// const glContext = WebGLRenderingContext.withView(handle.toNumber(), 1, true, false, false, false, 1, true, false, false, false, false, false);
10291133
// console.log(glContext, 'drawingBufferWidth', glContext.drawingBufferWidth, 'drawingBufferHeight', glContext.drawingBufferHeight);
10301134

1031-
const ctx = CanvasRenderingContext2D.withView(handle.toNumber(), glview.frame.size.width * scale, glview.frame.size.height * scale, 1, true, 0, 90, 1);
1135+
//const ctx = CanvasRenderingContext2D.withView(handle.toNumber(), glview.frame.size.width * scale, glview.frame.size.height * scale, 1, true, 0, 90, 1);
1136+
1137+
1138+
const mtlViewHandle = interop.handleof(mtlview);
1139+
const deviceHandle = interop.handleof(mtlview.device);
1140+
const queueHandle = interop.handleof(mtlview.queue);
1141+
const ctx = CanvasRenderingContext2D.withMtlViewDeviceQueue(
1142+
mtlViewHandle.toNumber(), deviceHandle.toNumber(), queueHandle.toNumber(), true, scale, 1, 0, 90, 1
1143+
);
1144+
1145+
const mtlCanvas = {
1146+
width: mtlview.frame.size.width,
1147+
height: mtlview.frame.size.height,
1148+
clientWidth: mtlview.frame.size.width,
1149+
clientHeight: mtlview.frame.size.height,
1150+
addEventListener: function() {
1151+
},
1152+
getContext: function() {
1153+
return ctx;
1154+
},
1155+
style: {}
1156+
};
1157+
1158+
mtlview._canvas = mtlCanvas;
1159+
10321160
ctx.fillStyle = 'white';
10331161

10341162
ctx.fillRect(0, 0, 1000, 1000);
@@ -1056,16 +1184,22 @@ function doTheThing() {
10561184
style: {}
10571185
};
10581186

1059-
// flappyBird(canvas);
1187+
//flappyBird(mtlCanvas);
10601188

1061-
solarSystem(canvas);
1189+
solarSystem(canvas);
10621190

10631191
// swarm(canvas);
1064-
//breathe_demo(canvas);
1192+
// breathe_demo(canvas);
10651193
//mdnPattern(canvas);
1066-
//mdnRadialGradient(canvas);
1194+
// mdnRadialGradient(canvas);
1195+
//mdnPutImageData(canvas);
1196+
1197+
//
1198+
// ctx.font = '50px serif';
1199+
// ctx.strokeText('Hello world', 50, 90);
1200+
10671201

1068-
// ctx.render();
1202+
// ctx.render();
10691203

10701204
/*
10711205

0 commit comments

Comments
 (0)