mirror of
https://github.com/oven-sh/bun
synced 2026-02-10 02:48:50 +00:00
880 lines
39 KiB
Zig
880 lines
39 KiB
Zig
const std = @import("std");
|
|
const bun = @import("root").bun;
|
|
const Allocator = std.mem.Allocator;
|
|
const ArrayList = std.ArrayListUnmanaged;
|
|
|
|
pub const css = @import("../css_parser.zig");
|
|
|
|
const SmallList = css.SmallList;
|
|
const Printer = css.Printer;
|
|
const PrintErr = css.PrintErr;
|
|
const Result = css.Result;
|
|
|
|
const ContainerName = css.css_rules.container.ContainerName;
|
|
|
|
const LengthPercentage = css.css_values.length.LengthPercentage;
|
|
const CustomIdent = css.css_values.ident.CustomIdent;
|
|
const CSSString = css.css_values.string.CSSString;
|
|
const CSSNumber = css.css_values.number.CSSNumber;
|
|
const LengthPercentageOrAuto = css.css_values.length.LengthPercentageOrAuto;
|
|
const Size2D = css.css_values.size.Size2D;
|
|
const DashedIdent = css.css_values.ident.DashedIdent;
|
|
const Image = css.css_values.image.Image;
|
|
const CssColor = css.css_values.color.CssColor;
|
|
const Ratio = css.css_values.ratio.Ratio;
|
|
const Length = css.css_values.length.LengthValue;
|
|
const Rect = css.css_values.rect.Rect;
|
|
const NumberOrPercentage = css.css_values.percentage.NumberOrPercentage;
|
|
const CustomIdentList = css.css_values.ident.CustomIdentList;
|
|
const Angle = css.css_values.angle.Angle;
|
|
const Url = css.css_values.url.Url;
|
|
const Percentage = css.css_values.percentage.Percentage;
|
|
|
|
const GenericBorder = css.css_properties.border.GenericBorder;
|
|
const LineStyle = css.css_properties.border.LineStyle;
|
|
|
|
/// A value for the [transform](https://www.w3.org/TR/2019/CR-css-transforms-1-20190214/#propdef-transform) property.
|
|
pub const TransformList = struct {
|
|
v: ArrayList(Transform),
|
|
|
|
pub fn parse(input: *css.Parser) Result(@This()) {
|
|
if (input.tryParse(css.Parser.expectIdentMatching, .{"none"}).isOk()) {
|
|
return .{ .result = .{ .v = .{} } };
|
|
}
|
|
|
|
input.skipWhitespace();
|
|
var results = ArrayList(Transform){};
|
|
switch (Transform.parse(input)) {
|
|
.result => |first| results.append(input.allocator(), first) catch bun.outOfMemory(),
|
|
.err => |e| return .{ .err = e },
|
|
}
|
|
|
|
while (true) {
|
|
input.skipWhitespace();
|
|
if (input.tryParse(Transform.parse, .{}).asValue()) |item| {
|
|
results.append(input.allocator(), item) catch bun.outOfMemory();
|
|
} else {
|
|
return .{ .result = .{ .v = results } };
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn toCss(this: *const @This(), comptime W: type, dest: *Printer(W)) PrintErr!void {
|
|
if (this.v.items.len == 0) {
|
|
return dest.writeStr("none");
|
|
}
|
|
|
|
// TODO: Re-enable with a better solution
|
|
// See: https://github.com/parcel-bundler/lightningcss/issues/288
|
|
if (dest.minify) {
|
|
var base = ArrayList(u8){};
|
|
const base_writer = base.writer(dest.allocator);
|
|
const WW = @TypeOf(base_writer);
|
|
|
|
var scratchbuf = std.ArrayList(u8).init(dest.allocator);
|
|
defer scratchbuf.deinit();
|
|
var p = Printer(WW).new(
|
|
dest.allocator,
|
|
scratchbuf,
|
|
base_writer,
|
|
css.PrinterOptions.defaultWithMinify(true),
|
|
dest.import_records,
|
|
);
|
|
defer p.deinit();
|
|
|
|
try this.toCssBase(WW, &p);
|
|
|
|
return dest.writeStr(base.items);
|
|
}
|
|
}
|
|
|
|
fn toCssBase(this: *const @This(), comptime W: type, dest: *Printer(W)) PrintErr!void {
|
|
for (this.v.items) |*item| {
|
|
try item.toCss(W, dest);
|
|
}
|
|
}
|
|
|
|
pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() {
|
|
return css.implementDeepClone(@This(), this, allocator);
|
|
}
|
|
};
|
|
|
|
/// An individual transform function (https://www.w3.org/TR/2019/CR-css-transforms-1-20190214/#two-d-transform-functions).
|
|
pub const Transform = union(enum) {
|
|
/// A 2D translation.
|
|
translate: struct {
|
|
x: LengthPercentage,
|
|
y: LengthPercentage,
|
|
|
|
pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() {
|
|
return css.implementDeepClone(@This(), this, allocator);
|
|
}
|
|
},
|
|
/// A translation in the X direction.
|
|
translate_x: LengthPercentage,
|
|
/// A translation in the Y direction.
|
|
translate_y: LengthPercentage,
|
|
/// A translation in the Z direction.
|
|
translate_z: Length,
|
|
/// A 3D translation.
|
|
translate_3d: struct {
|
|
x: LengthPercentage,
|
|
y: LengthPercentage,
|
|
z: Length,
|
|
|
|
pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() {
|
|
return css.implementDeepClone(@This(), this, allocator);
|
|
}
|
|
},
|
|
/// A 2D scale.
|
|
scale: struct {
|
|
x: NumberOrPercentage,
|
|
y: NumberOrPercentage,
|
|
|
|
pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() {
|
|
return css.implementDeepClone(@This(), this, allocator);
|
|
}
|
|
},
|
|
/// A scale in the X direction.
|
|
scale_x: NumberOrPercentage,
|
|
/// A scale in the Y direction.
|
|
scale_y: NumberOrPercentage,
|
|
/// A scale in the Z direction.
|
|
scale_z: NumberOrPercentage,
|
|
/// A 3D scale.
|
|
scale_3d: struct {
|
|
x: NumberOrPercentage,
|
|
y: NumberOrPercentage,
|
|
z: NumberOrPercentage,
|
|
|
|
pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() {
|
|
return css.implementDeepClone(@This(), this, allocator);
|
|
}
|
|
},
|
|
/// A 2D rotation.
|
|
rotate: Angle,
|
|
/// A rotation around the X axis.
|
|
rotate_x: Angle,
|
|
/// A rotation around the Y axis.
|
|
rotate_y: Angle,
|
|
/// A rotation around the Z axis.
|
|
rotate_z: Angle,
|
|
/// A 3D rotation.
|
|
rotate_3d: struct {
|
|
x: f32,
|
|
y: f32,
|
|
z: f32,
|
|
angle: Angle,
|
|
|
|
pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() {
|
|
return css.implementDeepClone(@This(), this, allocator);
|
|
}
|
|
},
|
|
/// A 2D skew.
|
|
skew: struct {
|
|
x: Angle,
|
|
y: Angle,
|
|
|
|
pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() {
|
|
return css.implementDeepClone(@This(), this, allocator);
|
|
}
|
|
},
|
|
/// A skew along the X axis.
|
|
skew_x: Angle,
|
|
/// A skew along the Y axis.
|
|
skew_y: Angle,
|
|
/// A perspective transform.
|
|
perspective: Length,
|
|
/// A 2D matrix transform.
|
|
matrix: Matrix(f32),
|
|
/// A 3D matrix transform.
|
|
matrix_3d: Matrix3d(f32),
|
|
|
|
pub fn parse(input: *css.Parser) Result(Transform) {
|
|
const function = switch (input.expectFunction()) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
|
|
const Closure = struct { function: []const u8 };
|
|
return input.parseNestedBlock(
|
|
Transform,
|
|
Closure{ .function = function },
|
|
struct {
|
|
fn parse(closure: Closure, i: *css.Parser) css.Result(Transform) {
|
|
const location = i.currentSourceLocation();
|
|
if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "matrix")) {
|
|
const a = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const b = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const c = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const d = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const e = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |ee| return .{ .err = ee };
|
|
const f = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |ee| return .{ .err = ee },
|
|
};
|
|
return .{ .result = .{ .matrix = .{ .a = a, .b = b, .c = c, .d = d, .e = e, .f = f } } };
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "matrix3d")) {
|
|
const m11 = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const m12 = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const m13 = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const m14 = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const m21 = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const m22 = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const m23 = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const m24 = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const m31 = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const m32 = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const m33 = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const m34 = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const m41 = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const m42 = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const m43 = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const m44 = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .matrix_3d = .{
|
|
.m11 = m11,
|
|
.m12 = m12,
|
|
.m13 = m13,
|
|
.m14 = m14,
|
|
.m21 = m21,
|
|
.m22 = m22,
|
|
.m23 = m23,
|
|
.m24 = m24,
|
|
.m31 = m31,
|
|
.m32 = m32,
|
|
.m33 = m33,
|
|
.m34 = m34,
|
|
.m41 = m41,
|
|
.m42 = m42,
|
|
.m43 = m43,
|
|
.m44 = m44,
|
|
} } };
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "translate")) {
|
|
const x = switch (LengthPercentage.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.tryParse(struct {
|
|
fn parse(p: *css.Parser) css.Result(void) {
|
|
return p.expectComma();
|
|
}
|
|
}.parse, .{}).isOk()) {
|
|
const y = switch (LengthPercentage.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .translate = .{ .x = x, .y = y } } };
|
|
} else {
|
|
return .{ .result = .{ .translate = .{ .x = x, .y = LengthPercentage.zero() } } };
|
|
}
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "translatex")) {
|
|
const x = switch (LengthPercentage.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .translate_x = x } };
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "translatey")) {
|
|
const y = switch (LengthPercentage.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .translate_y = y } };
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "translatez")) {
|
|
const z = switch (Length.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .translate_z = z } };
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "translate3d")) {
|
|
const x = switch (LengthPercentage.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const y = switch (LengthPercentage.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const z = switch (Length.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .translate_3d = .{ .x = x, .y = y, .z = z } } };
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "scale")) {
|
|
const x = switch (NumberOrPercentage.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.tryParse(struct {
|
|
fn parse(p: *css.Parser) css.Result(void) {
|
|
return p.expectComma();
|
|
}
|
|
}.parse, .{}).isOk()) {
|
|
const y = switch (NumberOrPercentage.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .scale = .{ .x = x, .y = y } } };
|
|
} else {
|
|
return .{ .result = .{ .scale = .{ .x = x, .y = x.deepClone(i.allocator()) } } };
|
|
}
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "scalex")) {
|
|
const x = switch (NumberOrPercentage.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .scale_x = x } };
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "scaley")) {
|
|
const y = switch (NumberOrPercentage.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .scale_y = y } };
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "scalez")) {
|
|
const z = switch (NumberOrPercentage.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .scale_z = z } };
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "scale3d")) {
|
|
const x = switch (NumberOrPercentage.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const y = switch (NumberOrPercentage.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const z = switch (NumberOrPercentage.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .scale_3d = .{ .x = x, .y = y, .z = z } } };
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "rotate")) {
|
|
const angle = switch (Angle.parseWithUnitlessZero(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .rotate = angle } };
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "rotatex")) {
|
|
const angle = switch (Angle.parseWithUnitlessZero(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .rotate_x = angle } };
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "rotatey")) {
|
|
const angle = switch (Angle.parseWithUnitlessZero(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .rotate_y = angle } };
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "rotatez")) {
|
|
const angle = switch (Angle.parseWithUnitlessZero(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .rotate_z = angle } };
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "rotate3d")) {
|
|
const x = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const y = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const z = switch (css.CSSNumberFns.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.expectComma().asErr()) |e| return .{ .err = e };
|
|
const angle = switch (Angle.parseWithUnitlessZero(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .rotate_3d = .{ .x = x, .y = y, .z = z, .angle = angle } } };
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "skew")) {
|
|
const x = switch (Angle.parseWithUnitlessZero(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
if (i.tryParse(struct {
|
|
fn parse(p: *css.Parser) css.Result(void) {
|
|
return p.expectComma();
|
|
}
|
|
}.parse, .{}).isOk()) {
|
|
const y = switch (Angle.parseWithUnitlessZero(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .skew = .{ .x = x, .y = y } } };
|
|
} else {
|
|
return .{ .result = .{ .skew = .{ .x = x, .y = Angle{ .deg = 0.0 } } } };
|
|
}
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "skewx")) {
|
|
const angle = switch (Angle.parseWithUnitlessZero(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .skew_x = angle } };
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "skewy")) {
|
|
const angle = switch (Angle.parseWithUnitlessZero(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .skew_y = angle } };
|
|
} else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "perspective")) {
|
|
const len = switch (Length.parse(i)) {
|
|
.result => |v| v,
|
|
.err => |e| return .{ .err = e },
|
|
};
|
|
return .{ .result = .{ .perspective = len } };
|
|
} else {
|
|
return .{ .err = location.newUnexpectedTokenError(.{ .ident = closure.function }) };
|
|
}
|
|
}
|
|
}.parse,
|
|
);
|
|
}
|
|
|
|
pub fn toCss(this: *const @This(), comptime W: type, dest: *Printer(W)) PrintErr!void {
|
|
switch (this.*) {
|
|
.translate => |t| {
|
|
if (dest.minify and t.x.isZero() and !t.y.isZero()) {
|
|
try dest.writeStr("translateY(");
|
|
try t.y.toCss(W, dest);
|
|
} else {
|
|
try dest.writeStr("translate(");
|
|
try t.x.toCss(W, dest);
|
|
if (!t.y.isZero()) {
|
|
try dest.delim(',', false);
|
|
try t.y.toCss(W, dest);
|
|
}
|
|
}
|
|
try dest.writeChar(')');
|
|
},
|
|
.translate_x => |x| {
|
|
try dest.writeStr(if (dest.minify) "translate(" else "translateX(");
|
|
try x.toCss(W, dest);
|
|
try dest.writeChar(')');
|
|
},
|
|
.translate_y => |y| {
|
|
try dest.writeStr("translateY(");
|
|
try y.toCss(W, dest);
|
|
try dest.writeChar(')');
|
|
},
|
|
.translate_z => |z| {
|
|
try dest.writeStr("translateZ(");
|
|
try z.toCss(W, dest);
|
|
try dest.writeChar(')');
|
|
},
|
|
.translate_3d => |t| {
|
|
if (dest.minify and !t.x.isZero() and t.y.isZero() and t.z.isZero()) {
|
|
try dest.writeStr("translate(");
|
|
try t.x.toCss(W, dest);
|
|
} else if (dest.minify and t.x.isZero() and !t.y.isZero() and t.z.isZero()) {
|
|
try dest.writeStr("translateY(");
|
|
try t.y.toCss(W, dest);
|
|
} else if (dest.minify and t.x.isZero() and t.y.isZero() and !t.z.isZero()) {
|
|
try dest.writeStr("translateZ(");
|
|
try t.z.toCss(W, dest);
|
|
} else if (dest.minify and t.z.isZero()) {
|
|
try dest.writeStr("translate(");
|
|
try t.x.toCss(W, dest);
|
|
try dest.delim(',', false);
|
|
try t.y.toCss(W, dest);
|
|
} else {
|
|
try dest.writeStr("translate3d(");
|
|
try t.x.toCss(W, dest);
|
|
try dest.delim(',', false);
|
|
try t.y.toCss(W, dest);
|
|
try dest.delim(',', false);
|
|
try t.z.toCss(W, dest);
|
|
}
|
|
try dest.writeChar(')');
|
|
},
|
|
.scale => |s| {
|
|
const x: f32 = s.x.intoF32();
|
|
const y: f32 = s.y.intoF32();
|
|
if (dest.minify and x == 1.0 and y != 1.0) {
|
|
try dest.writeStr("scaleY(");
|
|
try css.CSSNumberFns.toCss(&y, W, dest);
|
|
} else if (dest.minify and x != 1.0 and y == 1.0) {
|
|
try dest.writeStr("scaleX(");
|
|
try css.CSSNumberFns.toCss(&x, W, dest);
|
|
} else {
|
|
try dest.writeStr("scale(");
|
|
try css.CSSNumberFns.toCss(&x, W, dest);
|
|
if (y != x) {
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&y, W, dest);
|
|
}
|
|
}
|
|
try dest.writeChar(')');
|
|
},
|
|
.scale_x => |x| {
|
|
try dest.writeStr("scaleX(");
|
|
try css.CSSNumberFns.toCss(&x.intoF32(), W, dest);
|
|
try dest.writeChar(')');
|
|
},
|
|
.scale_y => |y| {
|
|
try dest.writeStr("scaleY(");
|
|
try css.CSSNumberFns.toCss(&y.intoF32(), W, dest);
|
|
try dest.writeChar(')');
|
|
},
|
|
.scale_z => |z| {
|
|
try dest.writeStr("scaleZ(");
|
|
try css.CSSNumberFns.toCss(&z.intoF32(), W, dest);
|
|
try dest.writeChar(')');
|
|
},
|
|
.scale_3d => |s| {
|
|
const x: f32 = s.x.intoF32();
|
|
const y: f32 = s.y.intoF32();
|
|
const z: f32 = s.z.intoF32();
|
|
if (dest.minify and z == 1.0 and x == y) {
|
|
try dest.writeStr("scale(");
|
|
try css.CSSNumberFns.toCss(&x, W, dest);
|
|
} else if (dest.minify and x != 1.0 and y == 1.0 and z == 1.0) {
|
|
try dest.writeStr("scaleX(");
|
|
try css.CSSNumberFns.toCss(&x, W, dest);
|
|
} else if (dest.minify and x == 1.0 and y != 1.0 and z == 1.0) {
|
|
try dest.writeStr("scaleY(");
|
|
try css.CSSNumberFns.toCss(&y, W, dest);
|
|
} else if (dest.minify and x == 1.0 and y == 1.0 and z != 1.0) {
|
|
try dest.writeStr("scaleZ(");
|
|
try css.CSSNumberFns.toCss(&z, W, dest);
|
|
} else if (dest.minify and z == 1.0) {
|
|
try dest.writeStr("scale(");
|
|
try css.CSSNumberFns.toCss(&x, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&y, W, dest);
|
|
} else {
|
|
try dest.writeStr("scale3d(");
|
|
try css.CSSNumberFns.toCss(&x, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&y, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&z, W, dest);
|
|
}
|
|
try dest.writeChar(')');
|
|
},
|
|
.rotate => |angle| {
|
|
try dest.writeStr("rotate(");
|
|
try angle.toCssWithUnitlessZero(W, dest);
|
|
try dest.writeChar(')');
|
|
},
|
|
.rotate_x => |angle| {
|
|
try dest.writeStr("rotateX(");
|
|
try angle.toCssWithUnitlessZero(W, dest);
|
|
try dest.writeChar(')');
|
|
},
|
|
.rotate_y => |angle| {
|
|
try dest.writeStr("rotateY(");
|
|
try angle.toCssWithUnitlessZero(W, dest);
|
|
try dest.writeChar(')');
|
|
},
|
|
.rotate_z => |angle| {
|
|
try dest.writeStr(if (dest.minify) "rotate(" else "rotateZ(");
|
|
try angle.toCssWithUnitlessZero(W, dest);
|
|
try dest.writeChar(')');
|
|
},
|
|
.rotate_3d => |r| {
|
|
if (dest.minify and r.x == 1.0 and r.y == 0.0 and r.z == 0.0) {
|
|
try dest.writeStr("rotateX(");
|
|
try r.angle.toCssWithUnitlessZero(W, dest);
|
|
} else if (dest.minify and r.x == 0.0 and r.y == 1.0 and r.z == 0.0) {
|
|
try dest.writeStr("rotateY(");
|
|
try r.angle.toCssWithUnitlessZero(W, dest);
|
|
} else if (dest.minify and r.x == 0.0 and r.y == 0.0 and r.z == 1.0) {
|
|
try dest.writeStr("rotate(");
|
|
try r.angle.toCssWithUnitlessZero(W, dest);
|
|
} else {
|
|
try dest.writeStr("rotate3d(");
|
|
try css.CSSNumberFns.toCss(&r.x, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&r.y, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&r.z, W, dest);
|
|
try dest.delim(',', false);
|
|
try r.angle.toCssWithUnitlessZero(W, dest);
|
|
}
|
|
try dest.writeChar(')');
|
|
},
|
|
.skew => |s| {
|
|
if (dest.minify and s.x.isZero() and !s.y.isZero()) {
|
|
try dest.writeStr("skewY(");
|
|
try s.y.toCssWithUnitlessZero(W, dest);
|
|
} else {
|
|
try dest.writeStr("skew(");
|
|
try s.x.toCss(W, dest);
|
|
if (!s.y.isZero()) {
|
|
try dest.delim(',', false);
|
|
try s.y.toCssWithUnitlessZero(W, dest);
|
|
}
|
|
}
|
|
try dest.writeChar(')');
|
|
},
|
|
.skew_x => |angle| {
|
|
try dest.writeStr(if (dest.minify) "skew(" else "skewX(");
|
|
try angle.toCssWithUnitlessZero(W, dest);
|
|
try dest.writeChar(')');
|
|
},
|
|
.skew_y => |angle| {
|
|
try dest.writeStr("skewY(");
|
|
try angle.toCssWithUnitlessZero(W, dest);
|
|
try dest.writeChar(')');
|
|
},
|
|
.perspective => |len| {
|
|
try dest.writeStr("perspective(");
|
|
try len.toCss(W, dest);
|
|
try dest.writeChar(')');
|
|
},
|
|
.matrix => |m| {
|
|
try dest.writeStr("matrix(");
|
|
try css.CSSNumberFns.toCss(&m.a, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.b, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.c, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.d, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.e, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.f, W, dest);
|
|
try dest.writeChar(')');
|
|
},
|
|
.matrix_3d => |m| {
|
|
try dest.writeStr("matrix3d(");
|
|
try css.CSSNumberFns.toCss(&m.m11, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.m12, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.m13, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.m14, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.m21, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.m22, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.m23, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.m24, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.m31, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.m32, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.m33, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.m34, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.m41, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.m42, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.m43, W, dest);
|
|
try dest.delim(',', false);
|
|
try css.CSSNumberFns.toCss(&m.m44, W, dest);
|
|
try dest.writeChar(')');
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() {
|
|
return css.implementDeepClone(@This(), this, allocator);
|
|
}
|
|
};
|
|
|
|
/// A 2D matrix.
|
|
pub fn Matrix(comptime T: type) type {
|
|
return struct {
|
|
a: T,
|
|
b: T,
|
|
c: T,
|
|
d: T,
|
|
e: T,
|
|
f: T,
|
|
|
|
pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() {
|
|
return css.implementDeepClone(@This(), this, allocator);
|
|
}
|
|
|
|
pub fn eql(lhs: *const @This(), rhs: *const @This()) bool {
|
|
return css.implementEql(@This(), lhs, rhs);
|
|
}
|
|
};
|
|
}
|
|
|
|
/// A 3D matrix.
|
|
pub fn Matrix3d(comptime T: type) type {
|
|
return struct {
|
|
m11: T,
|
|
m12: T,
|
|
m13: T,
|
|
m14: T,
|
|
m21: T,
|
|
m22: T,
|
|
m23: T,
|
|
m24: T,
|
|
m31: T,
|
|
m32: T,
|
|
m33: T,
|
|
m34: T,
|
|
m41: T,
|
|
m42: T,
|
|
m43: T,
|
|
m44: T,
|
|
};
|
|
}
|
|
|
|
/// A value for the [transform-style](https://drafts.csswg.org/css-transforms-2/#transform-style-property) property.
|
|
pub const TransformStyle = css.DefineEnumProperty(@compileError(css.todo_stuff.depth));
|
|
|
|
/// A value for the [transform-box](https://drafts.csswg.org/css-transforms-1/#transform-box) property.
|
|
pub const TransformBox = css.DefineEnumProperty(@compileError(css.todo_stuff.depth));
|
|
|
|
/// A value for the [backface-visibility](https://drafts.csswg.org/css-transforms-2/#backface-visibility-property) property.
|
|
pub const BackfaceVisibility = css.DefineEnumProperty(@compileError(css.todo_stuff.depth));
|
|
|
|
/// A value for the perspective property.
|
|
pub const Perspective = union(enum) {
|
|
/// No perspective transform is applied.
|
|
none,
|
|
/// Distance to the center of projection.
|
|
length: Length,
|
|
};
|
|
|
|
/// A value for the [translate](https://drafts.csswg.org/css-transforms-2/#propdef-translate) property.
|
|
pub const Translate = union(enum) {
|
|
/// The "none" keyword.
|
|
none,
|
|
|
|
/// The x, y, and z translations.
|
|
xyz: struct {
|
|
/// The x translation.
|
|
x: LengthPercentage,
|
|
/// The y translation.
|
|
y: LengthPercentage,
|
|
/// The z translation.
|
|
z: Length,
|
|
},
|
|
};
|
|
|
|
/// A value for the [rotate](https://drafts.csswg.org/css-transforms-2/#propdef-rotate) property.
|
|
pub const Rotate = struct {
|
|
/// Rotation around the x axis.
|
|
x: f32,
|
|
/// Rotation around the y axis.
|
|
y: f32,
|
|
/// Rotation around the z axis.
|
|
z: f32,
|
|
/// The angle of rotation.
|
|
angle: Angle,
|
|
};
|
|
|
|
/// A value for the [scale](https://drafts.csswg.org/css-transforms-2/#propdef-scale) property.
|
|
pub const Scale = union(enum) {
|
|
/// The "none" keyword.
|
|
none,
|
|
|
|
/// Scale on the x, y, and z axis.
|
|
xyz: struct {
|
|
/// Scale on the x axis.
|
|
x: NumberOrPercentage,
|
|
/// Scale on the y axis.
|
|
y: NumberOrPercentage,
|
|
/// Scale on the z axis.
|
|
z: NumberOrPercentage,
|
|
},
|
|
};
|