mirror of
https://github.com/oven-sh/bun
synced 2026-02-05 00:18:53 +00:00
Compare commits
4 Commits
claude/imp
...
claude/css
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d299786ee1 | ||
|
|
60388f3625 | ||
|
|
a1e904a36a | ||
|
|
cde03cc3e7 |
1
invalid.css
Normal file
1
invalid.css
Normal file
@@ -0,0 +1 @@
|
||||
.test{color:}
|
||||
@@ -298,6 +298,16 @@ pub fn voidWrap(comptime T: type, comptime parsefn: *const fn (*Parser) Result(T
|
||||
return Wrapper.wrapped;
|
||||
}
|
||||
|
||||
pub fn voidWrapRuntime(comptime T: type) type {
|
||||
return struct {
|
||||
parse_fn: *const fn (*Parser) Result(T),
|
||||
|
||||
pub fn wrapped(self: @This(), p: *Parser) Result(T) {
|
||||
return self.parse_fn(p);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn DefineListShorthand(comptime T: type) type {
|
||||
_ = T; // autofix
|
||||
// TODO: implement this when we implement visit?
|
||||
@@ -1157,7 +1167,7 @@ fn parse_until_before(
|
||||
error_behavior: ParseUntilErrorBehavior,
|
||||
comptime T: type,
|
||||
closure: anytype,
|
||||
comptime parse_fn: *const fn (@TypeOf(closure), *Parser) Result(T),
|
||||
parse_fn: *const fn (@TypeOf(closure), *Parser) Result(T),
|
||||
) Result(T) {
|
||||
const delimiters = bun.bits.@"or"(Delimiters, parser.stop_before, delimiters_);
|
||||
const result = result: {
|
||||
@@ -1227,7 +1237,7 @@ pub fn parse_until_after(
|
||||
return result;
|
||||
}
|
||||
|
||||
fn parse_nested_block(parser: *Parser, comptime T: type, closure: anytype, comptime parsefn: *const fn (@TypeOf(closure), *Parser) Result(T)) Result(T) {
|
||||
fn parse_nested_block(parser: *Parser, comptime T: type, closure: anytype, parsefn: *const fn (@TypeOf(closure), *Parser) Result(T)) Result(T) {
|
||||
const block_type: BlockType = if (parser.at_start_of) |block_type| brk: {
|
||||
parser.at_start_of = null;
|
||||
break :brk block_type;
|
||||
@@ -3925,7 +3935,7 @@ pub const Parser = struct {
|
||||
}
|
||||
|
||||
/// Implementation of Vec::<T>::parse
|
||||
pub fn parseList(this: *Parser, comptime T: type, comptime parse_one: *const fn (*Parser) Result(T)) Result(ArrayList(T)) {
|
||||
pub fn parseList(this: *Parser, comptime T: type, parse_one: *const fn (*Parser) Result(T)) Result(ArrayList(T)) {
|
||||
return this.parseCommaSeparated(T, parse_one);
|
||||
}
|
||||
|
||||
@@ -3943,16 +3953,17 @@ pub const Parser = struct {
|
||||
pub fn parseCommaSeparated(
|
||||
this: *Parser,
|
||||
comptime T: type,
|
||||
comptime parse_one: *const fn (*Parser) Result(T),
|
||||
parse_one: *const fn (*Parser) Result(T),
|
||||
) Result(ArrayList(T)) {
|
||||
return this.parseCommaSeparatedInternal(T, {}, voidWrap(T, parse_one), false);
|
||||
const wrapper = voidWrapRuntime(T){ .parse_fn = parse_one };
|
||||
return this.parseCommaSeparatedInternal(T, wrapper, voidWrapRuntime(T).wrapped, false);
|
||||
}
|
||||
|
||||
pub fn parseCommaSeparatedWithCtx(
|
||||
this: *Parser,
|
||||
comptime T: type,
|
||||
closure: anytype,
|
||||
comptime parse_one: *const fn (@TypeOf(closure), *Parser) Result(T),
|
||||
parse_one: *const fn (@TypeOf(closure), *Parser) Result(T),
|
||||
) Result(ArrayList(T)) {
|
||||
return this.parseCommaSeparatedInternal(T, closure, parse_one, false);
|
||||
}
|
||||
@@ -3961,7 +3972,7 @@ pub const Parser = struct {
|
||||
this: *Parser,
|
||||
comptime T: type,
|
||||
closure: anytype,
|
||||
comptime parse_one: *const fn (@TypeOf(closure), *Parser) Result(T),
|
||||
parse_one: *const fn (@TypeOf(closure), *Parser) Result(T),
|
||||
ignore_errors: bool,
|
||||
) Result(ArrayList(T)) {
|
||||
// Vec grows from 0 to 4 by default on first push(). So allocate with
|
||||
@@ -4039,7 +4050,7 @@ pub const Parser = struct {
|
||||
return result;
|
||||
}
|
||||
|
||||
pub inline fn parseNestedBlock(this: *Parser, comptime T: type, closure: anytype, comptime parsefn: *const fn (@TypeOf(closure), *Parser) Result(T)) Result(T) {
|
||||
pub inline fn parseNestedBlock(this: *Parser, comptime T: type, closure: anytype, parsefn: *const fn (@TypeOf(closure), *Parser) Result(T)) Result(T) {
|
||||
return parse_nested_block(this, T, closure, parsefn);
|
||||
}
|
||||
|
||||
@@ -4344,11 +4355,11 @@ pub const Parser = struct {
|
||||
);
|
||||
}
|
||||
|
||||
pub fn parseUntilBefore(this: *Parser, delimiters: Delimiters, comptime T: type, closure: anytype, comptime parse_fn: *const fn (@TypeOf(closure), *Parser) Result(T)) Result(T) {
|
||||
pub fn parseUntilBefore(this: *Parser, delimiters: Delimiters, comptime T: type, closure: anytype, parse_fn: *const fn (@TypeOf(closure), *Parser) Result(T)) Result(T) {
|
||||
return parse_until_before(this, delimiters, .consume, T, closure, parse_fn);
|
||||
}
|
||||
|
||||
pub fn parseEntirely(this: *Parser, comptime T: type, closure: anytype, comptime parsefn: *const fn (@TypeOf(closure), *Parser) Result(T)) Result(T) {
|
||||
pub fn parseEntirely(this: *Parser, comptime T: type, closure: anytype, parsefn: *const fn (@TypeOf(closure), *Parser) Result(T)) Result(T) {
|
||||
const result = switch (parsefn(closure, this)) {
|
||||
.err => |e| return .{ .err = e },
|
||||
.result => |v| v,
|
||||
|
||||
@@ -6,6 +6,7 @@ const SmallList = css.SmallList;
|
||||
const Printer = css.Printer;
|
||||
const PrintErr = css.PrintErr;
|
||||
|
||||
const LengthPercentage = css.css_values.length.LengthPercentage;
|
||||
const LengthPercentageOrAuto = css.css_values.length.LengthPercentageOrAuto;
|
||||
const Image = css.css_values.image.Image;
|
||||
const CssColor = css.css_values.color.CssColor;
|
||||
@@ -614,11 +615,11 @@ pub const BackgroundHandler = struct {
|
||||
const allocator = context.allocator;
|
||||
switch (property.*) {
|
||||
.@"background-color" => |*val| {
|
||||
this.flushHelper(allocator, "color", CssColor, val, dest, context);
|
||||
this.flushHelperColor(allocator, val, dest, context);
|
||||
this.color = val.deepClone(allocator);
|
||||
},
|
||||
.@"background-image" => |*val| {
|
||||
this.backgroundHelper(allocator, SmallList(Image, 1), val, property, dest, context);
|
||||
this.backgroundHelper(allocator, val, property, dest, context);
|
||||
this.images = val.deepClone(allocator);
|
||||
},
|
||||
.@"background-position" => |val| {
|
||||
@@ -679,9 +680,9 @@ pub const BackgroundHandler = struct {
|
||||
for (val.slice()) |*b| {
|
||||
images.appendAssumeCapacity(b.image.deepClone(allocator));
|
||||
}
|
||||
this.backgroundHelper(allocator, SmallList(Image, 1), &images, property, dest, context);
|
||||
this.backgroundHelper(allocator, &images, property, dest, context);
|
||||
const color = val.last().?.color.deepClone(allocator);
|
||||
this.flushHelper(allocator, "color", CssColor, &color, dest, context);
|
||||
this.flushHelperColor(allocator, &color, dest, context);
|
||||
var clips = SmallList(BackgroundClip, 1).initCapacity(allocator, val.len());
|
||||
for (val.slice()) |*b| {
|
||||
clips.appendAssumeCapacity(b.clip.deepClone(allocator));
|
||||
@@ -768,13 +769,12 @@ pub const BackgroundHandler = struct {
|
||||
fn backgroundHelper(
|
||||
this: *@This(),
|
||||
allocator: Allocator,
|
||||
comptime T: type,
|
||||
val: *const T,
|
||||
val: *const SmallList(Image, 1),
|
||||
property: *const Property,
|
||||
dest: *css.DeclarationList,
|
||||
context: *css.PropertyHandlerContext,
|
||||
) void {
|
||||
this.flushHelper(allocator, "images", T, val, dest, context);
|
||||
this.flushHelperImages(allocator, val, dest, context);
|
||||
|
||||
// Store prefixed properties. Clear if we hit an unprefixed property and we have
|
||||
// targets. In this case, the necessary prefixes will be generated.
|
||||
@@ -790,33 +790,94 @@ pub const BackgroundHandler = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn flushHelper(
|
||||
fn flushHelperColor(
|
||||
this: *@This(),
|
||||
allocator: Allocator,
|
||||
comptime field: []const u8,
|
||||
comptime T: type,
|
||||
val: *const T,
|
||||
val: *const CssColor,
|
||||
dest: *css.DeclarationList,
|
||||
context: *css.PropertyHandlerContext,
|
||||
) void {
|
||||
if (@field(this, field) != null and
|
||||
!@field(this, field).?.eql(val) and
|
||||
if (this.color != null and
|
||||
!this.color.?.eql(val) and
|
||||
context.targets.browsers != null and !val.isCompatible(context.targets.browsers.?))
|
||||
{
|
||||
this.flush(allocator, dest, context);
|
||||
}
|
||||
}
|
||||
|
||||
fn flushHelperImages(
|
||||
this: *@This(),
|
||||
allocator: Allocator,
|
||||
val: *const SmallList(Image, 1),
|
||||
dest: *css.DeclarationList,
|
||||
context: *css.PropertyHandlerContext,
|
||||
) void {
|
||||
if (this.images != null and
|
||||
!this.images.?.eql(val) and
|
||||
context.targets.browsers != null and !val.isCompatible(context.targets.browsers.?))
|
||||
{
|
||||
this.flush(allocator, dest, context);
|
||||
}
|
||||
}
|
||||
|
||||
fn pushBackground(self: *BackgroundHandler, alloc: Allocator, d: *css.DeclarationList, val: SmallList(Background, 1)) void {
|
||||
bun.handleOom(d.append(alloc, .{ .background = val }));
|
||||
bun.bits.insert(BackgroundProperty, &self.flushed_properties, BackgroundProperty.background);
|
||||
}
|
||||
|
||||
fn pushBackgroundFallback(self: *BackgroundHandler, alloc: Allocator, d: *css.DeclarationList, val: SmallList(Background, 1)) void {
|
||||
bun.handleOom(d.append(alloc, .{ .background = val }));
|
||||
bun.bits.insert(BackgroundProperty, &self.flushed_properties, BackgroundProperty.background);
|
||||
}
|
||||
|
||||
fn pushBackgroundColor(self: *BackgroundHandler, alloc: Allocator, d: *css.DeclarationList, val: CssColor) void {
|
||||
bun.handleOom(d.append(alloc, .{ .@"background-color" = val }));
|
||||
bun.bits.insert(BackgroundProperty, &self.flushed_properties, BackgroundProperty.@"background-color");
|
||||
}
|
||||
|
||||
fn pushBackgroundImage(self: *BackgroundHandler, alloc: Allocator, d: *css.DeclarationList, val: SmallList(Image, 1)) void {
|
||||
bun.handleOom(d.append(alloc, .{ .@"background-image" = val }));
|
||||
bun.bits.insert(BackgroundProperty, &self.flushed_properties, BackgroundProperty.@"background-image");
|
||||
}
|
||||
|
||||
fn pushBackgroundPosition(self: *BackgroundHandler, alloc: Allocator, d: *css.DeclarationList, val: SmallList(BackgroundPosition, 1)) void {
|
||||
bun.handleOom(d.append(alloc, .{ .@"background-position" = val }));
|
||||
bun.bits.insert(BackgroundProperty, &self.flushed_properties, BackgroundProperty.@"background-position");
|
||||
}
|
||||
|
||||
fn pushBackgroundPositionX(self: *BackgroundHandler, alloc: Allocator, d: *css.DeclarationList, val: SmallList(HorizontalPosition, 1)) void {
|
||||
bun.handleOom(d.append(alloc, .{ .@"background-position-x" = val }));
|
||||
bun.bits.insert(BackgroundProperty, &self.flushed_properties, BackgroundProperty.@"background-position-x");
|
||||
}
|
||||
|
||||
fn pushBackgroundPositionY(self: *BackgroundHandler, alloc: Allocator, d: *css.DeclarationList, val: SmallList(VerticalPosition, 1)) void {
|
||||
bun.handleOom(d.append(alloc, .{ .@"background-position-y" = val }));
|
||||
bun.bits.insert(BackgroundProperty, &self.flushed_properties, BackgroundProperty.@"background-position-y");
|
||||
}
|
||||
|
||||
fn pushBackgroundRepeat(self: *BackgroundHandler, alloc: Allocator, d: *css.DeclarationList, val: SmallList(BackgroundRepeat, 1)) void {
|
||||
bun.handleOom(d.append(alloc, .{ .@"background-repeat" = val }));
|
||||
bun.bits.insert(BackgroundProperty, &self.flushed_properties, BackgroundProperty.@"background-repeat");
|
||||
}
|
||||
|
||||
fn pushBackgroundSize(self: *BackgroundHandler, alloc: Allocator, d: *css.DeclarationList, val: SmallList(BackgroundSize, 1)) void {
|
||||
bun.handleOom(d.append(alloc, .{ .@"background-size" = val }));
|
||||
bun.bits.insert(BackgroundProperty, &self.flushed_properties, BackgroundProperty.@"background-size");
|
||||
}
|
||||
|
||||
fn pushBackgroundAttachment(self: *BackgroundHandler, alloc: Allocator, d: *css.DeclarationList, val: SmallList(BackgroundAttachment, 1)) void {
|
||||
bun.handleOom(d.append(alloc, .{ .@"background-attachment" = val }));
|
||||
bun.bits.insert(BackgroundProperty, &self.flushed_properties, BackgroundProperty.@"background-attachment");
|
||||
}
|
||||
|
||||
fn pushBackgroundOrigin(self: *BackgroundHandler, alloc: Allocator, d: *css.DeclarationList, val: SmallList(BackgroundOrigin, 1)) void {
|
||||
bun.handleOom(d.append(alloc, .{ .@"background-origin" = val }));
|
||||
bun.bits.insert(BackgroundProperty, &self.flushed_properties, BackgroundProperty.@"background-origin");
|
||||
}
|
||||
|
||||
fn flush(this: *@This(), allocator: Allocator, dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void {
|
||||
if (!this.has_any) return;
|
||||
this.has_any = false;
|
||||
const push = struct {
|
||||
fn push(self: *BackgroundHandler, alloc: Allocator, d: *css.DeclarationList, comptime property_field_name: []const u8, val: anytype) void {
|
||||
bun.handleOom(d.append(alloc, @unionInit(Property, property_field_name, val)));
|
||||
const prop = @field(BackgroundProperty, property_field_name);
|
||||
bun.bits.insert(BackgroundProperty, &self.flushed_properties, prop);
|
||||
}
|
||||
}.push;
|
||||
|
||||
var maybe_color: ?CssColor = bun.take(&this.color);
|
||||
var maybe_images: ?css.SmallList(Image, 1) = bun.take(&this.images);
|
||||
@@ -912,11 +973,11 @@ pub const BackgroundHandler = struct {
|
||||
|
||||
if (this.flushed_properties.isEmpty()) {
|
||||
for (backgrounds.getFallbacks(allocator, context.targets).slice()) |fallback| {
|
||||
push(this, allocator, dest, "background", fallback);
|
||||
this.pushBackgroundFallback(allocator, dest, fallback);
|
||||
}
|
||||
}
|
||||
|
||||
push(this, allocator, dest, "background", backgrounds);
|
||||
this.pushBackground(allocator, dest, backgrounds);
|
||||
|
||||
if (clip_property) |clip| {
|
||||
bun.handleOom(dest.append(allocator, clip));
|
||||
@@ -932,10 +993,10 @@ pub const BackgroundHandler = struct {
|
||||
var color: CssColor = color_const;
|
||||
if (!this.flushed_properties.color) {
|
||||
for (color.getFallbacks(allocator, context.targets).slice()) |fallback| {
|
||||
push(this, allocator, dest, "background-color", fallback);
|
||||
this.pushBackgroundColor(allocator, dest, fallback);
|
||||
}
|
||||
}
|
||||
push(this, allocator, dest, "background-color", color);
|
||||
this.pushBackgroundColor(allocator, dest, color);
|
||||
}
|
||||
|
||||
if (bun.take(&maybe_images)) |images_| {
|
||||
@@ -943,10 +1004,10 @@ pub const BackgroundHandler = struct {
|
||||
if (!this.flushed_properties.image) {
|
||||
var fallbacks = images.getFallbacks(allocator, context.targets);
|
||||
for (fallbacks.slice()) |fallback| {
|
||||
push(this, allocator, dest, "background-image", fallback);
|
||||
this.pushBackgroundImage(allocator, dest, fallback);
|
||||
}
|
||||
}
|
||||
push(this, allocator, dest, "background-image", images);
|
||||
this.pushBackgroundImage(allocator, dest, images);
|
||||
}
|
||||
|
||||
if (maybe_x_positions != null and maybe_y_positions != null and maybe_x_positions.?.len() == maybe_y_positions.?.len()) {
|
||||
@@ -956,30 +1017,30 @@ pub const BackgroundHandler = struct {
|
||||
}
|
||||
maybe_x_positions.?.clearRetainingCapacity();
|
||||
maybe_y_positions.?.clearRetainingCapacity();
|
||||
push(this, allocator, dest, "background-position", positions);
|
||||
this.pushBackgroundPosition(allocator, dest, positions);
|
||||
} else {
|
||||
if (bun.take(&maybe_x_positions)) |x| {
|
||||
push(this, allocator, dest, "background-position-x", x);
|
||||
this.pushBackgroundPositionX(allocator, dest, x);
|
||||
}
|
||||
if (bun.take(&maybe_y_positions)) |y| {
|
||||
push(this, allocator, dest, "background-position-y", y);
|
||||
this.pushBackgroundPositionY(allocator, dest, y);
|
||||
}
|
||||
}
|
||||
|
||||
if (bun.take(&maybe_repeats)) |rep| {
|
||||
push(this, allocator, dest, "background-repeat", rep);
|
||||
this.pushBackgroundRepeat(allocator, dest, rep);
|
||||
}
|
||||
|
||||
if (bun.take(&maybe_sizes)) |rep| {
|
||||
push(this, allocator, dest, "background-size", rep);
|
||||
this.pushBackgroundSize(allocator, dest, rep);
|
||||
}
|
||||
|
||||
if (bun.take(&maybe_attachments)) |rep| {
|
||||
push(this, allocator, dest, "background-attachment", rep);
|
||||
this.pushBackgroundAttachment(allocator, dest, rep);
|
||||
}
|
||||
|
||||
if (bun.take(&maybe_origins)) |rep| {
|
||||
push(this, allocator, dest, "background-origin", rep);
|
||||
this.pushBackgroundOrigin(allocator, dest, rep);
|
||||
}
|
||||
|
||||
if (bun.take(&maybe_clips)) |c| {
|
||||
|
||||
@@ -11,31 +11,30 @@ const PropertyCategory = css.PropertyCategory;
|
||||
const UnparsedProperty = css.css_properties.custom.UnparsedProperty;
|
||||
|
||||
/// A value for the [border-top](https://www.w3.org/TR/css-backgrounds-3/#propdef-border-top) shorthand property.
|
||||
pub const BorderTop = GenericBorder(LineStyle, 0);
|
||||
pub const BorderTop = GenericBorder(LineStyle);
|
||||
/// A value for the [border-right](https://www.w3.org/TR/css-backgrounds-3/#propdef-border-right) shorthand property.
|
||||
pub const BorderRight = GenericBorder(LineStyle, 1);
|
||||
pub const BorderRight = GenericBorder(LineStyle);
|
||||
/// A value for the [border-bottom](https://www.w3.org/TR/css-backgrounds-3/#propdef-border-bottom) shorthand property.
|
||||
pub const BorderBottom = GenericBorder(LineStyle, 2);
|
||||
pub const BorderBottom = GenericBorder(LineStyle);
|
||||
/// A value for the [border-left](https://www.w3.org/TR/css-backgrounds-3/#propdef-border-left) shorthand property.
|
||||
pub const BorderLeft = GenericBorder(LineStyle, 3);
|
||||
pub const BorderLeft = GenericBorder(LineStyle);
|
||||
/// A value for the [border-block-start](https://drafts.csswg.org/css-logical/#propdef-border-block-start) shorthand property.
|
||||
pub const BorderBlockStart = GenericBorder(LineStyle, 4);
|
||||
pub const BorderBlockStart = GenericBorder(LineStyle);
|
||||
/// A value for the [border-block-end](https://drafts.csswg.org/css-logical/#propdef-border-block-end) shorthand property.
|
||||
pub const BorderBlockEnd = GenericBorder(LineStyle, 5);
|
||||
pub const BorderBlockEnd = GenericBorder(LineStyle);
|
||||
/// A value for the [border-inline-start](https://drafts.csswg.org/css-logical/#propdef-border-inline-start) shorthand property.
|
||||
pub const BorderInlineStart = GenericBorder(LineStyle, 6);
|
||||
pub const BorderInlineStart = GenericBorder(LineStyle);
|
||||
/// A value for the [border-inline-end](https://drafts.csswg.org/css-logical/#propdef-border-inline-end) shorthand property.
|
||||
pub const BorderInlineEnd = GenericBorder(LineStyle, 7);
|
||||
pub const BorderInlineEnd = GenericBorder(LineStyle);
|
||||
/// A value for the [border-block](https://drafts.csswg.org/css-logical/#propdef-border-block) shorthand property.
|
||||
pub const BorderBlock = GenericBorder(LineStyle, 8);
|
||||
pub const BorderBlock = GenericBorder(LineStyle);
|
||||
/// A value for the [border-inline](https://drafts.csswg.org/css-logical/#propdef-border-inline) shorthand property.
|
||||
pub const BorderInline = GenericBorder(LineStyle, 9);
|
||||
pub const BorderInline = GenericBorder(LineStyle);
|
||||
/// A value for the [border](https://www.w3.org/TR/css-backgrounds-3/#propdef-border) shorthand property.
|
||||
pub const Border = GenericBorder(LineStyle, 10);
|
||||
pub const Border = GenericBorder(LineStyle);
|
||||
|
||||
/// A generic type that represents the `border` and `outline` shorthand properties.
|
||||
pub fn GenericBorder(comptime S: type, comptime P: u8) type {
|
||||
_ = P; // autofix
|
||||
pub fn GenericBorder(comptime S: type) type {
|
||||
return struct {
|
||||
/// The width of the border.
|
||||
width: BorderSideWidth,
|
||||
|
||||
@@ -829,6 +829,16 @@ pub const FontHandler = struct {
|
||||
flushed_properties: FontProperty = .{},
|
||||
has_any: bool = false,
|
||||
|
||||
const PropertyName = enum {
|
||||
family,
|
||||
size,
|
||||
style,
|
||||
weight,
|
||||
stretch,
|
||||
line_height,
|
||||
variant_caps,
|
||||
};
|
||||
|
||||
pub fn handleProperty(
|
||||
this: *FontHandler,
|
||||
property: *const css.Property,
|
||||
@@ -836,21 +846,21 @@ pub const FontHandler = struct {
|
||||
context: *css.PropertyHandlerContext,
|
||||
) bool {
|
||||
switch (property.*) {
|
||||
.@"font-family" => |*val| this.propertyHelper(dest, context, "family", val),
|
||||
.@"font-size" => |*val| this.propertyHelper(dest, context, "size", val),
|
||||
.@"font-style" => |*val| this.propertyHelper(dest, context, "style", val),
|
||||
.@"font-weight" => |*val| this.propertyHelper(dest, context, "weight", val),
|
||||
.@"font-stretch" => |*val| this.propertyHelper(dest, context, "stretch", val),
|
||||
.@"font-variant-caps" => |*val| this.propertyHelper(dest, context, "variant_caps", val),
|
||||
.@"line-height" => |*val| this.propertyHelper(dest, context, "line_height", val),
|
||||
.@"font-family" => |*val| this.propertyHelperFamily(dest, context, val),
|
||||
.@"font-size" => |*val| this.propertyHelperSize(dest, context, val),
|
||||
.@"font-style" => |*val| this.propertyHelperStyle(dest, context, val),
|
||||
.@"font-weight" => |*val| this.propertyHelperWeight(dest, context, val),
|
||||
.@"font-stretch" => |*val| this.propertyHelperStretch(dest, context, val),
|
||||
.@"font-variant-caps" => |*val| this.propertyHelperVariantCaps(dest, context, val),
|
||||
.@"line-height" => |*val| this.propertyHelperLineHeight(dest, context, val),
|
||||
.font => |*val| {
|
||||
this.flushHelper(dest, context, "family", &val.family);
|
||||
this.flushHelper(dest, context, "size", &val.size);
|
||||
this.flushHelper(dest, context, "style", &val.style);
|
||||
this.flushHelper(dest, context, "weight", &val.weight);
|
||||
this.flushHelper(dest, context, "stretch", &val.stretch);
|
||||
this.flushHelper(dest, context, "line_height", &val.line_height);
|
||||
this.flushHelper(dest, context, "variant_caps", &val.variant_caps);
|
||||
this.flushHelperFamily(dest, context, &val.family);
|
||||
this.flushHelperSize(dest, context, &val.size);
|
||||
this.flushHelperStyle(dest, context, &val.style);
|
||||
this.flushHelperWeight(dest, context, &val.weight);
|
||||
this.flushHelperStretch(dest, context, &val.stretch);
|
||||
this.flushHelperLineHeight(dest, context, &val.line_height);
|
||||
this.flushHelperVariantCaps(dest, context, &val.variant_caps);
|
||||
|
||||
this.family = css.generic.deepClone(bun.BabyList(FontFamily), &val.family, context.allocator);
|
||||
this.size = val.size.deepClone(context.allocator);
|
||||
@@ -877,25 +887,104 @@ pub const FontHandler = struct {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline fn propertyHelper(this: *FontHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, comptime prop: []const u8, val: anytype) void {
|
||||
this.flushHelper(dest, context, prop, val);
|
||||
@field(this, prop) = css.generic.deepClone(@TypeOf(val.*), val, context.allocator);
|
||||
fn propertyHelperFamily(this: *FontHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const bun.BabyList(FontFamily)) void {
|
||||
this.flushHelperFamily(dest, context, val);
|
||||
this.family = css.generic.deepClone(bun.BabyList(FontFamily), val, context.allocator);
|
||||
this.has_any = true;
|
||||
}
|
||||
|
||||
inline fn flushHelper(
|
||||
this: *FontHandler,
|
||||
dest: *css.DeclarationList,
|
||||
context: *css.PropertyHandlerContext,
|
||||
comptime prop: []const u8,
|
||||
val: anytype,
|
||||
) void {
|
||||
if (@field(this, prop) != null and
|
||||
!css.generic.eql(@TypeOf(@field(this, prop).?), &@field(this, prop).?, val) and
|
||||
context.targets.browsers != null and
|
||||
!css.generic.isCompatible(@TypeOf(@field(this, prop).?), val, context.targets.browsers.?))
|
||||
{
|
||||
this.flush(dest, context);
|
||||
fn propertyHelperSize(this: *FontHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const FontSize) void {
|
||||
this.flushHelperSize(dest, context, val);
|
||||
this.size = val.deepClone(context.allocator);
|
||||
this.has_any = true;
|
||||
}
|
||||
|
||||
fn propertyHelperStyle(this: *FontHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const FontStyle) void {
|
||||
this.flushHelperStyle(dest, context, val);
|
||||
this.style = val.deepClone(context.allocator);
|
||||
this.has_any = true;
|
||||
}
|
||||
|
||||
fn propertyHelperWeight(this: *FontHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const FontWeight) void {
|
||||
this.flushHelperWeight(dest, context, val);
|
||||
this.weight = val.deepClone(context.allocator);
|
||||
this.has_any = true;
|
||||
}
|
||||
|
||||
fn propertyHelperStretch(this: *FontHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const FontStretch) void {
|
||||
this.flushHelperStretch(dest, context, val);
|
||||
this.stretch = val.deepClone(context.allocator);
|
||||
this.has_any = true;
|
||||
}
|
||||
|
||||
fn propertyHelperLineHeight(this: *FontHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const LineHeight) void {
|
||||
this.flushHelperLineHeight(dest, context, val);
|
||||
this.line_height = val.deepClone(context.allocator);
|
||||
this.has_any = true;
|
||||
}
|
||||
|
||||
fn propertyHelperVariantCaps(this: *FontHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const FontVariantCaps) void {
|
||||
this.flushHelperVariantCaps(dest, context, val);
|
||||
this.variant_caps = val.deepClone(context.allocator);
|
||||
this.has_any = true;
|
||||
}
|
||||
|
||||
fn flushHelperFamily(this: *FontHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const bun.BabyList(FontFamily)) void {
|
||||
if (this.family) |*f| {
|
||||
if (!css.generic.eql(bun.BabyList(FontFamily), f, val) and
|
||||
context.targets.browsers != null and
|
||||
!css.generic.isCompatible(bun.BabyList(FontFamily), val, context.targets.browsers.?))
|
||||
{
|
||||
this.flush(dest, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flushHelperSize(this: *FontHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const FontSize) void {
|
||||
if (this.size) |*s| {
|
||||
if (!s.eql(val) and context.targets.browsers != null and !val.isCompatible(context.targets.browsers.?)) {
|
||||
this.flush(dest, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flushHelperStyle(this: *FontHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const FontStyle) void {
|
||||
if (this.style) |*s| {
|
||||
if (!s.eql(val) and context.targets.browsers != null and !val.isCompatible(context.targets.browsers.?)) {
|
||||
this.flush(dest, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flushHelperWeight(this: *FontHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const FontWeight) void {
|
||||
if (this.weight) |*w| {
|
||||
if (!w.eql(val) and context.targets.browsers != null and !val.isCompatible(context.targets.browsers.?)) {
|
||||
this.flush(dest, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flushHelperStretch(this: *FontHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const FontStretch) void {
|
||||
if (this.stretch) |*s| {
|
||||
if (!s.eql(val) and context.targets.browsers != null and !val.isCompatible(context.targets.browsers.?)) {
|
||||
this.flush(dest, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flushHelperLineHeight(this: *FontHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const LineHeight) void {
|
||||
if (this.line_height) |*l| {
|
||||
if (!l.eql(val) and context.targets.browsers != null and !val.isCompatible(context.targets.browsers.?)) {
|
||||
this.flush(dest, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flushHelperVariantCaps(this: *FontHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const FontVariantCaps) void {
|
||||
if (this.variant_caps) |*v| {
|
||||
if (!v.eql(val) and context.targets.browsers != null and !val.isCompatible(context.targets.browsers.?)) {
|
||||
this.flush(dest, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -904,15 +993,44 @@ pub const FontHandler = struct {
|
||||
this.flushed_properties = .{};
|
||||
}
|
||||
|
||||
fn push(self: *FontHandler, d: *css.DeclarationList, ctx: *css.PropertyHandlerContext, comptime prop: []const u8, val: anytype) void {
|
||||
bun.handleOom(d.append(ctx.allocator, @unionInit(css.Property, prop, val)));
|
||||
var insertion: FontProperty = .{};
|
||||
if (comptime std.mem.eql(u8, prop, "font")) {
|
||||
insertion = FontProperty.FONT;
|
||||
} else {
|
||||
@field(insertion, prop) = true;
|
||||
}
|
||||
bun.bits.insert(FontProperty, &self.flushed_properties, insertion);
|
||||
fn pushFont(self: *FontHandler, d: *css.DeclarationList, ctx: *css.PropertyHandlerContext, val: Font) void {
|
||||
bun.handleOom(d.append(ctx.allocator, .{ .font = val }));
|
||||
bun.bits.insert(FontProperty, &self.flushed_properties, FontProperty.FONT);
|
||||
}
|
||||
|
||||
fn pushFontFamily(self: *FontHandler, d: *css.DeclarationList, ctx: *css.PropertyHandlerContext, val: bun.BabyList(FontFamily)) void {
|
||||
bun.handleOom(d.append(ctx.allocator, .{ .@"font-family" = val }));
|
||||
bun.bits.insert(FontProperty, &self.flushed_properties, .{ .@"font-family" = true });
|
||||
}
|
||||
|
||||
fn pushFontSize(self: *FontHandler, d: *css.DeclarationList, ctx: *css.PropertyHandlerContext, val: FontSize) void {
|
||||
bun.handleOom(d.append(ctx.allocator, .{ .@"font-size" = val }));
|
||||
bun.bits.insert(FontProperty, &self.flushed_properties, .{ .@"font-size" = true });
|
||||
}
|
||||
|
||||
fn pushFontStyle(self: *FontHandler, d: *css.DeclarationList, ctx: *css.PropertyHandlerContext, val: FontStyle) void {
|
||||
bun.handleOom(d.append(ctx.allocator, .{ .@"font-style" = val }));
|
||||
bun.bits.insert(FontProperty, &self.flushed_properties, .{ .@"font-style" = true });
|
||||
}
|
||||
|
||||
fn pushFontWeight(self: *FontHandler, d: *css.DeclarationList, ctx: *css.PropertyHandlerContext, val: FontWeight) void {
|
||||
bun.handleOom(d.append(ctx.allocator, .{ .@"font-weight" = val }));
|
||||
bun.bits.insert(FontProperty, &self.flushed_properties, .{ .@"font-weight" = true });
|
||||
}
|
||||
|
||||
fn pushFontStretch(self: *FontHandler, d: *css.DeclarationList, ctx: *css.PropertyHandlerContext, val: FontStretch) void {
|
||||
bun.handleOom(d.append(ctx.allocator, .{ .@"font-stretch" = val }));
|
||||
bun.bits.insert(FontProperty, &self.flushed_properties, .{ .@"font-stretch" = true });
|
||||
}
|
||||
|
||||
fn pushFontVariantCaps(self: *FontHandler, d: *css.DeclarationList, ctx: *css.PropertyHandlerContext, val: FontVariantCaps) void {
|
||||
bun.handleOom(d.append(ctx.allocator, .{ .@"font-variant-caps" = val }));
|
||||
bun.bits.insert(FontProperty, &self.flushed_properties, .{ .@"font-variant-caps" = true });
|
||||
}
|
||||
|
||||
fn pushLineHeight(self: *FontHandler, d: *css.DeclarationList, ctx: *css.PropertyHandlerContext, val: LineHeight) void {
|
||||
bun.handleOom(d.append(ctx.allocator, .{ .@"line-height" = val }));
|
||||
bun.bits.insert(FontProperty, &self.flushed_properties, .{ .@"line-height" = true });
|
||||
}
|
||||
|
||||
fn flush(this: *FontHandler, decls: *css.DeclarationList, context: *css.PropertyHandlerContext) void {
|
||||
@@ -956,7 +1074,7 @@ pub const FontHandler = struct {
|
||||
|
||||
if (family != null and size != null and style != null and weight != null and stretch != null and line_height != null and variant_caps != null) {
|
||||
const caps = variant_caps.?;
|
||||
push(this, decls, context, "font", Font{
|
||||
this.pushFont(decls, context, Font{
|
||||
.family = family.?,
|
||||
.size = size.?,
|
||||
.style = style.?,
|
||||
@@ -969,35 +1087,35 @@ pub const FontHandler = struct {
|
||||
// The `font` property only accepts CSS 2.1 values for font-variant caps.
|
||||
// If we have a CSS 3+ value, we need to add a separate property.
|
||||
if (!caps.isCss2()) {
|
||||
push(this, decls, context, "font-variant-caps", caps);
|
||||
this.pushFontVariantCaps(decls, context, caps);
|
||||
}
|
||||
} else {
|
||||
if (family) |val| {
|
||||
push(this, decls, context, "font-family", val);
|
||||
this.pushFontFamily(decls, context, val);
|
||||
}
|
||||
|
||||
if (size) |val| {
|
||||
push(this, decls, context, "font-size", val);
|
||||
this.pushFontSize(decls, context, val);
|
||||
}
|
||||
|
||||
if (style) |val| {
|
||||
push(this, decls, context, "font-style", val);
|
||||
this.pushFontStyle(decls, context, val);
|
||||
}
|
||||
|
||||
if (variant_caps) |val| {
|
||||
push(this, decls, context, "font-variant-caps", val);
|
||||
this.pushFontVariantCaps(decls, context, val);
|
||||
}
|
||||
|
||||
if (weight) |val| {
|
||||
push(this, decls, context, "font-weight", val);
|
||||
this.pushFontWeight(decls, context, val);
|
||||
}
|
||||
|
||||
if (stretch) |val| {
|
||||
push(this, decls, context, "font-stretch", val);
|
||||
this.pushFontStretch(decls, context, val);
|
||||
}
|
||||
|
||||
if (line_height) |val| {
|
||||
push(this, decls, context, "line-height", val);
|
||||
this.pushLineHeight(decls, context, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ const GenericBorder = css.css_properties.border.GenericBorder;
|
||||
const LineStyle = css.css_properties.border.LineStyle;
|
||||
|
||||
/// A value for the [outline](https://drafts.csswg.org/css-ui/#outline) shorthand property.
|
||||
pub const Outline = GenericBorder(OutlineStyle, 11);
|
||||
pub const Outline = GenericBorder(OutlineStyle);
|
||||
|
||||
/// A value for the [outline-style](https://drafts.csswg.org/css-ui/#outline-style) property.
|
||||
pub const OutlineStyle = union(enum) {
|
||||
|
||||
@@ -112,10 +112,10 @@ pub const TransitionHandler = struct {
|
||||
|
||||
pub fn handleProperty(this: *@This(), prop: *const Property, dest: *css.DeclarationList, context: *css.PropertyHandlerContext) bool {
|
||||
switch (prop.*) {
|
||||
.@"transition-property" => |*x| this.property(dest, context, Feature.transition_property, "properties", &x.*[0], x.*[1]),
|
||||
.@"transition-duration" => |*x| this.property(dest, context, Feature.transition_duration, "durations", &x.*[0], x.*[1]),
|
||||
.@"transition-delay" => |*x| this.property(dest, context, Feature.transition_delay, "delays", &x.*[0], x.*[1]),
|
||||
.@"transition-timing-function" => |*x| this.property(dest, context, Feature.transition_timing_function, "timing_functions", &x.*[0], x.*[1]),
|
||||
.@"transition-property" => |*x| this.propertyProperties(dest, context, Feature.transition_property, &x.*[0], x.*[1]),
|
||||
.@"transition-duration" => |*x| this.propertyDurations(dest, context, Feature.transition_duration, &x.*[0], x.*[1]),
|
||||
.@"transition-delay" => |*x| this.propertyDelays(dest, context, Feature.transition_delay, &x.*[0], x.*[1]),
|
||||
.@"transition-timing-function" => |*x| this.propertyTimingFunctions(dest, context, Feature.transition_timing_function, &x.*[0], x.*[1]),
|
||||
.transition => |*x| {
|
||||
const val: *const SmallList(Transition, 1) = &x.*[0];
|
||||
const vp: VendorPrefix = x.*[1];
|
||||
@@ -132,27 +132,27 @@ pub const TransitionHandler = struct {
|
||||
for (val.slice(), properties.slice_mut()) |*item, *out_prop| {
|
||||
out_prop.* = item.property.deepClone(context.allocator);
|
||||
}
|
||||
this.maybeFlush(dest, context, "properties", &properties, vp);
|
||||
this.maybeFlushProperties(dest, context, &properties, vp);
|
||||
|
||||
for (val.slice(), durations.slice_mut()) |*item, *out_dur| {
|
||||
out_dur.* = item.duration.deepClone(context.allocator);
|
||||
}
|
||||
this.maybeFlush(dest, context, "durations", &durations, vp);
|
||||
this.maybeFlushDurations(dest, context, &durations, vp);
|
||||
|
||||
for (val.slice(), delays.slice_mut()) |*item, *out_delay| {
|
||||
out_delay.* = item.delay.deepClone(context.allocator);
|
||||
}
|
||||
this.maybeFlush(dest, context, "delays", &delays, vp);
|
||||
this.maybeFlushDelays(dest, context, &delays, vp);
|
||||
|
||||
for (val.slice(), timing_functions.slice_mut()) |*item, *out_timing| {
|
||||
out_timing.* = item.timing_function.deepClone(context.allocator);
|
||||
}
|
||||
this.maybeFlush(dest, context, "timing_functions", &timing_functions, vp);
|
||||
this.maybeFlushTimingFunctions(dest, context, &timing_functions, vp);
|
||||
|
||||
this.property(dest, context, Feature.transition_property, "properties", &properties, vp);
|
||||
this.property(dest, context, Feature.transition_duration, "durations", &durations, vp);
|
||||
this.property(dest, context, Feature.transition_delay, "delays", &delays, vp);
|
||||
this.property(dest, context, Feature.transition_timing_function, "timing_functions", &timing_functions, vp);
|
||||
this.propertyProperties(dest, context, Feature.transition_property, &properties, vp);
|
||||
this.propertyDurations(dest, context, Feature.transition_duration, &durations, vp);
|
||||
this.propertyDelays(dest, context, Feature.transition_delay, &delays, vp);
|
||||
this.propertyTimingFunctions(dest, context, Feature.transition_timing_function, &timing_functions, vp);
|
||||
},
|
||||
.unparsed => |*x| if (isTransitionProperty(&x.property_id)) {
|
||||
this.flush(dest, context);
|
||||
@@ -171,11 +171,10 @@ pub const TransitionHandler = struct {
|
||||
this.flush(dest, context);
|
||||
}
|
||||
|
||||
fn property(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext, comptime feature: Feature, comptime prop: []const u8, val: anytype, vp: VendorPrefix) void {
|
||||
this.maybeFlush(dest, context, prop, val, vp);
|
||||
fn propertyProperties(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext, feature: Feature, val: *const SmallList(PropertyId, 1), vp: VendorPrefix) void {
|
||||
this.maybeFlushProperties(dest, context, val, vp);
|
||||
|
||||
// Otherwise, update the value and add the prefix.
|
||||
if (@field(this, prop)) |*p| {
|
||||
if (this.properties) |*p| {
|
||||
const v = &p.*[0];
|
||||
const prefixes = &p.*[1];
|
||||
v.* = val.deepClone(context.allocator);
|
||||
@@ -184,15 +183,94 @@ pub const TransitionHandler = struct {
|
||||
} else {
|
||||
const prefixes = context.targets.prefixes(vp, feature);
|
||||
const cloned_val = val.deepClone(context.allocator);
|
||||
@field(this, prop) = .{ cloned_val, prefixes };
|
||||
this.properties = .{ cloned_val, prefixes };
|
||||
this.has_any = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn maybeFlush(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext, comptime prop: []const u8, val: anytype, vp: VendorPrefix) void {
|
||||
// If two vendor prefixes for the same property have different
|
||||
// values, we need to flush what we have immediately to preserve order.
|
||||
if (@field(this, prop)) |*p| {
|
||||
fn propertyDurations(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext, feature: Feature, val: *const SmallList(Time, 1), vp: VendorPrefix) void {
|
||||
this.maybeFlushDurations(dest, context, val, vp);
|
||||
|
||||
if (this.durations) |*p| {
|
||||
const v = &p.*[0];
|
||||
const prefixes = &p.*[1];
|
||||
v.* = val.deepClone(context.allocator);
|
||||
bun.bits.insert(VendorPrefix, prefixes, vp);
|
||||
prefixes.* = context.targets.prefixes(prefixes.*, feature);
|
||||
} else {
|
||||
const prefixes = context.targets.prefixes(vp, feature);
|
||||
const cloned_val = val.deepClone(context.allocator);
|
||||
this.durations = .{ cloned_val, prefixes };
|
||||
this.has_any = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn propertyDelays(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext, feature: Feature, val: *const SmallList(Time, 1), vp: VendorPrefix) void {
|
||||
this.maybeFlushDelays(dest, context, val, vp);
|
||||
|
||||
if (this.delays) |*p| {
|
||||
const v = &p.*[0];
|
||||
const prefixes = &p.*[1];
|
||||
v.* = val.deepClone(context.allocator);
|
||||
bun.bits.insert(VendorPrefix, prefixes, vp);
|
||||
prefixes.* = context.targets.prefixes(prefixes.*, feature);
|
||||
} else {
|
||||
const prefixes = context.targets.prefixes(vp, feature);
|
||||
const cloned_val = val.deepClone(context.allocator);
|
||||
this.delays = .{ cloned_val, prefixes };
|
||||
this.has_any = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn propertyTimingFunctions(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext, feature: Feature, val: *const SmallList(EasingFunction, 1), vp: VendorPrefix) void {
|
||||
this.maybeFlushTimingFunctions(dest, context, val, vp);
|
||||
|
||||
if (this.timing_functions) |*p| {
|
||||
const v = &p.*[0];
|
||||
const prefixes = &p.*[1];
|
||||
v.* = val.deepClone(context.allocator);
|
||||
bun.bits.insert(VendorPrefix, prefixes, vp);
|
||||
prefixes.* = context.targets.prefixes(prefixes.*, feature);
|
||||
} else {
|
||||
const prefixes = context.targets.prefixes(vp, feature);
|
||||
const cloned_val = val.deepClone(context.allocator);
|
||||
this.timing_functions = .{ cloned_val, prefixes };
|
||||
this.has_any = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn maybeFlushProperties(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const SmallList(PropertyId, 1), vp: VendorPrefix) void {
|
||||
if (this.properties) |*p| {
|
||||
const v = &p.*[0];
|
||||
const prefixes = &p.*[1];
|
||||
if (!val.eql(v) and !bun.bits.contains(VendorPrefix, prefixes.*, vp)) {
|
||||
this.flush(dest, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn maybeFlushDurations(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const SmallList(Time, 1), vp: VendorPrefix) void {
|
||||
if (this.durations) |*p| {
|
||||
const v = &p.*[0];
|
||||
const prefixes = &p.*[1];
|
||||
if (!val.eql(v) and !bun.bits.contains(VendorPrefix, prefixes.*, vp)) {
|
||||
this.flush(dest, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn maybeFlushDelays(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const SmallList(Time, 1), vp: VendorPrefix) void {
|
||||
if (this.delays) |*p| {
|
||||
const v = &p.*[0];
|
||||
const prefixes = &p.*[1];
|
||||
if (!val.eql(v) and !bun.bits.contains(VendorPrefix, prefixes.*, vp)) {
|
||||
this.flush(dest, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn maybeFlushTimingFunctions(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext, val: *const SmallList(EasingFunction, 1), vp: VendorPrefix) void {
|
||||
if (this.timing_functions) |*p| {
|
||||
const v = &p.*[0];
|
||||
const prefixes = &p.*[1];
|
||||
if (!val.eql(v) and !bun.bits.contains(VendorPrefix, prefixes.*, vp)) {
|
||||
|
||||
@@ -526,31 +526,10 @@ pub fn Calc(comptime V: type) type {
|
||||
break :brk s;
|
||||
} else RoundingStrategy.default();
|
||||
|
||||
const OpAndFallbackCtx = struct {
|
||||
strategy: RoundingStrategy,
|
||||
|
||||
pub fn op(this: *const @This(), a: f32, b: f32) f32 {
|
||||
return round({}, a, b, this.strategy);
|
||||
}
|
||||
|
||||
pub fn fallback(this: *const @This(), a: This, b: This) MathFunction(V) {
|
||||
return MathFunction(V){
|
||||
.round = .{
|
||||
.strategy = this.strategy,
|
||||
.value = a,
|
||||
.interval = b,
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
var ctx_for_op_and_fallback = OpAndFallbackCtx{
|
||||
.strategy = strategy,
|
||||
};
|
||||
return This.parseMathFn(
|
||||
i,
|
||||
&ctx_for_op_and_fallback,
|
||||
OpAndFallbackCtx.op,
|
||||
OpAndFallbackCtx.fallback,
|
||||
.round_mod,
|
||||
strategy,
|
||||
self.ctx,
|
||||
parseIdent,
|
||||
);
|
||||
@@ -568,25 +547,12 @@ pub fn Calc(comptime V: type) type {
|
||||
pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) {
|
||||
return This.parseMathFn(
|
||||
i,
|
||||
{},
|
||||
@This().rem,
|
||||
mathFunctionRem,
|
||||
.rem,
|
||||
null,
|
||||
self.ctx,
|
||||
parseIdent,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn rem(_: void, a: f32, b: f32) f32 {
|
||||
return @mod(a, b);
|
||||
}
|
||||
pub fn mathFunctionRem(_: void, a: This, b: This) MathFunction(V) {
|
||||
return MathFunction(V){
|
||||
.rem = .{
|
||||
.dividend = a,
|
||||
.divisor = b,
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
var closure = Closure{
|
||||
.ctx = ctx,
|
||||
@@ -600,26 +566,12 @@ pub fn Calc(comptime V: type) type {
|
||||
pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) {
|
||||
return This.parseMathFn(
|
||||
i,
|
||||
{},
|
||||
@This().modulo,
|
||||
mathFunctionMod,
|
||||
.mod,
|
||||
null,
|
||||
self.ctx,
|
||||
parseIdent,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn modulo(_: void, a: f32, b: f32) f32 {
|
||||
// return ((a % b) + b) % b;
|
||||
return @mod((@mod(a, b) + b), b);
|
||||
}
|
||||
pub fn mathFunctionMod(_: void, a: This, b: This) MathFunction(V) {
|
||||
return MathFunction(V){
|
||||
.mod_ = .{
|
||||
.dividend = a,
|
||||
.divisor = b,
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
var closure = Closure{
|
||||
.ctx = ctx,
|
||||
@@ -759,7 +711,7 @@ pub fn Calc(comptime V: type) type {
|
||||
.err => |e| return .{ .err = e },
|
||||
};
|
||||
return .{
|
||||
.result = if (This.applyMap(&v, i.allocator(), absf)) |vv| vv else This{
|
||||
.result = if (This.applyMap(&v, i.allocator(), .absf)) |vv| vv else This{
|
||||
.function = bun.create(
|
||||
i.allocator(),
|
||||
MathFunction(V),
|
||||
@@ -818,9 +770,11 @@ pub fn Calc(comptime V: type) type {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parseNumericFn(input: *css.Parser, comptime op: enum { sqrt, exp }, ctx: anytype, comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This) Result(This) {
|
||||
const Closure = struct { ctx: @TypeOf(ctx) };
|
||||
var closure = Closure{ .ctx = ctx };
|
||||
pub const NumericOp = enum { sqrt, exp };
|
||||
|
||||
pub fn parseNumericFn(input: *css.Parser, op: NumericOp, ctx: anytype, comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This) Result(This) {
|
||||
const Closure = struct { ctx: @TypeOf(ctx), op: NumericOp };
|
||||
var closure = Closure{ .ctx = ctx, .op = op };
|
||||
return input.parseNestedBlock(This, &closure, struct {
|
||||
pub fn parseNestedBlockFn(self: *Closure, i: *css.Parser) Result(This) {
|
||||
const v = switch (This.parseNumeric(i, self.ctx, parse_ident)) {
|
||||
@@ -830,7 +784,7 @@ pub fn Calc(comptime V: type) type {
|
||||
|
||||
return .{
|
||||
.result = This{
|
||||
.number = switch (op) {
|
||||
.number = switch (self.op) {
|
||||
.sqrt => std.math.sqrt(v),
|
||||
.exp => std.math.exp(v),
|
||||
},
|
||||
@@ -840,11 +794,16 @@ pub fn Calc(comptime V: type) type {
|
||||
}.parseNestedBlockFn);
|
||||
}
|
||||
|
||||
pub const MathOp = enum {
|
||||
round_mod,
|
||||
rem,
|
||||
mod,
|
||||
};
|
||||
|
||||
pub fn parseMathFn(
|
||||
input: *css.Parser,
|
||||
ctx_for_op_and_fallback: anytype,
|
||||
comptime op: *const fn (@TypeOf(ctx_for_op_and_fallback), f32, f32) f32,
|
||||
comptime fallback: *const fn (@TypeOf(ctx_for_op_and_fallback), This, This) MathFunction(V),
|
||||
math_op: MathOp,
|
||||
strategy: ?RoundingStrategy,
|
||||
ctx_for_parse_ident: anytype,
|
||||
comptime parse_ident: *const fn (@TypeOf(ctx_for_parse_ident), []const u8) ?This,
|
||||
) Result(This) {
|
||||
@@ -858,12 +817,71 @@ pub fn Calc(comptime V: type) type {
|
||||
.err => |e| return .{ .err = e },
|
||||
};
|
||||
|
||||
const val = This.applyOp(&a, &b, input.allocator(), ctx_for_op_and_fallback, op) orelse This{
|
||||
.function = bun.create(
|
||||
input.allocator(),
|
||||
MathFunction(V),
|
||||
fallback(ctx_for_op_and_fallback, a, b),
|
||||
),
|
||||
const val = switch (math_op) {
|
||||
.round_mod => blk: {
|
||||
const strat = strategy orelse RoundingStrategy.nearest;
|
||||
const op_fn = struct {
|
||||
fn op(s: RoundingStrategy, x: f32, y: f32) f32 {
|
||||
return switch (s) {
|
||||
.nearest => @round(x / y) * y,
|
||||
.down => @floor(x / y) * y,
|
||||
.up => @ceil(x / y) * y,
|
||||
.@"to-zero" => @trunc(x / y) * y,
|
||||
};
|
||||
}
|
||||
}.op;
|
||||
break :blk This.applyOp(&a, &b, input.allocator(), strat, op_fn) orelse This{
|
||||
.function = bun.create(
|
||||
input.allocator(),
|
||||
MathFunction(V),
|
||||
MathFunction(V){
|
||||
.round = .{
|
||||
.strategy = strat,
|
||||
.value = a,
|
||||
.interval = b,
|
||||
},
|
||||
},
|
||||
),
|
||||
};
|
||||
},
|
||||
.rem => blk: {
|
||||
const op_fn = struct {
|
||||
fn op(_: void, x: f32, y: f32) f32 {
|
||||
return @mod(x, y);
|
||||
}
|
||||
}.op;
|
||||
break :blk This.applyOp(&a, &b, input.allocator(), {}, op_fn) orelse This{
|
||||
.function = bun.create(
|
||||
input.allocator(),
|
||||
MathFunction(V),
|
||||
MathFunction(V){
|
||||
.rem = .{
|
||||
.dividend = a,
|
||||
.divisor = b,
|
||||
},
|
||||
},
|
||||
),
|
||||
};
|
||||
},
|
||||
.mod => blk: {
|
||||
const op_fn = struct {
|
||||
fn op(_: void, x: f32, y: f32) f32 {
|
||||
return @mod((@mod(x, y) + y), y);
|
||||
}
|
||||
}.op;
|
||||
break :blk This.applyOp(&a, &b, input.allocator(), {}, op_fn) orelse This{
|
||||
.function = bun.create(
|
||||
input.allocator(),
|
||||
MathFunction(V),
|
||||
MathFunction(V){
|
||||
.mod_ = .{
|
||||
.dividend = a,
|
||||
.divisor = b,
|
||||
},
|
||||
},
|
||||
),
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
return .{ .result = val };
|
||||
@@ -1261,7 +1279,7 @@ pub fn Calc(comptime V: type) type {
|
||||
const first = if (This.applyMap(
|
||||
&args.items[0],
|
||||
allocator,
|
||||
powi2,
|
||||
.powi2,
|
||||
)) |v| v else return .{ .result = null };
|
||||
i += 1;
|
||||
var errored: bool = false;
|
||||
@@ -1280,7 +1298,7 @@ pub fn Calc(comptime V: type) type {
|
||||
|
||||
if (errored) return .{ .result = null };
|
||||
|
||||
return .{ .result = This.applyMap(&sum, allocator, sqrtf32) };
|
||||
return .{ .result = This.applyMap(&sum, allocator, .sqrtf32) };
|
||||
}
|
||||
|
||||
pub fn applyOp(
|
||||
@@ -1312,19 +1330,31 @@ pub fn Calc(comptime V: type) type {
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn applyMap(this: *const This, allocator: Allocator, comptime op: *const fn (f32) f32) ?This {
|
||||
pub const MapOp = enum { absf, sqrtf32, powi2 };
|
||||
|
||||
pub fn applyMap(this: *const This, allocator: Allocator, op: MapOp) ?This {
|
||||
switch (this.*) {
|
||||
.number => |n| return This{ .number = op(n) },
|
||||
.number => |n| return This{
|
||||
.number = switch (op) {
|
||||
.absf => absf(n),
|
||||
.sqrtf32 => sqrtf32(n),
|
||||
.powi2 => powi2(n),
|
||||
},
|
||||
},
|
||||
.value => |v| {
|
||||
if (css.generic.tryMap(V, v, op)) |new_v| {
|
||||
return This{
|
||||
.value = bun.create(
|
||||
allocator,
|
||||
V,
|
||||
new_v,
|
||||
),
|
||||
};
|
||||
}
|
||||
const new_v = switch (op) {
|
||||
.absf => css.generic.tryMap(V, v, absf),
|
||||
.sqrtf32 => css.generic.tryMap(V, v, sqrtf32),
|
||||
.powi2 => css.generic.tryMap(V, v, powi2),
|
||||
} orelse return null;
|
||||
|
||||
return This{
|
||||
.value = bun.create(
|
||||
allocator,
|
||||
V,
|
||||
new_v,
|
||||
),
|
||||
};
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user