Skip to content

Commit 68197bc

Browse files
committed
feat(ext/canvas): shadows + patterns
1 parent 9397445 commit 68197bc

File tree

12 files changed

+1361
-139
lines changed

12 files changed

+1361
-139
lines changed

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ authors = ["the Andromeda team"]
77
edition = "2024"
88
license = "Mozilla Public License 2.0"
99
repository = "https://github.com/tryandromeda/andromeda"
10-
version = "0.1.0-draft45"
10+
version = "0.1.0-draft46"
1111

1212
[workspace.dependencies]
1313
andromeda-core = { path = "core" }

runtime/src/ext/canvas/context2d.rs

Lines changed: 127 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,15 @@ pub fn internal_canvas_clear_rect<'gc>(
475475
line_cap: LineCap::default(),
476476
line_join: LineJoin::default(),
477477
miter_limit: 10.0,
478+
shadow_blur: 0.0,
479+
shadow_color: FillStyle::Color {
480+
r: 0.0,
481+
g: 0.0,
482+
b: 0.0,
483+
a: 0.0,
484+
},
485+
shadow_offset_x: 0.0,
486+
shadow_offset_y: 0.0,
478487
composite_operation: CompositeOperation::default(),
479488
},
480489
);
@@ -570,18 +579,22 @@ pub fn internal_canvas_fill_rect<'gc>(
570579
},
571580
};
572581

573-
// Get the current fill style color
574582
let data = res.canvases.get(rid).unwrap();
583+
575584
res.renderers.get_mut(rid).unwrap().render_rect(
576585
rect,
577586
&RenderState {
578587
fill_style: data.fill_style,
579588
global_alpha: data.global_alpha,
580-
transform: [1.0, 0.0, 0.0, 1.0, 0.0, 0.0],
581-
line_cap: LineCap::default(),
582-
line_join: LineJoin::default(),
583-
miter_limit: 10.0,
584-
composite_operation: CompositeOperation::default(),
589+
transform: data.transform,
590+
line_cap: data.line_cap,
591+
line_join: data.line_join,
592+
miter_limit: data.miter_limit,
593+
shadow_blur: data.shadow_blur,
594+
shadow_color: data.shadow_color,
595+
shadow_offset_x: data.shadow_offset_x,
596+
shadow_offset_y: data.shadow_offset_y,
597+
composite_operation: data.composite_operation,
585598
},
586599
);
587600
} else {
@@ -714,10 +727,14 @@ pub fn internal_canvas_fill<'gc>(
714727
&RenderState {
715728
fill_style: data.fill_style,
716729
global_alpha: data.global_alpha,
717-
transform: [1.0, 0.0, 0.0, 1.0, 0.0, 0.0],
718-
line_cap: LineCap::default(),
719-
line_join: LineJoin::default(),
720-
miter_limit: 10.0,
730+
transform: data.transform,
731+
line_cap: data.line_cap,
732+
line_join: data.line_join,
733+
miter_limit: data.miter_limit,
734+
shadow_blur: data.shadow_blur,
735+
shadow_color: data.shadow_color,
736+
shadow_offset_x: data.shadow_offset_x,
737+
shadow_offset_y: data.shadow_offset_y,
721738
composite_operation: data.composite_operation,
722739
},
723740
);
@@ -762,10 +779,14 @@ pub fn internal_canvas_stroke<'gc>(
762779
&RenderState {
763780
fill_style: data.stroke_style,
764781
global_alpha: data.global_alpha,
765-
transform: [1.0, 0.0, 0.0, 1.0, 0.0, 0.0],
766-
line_cap: LineCap::default(),
767-
line_join: LineJoin::default(),
768-
miter_limit: 10.0,
782+
transform: data.transform,
783+
line_cap: data.line_cap,
784+
line_join: data.line_join,
785+
miter_limit: data.miter_limit,
786+
shadow_blur: data.shadow_blur,
787+
shadow_color: data.shadow_color,
788+
shadow_offset_x: data.shadow_offset_x,
789+
shadow_offset_y: data.shadow_offset_y,
769790
composite_operation: data.composite_operation,
770791
},
771792
);
@@ -1182,9 +1203,13 @@ pub fn internal_canvas_save<'gc>(
11821203
transform: data.transform,
11831204
line_dash: data.line_dash.clone(),
11841205
line_dash_offset: data.line_dash_offset,
1185-
line_cap: LineCap::default(),
1186-
line_join: LineJoin::default(),
1187-
miter_limit: 10.0,
1206+
line_cap: data.line_cap,
1207+
line_join: data.line_join,
1208+
miter_limit: data.miter_limit,
1209+
shadow_blur: data.shadow_blur,
1210+
shadow_color: data.shadow_color.clone(),
1211+
shadow_offset_x: data.shadow_offset_x,
1212+
shadow_offset_y: data.shadow_offset_y,
11881213
composite_operation: data.composite_operation,
11891214
};
11901215
data.state_stack.push(current_state);
@@ -1231,16 +1256,31 @@ pub fn internal_canvas_restore<'gc>(
12311256
Ok(Value::Undefined)
12321257
}
12331258

