mirror of
https://github.com/oven-sh/bun
synced 2026-02-14 12:51:54 +00:00
Replaced generic `property()` and `maybeFlush()` functions that used `comptime prop: []const u8` and `val: anytype` with specific typed functions for each transition property. **Changes:** - Created 4 specific property functions: - propertyProperties() for SmallList(PropertyId, 1) - propertyDurations() for SmallList(Time, 1) - propertyDelays() for SmallList(Time, 1) - propertyTimingFunctions() for SmallList(EasingFunction, 1) - Created 4 specific maybeFlush functions: - maybeFlushProperties() - maybeFlushDurations() - maybeFlushDelays() - maybeFlushTimingFunctions() - Updated all 8 call sites to use the specific functions This eliminates the last remaining comptime parameter bloat in transition property handlers, reducing instantiations from ~16 to 4. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
598 lines
30 KiB
Zig
598 lines
30 KiB
Zig
pub const css = @import("../css_parser.zig");
|
|
|
|
const SmallList = css.SmallList;
|
|
const Printer = css.Printer;
|
|
const PrintErr = css.PrintErr;
|
|
|
|
const Property = css.css_properties.Property;
|
|
const PropertyId = css.css_properties.PropertyId;
|
|
const Time = css.css_values.time.Time;
|
|
const EasingFunction = css.css_values.easing.EasingFunction;
|
|
|
|
const VendorPrefix = css.VendorPrefix;
|
|
const Feature = css.prefixes.Feature;
|
|
|
|
/// A value for the [transition](https://www.w3.org/TR/2018/WD-css-transitions-1-20181011/#transition-shorthand-property) property.
|
|
pub const Transition = struct {
|
|
/// The property to transition.
|
|
property: PropertyId,
|
|
/// The duration of the transition.
|
|
duration: Time,
|
|
/// The delay before the transition starts.
|
|
delay: Time,
|
|
/// The easing function for the transition.
|
|
timing_function: EasingFunction,
|
|
|
|
pub const PropertyFieldMap = .{
|
|
.property = css.PropertyIdTag.@"transition-property",
|
|
.duration = css.PropertyIdTag.@"transition-duration",
|
|
.delay = css.PropertyIdTag.@"transition-delay",
|
|
.timing_function = css.PropertyIdTag.@"transition-timing-function",
|
|
};
|
|
|
|
pub fn eql(lhs: *const @This(), rhs: *const @This()) bool {
|
|
return css.implementEql(@This(), lhs, rhs);
|
|
}
|
|
|
|
pub fn deepClone(this: *const @This(), allocator: Allocator) @This() {
|
|
return css.implementDeepClone(comptime @This(), this, allocator);
|
|
}
|
|
|
|
pub fn parse(parser: *css.Parser) css.Result(@This()) {
|
|
var property: ?PropertyId = null;
|
|
var duration: ?Time = null;
|
|
var delay: ?Time = null;
|
|
var timing_function: ?EasingFunction = null;
|
|
|
|
while (true) {
|
|
if (duration == null) {
|
|
if (parser.tryParse(Time.parse, .{}).asValue()) |value| {
|
|
duration = value;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (timing_function == null) {
|
|
if (parser.tryParse(EasingFunction.parse, .{}).asValue()) |value| {
|
|
timing_function = value;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (delay == null) {
|
|
if (parser.tryParse(Time.parse, .{}).asValue()) |value| {
|
|
delay = value;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (property == null) {
|
|
if (parser.tryParse(PropertyId.parse, .{}).asValue()) |value| {
|
|
property = value;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return .{ .result = .{
|
|
.property = property orelse .all,
|
|
.duration = duration orelse .{ .seconds = 0.0 },
|
|
.delay = delay orelse .{ .seconds = 0.0 },
|
|
.timing_function = timing_function orelse .ease,
|
|
} };
|
|
}
|
|
|
|
pub fn toCss(this: *const @This(), comptime W: type, dest: *Printer(W)) PrintErr!void {
|
|
try this.property.toCss(W, dest);
|
|
if (!this.duration.isZero() or !this.delay.isZero()) {
|
|
try dest.writeChar(' ');
|
|
try this.duration.toCss(W, dest);
|
|
}
|
|
|
|
if (!this.timing_function.isEase()) {
|
|
try dest.writeChar(' ');
|
|
try this.timing_function.toCss(W, dest);
|
|
}
|
|
|
|
if (!this.delay.isZero()) {
|
|
try dest.writeChar(' ');
|
|
try this.delay.toCss(W, dest);
|
|
}
|
|
}
|
|
};
|
|
|
|
pub const TransitionHandler = struct {
|
|
properties: ?struct { SmallList(PropertyId, 1), VendorPrefix } = null,
|
|
durations: ?struct { SmallList(Time, 1), VendorPrefix } = null,
|
|
delays: ?struct { SmallList(Time, 1), VendorPrefix } = null,
|
|
timing_functions: ?struct { SmallList(EasingFunction, 1), VendorPrefix } = null,
|
|
has_any: bool = false,
|
|
|
|
pub fn handleProperty(this: *@This(), prop: *const Property, dest: *css.DeclarationList, context: *css.PropertyHandlerContext) bool {
|
|
switch (prop.*) {
|
|
.@"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];
|
|
|
|
var properties = SmallList(PropertyId, 1).initCapacity(context.allocator, val.len());
|
|
var durations = SmallList(Time, 1).initCapacity(context.allocator, val.len());
|
|
var delays = SmallList(Time, 1).initCapacity(context.allocator, val.len());
|
|
var timing_functions = SmallList(EasingFunction, 1).initCapacity(context.allocator, val.len());
|
|
properties.setLen(val.len());
|
|
durations.setLen(val.len());
|
|
delays.setLen(val.len());
|
|
timing_functions.setLen(val.len());
|
|
|
|
for (val.slice(), properties.slice_mut()) |*item, *out_prop| {
|
|
out_prop.* = item.property.deepClone(context.allocator);
|
|
}
|
|
this.maybeFlushProperties(dest, context, &properties, vp);
|
|
|
|
for (val.slice(), durations.slice_mut()) |*item, *out_dur| {
|
|
out_dur.* = item.duration.deepClone(context.allocator);
|
|
}
|
|
this.maybeFlushDurations(dest, context, &durations, vp);
|
|
|
|
for (val.slice(), delays.slice_mut()) |*item, *out_delay| {
|
|
out_delay.* = item.delay.deepClone(context.allocator);
|
|
}
|
|
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.maybeFlushTimingFunctions(dest, context, &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);
|
|
dest.append(
|
|
context.allocator,
|
|
.{ .unparsed = x.getPrefixed(context.allocator, context.targets, Feature.transition) },
|
|
) catch |err| bun.handleOom(err);
|
|
} else return false,
|
|
else => return false,
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
pub fn finalize(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void {
|
|
this.flush(dest, context);
|
|
}
|
|
|
|
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);
|
|
|
|
if (this.properties) |*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.properties = .{ cloned_val, prefixes };
|
|
this.has_any = true;
|
|
}
|
|
}
|
|
|
|
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)) {
|
|
this.flush(dest, context);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn flush(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void {
|
|
if (!this.has_any) return;
|
|
this.has_any = false;
|
|
|
|
var _properties: ?struct { SmallList(PropertyId, 1), VendorPrefix } = bun.take(&this.properties);
|
|
var _durations: ?struct { SmallList(Time, 1), VendorPrefix } = bun.take(&this.durations);
|
|
var _delays: ?struct { SmallList(Time, 1), VendorPrefix } = bun.take(&this.delays);
|
|
var _timing_functions: ?struct { SmallList(EasingFunction, 1), VendorPrefix } = bun.take(&this.timing_functions);
|
|
|
|
var rtl_properties: ?SmallList(PropertyId, 1) = if (_properties) |*p| expandProperties(&p.*[0], context) else null;
|
|
|
|
if (_properties != null and _durations != null and _delays != null and _timing_functions != null) {
|
|
const properties: *SmallList(PropertyId, 1) = &_properties.?[0];
|
|
const property_prefixes: *VendorPrefix = &_properties.?[1];
|
|
const durations: *SmallList(Time, 1) = &_durations.?[0];
|
|
const duration_prefixes: *VendorPrefix = &_durations.?[1];
|
|
const delays: *SmallList(Time, 1) = &_delays.?[0];
|
|
const delay_prefixes: *VendorPrefix = &_delays.?[1];
|
|
const timing_functions: *SmallList(EasingFunction, 1) = &_timing_functions.?[0];
|
|
const timing_prefixes: *VendorPrefix = &_timing_functions.?[1];
|
|
|
|
// Find the intersection of prefixes with the same value.
|
|
// Remove that from the prefixes of each of the properties. The remaining
|
|
// prefixes will be handled by outputting individual properties below.
|
|
const intersection = property_prefixes.bitwiseAnd(duration_prefixes.*).bitwiseAnd(delay_prefixes.*).bitwiseAnd(timing_prefixes.*);
|
|
if (!intersection.isEmpty()) {
|
|
const transitions = getTransitions(context, properties, durations, delays, timing_functions);
|
|
|
|
if (rtl_properties) |*rtl_properties2| {
|
|
const rtl_transitions = getTransitions(context, rtl_properties2, durations, delays, timing_functions);
|
|
context.addLogicalRule(
|
|
context.allocator,
|
|
Property{
|
|
.transition = .{ transitions, intersection },
|
|
},
|
|
Property{
|
|
.transition = .{ rtl_transitions, intersection },
|
|
},
|
|
);
|
|
} else {
|
|
dest.append(
|
|
context.allocator,
|
|
Property{ .transition = .{ transitions.deepClone(context.allocator), intersection } },
|
|
) catch |err| bun.handleOom(err);
|
|
}
|
|
|
|
bun.bits.remove(VendorPrefix, property_prefixes, intersection);
|
|
bun.bits.remove(VendorPrefix, duration_prefixes, intersection);
|
|
bun.bits.remove(VendorPrefix, timing_prefixes, intersection);
|
|
bun.bits.remove(VendorPrefix, delay_prefixes, intersection);
|
|
}
|
|
}
|
|
|
|
if (_properties != null) {
|
|
const properties: SmallList(PropertyId, 1) = _properties.?[0];
|
|
const prefix: VendorPrefix = _properties.?[1];
|
|
_properties = null;
|
|
if (!prefix.isEmpty()) {
|
|
if (rtl_properties) |rtl_properties2| {
|
|
context.addLogicalRule(
|
|
context.allocator,
|
|
Property{ .@"transition-property" = .{ properties, prefix } },
|
|
Property{ .@"transition-property" = .{ rtl_properties2, prefix } },
|
|
);
|
|
rtl_properties = null;
|
|
} else {
|
|
bun.handleOom(dest.append(context.allocator, Property{ .@"transition-property" = .{ properties, prefix } }));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_durations != null) {
|
|
const durations: SmallList(Time, 1) = _durations.?[0];
|
|
const prefix: VendorPrefix = _durations.?[1];
|
|
_durations = null;
|
|
if (!prefix.isEmpty()) {
|
|
bun.handleOom(dest.append(context.allocator, Property{ .@"transition-duration" = .{ durations, prefix } }));
|
|
}
|
|
}
|
|
|
|
if (_delays != null) {
|
|
const delays: SmallList(Time, 1) = _delays.?[0];
|
|
const prefix: VendorPrefix = _delays.?[1];
|
|
_delays = null;
|
|
if (!prefix.isEmpty()) {
|
|
bun.handleOom(dest.append(context.allocator, Property{ .@"transition-delay" = .{ delays, prefix } }));
|
|
}
|
|
}
|
|
|
|
if (_timing_functions != null) {
|
|
const timing_functions: SmallList(EasingFunction, 1) = _timing_functions.?[0];
|
|
const prefix: VendorPrefix = _timing_functions.?[1];
|
|
_timing_functions = null;
|
|
if (!prefix.isEmpty()) {
|
|
bun.handleOom(dest.append(context.allocator, Property{ .@"transition-timing-function" = .{ timing_functions, prefix } }));
|
|
}
|
|
}
|
|
|
|
this.reset();
|
|
}
|
|
|
|
inline fn getTransitions(
|
|
context: *const css.PropertyHandlerContext,
|
|
properties: *SmallList(PropertyId, 1),
|
|
durations: *SmallList(Time, 1),
|
|
delays: *SmallList(Time, 1),
|
|
timing_functions: *SmallList(EasingFunction, 1),
|
|
) SmallList(Transition, 1) {
|
|
const cycleBump = struct {
|
|
inline fn cycleBump(idx: *u32, len: u32) void {
|
|
idx.* = (idx.* + 1) % len;
|
|
}
|
|
}.cycleBump;
|
|
|
|
// transition-property determines the number of transitions. The values of other
|
|
// properties are repeated to match this length.
|
|
var transitions = SmallList(Transition, 1).initCapacity(context.allocator, 1);
|
|
var durations_idx: u32 = 0;
|
|
var delays_idx: u32 = 0;
|
|
var timing_idx: u32 = 0;
|
|
for (properties.slice()) |*property_id| {
|
|
const duration = if (durations.len() > durations_idx) durations.at(durations_idx).deepClone(context.allocator) else Time{ .seconds = 0.0 };
|
|
const delay = if (delays.len() > delays_idx) delays.at(delays_idx).deepClone(context.allocator) else Time{ .seconds = 0.0 };
|
|
const timing_function = if (timing_functions.len() > timing_idx) timing_functions.at(timing_idx).deepClone(context.allocator) else EasingFunction.ease;
|
|
cycleBump(&durations_idx, durations.len());
|
|
cycleBump(&delays_idx, delays.len());
|
|
cycleBump(&timing_idx, timing_functions.len());
|
|
const transition = Transition{
|
|
.property = property_id.deepClone(context.allocator),
|
|
.duration = duration,
|
|
.delay = delay,
|
|
.timing_function = timing_function,
|
|
};
|
|
var cloned = false;
|
|
|
|
const prefix_to_iter = property_id.prefix().orNone();
|
|
// Expand vendor prefixes into multiple transitions.
|
|
inline for (VendorPrefix.FIELDS) |prefix_field| {
|
|
if (@field(prefix_to_iter, prefix_field)) {
|
|
var t = if (cloned) transition.deepClone(context.allocator) else transition;
|
|
cloned = true;
|
|
var new_prefix = VendorPrefix{};
|
|
@field(new_prefix, prefix_field) = true;
|
|
t.property = property_id.withPrefix(new_prefix);
|
|
transitions.append(context.allocator, t);
|
|
}
|
|
}
|
|
}
|
|
return transitions;
|
|
}
|
|
|
|
pub fn reset(this: *@This()) void {
|
|
this.properties = null;
|
|
this.durations = null;
|
|
this.delays = null;
|
|
this.timing_functions = null;
|
|
this.has_any = false;
|
|
}
|
|
};
|
|
|
|
fn expandProperties(properties: *css.SmallList(PropertyId, 1), context: *css.PropertyHandlerContext) ?SmallList(PropertyId, 1) {
|
|
const replace = struct {
|
|
inline fn replace(allocator: Allocator, propertiez: anytype, props: []const PropertyId, i: u32) void {
|
|
propertiez.mut(i).* = props[0].deepClone(allocator);
|
|
if (props.len > 1) {
|
|
propertiez.insertSlice(allocator, i + 1, props[1..]);
|
|
}
|
|
}
|
|
}.replace;
|
|
|
|
var rtl_properties: ?SmallList(PropertyId, 1) = null;
|
|
var i: u32 = 0;
|
|
|
|
// Expand logical properties in place.
|
|
while (i < properties.len()) {
|
|
const result = getLogicalProperties(properties.at(i));
|
|
if (result == .block and context.shouldCompileLogical(result.block[0])) {
|
|
replace(context.allocator, properties, result.block[1], i);
|
|
if (rtl_properties) |*rtl| {
|
|
replace(context.allocator, rtl, result.block[1], i);
|
|
}
|
|
i += 1;
|
|
} else if (result == .@"inline" and context.shouldCompileLogical(result.@"inline"[0])) {
|
|
const ltr = result.@"inline"[1];
|
|
const rtl = result.@"inline"[2];
|
|
// Clone properties to create RTL version only when needed.
|
|
if (rtl_properties == null) {
|
|
rtl_properties = properties.deepClone(context.allocator);
|
|
}
|
|
|
|
replace(context.allocator, properties, ltr, i);
|
|
if (rtl_properties) |*rtl_props| {
|
|
replace(context.allocator, rtl_props, rtl, i);
|
|
}
|
|
|
|
i += @intCast(ltr.len);
|
|
} else {
|
|
// Expand vendor prefixes for targets.
|
|
properties.mut(i).setPrefixesForTargets(context.targets);
|
|
|
|
// Expand mask properties, which use different vendor-prefixed names.
|
|
if (css.css_properties.masking.getWebkitMaskProperty(properties.at(i))) |property_id| {
|
|
if (context.targets.prefixes(VendorPrefix.NONE, Feature.mask_border).webkit) {
|
|
properties.insert(context.allocator, i, property_id);
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
if (rtl_properties) |*rtl_props| {
|
|
rtl_props.mut(i).setPrefixesForTargets(context.targets);
|
|
|
|
if (css.css_properties.masking.getWebkitMaskProperty(rtl_props.at(i))) |property_id| {
|
|
if (context.targets.prefixes(VendorPrefix.NONE, Feature.mask_border).webkit) {
|
|
rtl_props.insert(context.allocator, i, property_id);
|
|
i += 1;
|
|
}
|
|
}
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
return rtl_properties;
|
|
}
|
|
|
|
const LogicalPropertyId = union(enum) {
|
|
none,
|
|
block: struct { css.compat.Feature, []const PropertyId },
|
|
@"inline": struct { css.compat.Feature, []const PropertyId, []const PropertyId },
|
|
};
|
|
|
|
fn getLogicalProperties(property_id: *const PropertyId) LogicalPropertyId {
|
|
return switch (property_id.*) {
|
|
.@"block-size" => .{ .block = .{ .logical_size, &[_]PropertyId{.height} } },
|
|
.@"inline-size" => .{ .@"inline" = .{ .logical_size, &[_]PropertyId{.width}, &[_]PropertyId{.height} } },
|
|
.@"min-block-size" => .{ .block = .{ .logical_size, &[_]PropertyId{.@"min-height"} } },
|
|
.@"max-block-size" => .{ .block = .{ .logical_size, &[_]PropertyId{.@"max-height"} } },
|
|
.@"min-inline-size" => .{ .@"inline" = .{ .logical_size, &[_]PropertyId{.@"min-width"}, &[_]PropertyId{.@"min-height"} } },
|
|
.@"max-inline-size" => .{ .@"inline" = .{ .logical_size, &[_]PropertyId{.@"max-width"}, &[_]PropertyId{.@"max-height"} } },
|
|
|
|
.@"inset-block-start" => .{ .block = .{ .logical_inset, &[_]PropertyId{.top} } },
|
|
.@"inset-block-end" => .{ .block = .{ .logical_inset, &[_]PropertyId{.bottom} } },
|
|
.@"inset-inline-start" => .{ .@"inline" = .{ .logical_inset, &[_]PropertyId{.left}, &[_]PropertyId{.right} } },
|
|
.@"inset-inline-end" => .{ .@"inline" = .{ .logical_inset, &[_]PropertyId{.right}, &[_]PropertyId{.left} } },
|
|
.@"inset-block" => .{ .block = .{ .logical_inset, &[_]PropertyId{ .top, .bottom } } },
|
|
.@"inset-inline" => .{ .block = .{ .logical_inset, &[_]PropertyId{ .left, .right } } },
|
|
.inset => .{ .block = .{ .logical_inset, &[_]PropertyId{ .top, .bottom, .left, .right } } },
|
|
|
|
.@"margin-block-start" => .{ .block = .{ .logical_margin, &[_]PropertyId{.@"margin-top"} } },
|
|
.@"margin-block-end" => .{ .block = .{ .logical_margin, &[_]PropertyId{.@"margin-bottom"} } },
|
|
.@"margin-inline-start" => .{ .@"inline" = .{ .logical_margin, &[_]PropertyId{.@"margin-left"}, &[_]PropertyId{.@"margin-right"} } },
|
|
.@"margin-inline-end" => .{ .@"inline" = .{ .logical_margin, &[_]PropertyId{.@"margin-right"}, &[_]PropertyId{.@"margin-left"} } },
|
|
.@"margin-block" => .{ .block = .{ .logical_margin, &[_]PropertyId{ .@"margin-top", .@"margin-bottom" } } },
|
|
.@"margin-inline" => .{ .block = .{ .logical_margin, &[_]PropertyId{ .@"margin-left", .@"margin-right" } } },
|
|
|
|
.@"padding-block-start" => .{ .block = .{ .logical_padding, &[_]PropertyId{.@"padding-top"} } },
|
|
.@"padding-block-end" => .{ .block = .{ .logical_padding, &[_]PropertyId{.@"padding-bottom"} } },
|
|
.@"padding-inline-start" => .{ .@"inline" = .{ .logical_padding, &[_]PropertyId{.@"padding-left"}, &[_]PropertyId{.@"padding-right"} } },
|
|
.@"padding-inline-end" => .{ .@"inline" = .{ .logical_padding, &[_]PropertyId{.@"padding-right"}, &[_]PropertyId{.@"padding-left"} } },
|
|
.@"padding-block" => .{ .block = .{ .logical_padding, &[_]PropertyId{ .@"padding-top", .@"padding-bottom" } } },
|
|
.@"padding-inline" => .{ .block = .{ .logical_padding, &[_]PropertyId{ .@"padding-left", .@"padding-right" } } },
|
|
|
|
.@"border-block-start" => .{ .block = .{ .logical_borders, &[_]PropertyId{.@"border-top"} } },
|
|
.@"border-block-start-width" => .{ .block = .{ .logical_borders, &[_]PropertyId{.@"border-top-width"} } },
|
|
.@"border-block-start-color" => .{ .block = .{ .logical_borders, &[_]PropertyId{.@"border-top-color"} } },
|
|
.@"border-block-start-style" => .{ .block = .{ .logical_borders, &[_]PropertyId{.@"border-top-style"} } },
|
|
|
|
.@"border-block-end" => .{ .block = .{ .logical_borders, &[_]PropertyId{.@"border-bottom"} } },
|
|
.@"border-block-end-width" => .{ .block = .{ .logical_borders, &[_]PropertyId{.@"border-bottom-width"} } },
|
|
.@"border-block-end-color" => .{ .block = .{ .logical_borders, &[_]PropertyId{.@"border-bottom-color"} } },
|
|
.@"border-block-end-style" => .{ .block = .{ .logical_borders, &[_]PropertyId{.@"border-bottom-style"} } },
|
|
|
|
.@"border-inline-start" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{.@"border-left"}, &[_]PropertyId{.@"border-right"} } },
|
|
.@"border-inline-start-width" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{.@"border-left-width"}, &[_]PropertyId{.@"border-right-width"} } },
|
|
.@"border-inline-start-color" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{.@"border-left-color"}, &[_]PropertyId{.@"border-right-color"} } },
|
|
.@"border-inline-start-style" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{.@"border-left-style"}, &[_]PropertyId{.@"border-right-style"} } },
|
|
|
|
.@"border-inline-end" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{.@"border-right"}, &[_]PropertyId{.@"border-left"} } },
|
|
.@"border-inline-end-width" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{.@"border-right-width"}, &[_]PropertyId{.@"border-left-width"} } },
|
|
.@"border-inline-end-color" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{.@"border-right-color"}, &[_]PropertyId{.@"border-left-color"} } },
|
|
.@"border-inline-end-style" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{.@"border-right-style"}, &[_]PropertyId{.@"border-left-style"} } },
|
|
|
|
.@"border-block" => .{ .block = .{ .logical_borders, &[_]PropertyId{ .@"border-top", .@"border-bottom" } } },
|
|
.@"border-block-color" => .{ .block = .{ .logical_borders, &[_]PropertyId{ .@"border-top-color", .@"border-bottom-color" } } },
|
|
.@"border-block-width" => .{ .block = .{ .logical_borders, &[_]PropertyId{ .@"border-top-width", .@"border-bottom-width" } } },
|
|
.@"border-block-style" => .{ .block = .{ .logical_borders, &[_]PropertyId{ .@"border-top-style", .@"border-bottom-style" } } },
|
|
|
|
.@"border-inline" => .{ .block = .{ .logical_borders, &[_]PropertyId{ .@"border-left", .@"border-right" } } },
|
|
.@"border-inline-color" => .{ .block = .{ .logical_borders, &[_]PropertyId{ .@"border-left-color", .@"border-right-color" } } },
|
|
.@"border-inline-width" => .{ .block = .{ .logical_borders, &[_]PropertyId{ .@"border-left-width", .@"border-right-width" } } },
|
|
.@"border-inline-style" => .{ .block = .{ .logical_borders, &[_]PropertyId{ .@"border-left-style", .@"border-right-style" } } },
|
|
|
|
.@"border-start-start-radius" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{PropertyId{ .@"border-top-left-radius" = VendorPrefix.NONE }}, &[_]PropertyId{PropertyId{ .@"border-top-right-radius" = VendorPrefix.NONE }} } },
|
|
.@"border-start-end-radius" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{PropertyId{ .@"border-top-right-radius" = VendorPrefix.NONE }}, &[_]PropertyId{PropertyId{ .@"border-top-left-radius" = VendorPrefix.NONE }} } },
|
|
.@"border-end-start-radius" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{PropertyId{ .@"border-bottom-left-radius" = VendorPrefix.NONE }}, &[_]PropertyId{PropertyId{ .@"border-bottom-right-radius" = VendorPrefix.NONE }} } },
|
|
.@"border-end-end-radius" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{PropertyId{ .@"border-bottom-right-radius" = VendorPrefix.NONE }}, &[_]PropertyId{PropertyId{ .@"border-bottom-left-radius" = VendorPrefix.NONE }} } },
|
|
|
|
else => .none,
|
|
};
|
|
}
|
|
|
|
fn isTransitionProperty(property_id: *const PropertyId) bool {
|
|
return switch (property_id.*) {
|
|
.@"transition-property",
|
|
.@"transition-duration",
|
|
.@"transition-delay",
|
|
.@"transition-timing-function",
|
|
.transition,
|
|
=> true,
|
|
else => false,
|
|
};
|
|
}
|
|
|
|
const bun = @import("bun");
|
|
const std = @import("std");
|
|
const Allocator = std.mem.Allocator;
|