tiny.css.value
Defined in tiny.css.
Typed CSS values and the sixteen byte declaration record they lower into.
API (31)
Actions
Public operations.
Declaration.importantDeclaration.value: The value this declaration carries.Keyword.parse: Resolves a keyword by its CSS spelling, where an underscore in the tag stands for a hyphen.Keyword.spelling: The CSS spelling of this keyword, with hyphens restored.Unit.parse: Resolves a dimension unit by name, folded to ASCII lower case.Value.asKeyword: The keyword behind a keyword value, orinvalidfor any other kind.Value.asNumber: The scalar behind a length, percentage, or number.Value.asString: The source span behind a string value.Value.colorValue.declare: Binds this value to a property, producing the published record.Value.keywordValue.lengthValue.numberValue.percentValue.presentValue.stringValue.valueKindValue.valueUnitaccepted: The admitted shapes of one grammar.hasVariable: Whethersource[start..end]carries avar()reference, which defers the value to computed value time.parse: Readssource[start..end]undergrammar.
Types and contracts
Public types and contracts.
Accept: Which shapes a grammar admits, plus the keywords it names.DeclarationGrammar: The value grammar a property accepts.Keyword: Every keyword this engine understands, in one closed set so that a computed keyword is an integer rather than a byte slice.Kind: How theaandbwords of a value are read.Unit: The unit alengthcarries.Value: One computed value.
Namespaces
Public namespaces.
Values and defaults
Public values and defaults.
flag_important: Bit zero of theflagsword marks an important declaration.wide: The four keywords every property accepts.
Source
Source: lib/css/src/value/parse.zig:14
/// Which shapes a grammar admits, plus the keywords it names. One generic/// reader consumes this so a property table entry stays a single enum tag.pub const Accept = struct { length: bool = false, percent: bool = false, number: bool = false, integer: bool = false, color: bool = false, string: bool = false, url: bool = false, raw: bool = false, keywords: []const Keyword = &.{},};Source: lib/css/src/value/scalar.zig:355
pub const Declaration = extern struct { property: u32, kind: u8, unit: u8, flags: u16, a: u32, b: u32, /// The value this declaration carries. Importance is a cascade input /// rather than part of the value, so it is dropped here. pub fn value(self: Declaration) Value { return .{ .kind = self.kind, .unit = self.unit, .flags = self.flags & ~flag_important, .a = self.a, .b = self.b, }; } pub fn important(self: Declaration) bool { return self.flags & flag_important != 0; }};Source: lib/css/src/value/scalar.zig:210
/// The value grammar a property accepts. `value.parse` switches on it, so a/// property table entry names a grammar rather than carrying a parser.pub const Grammar = enum(u8) { length, length_percentage, length_percentage_auto, size, number, integer, opacity, color, string, url, display, position, overflow, visibility, box_sizing, flex_direction, flex_wrap, justify, @"align", align_self, text_align, text_transform, white_space, font_style, font_weight, font_family, line_height, border_style, text_decoration_line, cursor, list_style_type, vertical_align, content, z_index, gap, flex_basis, length_normal, direction, text_overflow, word_break, overflow_wrap, object_fit, pointer_events, user_select, list_style_position, background_repeat, background_size, background_box, background_attachment,};Source: lib/css/src/value/scalar.zig:51
/// Every keyword this engine understands, in one closed set so that a computed/// keyword is an integer rather than a byte slice.pub const Keyword = enum(u32) { invalid = 0, inherit, initial, unset, revert, auto, none, normal, block, @"inline", inline_block, flex, inline_flex, contents, static, relative, absolute, fixed, sticky, visible, hidden, scroll, clip, collapse, content_box, border_box, row, row_reverse, column, column_reverse, nowrap, wrap, wrap_reverse, flex_start, flex_end, center, space_between, space_around, space_evenly, start, end, stretch, baseline, left, right, justify, capitalize, uppercase, lowercase, pre, pre_wrap, pre_line, break_spaces, italic, oblique, bold, bolder, lighter, solid, dashed, dotted, double, groove, ridge, inset, outset, underline, overline, line_through, default, pointer, text, move, not_allowed, grab, grabbing, crosshair, wait, help, progress, disc, circle, square, decimal, lower_alpha, upper_alpha, lower_roman, upper_roman, top, middle, bottom, sub, super, text_top, text_bottom, min_content, max_content, fit_content, content, currentcolor, transparent, ltr, rtl, ellipsis, break_all, keep_all, break_word, anywhere, fill, contain, cover, scale_down, all, inside, outside, repeat, repeat_x, repeat_y, no_repeat, space, round, padding_box, local, /// Resolves a keyword by its CSS spelling, where an underscore in the tag /// stands for a hyphen. pub fn parse(word: []const u8) ?Keyword { if (word.len == 0 or word.len > max_keyword_bytes) return null; var buffer: [max_keyword_bytes]u8 = undefined; for (word, 0..) |byte, index| { buffer[index] = if (byte == '-') '_' else std.ascii.toLower(byte); } return std.meta.stringToEnum(Keyword, buffer[0..word.len]); } /// The CSS spelling of this keyword, with hyphens restored. pub fn spelling(self: Keyword) []const u8 { @setEvalBranchQuota(64_000); return switch (self) { inline else => |tag| comptime spell(@tagName(tag)), }; }};Source: lib/css/src/value/scalar.zig:7
/// How the `a` and `b` words of a value are read.////// `asset` and `pair` are part of the published record layout and are produced/// by the tree publisher rather than by a stylesheet.pub const Kind = enum(u8) { invalid = 0, keyword = 1, length = 2, percent = 3, number = 4, color = 5, string = 6, asset = 7, pair = 8,};Source: lib/css/src/value/scalar.zig:20
/// The unit a `length` carries. A percentage is a `Kind`, not a unit.pub const Unit = enum(u8) { none = 0, px = 1, em = 2, rem = 3, ch = 4, lh = 5, ex = 6, vw = 7, vh = 8, vmin = 9, vmax = 10, fr = 11, deg = 12, s = 13, ms = 14, /// Resolves a dimension unit by name, folded to ASCII lower case. pub fn parse(spelling: []const u8) ?Unit { const info = @typeInfo(Unit).@"enum"; inline for (info.field_names, info.field_values) |field_name, field_value| { if (field_value != 0 and std.ascii.eqlIgnoreCase(spelling, field_name)) { return @fromBackingInt(@intCast(field_value)); } } return null; }};Source: lib/css/src/value/scalar.zig:267
/// One computed value. Twelve bytes, laid out as the published declaration/// record minus its property word.pub const Value = extern struct { kind: u8 = @backingInt(Kind.invalid), unit: u8 = @backingInt(Unit.none), flags: u16 = 0, a: u32 = 0, b: u32 = 0, pub fn keyword(word: Keyword) Value { return .{ .kind = @backingInt(Kind.keyword), .a = @backingInt(word) }; } pub fn length(amount: f32, unit: Unit) Value { return .{ .kind = @backingInt(Kind.length), .unit = @backingInt(unit), .a = @bitCast(amount), }; } pub fn percent(amount: f32) Value { return .{ .kind = @backingInt(Kind.percent), .a = @bitCast(amount) }; } pub fn number(amount: f32) Value { return .{ .kind = @backingInt(Kind.number), .a = @bitCast(amount) }; } pub fn color(packed_rgba: u32) Value { return .{ .kind = @backingInt(Kind.color), .a = packed_rgba }; } pub fn string(offset: u32, length_bytes: u32) Value { return .{ .kind = @backingInt(Kind.string), .a = offset, .b = length_bytes }; } pub fn valueKind(self: Value) Kind { return @fromBackingInt(@intCast(self.kind)); } pub fn valueUnit(self: Value) Unit { return @fromBackingInt(@intCast(self.unit)); } /// The keyword behind a keyword value, or `invalid` for any other kind. pub fn asKeyword(self: Value) Keyword { if (self.valueKind() != .keyword) return .invalid; return @fromBackingInt(@intCast(self.a)); } /// The scalar behind a length, percentage, or number. pub fn asNumber(self: Value) f32 { std.debug.assert(numeric(self.valueKind())); return @bitCast(self.a); } /// The source span behind a string value. pub fn asString(self: Value, source: []const u8) []const u8 { std.debug.assert(self.valueKind() == .string); return source[self.a..][0..self.b]; } pub fn present(self: Value) bool { return self.valueKind() != .invalid; } /// Binds this value to a property, producing the published record. pub fn declare(self: Value, property: u32, important: bool) Declaration { return .{ .property = property, .kind = self.kind, .unit = self.unit, .flags = self.flags | (if (important) flag_important else 0), .a = self.a, .b = self.b, }; }};Source: lib/css/src/value/parse.zig:72
/// The admitted shapes of one grammar.pub fn accepted(grammar: Grammar) Accept { return switch (grammar) { .length => .{ .length = true }, .length_percentage => .{ .length = true, .percent = true }, .length_percentage_auto => .{ .length = true, .percent = true, .keywords = &.{.auto} }, .size => .{ .length = true, .percent = true, .keywords = &.{ .auto, .none, .min_content, .max_content, .fit_content, } }, .number => .{ .number = true }, .integer => .{ .integer = true }, .opacity => .{ .number = true, .percent = true }, .color => .{ .color = true }, .string => .{ .string = true }, .url => .{ .url = true, .keywords = &.{.none} }, .display => .{ .keywords = &.{ .block, .@"inline", .inline_block, .flex, .inline_flex, .none, .contents, } }, .position => .{ .keywords = &.{ .static, .relative, .absolute, .fixed, .sticky } }, .overflow => .{ .keywords = &.{ .visible, .hidden, .scroll, .auto, .clip } }, .visibility => .{ .keywords = &.{ .visible, .hidden, .collapse } }, .box_sizing => .{ .keywords = &.{ .content_box, .border_box } }, .flex_direction => .{ .keywords = &.{ .row, .row_reverse, .column, .column_reverse } }, .flex_wrap => .{ .keywords = &.{ .nowrap, .wrap, .wrap_reverse } }, .justify => .{ .keywords = &.{ .flex_start, .flex_end, .center, .space_between, .space_around, .space_evenly, .start, .end, .stretch, .normal, .left, .right, } }, .@"align" => .{ .keywords = &.{ .flex_start, .flex_end, .center, .baseline, .stretch, .start, .end, .normal, } }, .align_self => .{ .keywords = &.{ .auto, .flex_start, .flex_end, .center, .baseline, .stretch, .start, .end, } }, .text_align => .{ .keywords = &.{ .left, .right, .center, .justify, .start, .end } }, .text_transform => .{ .keywords = &.{ .none, .capitalize, .uppercase, .lowercase } }, .white_space => .{ .keywords = &.{ .normal, .nowrap, .pre, .pre_wrap, .pre_line, .break_spaces, } }, .font_style => .{ .keywords = &.{ .normal, .italic, .oblique } }, .font_weight => .{ .number = true, .keywords = &.{ .normal, .bold, .bolder, .lighter } }, .font_family => .{ .raw = true }, .line_height => .{ .number = true, .length = true, .percent = true, .keywords = &.{.normal}, }, .border_style => .{ .keywords = &.{ .none, .hidden, .solid, .dashed, .dotted, .double, .groove, .ridge, .inset, .outset, } }, .text_decoration_line => .{ .keywords = &.{ .none, .underline, .overline, .line_through, } }, .cursor => .{ .keywords = &.{ .auto, .default, .pointer, .text, .move, .not_allowed, .grab, .grabbing, .crosshair, .wait, .help, .progress, } }, .list_style_type => .{ .keywords = &.{ .none, .disc, .circle, .square, .decimal, .lower_alpha, .upper_alpha, .lower_roman, .upper_roman, } }, .vertical_align => .{ .length = true, .percent = true, .keywords = &.{ .baseline, .top, .middle, .bottom, .sub, .super, .text_top, .text_bottom, } }, .content => .{ .string = true, .keywords = &.{ .none, .normal } }, .z_index => .{ .integer = true, .keywords = &.{.auto} }, .gap => .{ .length = true, .percent = true, .keywords = &.{.normal} }, .flex_basis => .{ .length = true, .percent = true, .keywords = &.{ .auto, .content } }, .length_normal => .{ .length = true, .keywords = &.{.normal} }, .direction => .{ .keywords = &.{ .ltr, .rtl } }, .text_overflow => .{ .keywords = &.{ .clip, .ellipsis } }, .word_break => .{ .keywords = &.{ .normal, .break_all, .keep_all } }, .overflow_wrap => .{ .keywords = &.{ .normal, .break_word, .anywhere } }, .object_fit => .{ .keywords = &.{ .fill, .contain, .cover, .none, .scale_down } }, .pointer_events => .{ .keywords = &.{ .auto, .none } }, .user_select => .{ .keywords = &.{ .auto, .none, .text, .all } }, .list_style_position => .{ .keywords = &.{ .inside, .outside } }, .background_repeat => .{ .keywords = &.{ .repeat, .repeat_x, .repeat_y, .no_repeat, .space, .round, } }, .background_size => .{ .length = true, .percent = true, .keywords = &.{ .auto, .cover, .contain, } }, .background_box => .{ .keywords = &.{ .border_box, .padding_box, .content_box } }, .background_attachment => .{ .keywords = &.{ .scroll, .fixed, .local } }, };}Source: lib/css/src/value/parse.zig:57
/// Whether `source[start..end]` carries a `var()` reference, which defers the/// value to computed value time.pub fn hasVariable(source: []const u8, start: u32, end: u32) bool { std.debug.assert(start <= end); std.debug.assert(end <= source.len); var tokenizer = token.Tokenizer{ .source = source[0..end], .index = start }; var guard: usize = 0; while (guard <= source.len + 1) : (guard += 1) { const next = tokenizer.next(); if (next.kind == .eof) return false; if (next.kind != .function) continue; if (std.ascii.eqlIgnoreCase(next.value(source), "var")) return true; } return false;}Source: lib/css/src/value/parse.zig:32
/// Reads `source[start..end]` under `grammar`. String offsets are absolute, so/// a computed string value indexes the same source the sheet borrows./// Returns an invalid value when the text is not a complete match.pub fn parse(grammar: Grammar, source: []const u8, start: u32, end: u32) Value { std.debug.assert(start <= end); std.debug.assert(end <= source.len); const rules = accepted(grammar); var tokenizer = token.Tokenizer{ .source = source[0..end], .index = start }; const first = nextMeaningful(&tokenizer); if (first.kind == .eof) return .{}; if (first.kind == .ident) { if (Keyword.parse(first.value(source))) |word| { if (contains(&wide, word)) return sealed(&tokenizer, Value.keyword(word)); } } if (rules.raw) { const body = std.mem.trim(u8, source[start..end], " \t\r\n\x0C"); if (body.len == 0) return .{}; const offset = @intFromPtr(body.ptr) - @intFromPtr(source.ptr); return Value.string(@intCast(offset), @intCast(body.len)); } const value = single(rules, &tokenizer, first, source); if (!value.present()) return .{}; return sealed(&tokenizer, value);}Source: lib/css/src/value/parse.zig:27
/// The four keywords every property accepts.pub const wide = [_]Keyword{ .inherit, .initial, .unset, .revert };Source: lib/css/src/value/scalar.zig:263
/// Bit zero of the `flags` word marks an important declaration.pub const flag_important: u16 = 1;Source: lib/css/src/root.zig:45
pub const value = @import("value/root.zig");Source: lib/css/src/value/root.zig
//! Typed CSS values and the sixteen byte declaration record they lower into.//!//! A stylesheet parses strings once at load. Everything downstream reads a//! `Declaration`: a property word, a kind, a unit, a flag word, and two scalar//! words. A directly authored inline style writes the same record without//! parsing anything, so one representation serves both producers.//!//! Lengths, percentages, numbers, colours, and keywords fit the two scalar//! words outright. A string keeps a byte offset and a length into the source//! the stylesheet borrows, so no value owns heap memory.//!//! `parse` is driven by a `Grammar` tag rather than by a property identifier,//! which keeps this namespace free of the property table and makes the value//! reader testable one grammar at a time.const parser = @import("parse.zig");const scalar = @import("scalar.zig");pub const color = @import("color.zig");pub const Accept = parser.Accept;pub const Declaration = scalar.Declaration;pub const Grammar = scalar.Grammar;pub const Keyword = scalar.Keyword;pub const Kind = scalar.Kind;pub const Unit = scalar.Unit;pub const Value = scalar.Value;pub const accepted = parser.accepted;pub const flag_important = scalar.flag_important;pub const hasVariable = parser.hasVariable;pub const parse = parser.parse;pub const wide = parser.wide;Complete call list for value.parse
8 direct calls.
tiny.css.value.accepted[function] atlib/css/src/value/parse.zig:72lib.css.src.value.parse.contains[function] — private source atlib/css/src/value/parse.zig:276in nearest public ownerlib.css.src.value.parselib.css.src.value.parse.nextMeaningful[function] — private source atlib/css/src/value/parse.zig:266in nearest public ownerlib.css.src.value.parselib.css.src.value.parse.sealed[function] — private source atlib/css/src/value/parse.zig:260in nearest public ownerlib.css.src.value.parselib.css.src.value.parse.single[function] — private source atlib/css/src/value/parse.zig:166in nearest public ownerlib.css.src.value.parsetiny.css.value.Keyword.parse[function] atlib/css/src/value/scalar.zig:178tiny.css.value.Value.keyword[function] atlib/css/src/value/scalar.zig:274tiny.css.value.Value.string[function] atlib/css/src/value/scalar.zig:298
Complete caller list for value.Value.keyword
9 direct callers.
lib.css.src.cascade.resolve.test_revert_drops_its_own_origin_and_re-picks_the_level_below[function] — test source atlib/css/src/cascade/resolve.zig:486in nearest public ownerlib.css.src.cascade.resolvelib.css.src.cascade.resolve.test_the_four_wide_keywords_resolve_against_the_parent_and_the_initial_value[function] — test source atlib/css/src/cascade/resolve.zig:459in nearest public ownerlib.css.src.cascade.resolvetiny.css.property.expand[function] atlib/css/src/property/expand.zig:60lib.css.src.value.parse.identColor[function] — private source atlib/css/src/value/parse.zig:197in nearest public ownerlib.css.src.value.parsetiny.css.value.parse[function] atlib/css/src/value/parse.zig:32lib.css.src.value.parse.single[function] — private source atlib/css/src/value/parse.zig:166in nearest public ownerlib.css.src.value.parselib.css.src.value.scalar.test_an_absent_value_reports_itself_absent_and_a_keyword_reads_back[function] — test source atlib/css/src/value/scalar.zig:417in nearest public ownerlib.css.src.value.scalarlib.ui.src.style.computed.test_lowering_fills_all_text_flags_and_keyword_weight[function] — test source atlib/ui/src/style/computed.zig:286in nearest public ownertiny.ui.style.computedlib.ui.src.style.computed.test_lowering_places_outline_reach_and_z_index_in_computed_records[function] — test source atlib/ui/src/style/computed.zig:274in nearest public ownertiny.ui.style.computed
Complete caller list for value.Value.length
8 direct callers.
lib.css.src.cascade.resolve.test_an_undeclared_property_inherits_or_takes_its_initial_value[function] — test source atlib/css/src/cascade/resolve.zig:447in nearest public ownerlib.css.src.cascade.resolvelib.css.src.cascade.resolve.test_specificity_settles_a_level_before_source_order_does[function] — test source atlib/css/src/cascade/resolve.zig:432in nearest public ownerlib.css.src.cascade.resolvelib.css.src.cascade.resolve.test_the_four_wide_keywords_resolve_against_the_parent_and_the_initial_value[function] — test source atlib/css/src/cascade/resolve.zig:459in nearest public ownerlib.css.src.cascade.resolvelib.css.src.property.expand.flex[function] — private source atlib/css/src/property/expand.zig:227in nearest public ownerlib.css.src.property.expandlib.css.src.value.parse.dimension[function] — private source atlib/css/src/value/parse.zig:205in nearest public ownerlib.css.src.value.parselib.css.src.value.parse.numeric[function] — private source atlib/css/src/value/parse.zig:211in nearest public ownerlib.css.src.value.parselib.css.src.value.scalar.test_the_published_declaration_record_matches_the_fixed_layout[function] — test source atlib/css/src/value/scalar.zig:392in nearest public ownerlib.css.src.value.scalarlib.ui.src.style.computed.test_lowering_places_outline_reach_and_z_index_in_computed_records[function] — test source atlib/ui/src/style/computed.zig:274in nearest public ownertiny.ui.style.computed
Audit
| Definitions | 31 |
|---|---|
| Public names | 31 |
| Members | 216 |
| Version | 26.7.0 |
| Revision | daab053ee433 |