Skip to content

Commit d193ab6

Browse files
committed
implement basic support for fillStyle
1 parent 4872aab commit d193ab6

File tree

2 files changed

+206
-11
lines changed

2 files changed

+206
-11
lines changed

src/browser/canvas/CanvasRenderingContext2D.zig

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,43 @@
1616
// You should have received a copy of the GNU Affero General Public License
1717
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1818

19+
const std = @import("std");
20+
21+
const color = @import("../cssom/color.zig");
22+
const Page = @import("../page.zig").Page;
23+
1924
/// This class doesn't implement a `constructor`.
2025
/// It can be obtained with a call to `HTMLCanvasElement#getContext`.
2126
/// https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
2227
const CanvasRenderingContext2D = @This();
28+
/// Fill color.
29+
/// TODO: Add support for `CanvasGradient` and `CanvasPattern`.
30+
fill_style: color.RGBA = color.RGBA.Named.black,
2331

24-
pub fn _fillRect(x: f64, y: f64, width: f64, height: f64) void {
32+
pub fn _fillRect(
33+
self: *const CanvasRenderingContext2D,
34+
x: f64,
35+
y: f64,
36+
width: f64,
37+
height: f64,
38+
) void {
39+
_ = self;
2540
_ = x;
2641
_ = y;
2742
_ = width;
2843
_ = height;
2944
}
3045

31-
pub fn get_fillStyle(_: *const CanvasRenderingContext2D) []const u8 {
32-
return "";
46+
pub fn get_fillStyle(self: *const CanvasRenderingContext2D, page: *Page) ![]const u8 {
47+
var w = std.Io.Writer.Allocating.init(page.call_arena);
48+
try self.fill_style.format(&w.writer);
49+
return w.written();
3350
}
3451

35-
pub fn set_fillStyle(_: *const CanvasRenderingContext2D, _: []const u8) void {}
52+
pub fn set_fillStyle(
53+
self: *CanvasRenderingContext2D,
54+
value: []const u8,
55+
) !void {
56+
// Prefer the same fill_style if fails.
57+
self.fill_style = color.RGBA.parse(value) catch self.fill_style;
58+
}

src/browser/cssom/color.zig

Lines changed: 179 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,195 @@
1919
const std = @import("std");
2020
const Io = std.Io;
2121

22+
const CSSParser = @import("CSSParser.zig");
23+
const isHexColor = @import("CSSStyleDeclaration.zig").isHexColor;
24+
2225
pub const RGBA = packed struct(u32) {
2326
r: u8,
2427
g: u8,
2528
b: u8,
29+
/// Opaque by default.
2630
a: u8 = std.math.maxInt(u8),
2731

32+
pub const Named = struct {
33+
// Basic colors (CSS Level 1)
34+
pub const black: RGBA = .init(0, 0, 0, 1);
35+
pub const silver: RGBA = .init(192, 192, 192, 1);
36+
pub const gray: RGBA = .init(128, 128, 128, 1);
37+
pub const white: RGBA = .init(255, 255, 255, 1);
38+
pub const maroon: RGBA = .init(128, 0, 0, 1);
39+
pub const red: RGBA = .init(255, 0, 0, 1);
40+
pub const purple: RGBA = .init(128, 0, 128, 1);
41+
pub const fuchsia: RGBA = .init(255, 0, 255, 1);
42+
pub const green: RGBA = .init(0, 128, 0, 1);
43+
pub const lime: RGBA = .init(0, 255, 0, 1);
44+
pub const olive: RGBA = .init(128, 128, 0, 1);
45+
pub const yellow: RGBA = .init(255, 255, 0, 1);
46+
pub const navy: RGBA = .init(0, 0, 128, 1);
47+
pub const blue: RGBA = .init(0, 0, 255, 1);
48+
pub const teal: RGBA = .init(0, 128, 128, 1);
49+
pub const aqua: RGBA = .init(0, 255, 255, 1);
50+
51+
// Extended colors (CSS Level 2+)
52+
pub const aliceblue: RGBA = .init(240, 248, 255, 1);
53+
pub const antiquewhite: RGBA = .init(250, 235, 215, 1);
54+
pub const aquamarine: RGBA = .init(127, 255, 212, 1);
55+
pub const azure: RGBA = .init(240, 255, 255, 1);
56+
pub const beige: RGBA = .init(245, 245, 220, 1);
57+
pub const bisque: RGBA = .init(255, 228, 196, 1);
58+
pub const blanchedalmond: RGBA = .init(255, 235, 205, 1);
59+
pub const blueviolet: RGBA = .init(138, 43, 226, 1);
60+
pub const brown: RGBA = .init(165, 42, 42, 1);
61+
pub const burlywood: RGBA = .init(222, 184, 135, 1);
62+
pub const cadetblue: RGBA = .init(95, 158, 160, 1);
63+
pub const chartreuse: RGBA = .init(127, 255, 0, 1);
64+
pub const chocolate: RGBA = .init(210, 105, 30, 1);
65+
pub const coral: RGBA = .init(255, 127, 80, 1);
66+
pub const cornflowerblue: RGBA = .init(100, 149, 237, 1);
67+
pub const cornsilk: RGBA = .init(255, 248, 220, 1);
68+
pub const crimson: RGBA = .init(220, 20, 60, 1);
69+
pub const cyan: RGBA = .init(0, 255, 255, 1); // Synonym of aqua
70+
pub const darkblue: RGBA = .init(0, 0, 139, 1);
71+
pub const darkcyan: RGBA = .init(0, 139, 139, 1);
72+
pub const darkgoldenrod: RGBA = .init(184, 134, 11, 1);
73+
pub const darkgray: RGBA = .init(169, 169, 169, 1);
74+
pub const darkgreen: RGBA = .init(0, 100, 0, 1);
75+
pub const darkgrey: RGBA = .init(169, 169, 169, 1); // Synonym of darkgray
76+
pub const darkkhaki: RGBA = .init(189, 183, 107, 1);
77+
pub const darkmagenta: RGBA = .init(139, 0, 139, 1);
78+
pub const darkolivegreen: RGBA = .init(85, 107, 47, 1);
79+
pub const darkorange: RGBA = .init(255, 140, 0, 1);
80+
pub const darkorchid: RGBA = .init(153, 50, 204, 1);
81+
pub const darkred: RGBA = .init(139, 0, 0, 1);
82+
pub const darksalmon: RGBA = .init(233, 150, 122, 1);
83+
pub const darkseagreen: RGBA = .init(143, 188, 143, 1);
84+
pub const darkslateblue: RGBA = .init(72, 61, 139, 1);
85+
pub const darkslategray: RGBA = .init(47, 79, 79, 1);
86+
pub const darkslategrey: RGBA = .init(47, 79, 79, 1); // Synonym of darkslategray
87+
pub const darkturquoise: RGBA = .init(0, 206, 209, 1);
88+
pub const darkviolet: RGBA = .init(148, 0, 211, 1);
89+
pub const deeppink: RGBA = .init(255, 20, 147, 1);
90+
pub const deepskyblue: RGBA = .init(0, 191, 255, 1);
91+
pub const dimgray: RGBA = .init(105, 105, 105, 1);
92+
pub const dimgrey: RGBA = .init(105, 105, 105, 1); // Synonym of dimgray
93+
pub const dodgerblue: RGBA = .init(30, 144, 255, 1);
94+
pub const firebrick: RGBA = .init(178, 34, 34, 1);
95+
pub const floralwhite: RGBA = .init(255, 250, 240, 1);
96+
pub const forestgreen: RGBA = .init(34, 139, 34, 1);
97+
pub const gainsboro: RGBA = .init(220, 220, 220, 1);
98+
pub const ghostwhite: RGBA = .init(248, 248, 255, 1);
99+
pub const gold: RGBA = .init(255, 215, 0, 1);
100+
pub const goldenrod: RGBA = .init(218, 165, 32, 1);
101+
pub const greenyellow: RGBA = .init(173, 255, 47, 1);
102+
pub const grey: RGBA = .init(128, 128, 128, 1); // Synonym of gray
103+
pub const honeydew: RGBA = .init(240, 255, 240, 1);
104+
pub const hotpink: RGBA = .init(255, 105, 180, 1);
105+
pub const indianred: RGBA = .init(205, 92, 92, 1);
106+
pub const indigo: RGBA = .init(75, 0, 130, 1);
107+
pub const ivory: RGBA = .init(255, 255, 240, 1);
108+
pub const khaki: RGBA = .init(240, 230, 140, 1);
109+
pub const lavender: RGBA = .init(230, 230, 250, 1);
110+
pub const lavenderblush: RGBA = .init(255, 240, 245, 1);
111+
pub const lawngreen: RGBA = .init(124, 252, 0, 1);
112+
pub const lemonchiffon: RGBA = .init(255, 250, 205, 1);
113+
pub const lightblue: RGBA = .init(173, 216, 230, 1);
114+
pub const lightcoral: RGBA = .init(240, 128, 128, 1);
115+
pub const lightcyan: RGBA = .init(224, 255, 255, 1);
116+
pub const lightgoldenrodyellow: RGBA = .init(250, 250, 210, 1);
117+
pub const lightgray: RGBA = .init(211, 211, 211, 1);
118+
pub const lightgreen: RGBA = .init(144, 238, 144, 1);
119+
pub const lightgrey: RGBA = .init(211, 211, 211, 1); // Synonym of lightgray
120+
pub const lightpink: RGBA = .init(255, 182, 193, 1);
121+
pub const lightsalmon: RGBA = .init(255, 160, 122, 1);
122+
pub const lightseagreen: RGBA = .init(32, 178, 170, 1);
123+
pub const lightskyblue: RGBA = .init(135, 206, 250, 1);
124+
pub const lightslategray: RGBA = .init(119, 136, 153, 1);
125+
pub const lightslategrey: RGBA = .init(119, 136, 153, 1); // Synonym of lightslategray
126+
pub const lightsteelblue: RGBA = .init(176, 196, 222, 1);
127+
pub const lightyellow: RGBA = .init(255, 255, 224, 1);
128+
pub const limegreen: RGBA = .init(50, 205, 50, 1);
129+
pub const linen: RGBA = .init(250, 240, 230, 1);
130+
pub const magenta: RGBA = .init(255, 0, 255, 1); // Synonym of fuchsia
131+
pub const mediumaquamarine: RGBA = .init(102, 205, 170, 1);
132+
pub const mediumblue: RGBA = .init(0, 0, 205, 1);
133+
pub const mediumorchid: RGBA = .init(186, 85, 211, 1);
134+
pub const mediumpurple: RGBA = .init(147, 112, 219, 1);
135+
pub const mediumseagreen: RGBA = .init(60, 179, 113, 1);
136+
pub const mediumslateblue: RGBA = .init(123, 104, 238, 1);
137+
pub const mediumspringgreen: RGBA = .init(0, 250, 154, 1);
138+
pub const mediumturquoise: RGBA = .init(72, 209, 204, 1);
139+
pub const mediumvioletred: RGBA = .init(199, 21, 133, 1);
140+
pub const midnightblue: RGBA = .init(25, 25, 112, 1);
141+
pub const mintcream: RGBA = .init(245, 255, 250, 1);
142+
pub const mistyrose: RGBA = .init(255, 228, 225, 1);
143+
pub const moccasin: RGBA = .init(255, 228, 181, 1);
144+
pub const navajowhite: RGBA = .init(255, 222, 173, 1);
145+
pub const oldlace: RGBA = .init(253, 245, 230, 1);
146+
pub const olivedrab: RGBA = .init(107, 142, 35, 1);
147+
pub const orange: RGBA = .init(255, 165, 0, 1);
148+
pub const orangered: RGBA = .init(255, 69, 0, 1);
149+
pub const orchid: RGBA = .init(218, 112, 214, 1);
150+
pub const palegoldenrod: RGBA = .init(238, 232, 170, 1);
151+
pub const palegreen: RGBA = .init(152, 251, 152, 1);
152+
pub const paleturquoise: RGBA = .init(175, 238, 238, 1);
153+
pub const palevioletred: RGBA = .init(219, 112, 147, 1);
154+
pub const papayawhip: RGBA = .init(255, 239, 213, 1);
155+
pub const peachpuff: RGBA = .init(255, 218, 185, 1);
156+
pub const peru: RGBA = .init(205, 133, 63, 1);
157+
pub const pink: RGBA = .init(255, 192, 203, 1);
158+
pub const plum: RGBA = .init(221, 160, 221, 1);
159+
pub const powderblue: RGBA = .init(176, 224, 230, 1);
160+
pub const rebeccapurple: RGBA = .init(102, 51, 153, 1);
161+
pub const rosybrown: RGBA = .init(188, 143, 143, 1);
162+
pub const royalblue: RGBA = .init(65, 105, 225, 1);
163+
pub const saddlebrown: RGBA = .init(139, 69, 19, 1);
164+
pub const salmon: RGBA = .init(250, 128, 114, 1);
165+
pub const sandybrown: RGBA = .init(244, 164, 96, 1);
166+
pub const seagreen: RGBA = .init(46, 139, 87, 1);
167+
pub const seashell: RGBA = .init(255, 245, 238, 1);
168+
pub const sienna: RGBA = .init(160, 82, 45, 1);
169+
pub const skyblue: RGBA = .init(135, 206, 235, 1);
170+
pub const slateblue: RGBA = .init(106, 90, 205, 1);
171+
pub const slategray: RGBA = .init(112, 128, 144, 1);
172+
pub const slategrey: RGBA = .init(112, 128, 144, 1); // Synonym of slategray
173+
pub const snow: RGBA = .init(255, 250, 250, 1);
174+
pub const springgreen: RGBA = .init(0, 255, 127, 1);
175+
pub const steelblue: RGBA = .init(70, 130, 180, 1);
176+
pub const tan: RGBA = .init(210, 180, 140, 1);
177+
pub const thistle: RGBA = .init(216, 191, 216, 1);
178+
pub const tomato: RGBA = .init(255, 99, 71, 1);
179+
pub const transparent: RGBA = .init(0, 0, 0, 0);
180+
pub const turquoise: RGBA = .init(64, 224, 208, 1);
181+
pub const violet: RGBA = .init(238, 130, 238, 1);
182+
pub const wheat: RGBA = .init(245, 222, 179, 1);
183+
pub const whitesmoke: RGBA = .init(245, 245, 245, 1);
184+
pub const yellowgreen: RGBA = .init(154, 205, 50, 1);
185+
};
186+
28187
pub fn init(r: u8, g: u8, b: u8, a: f32) RGBA {
29188
const clamped = std.math.clamp(a, 0, 1);
30189
return .{ .r = r, .g = g, .b = b, .a = @intFromFloat(clamped * 255) };
31190
}
32191

33-
/// Initializes a `Color` by parsing the given HEX.
34-
/// HEX is either represented as RGB or RGBA by `Color`.
35-
pub fn initFromHex(hex: []const u8) !RGBA {
36-
// HEX is bit weird; its length (hash omitted) can be 3, 4, 6 or 8.
37-
// The parsing gets a bit different depending on it.
38-
const slice = hex[1..];
192+
/// Finds a color by its name.
193+
pub fn find(name: []const u8) ?RGBA {
194+
const match = std.meta.stringToEnum(std.meta.DeclEnum(Named), name) orelse return null;
195+
196+
return switch (match) {
197+
inline else => |comptime_enum| @field(Named, @tagName(comptime_enum)),
198+
};
199+
}
200+
201+
/// Parses the given color.
202+
/// Currently we only parse hex colors and named colors; other variants
203+
/// require CSS evaluation.
204+
pub fn parse(input: []const u8) !RGBA {
205+
if (!isHexColor(input)) {
206+
// Try named colors.
207+
return find(input) orelse return error.Invalid;
208+
}
209+
210+
const slice = input[1..];
39211
switch (slice.len) {
40212
// This means the digit for a color is repeated.
41213
// Given HEX is #f0c, its interpreted the same as #FF00CC.
@@ -66,7 +238,7 @@ pub const RGBA = packed struct(u32) {
66238
const a = try std.fmt.parseInt(u8, slice[6..8], 16);
67239
return .{ .r = r, .g = g, .b = b, .a = a };
68240
},
69-
else => unreachable,
241+
else => return error.Invalid,
70242
}
71243
}
72244

0 commit comments

Comments
 (0)