1259+
/// Rendering context parameters grouped to avoid too many function arguments
1260+
#[allow(dead_code)]
1261+
pub struct RenderContext<'a> {
1262+
pub fill_style: &'a crate::ext::canvas::FillStyle,
1263+
pub stroke_style: &'a crate::ext::canvas::FillStyle,
1264+
pub line_width: f64,
1265+
pub global_alpha: f32,
1266+
pub transform: [f64; 6],
1267+
pub line_cap: LineCap,
1268+
pub line_join: LineJoin,
1269+
pub miter_limit: f64,
1270+
pub composite_operation: CompositeOperation,
1271+
pub shadow_blur: f64,
1272+
pub shadow_color: &'a crate::ext::canvas::FillStyle,
1273+
pub shadow_offset_x: f64,
1274+
pub shadow_offset_y: f64,
1275+
}
1276+
12341277
/// Process all saved commands and render them using the renderer
12351278
#[allow(dead_code, clippy::needless_lifetimes)]
12361279
pub fn process_all_commands<'gc>(
12371280
commands: &Vec<CanvasCommand<'gc>>,
12381281
renderer: &mut crate::ext::canvas::renderer::Renderer,
12391282
agent: &mut Agent,
1240-
fill_style: &crate::ext::canvas::FillStyle,
1241-
stroke_style: &crate::ext::canvas::FillStyle,
1242-
line_width: f64,
1243-
global_alpha: f32,
1283+
ctx: &RenderContext<'_>,
12441284
) {
12451285
let mut current_path = Vec::new();
12461286

@@ -1371,13 +1411,17 @@ pub fn process_all_commands<'gc>(
13711411
renderer.render_polygon(
13721412
current_path.clone(),
13731413
&RenderState {
1374-
fill_style: fill_style.clone(),
1375-
global_alpha,
1376-
transform: [1.0, 0.0, 0.0, 1.0, 0.0, 0.0],
1377-
line_cap: LineCap::default(),
1378-
line_join: LineJoin::default(),
1379-
miter_limit: 10.0,
1380-
composite_operation: CompositeOperation::default(),
1414+
fill_style: ctx.fill_style.clone(),
1415+
global_alpha: ctx.global_alpha,
1416+
transform: ctx.transform,
1417+
line_cap: ctx.line_cap,
1418+
line_join: ctx.line_join,
1419+
miter_limit: ctx.miter_limit,
1420+
shadow_blur: ctx.shadow_blur,
1421+
shadow_color: ctx.shadow_color.clone(),
1422+
shadow_offset_x: ctx.shadow_offset_x,
1423+
shadow_offset_y: ctx.shadow_offset_y,
1424+
composite_operation: ctx.composite_operation,
13811425
},
13821426
);
13831427
}
@@ -1387,15 +1431,19 @@ pub fn process_all_commands<'gc>(
13871431
renderer.render_polyline(
13881432
current_path.clone(),
13891433
&RenderState {
1390-
fill_style: stroke_style.clone(),
1391-
global_alpha,
1392-
transform: [1.0, 0.0, 0.0, 1.0, 0.0, 0.0],
1393-
line_cap: LineCap::default(),
1394-
line_join: LineJoin::default(),
1395-
miter_limit: 10.0,
1396-
composite_operation: CompositeOperation::default(),
1434+
fill_style: ctx.stroke_style.clone(),
1435+
global_alpha: ctx.global_alpha,
1436+
transform: ctx.transform,
1437+
line_cap: ctx.line_cap,
1438+
line_join: ctx.line_join,
1439+
miter_limit: ctx.miter_limit,
1440+
shadow_blur: ctx.shadow_blur,
1441+
shadow_color: ctx.shadow_color.clone(),
1442+
shadow_offset_x: ctx.shadow_offset_x,
1443+
shadow_offset_y: ctx.shadow_offset_y,
1444+
composite_operation: ctx.composite_operation,
13971445
},
1398-
line_width,
1446+
ctx.line_width,
13991447
);
14001448
}
14011449
}
@@ -1420,13 +1468,17 @@ pub fn process_all_commands<'gc>(
14201468
renderer.render_rect(
14211469
rect,
14221470
&RenderState {
1423-
fill_style: fill_style.clone(),
1424-
global_alpha,
1425-
transform: [1.0, 0.0, 0.0, 1.0, 0.0, 0.0],
1426-
line_cap: LineCap::default(),
1427-
line_join: LineJoin::default(),
1428-
miter_limit: 10.0,
1429-
composite_operation: CompositeOperation::default(),
1471+
fill_style: ctx.fill_style.clone(),
1472+
global_alpha: ctx.global_alpha,
1473+
transform: ctx.transform,
1474+
line_cap: ctx.line_cap,
1475+
line_join: ctx.line_join,
1476+
miter_limit: ctx.miter_limit,
1477+
shadow_blur: ctx.shadow_blur,
1478+
shadow_color: ctx.shadow_color.clone(),
1479+
shadow_offset_x: ctx.shadow_offset_x,
1480+
shadow_offset_y: ctx.shadow_offset_y,
1481+
composite_operation: ctx.composite_operation,
14301482
},
14311483
);
14321484
}
@@ -1461,15 +1513,19 @@ pub fn process_all_commands<'gc>(
14611513
renderer.render_polyline(
14621514
rect_path,
14631515
&RenderState {
1464-
fill_style: stroke_style.clone(),
1465-
global_alpha,
1466-
transform: [1.0, 0.0, 0.0, 1.0, 0.0, 0.0],
1467-
line_cap: LineCap::default(),
1468-
line_join: LineJoin::default(),
1469-
miter_limit: 10.0,
1470-
composite_operation: CompositeOperation::default(),
1516+
fill_style: ctx.stroke_style.clone(),
1517+
global_alpha: ctx.global_alpha,
1518+
transform: ctx.transform,
1519+
line_cap: ctx.line_cap,
1520+
line_join: ctx.line_join,
1521+
miter_limit: ctx.miter_limit,
1522+
shadow_blur: ctx.shadow_blur,
1523+
shadow_color: ctx.shadow_color.clone(),
1524+
shadow_offset_x: ctx.shadow_offset_x,
1525+
shadow_offset_y: ctx.shadow_offset_y,
1526+
composite_operation: ctx.composite_operation,
14711527
},
1472-
line_width,
1528+
ctx.line_width,
14731529
);
14741530
}
14751531
CanvasCommand::ClearRect {
@@ -1505,6 +1561,15 @@ pub fn process_all_commands<'gc>(
15051561
line_cap: LineCap::default(),
15061562
line_join: LineJoin::default(),
15071563
miter_limit: 10.0,
1564+
shadow_blur: 0.0,
1565+
shadow_color: FillStyle::Color {
1566+
r: 0.0,
1567+
g: 0.0,
1568+
b: 0.0,
1569+
a: 0.0,
1570+
},
1571+
shadow_offset_x: 0.0,
1572+
shadow_offset_y: 0.0,
15081573
composite_operation: CompositeOperation::default(),
15091574
},
15101575
); // White background
@@ -1553,13 +1618,17 @@ pub fn process_all_commands<'gc>(
15531618
} => {
15541619
// Create render state for the image
15551620
let render_state = RenderState {
1556-
fill_style: fill_style.clone(),
1557-
global_alpha,
1558-
transform: [1.0, 0.0, 0.0, 1.0, 0.0, 0.0], // Use identity transform for now
1559-
line_cap: LineCap::default(),
1560-
line_join: LineJoin::default(),
1561-
miter_limit: 10.0,
1562-
composite_operation: CompositeOperation::default(),
1621+
fill_style: ctx.fill_style.clone(),
1622+
global_alpha: ctx.global_alpha,
1623+
transform: ctx.transform,
1624+
line_cap: ctx.line_cap,
1625+
line_join: ctx.line_join,
1626+
miter_limit: ctx.miter_limit,
1627+
shadow_blur: ctx.shadow_blur,
1628+
shadow_color: ctx.shadow_color.clone(),
1629+
shadow_offset_x: ctx.shadow_offset_x,
1630+
shadow_offset_y: ctx.shadow_offset_y,
1631+
composite_operation: ctx.composite_operation,
15631632
};
15641633

15651634
// Render the image

runtime/src/ext/canvas/fill_style.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

55
use crate::ext::canvas::renderer::{ColorStop, Coordinate};
6+
use std::str::FromStr;
67

78
/// Represents different fill styles for Canvas 2D operations
89
#[derive(Clone, Debug)]
@@ -17,8 +18,33 @@ pub enum FillStyle {
1718
LinearGradient(LinearGradient),
1819
RadialGradient(RadialGradient),
1920
ConicGradient(ConicGradient),
20-
/// Pattern (placeholder for future implementation)
21-
Pattern,
21+
/// Pattern with image resource ID and repetition mode
22+
Pattern {
23+
image_rid: u32,
24+
repetition: PatternRepetition,
25+
},
26+
}
27+
28+
/// Pattern repetition modes
29+
#[derive(Clone, Debug, PartialEq)]
30+
pub enum PatternRepetition {
31+
Repeat,
32+
RepeatX,
33+
RepeatY,
34+
NoRepeat,
35+
}
36+
37+
impl FromStr for PatternRepetition {
38+
type Err = ();
39+
40+
fn from_str(s: &str) -> Result<Self, Self::Err> {
41+
Ok(match s {
42+
"repeat-x" => Self::RepeatX,
43+
"repeat-y" => Self::RepeatY,
44+
"no-repeat" => Self::NoRepeat,
45+
_ => Self::Repeat, // default
46+
})
47+
}
2248
}
2349

2450
#[derive(Clone, Debug)]

0 commit comments

Comments
 (0)