From f5b17fe9cf87ba4cfda1184afe25f43e8d221ede Mon Sep 17 00:00:00 2001 From: Benoit KUGLER Date: Fri, 17 Jan 2025 11:28:47 +0100 Subject: [PATCH] [css] optimize justify- and align- props (for #2) --- css/properties/keywords/keywords.go | 77 +++++++ css/properties/keywords/keywords_test.go | 56 +++++ css/properties/properties.go | 17 +- css/properties/props_gen.go | 48 ++-- css/properties/types.go | 19 ++ css/validation/validation.go | 222 +++++++++--------- css/validation/validation_test.go | 273 ++++++++++++----------- html/layout/flex.go | 81 +++---- html/layout/grid.go | 47 ++-- html/tree/accessors.go | 72 +++--- 10 files changed, 539 insertions(+), 373 deletions(-) create mode 100644 css/properties/keywords/keywords.go create mode 100644 css/properties/keywords/keywords_test.go diff --git a/css/properties/keywords/keywords.go b/css/properties/keywords/keywords.go new file mode 100644 index 0000000..aefdf44 --- /dev/null +++ b/css/properties/keywords/keywords.go @@ -0,0 +1,77 @@ +package keywords + +// Keyword efficiently stores CSS keywords +type Keyword uint8 + +const ( + _ Keyword = iota + Auto + Baseline + Center + End + First + FlexEnd + FlexStart + Last + Left + Legacy + Normal + Right + Safe + SelfEnd + SelfStart + SpaceAround + SpaceBetween + SpaceEvenly + Start + Stretch + Unsafe +) + +func NewKeyword(s string) Keyword { + switch s { + case "auto": + return Auto + case "baseline": + return Baseline + case "center": + return Center + case "end": + return End + case "first": + return First + case "flex-end": + return FlexEnd + case "flex-start": + return FlexStart + case "last": + return Last + case "left": + return Left + case "legacy": + return Legacy + case "normal": + return Normal + case "right": + return Right + case "safe": + return Safe + case "self-end": + return SelfEnd + case "self-start": + return SelfStart + case "space-around": + return SpaceAround + case "space-between": + return SpaceBetween + case "space-evenly": + return SpaceEvenly + case "start": + return Start + case "stretch": + return Stretch + case "unsafe": + return Unsafe + } + return 0 +} diff --git a/css/properties/keywords/keywords_test.go b/css/properties/keywords/keywords_test.go new file mode 100644 index 0000000..d2b0e21 --- /dev/null +++ b/css/properties/keywords/keywords_test.go @@ -0,0 +1,56 @@ +package keywords + +import ( + "fmt" + "sort" + "testing" + + "github.com/benoitkugler/webrender/utils" +) + +func TestKeywordSorted(t *testing.T) { + l := [...]string{ + "center", "space-between", "space-around", "space-evenly", + "stretch", "normal", "flex-start", "flex-end", + "start", "end", "left", "right", + "safe", "unsafe", + "center", "start", "end", "flex-start", "flex-end", "left", + "right", + "normal", "stretch", "center", "start", "end", "self-start", + "self-end", "flex-start", "flex-end", "left", "right", + "legacy", + "baseline", + "center", "start", "end", "self-start", "self-end", + "flex-start", "flex-end", "left", "right", + "auto", "normal", "stretch", "center", "start", "end", + "self-start", "self-end", "flex-start", "flex-end", "left", + "right", + "center", "start", "end", "self-start", "self-end", + "flex-start", "flex-end", "left", "right", + "normal", "stretch", "center", "start", "end", "self-start", + "self-end", "flex-start", "flex-end", + "baseline", + "center", "start", "end", "self-start", "self-end", + "flex-start", "flex-end", + "auto", "normal", "stretch", "center", "start", "end", + "self-start", "self-end", "flex-start", "flex-end", + "center", "start", "end", "self-start", "self-end", + "flex-start", "flex-end", + "center", "space-between", "space-around", "space-evenly", + "stretch", "normal", "flex-start", "flex-end", + "start", "end", + "baseline", + "center", "start", "end", "flex-start", "flex-end", + "first", "last", + } + + m := utils.NewSet(l[:]...) + var out []string + for l := range m { + out = append(out, l) + } + sort.Strings(out) + for _, s := range out { + fmt.Printf("case %q:\nreturn %s\n", s, s) + } +} diff --git a/css/properties/properties.go b/css/properties/properties.go index fd3304a..77d07a7 100644 --- a/css/properties/properties.go +++ b/css/properties/properties.go @@ -1,6 +1,9 @@ package properties -import "github.com/benoitkugler/webrender/css/parser" +import ( + "github.com/benoitkugler/webrender/css/parser" + kw "github.com/benoitkugler/webrender/css/properties/keywords" +) // This file is used to generate typed accessors //go:generate go run gen/gen.go @@ -437,12 +440,12 @@ var InitialValues = Properties{ PGridColumnEnd: GridLine{Tag: Auto}, // CSS Box Alignment Module Level 3 (WD): https://www.w3.org/TR/css-align-3/ - PAlignContent: Strings{"normal"}, - PAlignItems: Strings{"normal"}, - PAlignSelf: Strings{"auto"}, - PJustifyContent: Strings{"normal"}, - PJustifyItems: Strings{"normal"}, - PJustifySelf: Strings{"auto"}, + PAlignContent: JustifyOrAlign{kw.Normal}, + PAlignItems: JustifyOrAlign{kw.Normal}, + PAlignSelf: JustifyOrAlign{kw.Auto}, + PJustifyContent: JustifyOrAlign{kw.Normal}, + PJustifyItems: JustifyOrAlign{kw.Normal}, + PJustifySelf: JustifyOrAlign{kw.Auto}, POrder: Int(0), PColumnGap: DimOrS{S: "normal"}, PRowGap: DimOrS{S: "normal"}, diff --git a/css/properties/props_gen.go b/css/properties/props_gen.go index 1061589..4509d0b 100755 --- a/css/properties/props_gen.go +++ b/css/properties/props_gen.go @@ -2,14 +2,14 @@ package properties // Code generated from properties/properties.go DO NOT EDIT -func (s Properties) GetAlignContent() Strings { return s[PAlignContent].(Strings) } -func (s Properties) SetAlignContent(v Strings) { s[PAlignContent] = v } +func (s Properties) GetAlignContent() JustifyOrAlign { return s[PAlignContent].(JustifyOrAlign) } +func (s Properties) SetAlignContent(v JustifyOrAlign) { s[PAlignContent] = v } -func (s Properties) GetAlignItems() Strings { return s[PAlignItems].(Strings) } -func (s Properties) SetAlignItems(v Strings) { s[PAlignItems] = v } +func (s Properties) GetAlignItems() JustifyOrAlign { return s[PAlignItems].(JustifyOrAlign) } +func (s Properties) SetAlignItems(v JustifyOrAlign) { s[PAlignItems] = v } -func (s Properties) GetAlignSelf() Strings { return s[PAlignSelf].(Strings) } -func (s Properties) SetAlignSelf(v Strings) { s[PAlignSelf] = v } +func (s Properties) GetAlignSelf() JustifyOrAlign { return s[PAlignSelf].(JustifyOrAlign) } +func (s Properties) SetAlignSelf(v JustifyOrAlign) { s[PAlignSelf] = v } func (s Properties) GetAnchor() String { return s[PAnchor].(String) } func (s Properties) SetAnchor(v String) { s[PAnchor] = v } @@ -348,14 +348,14 @@ func (s Properties) SetImageRendering(v String) { s[PImageRendering] = v } func (s Properties) GetImageResolution() DimOrS { return s[PImageResolution].(DimOrS) } func (s Properties) SetImageResolution(v DimOrS) { s[PImageResolution] = v } -func (s Properties) GetJustifyContent() Strings { return s[PJustifyContent].(Strings) } -func (s Properties) SetJustifyContent(v Strings) { s[PJustifyContent] = v } +func (s Properties) GetJustifyContent() JustifyOrAlign { return s[PJustifyContent].(JustifyOrAlign) } +func (s Properties) SetJustifyContent(v JustifyOrAlign) { s[PJustifyContent] = v } -func (s Properties) GetJustifyItems() Strings { return s[PJustifyItems].(Strings) } -func (s Properties) SetJustifyItems(v Strings) { s[PJustifyItems] = v } +func (s Properties) GetJustifyItems() JustifyOrAlign { return s[PJustifyItems].(JustifyOrAlign) } +func (s Properties) SetJustifyItems(v JustifyOrAlign) { s[PJustifyItems] = v } -func (s Properties) GetJustifySelf() Strings { return s[PJustifySelf].(Strings) } -func (s Properties) SetJustifySelf(v Strings) { s[PJustifySelf] = v } +func (s Properties) GetJustifySelf() JustifyOrAlign { return s[PJustifySelf].(JustifyOrAlign) } +func (s Properties) SetJustifySelf(v JustifyOrAlign) { s[PJustifySelf] = v } func (s Properties) GetLang() TaggedString { return s[PLang].(TaggedString) } func (s Properties) SetLang(v TaggedString) { s[PLang] = v } @@ -544,14 +544,14 @@ func (s Properties) GetZIndex() IntString { return s[PZIndex].(IntString) } func (s Properties) SetZIndex(v IntString) { s[PZIndex] = v } type StyleAccessor interface { - GetAlignContent() Strings - SetAlignContent(v Strings) + GetAlignContent() JustifyOrAlign + SetAlignContent(v JustifyOrAlign) - GetAlignItems() Strings - SetAlignItems(v Strings) + GetAlignItems() JustifyOrAlign + SetAlignItems(v JustifyOrAlign) - GetAlignSelf() Strings - SetAlignSelf(v Strings) + GetAlignSelf() JustifyOrAlign + SetAlignSelf(v JustifyOrAlign) GetAnchor() String SetAnchor(v String) @@ -880,14 +880,14 @@ type StyleAccessor interface { GetImageResolution() DimOrS SetImageResolution(v DimOrS) - GetJustifyContent() Strings - SetJustifyContent(v Strings) + GetJustifyContent() JustifyOrAlign + SetJustifyContent(v JustifyOrAlign) - GetJustifyItems() Strings - SetJustifyItems(v Strings) + GetJustifyItems() JustifyOrAlign + SetJustifyItems(v JustifyOrAlign) - GetJustifySelf() Strings - SetJustifySelf(v Strings) + GetJustifySelf() JustifyOrAlign + SetJustifySelf(v JustifyOrAlign) GetLang() TaggedString SetLang(v TaggedString) diff --git a/css/properties/types.go b/css/properties/types.go index 8b08885..bad564d 100644 --- a/css/properties/types.go +++ b/css/properties/types.go @@ -4,6 +4,7 @@ import ( "fmt" pa "github.com/benoitkugler/webrender/css/parser" + "github.com/benoitkugler/webrender/css/properties/keywords" ) // ------------- Top levels types, implementing CssProperty ------------ @@ -122,6 +123,22 @@ func (ft FontFeature) String() string { // An empty slice means 'normal' type FontFeatures []FontFeature +// JustifyOrAlign stores properties for 'justify-*' or 'align-*' +type JustifyOrAlign [2]keywords.Keyword + +func (ja JustifyOrAlign) Has(kw keywords.Keyword) bool { return ja[0] == kw || ja[1] == kw } + +// Intersects returns true if at least one value in [kws] +// is also in the list. +func (ja JustifyOrAlign) Intersects(kws ...keywords.Keyword) bool { + for _, kw := range kws { + if ja.Has(kw) { + return true + } + } + return false +} + type Page string // Dimension or "auto" or "cover" or "contain" @@ -605,6 +622,7 @@ func (Images) isCssProperty() {} func (Int) isCssProperty() {} func (IntString) isCssProperty() {} func (Marks) isCssProperty() {} +func (JustifyOrAlign) isCssProperty() {} func (Decorations) isCssProperty() {} func (NamedString) isCssProperty() {} func (CounterStyleID) isCssProperty() {} @@ -651,6 +669,7 @@ func (Int) isDeclaredValue() {} func (IntString) isDeclaredValue() {} func (Limits) isDeclaredValue() {} func (Marks) isDeclaredValue() {} +func (JustifyOrAlign) isDeclaredValue() {} func (Decorations) isDeclaredValue() {} func (NamedString) isDeclaredValue() {} func (CounterStyleID) isDeclaredValue() {} diff --git a/css/validation/validation.go b/css/validation/validation.go index 3780f88..2394f72 100644 --- a/css/validation/validation.go +++ b/css/validation/validation.go @@ -11,6 +11,7 @@ import ( pa "github.com/benoitkugler/webrender/css/parser" pr "github.com/benoitkugler/webrender/css/properties" + kw "github.com/benoitkugler/webrender/css/properties/keywords" "github.com/benoitkugler/webrender/css/selector" ) @@ -699,6 +700,13 @@ func getKeyword(token Token) string { return "" } +func getKeywordT(token Token) kw.Keyword { + if ident, ok := token.(pa.Ident); ok { + return kw.NewKeyword(utils.AsciiLower(ident.Value)) + } + return 0 +} + // If `tokens` is a 1-element list of [Ident], return its name. // Otherwise return empty string. func getSingleKeyword(tokens []Token) string { @@ -3252,19 +3260,19 @@ func flexWrap(tokens []Token, _ string) pr.CssProperty { // “justify-content“ property validation. func justifyContent(tokens []Token, _ string) pr.CssProperty { if len(tokens) == 1 { - switch keyword := getKeyword(tokens[0]); keyword { - case "center", "space-between", "space-around", "space-evenly", - "stretch", "normal", "flex-start", "flex-end", - "start", "end", "left", "right": - return pr.Strings{keyword} + switch keyword := getKeywordT(tokens[0]); keyword { + case kw.Center, kw.SpaceBetween, kw.SpaceAround, kw.SpaceEvenly, + kw.Stretch, kw.Normal, kw.FlexStart, kw.FlexEnd, + kw.Start, kw.End, kw.Left, kw.Right: + return pr.JustifyOrAlign{keyword} } } else if len(tokens) == 2 { - kw1, kw2 := getKeyword(tokens[0]), getKeyword(tokens[1]) - if kw1 == "safe" || kw1 == "unsafe" { + kw1, kw2 := getKeywordT(tokens[0]), getKeywordT(tokens[1]) + if kw1 == kw.Safe || kw1 == kw.Unsafe { switch kw2 { - case "center", "start", "end", "flex-start", "flex-end", "left", - "right": - return pr.Strings{kw1, kw2} + case kw.Center, kw.Start, kw.End, kw.FlexStart, kw.FlexEnd, kw.Left, + kw.Right: + return pr.JustifyOrAlign{kw1, kw2} } } } @@ -3275,37 +3283,37 @@ func justifyContent(tokens []Token, _ string) pr.CssProperty { // “align-items“ property validation. func justifyItems(tokens []Token, _ string) pr.CssProperty { if len(tokens) == 1 { - switch keyword := getKeyword(tokens[0]); keyword { - case "normal", "stretch", "center", "start", "end", "self-start", - "self-end", "flex-start", "flex-end", "left", "right", - "legacy": - return pr.Strings{keyword} - case "baseline": - return pr.Strings{"first", keyword} + switch keyword := getKeywordT(tokens[0]); keyword { + case kw.Normal, kw.Stretch, kw.Center, kw.Start, kw.End, kw.SelfStart, + kw.SelfEnd, kw.FlexStart, kw.FlexEnd, kw.Left, kw.Right, + kw.Legacy: + return pr.JustifyOrAlign{keyword} + case kw.Baseline: + return pr.JustifyOrAlign{kw.First, keyword} } } else if len(tokens) == 2 { - kw1, kw2 := getKeyword(tokens[0]), getKeyword(tokens[1]) - if kw1 == "safe" || kw1 == "unsafe" { + kw1, kw2 := getKeywordT(tokens[0]), getKeywordT(tokens[1]) + if kw1 == kw.Safe || kw1 == kw.Unsafe { switch kw2 { - case "center", "start", "end", "self-start", "self-end", - "flex-start", "flex-end", "left", "right": - return pr.Strings{kw1, kw2} + case kw.Center, kw.Start, kw.End, kw.SelfStart, kw.SelfEnd, + kw.FlexStart, kw.FlexEnd, kw.Left, kw.Right: + return pr.JustifyOrAlign{kw1, kw2} } - } else if kw1 == "baseline" { - if kw2 == "first" || kw2 == "last" { - return pr.Strings{kw1, kw2} + } else if kw1 == kw.Baseline { + if kw2 == kw.First || kw2 == kw.Last { + return pr.JustifyOrAlign{kw1, kw2} } - } else if kw2 == "baseline" { - if kw1 == "first" || kw1 == "last" { - return pr.Strings{kw1, kw2} + } else if kw2 == kw.Baseline { + if kw1 == kw.First || kw1 == kw.Last { + return pr.JustifyOrAlign{kw1, kw2} } - } else if kw1 == "legacy" { - if kw2 == "left" || kw2 == "right" || kw2 == "center" { - return pr.Strings{kw1, kw2} + } else if kw1 == kw.Legacy { + if kw2 == kw.Left || kw2 == kw.Right || kw2 == kw.Center { + return pr.JustifyOrAlign{kw1, kw2} } - } else if kw2 == "legacy" { - if kw1 == "left" || kw1 == "right" || kw1 == "center" { - return pr.Strings{kw1, kw2} + } else if kw2 == kw.Legacy { + if kw1 == kw.Left || kw1 == kw.Right || kw1 == kw.Center { + return pr.JustifyOrAlign{kw1, kw2} } } } @@ -3313,32 +3321,32 @@ func justifyItems(tokens []Token, _ string) pr.CssProperty { } // @validator() -// “align-items“ property validation. +// align-items property validation. func justifySelf(tokens []Token, _ string) pr.CssProperty { if len(tokens) == 1 { - switch keyword := getKeyword(tokens[0]); keyword { - case "auto", "normal", "stretch", "center", "start", "end", - "self-start", "self-end", "flex-start", "flex-end", "left", - "right": - return pr.Strings{keyword} - case "baseline": - return pr.Strings{"first", keyword} + switch keyword := getKeywordT(tokens[0]); keyword { + case kw.Auto, kw.Normal, kw.Stretch, kw.Center, kw.Start, kw.End, + kw.SelfStart, kw.SelfEnd, kw.FlexStart, kw.FlexEnd, kw.Left, + kw.Right: + return pr.JustifyOrAlign{keyword} + case kw.Baseline: + return pr.JustifyOrAlign{kw.First, keyword} } } else if len(tokens) == 2 { - kw1, kw2 := getKeyword(tokens[0]), getKeyword(tokens[1]) - if kw1 == "safe" || kw1 == "unsafe" { + kw1, kw2 := getKeywordT(tokens[0]), getKeywordT(tokens[1]) + if kw1 == kw.Safe || kw1 == kw.Unsafe { switch kw2 { - case "center", "start", "end", "self-start", "self-end", - "flex-start", "flex-end", "left", "right": - return pr.Strings{kw1, kw2} + case kw.Center, kw.Start, kw.End, kw.SelfStart, kw.SelfEnd, + kw.FlexStart, kw.FlexEnd, kw.Left, kw.Right: + return pr.JustifyOrAlign{kw1, kw2} } - } else if kw1 == "baseline" { - if kw2 == "first" || kw2 == "last" { - return pr.Strings{kw1, kw2} + } else if kw1 == kw.Baseline { + if kw2 == kw.First || kw2 == kw.Last { + return pr.JustifyOrAlign{kw1, kw2} } - } else if kw2 == "baseline" { - if kw1 == "first" || kw1 == "last" { - return pr.Strings{kw1, kw2} + } else if kw2 == kw.Baseline { + if kw1 == kw.First || kw1 == kw.Last { + return pr.JustifyOrAlign{kw1, kw2} } } } @@ -3346,31 +3354,31 @@ func justifySelf(tokens []Token, _ string) pr.CssProperty { } // @validator() -// “align-items“ property validation. +// align-items property validation. func alignItems(tokens []Token, _ string) pr.CssProperty { if len(tokens) == 1 { - switch keyword := getKeyword(tokens[0]); keyword { - case "normal", "stretch", "center", "start", "end", "self-start", - "self-end", "flex-start", "flex-end": - return pr.Strings{keyword} - case "baseline": - return pr.Strings{"first", keyword} + switch keyword := getKeywordT(tokens[0]); keyword { + case kw.Normal, kw.Stretch, kw.Center, kw.Start, kw.End, kw.SelfStart, + kw.SelfEnd, kw.FlexStart, kw.FlexEnd: + return pr.JustifyOrAlign{keyword} + case kw.Baseline: + return pr.JustifyOrAlign{kw.First, keyword} } } else if len(tokens) == 2 { - kw1, kw2 := getKeyword(tokens[0]), getKeyword(tokens[1]) - if kw1 == "safe" || kw1 == "unsafe" { + kw1, kw2 := getKeywordT(tokens[0]), getKeywordT(tokens[1]) + if kw1 == kw.Safe || kw1 == kw.Unsafe { switch kw2 { - case "center", "start", "end", "self-start", "self-end", - "flex-start", "flex-end": - return pr.Strings{kw1, kw2} + case kw.Center, kw.Start, kw.End, kw.SelfStart, kw.SelfEnd, + kw.FlexStart, kw.FlexEnd: + return pr.JustifyOrAlign{kw1, kw2} } - } else if kw1 == "baseline" { - if kw2 == "first" || kw2 == "last" { - return pr.Strings{kw1, kw2} + } else if kw1 == kw.Baseline { + if kw2 == kw.First || kw2 == kw.Last { + return pr.JustifyOrAlign{kw1, kw2} } - } else if kw2 == "baseline" { - if kw1 == "first" || kw1 == "last" { - return pr.Strings{kw1, kw2} + } else if kw2 == kw.Baseline { + if kw1 == kw.First || kw1 == kw.Last { + return pr.JustifyOrAlign{kw1, kw2} } } } @@ -3379,31 +3387,31 @@ func alignItems(tokens []Token, _ string) pr.CssProperty { // @validator() // @singleKeyword -// “align-self“ property validation. +// align-self property validation. func alignSelf(tokens []Token, _ string) pr.CssProperty { if len(tokens) == 1 { - switch keyword := getKeyword(tokens[0]); keyword { - case "auto", "normal", "stretch", "center", "start", "end", - "self-start", "self-end", "flex-start", "flex-end": - return pr.Strings{keyword} - case "baseline": - return pr.Strings{"first", keyword} + switch keyword := getKeywordT(tokens[0]); keyword { + case kw.Auto, kw.Normal, kw.Stretch, kw.Center, kw.Start, kw.End, + kw.SelfStart, kw.SelfEnd, kw.FlexStart, kw.FlexEnd: + return pr.JustifyOrAlign{keyword} + case kw.Baseline: + return pr.JustifyOrAlign{kw.First, keyword} } } else if len(tokens) == 2 { - kw1, kw2 := getKeyword(tokens[0]), getKeyword(tokens[1]) - if kw1 == "safe" || kw1 == "unsafe" { + kw1, kw2 := getKeywordT(tokens[0]), getKeywordT(tokens[1]) + if kw1 == kw.Safe || kw1 == kw.Unsafe { switch kw2 { - case "center", "start", "end", "self-start", "self-end", - "flex-start", "flex-end": - return pr.Strings{kw1, kw2} + case kw.Center, kw.Start, kw.End, kw.SelfStart, kw.SelfEnd, + kw.FlexStart, kw.FlexEnd: + return pr.JustifyOrAlign{kw1, kw2} } - } else if kw1 == "baseline" { - if kw2 == "first" || kw2 == "last" { - return pr.Strings{kw1, kw2} + } else if kw1 == kw.Baseline { + if kw2 == kw.First || kw2 == kw.Last { + return pr.JustifyOrAlign{kw1, kw2} } - } else if kw2 == "baseline" { - if kw1 == "first" || kw1 == "last" { - return pr.Strings{kw1, kw2} + } else if kw2 == kw.Baseline { + if kw1 == kw.First || kw1 == kw.Last { + return pr.JustifyOrAlign{kw1, kw2} } } } @@ -3411,31 +3419,31 @@ func alignSelf(tokens []Token, _ string) pr.CssProperty { } // @validator() -// “align-content“ property validation. +// align-content property validation. func alignContent(tokens []Token, _ string) pr.CssProperty { if len(tokens) == 1 { - switch keyword := getKeyword(tokens[0]); keyword { - case "center", "space-between", "space-around", "space-evenly", - "stretch", "normal", "flex-start", "flex-end", - "start", "end": - return pr.Strings{keyword} - case "baseline": - return pr.Strings{"first", keyword} + switch keyword := getKeywordT(tokens[0]); keyword { + case kw.Center, kw.SpaceBetween, kw.SpaceAround, kw.SpaceEvenly, + kw.Stretch, kw.Normal, kw.FlexStart, kw.FlexEnd, + kw.Start, kw.End: + return pr.JustifyOrAlign{keyword} + case kw.Baseline: + return pr.JustifyOrAlign{kw.First, keyword} } } else if len(tokens) == 2 { - kw1, kw2 := getKeyword(tokens[0]), getKeyword(tokens[1]) - if kw1 == "safe" || kw1 == "unsafe" { + kw1, kw2 := getKeywordT(tokens[0]), getKeywordT(tokens[1]) + if kw1 == kw.Safe || kw1 == kw.Unsafe { switch kw2 { - case "center", "start", "end", "flex-start", "flex-end": - return pr.Strings{kw1, kw2} + case kw.Center, kw.Start, kw.End, kw.FlexStart, kw.FlexEnd: + return pr.JustifyOrAlign{kw1, kw2} } - } else if kw1 == "baseline" { - if kw2 == "first" || kw2 == "last" { - return pr.Strings{kw1, kw2} + } else if kw1 == kw.Baseline { + if kw2 == kw.First || kw2 == kw.Last { + return pr.JustifyOrAlign{kw1, kw2} } - } else if kw2 == "baseline" { - if kw1 == "first" || kw1 == "last" { - return pr.Strings{kw1, kw2} + } else if kw2 == kw.Baseline { + if kw1 == kw.First || kw1 == kw.Last { + return pr.JustifyOrAlign{kw1, kw2} } } } diff --git a/css/validation/validation_test.go b/css/validation/validation_test.go index 2d31852..918816d 100644 --- a/css/validation/validation_test.go +++ b/css/validation/validation_test.go @@ -9,6 +9,7 @@ import ( "github.com/benoitkugler/webrender/css/parser" pr "github.com/benoitkugler/webrender/css/properties" + kw "github.com/benoitkugler/webrender/css/properties/keywords" "github.com/benoitkugler/webrender/utils" tu "github.com/benoitkugler/webrender/utils/testutils" ) @@ -1129,27 +1130,27 @@ func TestAlignContent(t *testing.T) { for _, test := range []struct { css string - value pr.Strings + value pr.JustifyOrAlign }{ - {"normal", pr.Strings{"normal"}}, - {"baseline", pr.Strings{"first", "baseline"}}, - {"first baseline", pr.Strings{"first", "baseline"}}, - {"last baseline", pr.Strings{"last", "baseline"}}, - {"baseline last", pr.Strings{"baseline", "last"}}, - {"space-between", pr.Strings{"space-between"}}, - {"space-around", pr.Strings{"space-around"}}, - {"space-evenly", pr.Strings{"space-evenly"}}, - {"stretch", pr.Strings{"stretch"}}, - {"center", pr.Strings{"center"}}, - {"start", pr.Strings{"start"}}, - {"end", pr.Strings{"end"}}, - {"flex-start", pr.Strings{"flex-start"}}, - {"flex-end", pr.Strings{"flex-end"}}, - {"safe center", pr.Strings{"safe", "center"}}, - {"unsafe start", pr.Strings{"unsafe", "start"}}, - {"safe end", pr.Strings{"safe", "end"}}, - {"safe flex-start", pr.Strings{"safe", "flex-start"}}, - {"unsafe flex-start", pr.Strings{"unsafe", "flex-start"}}, + {"normal", pr.JustifyOrAlign{kw.Normal}}, + {"baseline", pr.JustifyOrAlign{kw.First, kw.Baseline}}, + {"first baseline", pr.JustifyOrAlign{kw.First, kw.Baseline}}, + {"last baseline", pr.JustifyOrAlign{kw.Last, kw.Baseline}}, + {"baseline last", pr.JustifyOrAlign{kw.Baseline, kw.Last}}, + {"space-between", pr.JustifyOrAlign{kw.SpaceBetween}}, + {"space-around", pr.JustifyOrAlign{kw.SpaceAround}}, + {"space-evenly", pr.JustifyOrAlign{kw.SpaceEvenly}}, + {"stretch", pr.JustifyOrAlign{kw.Stretch}}, + {"center", pr.JustifyOrAlign{kw.Center}}, + {"start", pr.JustifyOrAlign{kw.Start}}, + {"end", pr.JustifyOrAlign{kw.End}}, + {"flex-start", pr.JustifyOrAlign{kw.FlexStart}}, + {"flex-end", pr.JustifyOrAlign{kw.FlexEnd}}, + {"safe center", pr.JustifyOrAlign{kw.Safe, kw.Center}}, + {"unsafe start", pr.JustifyOrAlign{kw.Unsafe, kw.Start}}, + {"safe end", pr.JustifyOrAlign{kw.Safe, kw.End}}, + {"safe flex-start", pr.JustifyOrAlign{kw.Safe, kw.FlexStart}}, + {"unsafe flex-start", pr.JustifyOrAlign{kw.Unsafe, kw.FlexStart}}, } { assertValidDict(t, fmt.Sprintf("align-content: %s", test.css), map[pr.KnownProp]pr.DeclaredValue{ pr.PAlignContent: test.value, @@ -1177,28 +1178,28 @@ func TestAlignItems(t *testing.T) { for _, test := range []struct { css string - value pr.Strings + value pr.JustifyOrAlign }{ - {"normal", pr.Strings{"normal"}}, - {"stretch", pr.Strings{"stretch"}}, - {"baseline", pr.Strings{"first", "baseline"}}, - {"first baseline", pr.Strings{"first", "baseline"}}, - {"last baseline", pr.Strings{"last", "baseline"}}, - {"baseline last", pr.Strings{"baseline", "last"}}, - {"center", pr.Strings{"center"}}, - {"self-start", pr.Strings{"self-start"}}, - {"self-end", pr.Strings{"self-end"}}, - {"start", pr.Strings{"start"}}, - {"end", pr.Strings{"end"}}, - {"flex-start", pr.Strings{"flex-start"}}, - {"flex-end", pr.Strings{"flex-end"}}, - {"safe center", pr.Strings{"safe", "center"}}, - {"unsafe start", pr.Strings{"unsafe", "start"}}, - {"safe end", pr.Strings{"safe", "end"}}, - {"unsafe self-start", pr.Strings{"unsafe", "self-start"}}, - {"safe self-end", pr.Strings{"safe", "self-end"}}, - {"safe flex-start", pr.Strings{"safe", "flex-start"}}, - {"unsafe flex-start", pr.Strings{"unsafe", "flex-start"}}, + {"normal", pr.JustifyOrAlign{kw.Normal}}, + {"stretch", pr.JustifyOrAlign{kw.Stretch}}, + {"baseline", pr.JustifyOrAlign{kw.First, kw.Baseline}}, + {"first baseline", pr.JustifyOrAlign{kw.First, kw.Baseline}}, + {"last baseline", pr.JustifyOrAlign{kw.Last, kw.Baseline}}, + {"baseline last", pr.JustifyOrAlign{kw.Baseline, kw.Last}}, + {"center", pr.JustifyOrAlign{kw.Center}}, + {"self-start", pr.JustifyOrAlign{kw.SelfStart}}, + {"self-end", pr.JustifyOrAlign{kw.SelfEnd}}, + {"start", pr.JustifyOrAlign{kw.Start}}, + {"end", pr.JustifyOrAlign{kw.End}}, + {"flex-start", pr.JustifyOrAlign{kw.FlexStart}}, + {"flex-end", pr.JustifyOrAlign{kw.FlexEnd}}, + {"safe center", pr.JustifyOrAlign{kw.Safe, kw.Center}}, + {"unsafe start", pr.JustifyOrAlign{kw.Unsafe, kw.Start}}, + {"safe end", pr.JustifyOrAlign{kw.Safe, kw.End}}, + {"unsafe self-start", pr.JustifyOrAlign{kw.Unsafe, kw.SelfStart}}, + {"safe self-end", pr.JustifyOrAlign{kw.Safe, kw.SelfEnd}}, + {"safe flex-start", pr.JustifyOrAlign{kw.Safe, kw.FlexStart}}, + {"unsafe flex-start", pr.JustifyOrAlign{kw.Unsafe, kw.FlexStart}}, } { assertValidDict(t, fmt.Sprintf("align-items: %s", test.css), map[pr.KnownProp]pr.DeclaredValue{ pr.PAlignItems: test.value, @@ -1227,29 +1228,29 @@ func TestAlignSelf(t *testing.T) { for _, test := range []struct { css string - value pr.Strings + value pr.JustifyOrAlign }{ - {"auto", pr.Strings{"auto"}}, - {"normal", pr.Strings{"normal"}}, - {"stretch", pr.Strings{"stretch"}}, - {"baseline", pr.Strings{"first", "baseline"}}, - {"first baseline", pr.Strings{"first", "baseline"}}, - {"last baseline", pr.Strings{"last", "baseline"}}, - {"baseline last", pr.Strings{"baseline", "last"}}, - {"center", pr.Strings{"center"}}, - {"self-start", pr.Strings{"self-start"}}, - {"self-end", pr.Strings{"self-end"}}, - {"start", pr.Strings{"start"}}, - {"end", pr.Strings{"end"}}, - {"flex-start", pr.Strings{"flex-start"}}, - {"flex-end", pr.Strings{"flex-end"}}, - {"safe center", pr.Strings{"safe", "center"}}, - {"unsafe start", pr.Strings{"unsafe", "start"}}, - {"safe end", pr.Strings{"safe", "end"}}, - {"unsafe self-start", pr.Strings{"unsafe", "self-start"}}, - {"safe self-end", pr.Strings{"safe", "self-end"}}, - {"safe flex-start", pr.Strings{"safe", "flex-start"}}, - {"unsafe flex-start", pr.Strings{"unsafe", "flex-start"}}, + {"auto", pr.JustifyOrAlign{kw.Auto}}, + {"normal", pr.JustifyOrAlign{kw.Normal}}, + {"stretch", pr.JustifyOrAlign{kw.Stretch}}, + {"baseline", pr.JustifyOrAlign{kw.First, kw.Baseline}}, + {"first baseline", pr.JustifyOrAlign{kw.First, kw.Baseline}}, + {"last baseline", pr.JustifyOrAlign{kw.Last, kw.Baseline}}, + {"baseline last", pr.JustifyOrAlign{kw.Baseline, kw.Last}}, + {"center", pr.JustifyOrAlign{kw.Center}}, + {"self-start", pr.JustifyOrAlign{kw.SelfStart}}, + {"self-end", pr.JustifyOrAlign{kw.SelfEnd}}, + {"start", pr.JustifyOrAlign{kw.Start}}, + {"end", pr.JustifyOrAlign{kw.End}}, + {"flex-start", pr.JustifyOrAlign{kw.FlexStart}}, + {"flex-end", pr.JustifyOrAlign{kw.FlexEnd}}, + {"safe center", pr.JustifyOrAlign{kw.Safe, kw.Center}}, + {"unsafe start", pr.JustifyOrAlign{kw.Unsafe, kw.Start}}, + {"safe end", pr.JustifyOrAlign{kw.Safe, kw.End}}, + {"unsafe self-start", pr.JustifyOrAlign{kw.Unsafe, kw.SelfStart}}, + {"safe self-end", pr.JustifyOrAlign{kw.Safe, kw.SelfEnd}}, + {"safe flex-start", pr.JustifyOrAlign{kw.Safe, kw.FlexStart}}, + {"unsafe flex-start", pr.JustifyOrAlign{kw.Unsafe, kw.FlexStart}}, } { assertValidDict(t, fmt.Sprintf("align-self: %s", test.css), map[pr.KnownProp]pr.DeclaredValue{ pr.PAlignSelf: test.value, @@ -1277,27 +1278,27 @@ func TestJustifyContent(t *testing.T) { for _, test := range []struct { css string - value pr.Strings + value pr.JustifyOrAlign }{ - {"normal", pr.Strings{"normal"}}, - {"space-between", pr.Strings{"space-between"}}, - {"space-around", pr.Strings{"space-around"}}, - {"space-evenly", pr.Strings{"space-evenly"}}, - {"stretch", pr.Strings{"stretch"}}, - {"center", pr.Strings{"center"}}, - {"left", pr.Strings{"left"}}, - {"right", pr.Strings{"right"}}, - {"start", pr.Strings{"start"}}, - {"end", pr.Strings{"end"}}, - {"flex-start", pr.Strings{"flex-start"}}, - {"flex-end", pr.Strings{"flex-end"}}, - {"safe center", pr.Strings{"safe", "center"}}, - {"unsafe start", pr.Strings{"unsafe", "start"}}, - {"safe end", pr.Strings{"safe", "end"}}, - {"unsafe left", pr.Strings{"unsafe", "left"}}, - {"safe right", pr.Strings{"safe", "right"}}, - {"safe flex-start", pr.Strings{"safe", "flex-start"}}, - {"unsafe flex-start", pr.Strings{"unsafe", "flex-start"}}, + {"normal", pr.JustifyOrAlign{kw.Normal}}, + {"space-between", pr.JustifyOrAlign{kw.SpaceBetween}}, + {"space-around", pr.JustifyOrAlign{kw.SpaceAround}}, + {"space-evenly", pr.JustifyOrAlign{kw.SpaceEvenly}}, + {"stretch", pr.JustifyOrAlign{kw.Stretch}}, + {"center", pr.JustifyOrAlign{kw.Center}}, + {"left", pr.JustifyOrAlign{kw.Left}}, + {"right", pr.JustifyOrAlign{kw.Right}}, + {"start", pr.JustifyOrAlign{kw.Start}}, + {"end", pr.JustifyOrAlign{kw.End}}, + {"flex-start", pr.JustifyOrAlign{kw.FlexStart}}, + {"flex-end", pr.JustifyOrAlign{kw.FlexEnd}}, + {"safe center", pr.JustifyOrAlign{kw.Safe, kw.Center}}, + {"unsafe start", pr.JustifyOrAlign{kw.Unsafe, kw.Start}}, + {"safe end", pr.JustifyOrAlign{kw.Safe, kw.End}}, + {"unsafe left", pr.JustifyOrAlign{kw.Unsafe, kw.Left}}, + {"safe right", pr.JustifyOrAlign{kw.Safe, kw.Right}}, + {"safe flex-start", pr.JustifyOrAlign{kw.Safe, kw.FlexStart}}, + {"unsafe flex-start", pr.JustifyOrAlign{kw.Unsafe, kw.FlexStart}}, } { assertValidDict(t, fmt.Sprintf("justify-content: %s", test.css), map[pr.KnownProp]pr.DeclaredValue{ pr.PJustifyContent: test.value, @@ -1324,34 +1325,34 @@ func TestJustifyItems(t *testing.T) { for _, test := range []struct { css string - value pr.Strings + value pr.JustifyOrAlign }{ - {"normal", pr.Strings{"normal"}}, - {"stretch", pr.Strings{"stretch"}}, - {"baseline", pr.Strings{"first", "baseline"}}, - {"first baseline", pr.Strings{"first", "baseline"}}, - {"last baseline", pr.Strings{"last", "baseline"}}, - {"baseline last", pr.Strings{"baseline", "last"}}, - {"center", pr.Strings{"center"}}, - {"self-start", pr.Strings{"self-start"}}, - {"self-end", pr.Strings{"self-end"}}, - {"start", pr.Strings{"start"}}, - {"end", pr.Strings{"end"}}, - {"left", pr.Strings{"left"}}, - {"right", pr.Strings{"right"}}, - {"flex-start", pr.Strings{"flex-start"}}, - {"flex-end", pr.Strings{"flex-end"}}, - {"safe center", pr.Strings{"safe", "center"}}, - {"unsafe start", pr.Strings{"unsafe", "start"}}, - {"safe end", pr.Strings{"safe", "end"}}, - {"unsafe self-start", pr.Strings{"unsafe", "self-start"}}, - {"safe self-end", pr.Strings{"safe", "self-end"}}, - {"safe flex-start", pr.Strings{"safe", "flex-start"}}, - {"unsafe flex-start", pr.Strings{"unsafe", "flex-start"}}, - {"legacy", pr.Strings{"legacy"}}, - {"legacy left", pr.Strings{"legacy", "left"}}, - {"left legacy", pr.Strings{"left", "legacy"}}, - {"legacy center", pr.Strings{"legacy", "center"}}, + {"normal", pr.JustifyOrAlign{kw.Normal}}, + {"stretch", pr.JustifyOrAlign{kw.Stretch}}, + {"baseline", pr.JustifyOrAlign{kw.First, kw.Baseline}}, + {"first baseline", pr.JustifyOrAlign{kw.First, kw.Baseline}}, + {"last baseline", pr.JustifyOrAlign{kw.Last, kw.Baseline}}, + {"baseline last", pr.JustifyOrAlign{kw.Baseline, kw.Last}}, + {"center", pr.JustifyOrAlign{kw.Center}}, + {"self-start", pr.JustifyOrAlign{kw.SelfStart}}, + {"self-end", pr.JustifyOrAlign{kw.SelfEnd}}, + {"start", pr.JustifyOrAlign{kw.Start}}, + {"end", pr.JustifyOrAlign{kw.End}}, + {"left", pr.JustifyOrAlign{kw.Left}}, + {"right", pr.JustifyOrAlign{kw.Right}}, + {"flex-start", pr.JustifyOrAlign{kw.FlexStart}}, + {"flex-end", pr.JustifyOrAlign{kw.FlexEnd}}, + {"safe center", pr.JustifyOrAlign{kw.Safe, kw.Center}}, + {"unsafe start", pr.JustifyOrAlign{kw.Unsafe, kw.Start}}, + {"safe end", pr.JustifyOrAlign{kw.Safe, kw.End}}, + {"unsafe self-start", pr.JustifyOrAlign{kw.Unsafe, kw.SelfStart}}, + {"safe self-end", pr.JustifyOrAlign{kw.Safe, kw.SelfEnd}}, + {"safe flex-start", pr.JustifyOrAlign{kw.Safe, kw.FlexStart}}, + {"unsafe flex-start", pr.JustifyOrAlign{kw.Unsafe, kw.FlexStart}}, + {"legacy", pr.JustifyOrAlign{kw.Legacy}}, + {"legacy left", pr.JustifyOrAlign{kw.Legacy, kw.Left}}, + {"left legacy", pr.JustifyOrAlign{kw.Left, kw.Legacy}}, + {"legacy center", pr.JustifyOrAlign{kw.Legacy, kw.Center}}, } { assertValidDict(t, fmt.Sprintf("justify-items: %s", test.css), map[pr.KnownProp]pr.DeclaredValue{ pr.PJustifyItems: test.value, @@ -1378,33 +1379,33 @@ func TestJustifySelf(t *testing.T) { for _, test := range []struct { css string - value pr.Strings + value pr.JustifyOrAlign }{ - {"auto", pr.Strings{"auto"}}, - {"normal", pr.Strings{"normal"}}, - {"stretch", pr.Strings{"stretch"}}, - {"baseline", pr.Strings{"first", "baseline"}}, - {"first baseline", pr.Strings{"first", "baseline"}}, - {"last baseline", pr.Strings{"last", "baseline"}}, - {"baseline last", pr.Strings{"baseline", "last"}}, - {"center", pr.Strings{"center"}}, - {"self-start", pr.Strings{"self-start"}}, - {"self-end", pr.Strings{"self-end"}}, - {"start", pr.Strings{"start"}}, - {"end", pr.Strings{"end"}}, - {"left", pr.Strings{"left"}}, - {"right", pr.Strings{"right"}}, - {"flex-start", pr.Strings{"flex-start"}}, - {"flex-end", pr.Strings{"flex-end"}}, - {"safe center", pr.Strings{"safe", "center"}}, - {"unsafe start", pr.Strings{"unsafe", "start"}}, - {"safe end", pr.Strings{"safe", "end"}}, - {"unsafe left", pr.Strings{"unsafe", "left"}}, - {"safe right", pr.Strings{"safe", "right"}}, - {"unsafe self-start", pr.Strings{"unsafe", "self-start"}}, - {"safe self-end", pr.Strings{"safe", "self-end"}}, - {"safe flex-start", pr.Strings{"safe", "flex-start"}}, - {"unsafe flex-start", pr.Strings{"unsafe", "flex-start"}}, + {"auto", pr.JustifyOrAlign{kw.Auto}}, + {"normal", pr.JustifyOrAlign{kw.Normal}}, + {"stretch", pr.JustifyOrAlign{kw.Stretch}}, + {"baseline", pr.JustifyOrAlign{kw.First, kw.Baseline}}, + {"first baseline", pr.JustifyOrAlign{kw.First, kw.Baseline}}, + {"last baseline", pr.JustifyOrAlign{kw.Last, kw.Baseline}}, + {"baseline last", pr.JustifyOrAlign{kw.Baseline, kw.Last}}, + {"center", pr.JustifyOrAlign{kw.Center}}, + {"self-start", pr.JustifyOrAlign{kw.SelfStart}}, + {"self-end", pr.JustifyOrAlign{kw.SelfEnd}}, + {"start", pr.JustifyOrAlign{kw.Start}}, + {"end", pr.JustifyOrAlign{kw.End}}, + {"left", pr.JustifyOrAlign{kw.Left}}, + {"right", pr.JustifyOrAlign{kw.Right}}, + {"flex-start", pr.JustifyOrAlign{kw.FlexStart}}, + {"flex-end", pr.JustifyOrAlign{kw.FlexEnd}}, + {"safe center", pr.JustifyOrAlign{kw.Safe, kw.Center}}, + {"unsafe start", pr.JustifyOrAlign{kw.Unsafe, kw.Start}}, + {"safe end", pr.JustifyOrAlign{kw.Safe, kw.End}}, + {"unsafe left", pr.JustifyOrAlign{kw.Unsafe, kw.Left}}, + {"safe right", pr.JustifyOrAlign{kw.Safe, kw.Right}}, + {"unsafe self-start", pr.JustifyOrAlign{kw.Unsafe, kw.SelfStart}}, + {"safe self-end", pr.JustifyOrAlign{kw.Safe, kw.SelfEnd}}, + {"safe flex-start", pr.JustifyOrAlign{kw.Safe, kw.FlexStart}}, + {"unsafe flex-start", pr.JustifyOrAlign{kw.Unsafe, kw.FlexStart}}, } { assertValidDict(t, fmt.Sprintf("justify-self: %s", test.css), map[pr.KnownProp]pr.DeclaredValue{ pr.PJustifySelf: test.value, diff --git a/html/layout/flex.go b/html/layout/flex.go index dfc0208..7097714 100644 --- a/html/layout/flex.go +++ b/html/layout/flex.go @@ -9,6 +9,7 @@ import ( "github.com/benoitkugler/webrender/html/tree" pr "github.com/benoitkugler/webrender/css/properties" + kw "github.com/benoitkugler/webrender/css/properties/keywords" bo "github.com/benoitkugler/webrender/html/boxes" ) @@ -671,7 +672,7 @@ func flexLayout(context *layoutContext, box_ Box, bottomSpace pr.Float, skipStac for _, v := range line.line { child := v.box.Box() alignSelf := child.Style.GetAlignSelf() - if strings.HasPrefix(string(box.Style.GetFlexDirection()), "row") && alignSelf.Intersects("baseline") && + if strings.HasPrefix(string(box.Style.GetFlexDirection()), "row") && alignSelf.Intersects(kw.Baseline) && child.MarginTop != pr.AutoF && child.MarginBottom != pr.AutoF { collectedItems = append(collectedItems, child) } else { @@ -730,10 +731,10 @@ func flexLayout(context *layoutContext, box_ Box, bottomSpace pr.Float, skipStac // Step 9 alignContent := box.Style.GetAlignContent() - if alignContent.Intersects("normal") { - alignContent = pr.Strings{"stretch"} + if alignContent.Intersects(kw.Normal) { + alignContent = pr.JustifyOrAlign{kw.Stretch} } - if alignContent.Intersects("stretch") { + if alignContent.Intersects(kw.Stretch) { var definiteCrossSize pr.MaybeFloat if he := box.Style.GetHeight(); cross == pr.PHeight && he.S != "auto" { definiteCrossSize = he.Value @@ -764,19 +765,19 @@ func flexLayout(context *layoutContext, box_ Box, bottomSpace pr.Float, skipStac // Step 11 alignItems := box.Style.GetAlignItems() - if alignItems.Intersects("normal") { - alignItems = pr.Strings{"stretch"} + if alignItems.Intersects(kw.Normal) { + alignItems = pr.JustifyOrAlign{kw.Stretch} } for _, line := range flexLines { for _, v := range line.line { child := v.box.Box() alignSelf := child.Style.GetAlignSelf() - if alignSelf.Intersects("normal") { - alignSelf = pr.Strings{"stretch"} - } else if alignSelf.Intersects("auto") { + if alignSelf.Intersects(kw.Normal) { + alignSelf = pr.JustifyOrAlign{kw.Stretch} + } else if alignSelf.Intersects(kw.Auto) { alignSelf = alignItems } - if alignSelf.Intersects("stretch") && getCross(child, cross).S == "auto" { + if alignSelf.Intersects(kw.Stretch) && getCross(child, cross).S == "auto" { crossMargins := getCrossMargins(child, cross) if getCross(child, cross).S == "auto" { if !(crossMargins[0] == pr.AutoF || crossMargins[1] == pr.AutoF) { @@ -806,14 +807,14 @@ func flexLayout(context *layoutContext, box_ Box, bottomSpace pr.Float, skipStac originalPositionAxis = box.ContentBoxX() } justifyContent := box.Style.GetJustifyContent() - if justifyContent.Intersects("normal") { - justifyContent = pr.Strings{"flex-start"} + if justifyContent.Intersects(kw.Normal) { + justifyContent = pr.JustifyOrAlign{kw.FlexStart} } if strings.HasSuffix(string(box.Style.GetFlexDirection()), "-reverse") { - if justifyContent.Intersects("flex-start") { - justifyContent = pr.Strings{"flex-end"} - } else if justifyContent.Intersects("flex-end") { - justifyContent = pr.Strings{"flex-start"} + if justifyContent.Intersects(kw.FlexStart) { + justifyContent = pr.JustifyOrAlign{kw.FlexEnd} + } else if justifyContent.Intersects(kw.FlexEnd) { + justifyContent = pr.JustifyOrAlign{kw.FlexStart} } } @@ -892,13 +893,13 @@ func flexLayout(context *layoutContext, box_ Box, bottomSpace pr.Float, skipStac freeSpace = -freeSpace } - if justifyContent.Intersects("flex-end", "end", "right") { + if justifyContent.Intersects(kw.FlexEnd, kw.End, kw.Right) { positionAxis += freeSpace - } else if justifyContent.Intersects("center") { + } else if justifyContent.Intersects(kw.Center) { positionAxis += freeSpace / 2 - } else if justifyContent.Intersects("space-around") { + } else if justifyContent.Intersects(kw.SpaceAround) { positionAxis += freeSpace / pr.Float(len(line.line)) / 2 - } else if justifyContent.Intersects("space-evenly") { + } else if justifyContent.Intersects(kw.SpaceEvenly) { positionAxis += freeSpace / (pr.Float(len(line.line)) + 1) } @@ -906,7 +907,7 @@ func flexLayout(context *layoutContext, box_ Box, bottomSpace pr.Float, skipStac child := v.box.Box() if axis == pr.PWidth { child.PositionX = positionAxis - if justifyContent.Intersects("stretch") { + if justifyContent.Intersects(kw.Stretch) { child.Width = child.Width.V() + freeSpace/pr.Float(len(line.line)) } @@ -924,13 +925,13 @@ func flexLayout(context *layoutContext, box_ Box, bottomSpace pr.Float, skipStac positionAxis += child.MarginHeight() } - if justifyContent.Intersects("space-around") { + if justifyContent.Intersects(kw.SpaceAround) { positionAxis += freeSpace / pr.Float(len(line.line)) - } else if justifyContent.Intersects("space-between") { + } else if justifyContent.Intersects(kw.SpaceBetween) { if len(line.line) > 1 { positionAxis += freeSpace / (pr.Float(len(line.line)) - 1) } - } else if justifyContent.Intersects("space-evenly") { + } else if justifyContent.Intersects(kw.SpaceEvenly) { positionAxis += freeSpace / (pr.Float(len(line.line)) + 1) } } @@ -947,10 +948,10 @@ func flexLayout(context *layoutContext, box_ Box, bottomSpace pr.Float, skipStac for _, v := range line.line { child := v.box.Box() alignSelf := child.Style.GetAlignSelf() - if alignSelf.Intersects("auto") { + if alignSelf.Intersects(kw.Auto) { alignSelf = box.Style.GetAlignItems() } - if alignSelf.Intersects("baseline") && axis == pr.PWidth { + if alignSelf.Intersects(kw.Baseline) && axis == pr.PWidth { // TODO: handle vertical text child.Baseline = child.Baseline.V() - positionCross line.lowerBaseline = pr.Max(line.lowerBaseline, child.Baseline.V()) @@ -1025,9 +1026,9 @@ func flexLayout(context *layoutContext, box_ Box, bottomSpace pr.Float, skipStac } else { // Step 14 alignSelf := child.Style.GetAlignSelf() - if alignSelf.Intersects("normal") { - alignSelf = pr.Strings{"stretch"} - } else if alignSelf.Intersects("auto") { + if alignSelf.Intersects(kw.Normal) { + alignSelf = pr.JustifyOrAlign{kw.Stretch} + } else if alignSelf.Intersects(kw.Auto) { alignSelf = alignItems } if cross == pr.PHeight { @@ -1035,24 +1036,24 @@ func flexLayout(context *layoutContext, box_ Box, bottomSpace pr.Float, skipStac } else { child.PositionX = positionCross } - if alignSelf.Intersects("end", "self-end", "flex-end") { + if alignSelf.Intersects(kw.End, kw.SelfEnd, kw.FlexEnd) { if cross == pr.PHeight { child.PositionY += line.crossSize - child.MarginHeight() } else { child.PositionX += line.crossSize - child.MarginWidth() } - } else if alignSelf.Intersects("center") { + } else if alignSelf.Intersects(kw.Center) { if cross == pr.PHeight { child.PositionY += (line.crossSize - child.MarginHeight()) / 2 } else { child.PositionX += (line.crossSize - child.MarginWidth()) / 2 } - } else if alignSelf.Intersects("baseline") { + } else if alignSelf.Intersects(kw.Baseline) { if cross == pr.PHeight { child.PositionY += line.lowerBaseline - child.Baseline.V() } // else Handle vertical text - } else if alignSelf.Intersects("stretch") { + } else if alignSelf.Intersects(kw.Stretch) { if getCross(child, cross).S == "auto" { var margins pr.Float if cross == pr.PHeight { @@ -1109,23 +1110,23 @@ func flexLayout(context *layoutContext, box_ Box, bottomSpace pr.Float, skipStac setDirection(child, direction, currentValue) switch { - case alignContent.Intersects("end", "flex-end"): + case alignContent.Intersects(kw.End, kw.FlexEnd): setDirection(child, direction, currentValue+extraCrossSize) - case alignContent.Intersects("center"): + case alignContent.Intersects(kw.Center): setDirection(child, direction, currentValue+extraCrossSize/2) - case alignContent.Intersects("space-around"): + case alignContent.Intersects(kw.SpaceAround): setDirection(child, direction, currentValue+extraCrossSize/pr.Float(len(flexLines))/2) - case alignContent.Intersects("space-evenly"): + case alignContent.Intersects(kw.SpaceEvenly): setDirection(child, direction, currentValue+extraCrossSize/(pr.Float(len(flexLines))+1)) } } } switch { - case alignContent.Intersects("space-between"): + case alignContent.Intersects(kw.SpaceBetween): crossTranslate += extraCrossSize / (pr.Float(len(flexLines)) - 1) - case alignContent.Intersects("space-around"): + case alignContent.Intersects(kw.SpaceAround): crossTranslate += extraCrossSize / pr.Float(len(flexLines)) - case alignContent.Intersects("space-evenly"): + case alignContent.Intersects(kw.SpaceEvenly): crossTranslate += extraCrossSize / (pr.Float(len(flexLines)) + 1) } } diff --git a/html/layout/grid.go b/html/layout/grid.go index be47235..d04b96d 100644 --- a/html/layout/grid.go +++ b/html/layout/grid.go @@ -5,6 +5,7 @@ import ( "sort" pr "github.com/benoitkugler/webrender/css/properties" + kw "github.com/benoitkugler/webrender/css/properties/keywords" bo "github.com/benoitkugler/webrender/html/boxes" "github.com/benoitkugler/webrender/html/tree" "github.com/benoitkugler/webrender/logger" @@ -781,8 +782,8 @@ func resolveTracksSizes(context *layoutContext, sizingFunctions [][2]pr.DimOrS, // 1.5 Expand stretched auto tracks. justifyContent := containingBlock.Box().Style.GetJustifyContent() alignContent := containingBlock.Box().Style.GetAlignContent() - xStretch := direction == 'x' && justifyContent.Intersects("normal", "stretch") - yStretch := direction == 'y' && alignContent.Intersects("normal", "stretch") + xStretch := direction == 'x' && justifyContent.Intersects(kw.Normal, kw.Stretch) + yStretch := direction == 'y' && alignContent.Intersects(kw.Normal, kw.Stretch) if (xStretch || yStretch) && freeSpace != nil && freeSpace.V() > 0 { var autoTracksSizes []*[2]pr.MaybeFloat for i := range tracksSizes { @@ -1341,32 +1342,32 @@ func gridLayout(context *layoutContext, box_ Box, bottomSpace pr.Float, skipStac freeWidth := pr.Max(0, box.Width.V()-sum0(columnsSizes)) columnsNumber := pr.Float(len(columnsSizes)) columnsPositions := make([]pr.Float, len(columnsSizes)) - if justifyContent.Intersects("center") { + if justifyContent.Intersects(kw.Center) { x += freeWidth / 2 for i, size := range columnsSizes { columnsPositions[i] = x x += size[0] + columnGap } - } else if justifyContent.Intersects("right", "end", "flex-end") { + } else if justifyContent.Intersects(kw.Right, kw.End, kw.FlexEnd) { x += freeWidth for i, size := range columnsSizes { columnsPositions[i] = x x += size[0] + columnGap } - } else if justifyContent.Intersects("space-around") { + } else if justifyContent.Intersects(kw.SpaceAround) { x += freeWidth / 2 / columnsNumber for i, size := range columnsSizes { columnsPositions[i] = x x += size[0] + freeWidth/columnsNumber + columnGap } - } else if justifyContent.Intersects("space-between") { + } else if justifyContent.Intersects(kw.SpaceBetween) { for i, size := range columnsSizes { columnsPositions[i] = x if columnsNumber >= 2 { x += size[0] + freeWidth/(columnsNumber-1) + columnGap } } - } else if justifyContent.Intersects("space-evenly") { + } else if justifyContent.Intersects(kw.SpaceEvenly) { x += freeWidth / (columnsNumber + 1) for i, size := range columnsSizes { columnsPositions[i] = x @@ -1388,39 +1389,39 @@ func gridLayout(context *layoutContext, box_ Box, bottomSpace pr.Float, skipStac } rowsNumber := pr.Float(len(rowsSizes)) rowsPositions := make([]pr.Float, len(rowsSizes)) - if alignContent.Intersects("center") { + if alignContent.Intersects(kw.Center) { y += freeHeight / 2 for i, size := range rowsSizes { rowsPositions[i] = y y += size[0] + rowGap } - } else if alignContent.Intersects("right", "end", "flex-end") { + } else if alignContent.Intersects(kw.Right, kw.End, kw.FlexEnd) { y += freeHeight for i, size := range rowsSizes { rowsPositions[i] = y y += size[0] + rowGap } - } else if alignContent.Intersects("space-around") { + } else if alignContent.Intersects(kw.SpaceAround) { y += freeHeight / 2 / rowsNumber for i, size := range rowsSizes { rowsPositions[i] = y y += size[0] + freeHeight/rowsNumber + rowGap } - } else if alignContent.Intersects("space-between") { + } else if alignContent.Intersects(kw.SpaceBetween) { for i, size := range rowsSizes { rowsPositions[i] = y if rowsNumber >= 2 { y += size[0] + freeHeight/(rowsNumber-1) + rowGap } } - } else if alignContent.Intersects("space-evenly") { + } else if alignContent.Intersects(kw.SpaceEvenly) { y += freeHeight / (rowsNumber + 1) for i, size := range rowsSizes { rowsPositions[i] = y y += size[0] + freeHeight/(rowsNumber+1) + rowGap } } else { - if alignContent.Intersects("baseline") { + if alignContent.Intersects(kw.Baseline) { // TODO: Support baseline value. logger.WarningLogger.Println("Baseline alignment is not supported for grid layout") } @@ -1505,19 +1506,19 @@ func gridLayout(context *layoutContext, box_ Box, bottomSpace pr.Float, skipStac childB.MarginBottom.V() + childB.BorderBottomWidth + childB.PaddingBottom.V()) justifySelf := childB.Style.GetJustifySelf() - if justifySelf.Intersects("auto") { + if justifySelf.Intersects(kw.Auto) { justifySelf = justifyItems } - if justifySelf.Intersects("normal", "stretch") { + if justifySelf.Intersects(kw.Normal, kw.Stretch) { if childB.Style.GetWidth().S == "auto" { childB.Style.SetWidth(pr.FToPx(childWidth)) } } alignSelf := childB.Style.GetAlignSelf() - if alignSelf.Intersects("auto") { + if alignSelf.Intersects(kw.Auto) { alignSelf = alignItems } - if alignSelf.Intersects("normal", "stretch") { + if alignSelf.Intersects(kw.Normal, kw.Stretch) { if childB.Style.GetHeight().S == "auto" { childB.Style.SetHeight(pr.FToPx(childHeight)) } @@ -1542,26 +1543,26 @@ func gridLayout(context *layoutContext, box_ Box, bottomSpace pr.Float, skipStac } // TODO: Apply auto margins. - if justifySelf.Intersects("normal", "stretch") { + if justifySelf.Intersects(kw.Normal, kw.Stretch) { newChild.Box().Width = pr.Max(childWidth, newChild.Box().Width.V()) } else { newChild.Box().Width = maxContentWidth(context, newChild, true) diff := childWidth - newChild.Box().Width.V() - if justifySelf.Intersects("center") { + if justifySelf.Intersects(kw.Center) { newChild.Translate(newChild, diff/2, 0, false) - } else if justifySelf.Intersects("right", "end", "flex-end", "self-end") { + } else if justifySelf.Intersects(kw.Right, kw.End, kw.FlexEnd, kw.SelfEnd) { newChild.Translate(newChild, diff, 0, false) } } // TODO: Apply auto margins. - if alignSelf.Intersects("normal", "stretch") { + if alignSelf.Intersects(kw.Normal, kw.Stretch) { newChild.Box().Height = pr.Max(childHeight, newChild.Box().Height.V()) } else { diff := childHeight - newChild.Box().Height.V() - if alignSelf.Intersects("center") { + if alignSelf.Intersects(kw.Center) { newChild.Translate(newChild, 0, diff/2, false) - } else if alignSelf.Intersects("end", "flex-end", "self-end") { + } else if alignSelf.Intersects(kw.End, kw.FlexEnd, kw.SelfEnd) { newChild.Translate(newChild, 0, diff, false) } } diff --git a/html/tree/accessors.go b/html/tree/accessors.go index 4e806d2..8902fe3 100644 --- a/html/tree/accessors.go +++ b/html/tree/accessors.go @@ -4,45 +4,45 @@ package tree import pr "github.com/benoitkugler/webrender/css/properties" -func (s *ComputedStyle) GetAlignContent() pr.Strings { - return s.Get(pr.PAlignContent.Key()).(pr.Strings) +func (s *ComputedStyle) GetAlignContent() pr.JustifyOrAlign { + return s.Get(pr.PAlignContent.Key()).(pr.JustifyOrAlign) } -func (s *ComputedStyle) SetAlignContent(v pr.Strings) { +func (s *ComputedStyle) SetAlignContent(v pr.JustifyOrAlign) { s.propsCache.known[pr.PAlignContent] = v } -func (s *AnonymousStyle) GetAlignContent() pr.Strings { - return s.Get(pr.PAlignContent.Key()).(pr.Strings) +func (s *AnonymousStyle) GetAlignContent() pr.JustifyOrAlign { + return s.Get(pr.PAlignContent.Key()).(pr.JustifyOrAlign) } -func (s *AnonymousStyle) SetAlignContent(v pr.Strings) { +func (s *AnonymousStyle) SetAlignContent(v pr.JustifyOrAlign) { s.propsCache.known[pr.PAlignContent] = v } -func (s *ComputedStyle) GetAlignItems() pr.Strings { - return s.Get(pr.PAlignItems.Key()).(pr.Strings) +func (s *ComputedStyle) GetAlignItems() pr.JustifyOrAlign { + return s.Get(pr.PAlignItems.Key()).(pr.JustifyOrAlign) } -func (s *ComputedStyle) SetAlignItems(v pr.Strings) { +func (s *ComputedStyle) SetAlignItems(v pr.JustifyOrAlign) { s.propsCache.known[pr.PAlignItems] = v } -func (s *AnonymousStyle) GetAlignItems() pr.Strings { - return s.Get(pr.PAlignItems.Key()).(pr.Strings) +func (s *AnonymousStyle) GetAlignItems() pr.JustifyOrAlign { + return s.Get(pr.PAlignItems.Key()).(pr.JustifyOrAlign) } -func (s *AnonymousStyle) SetAlignItems(v pr.Strings) { +func (s *AnonymousStyle) SetAlignItems(v pr.JustifyOrAlign) { s.propsCache.known[pr.PAlignItems] = v } -func (s *ComputedStyle) GetAlignSelf() pr.Strings { - return s.Get(pr.PAlignSelf.Key()).(pr.Strings) +func (s *ComputedStyle) GetAlignSelf() pr.JustifyOrAlign { + return s.Get(pr.PAlignSelf.Key()).(pr.JustifyOrAlign) } -func (s *ComputedStyle) SetAlignSelf(v pr.Strings) { +func (s *ComputedStyle) SetAlignSelf(v pr.JustifyOrAlign) { s.propsCache.known[pr.PAlignSelf] = v } -func (s *AnonymousStyle) GetAlignSelf() pr.Strings { - return s.Get(pr.PAlignSelf.Key()).(pr.Strings) +func (s *AnonymousStyle) GetAlignSelf() pr.JustifyOrAlign { + return s.Get(pr.PAlignSelf.Key()).(pr.JustifyOrAlign) } -func (s *AnonymousStyle) SetAlignSelf(v pr.Strings) { +func (s *AnonymousStyle) SetAlignSelf(v pr.JustifyOrAlign) { s.propsCache.known[pr.PAlignSelf] = v } @@ -1572,45 +1572,45 @@ func (s *AnonymousStyle) SetImageResolution(v pr.DimOrS) { s.propsCache.known[pr.PImageResolution] = v } -func (s *ComputedStyle) GetJustifyContent() pr.Strings { - return s.Get(pr.PJustifyContent.Key()).(pr.Strings) +func (s *ComputedStyle) GetJustifyContent() pr.JustifyOrAlign { + return s.Get(pr.PJustifyContent.Key()).(pr.JustifyOrAlign) } -func (s *ComputedStyle) SetJustifyContent(v pr.Strings) { +func (s *ComputedStyle) SetJustifyContent(v pr.JustifyOrAlign) { s.propsCache.known[pr.PJustifyContent] = v } -func (s *AnonymousStyle) GetJustifyContent() pr.Strings { - return s.Get(pr.PJustifyContent.Key()).(pr.Strings) +func (s *AnonymousStyle) GetJustifyContent() pr.JustifyOrAlign { + return s.Get(pr.PJustifyContent.Key()).(pr.JustifyOrAlign) } -func (s *AnonymousStyle) SetJustifyContent(v pr.Strings) { +func (s *AnonymousStyle) SetJustifyContent(v pr.JustifyOrAlign) { s.propsCache.known[pr.PJustifyContent] = v } -func (s *ComputedStyle) GetJustifyItems() pr.Strings { - return s.Get(pr.PJustifyItems.Key()).(pr.Strings) +func (s *ComputedStyle) GetJustifyItems() pr.JustifyOrAlign { + return s.Get(pr.PJustifyItems.Key()).(pr.JustifyOrAlign) } -func (s *ComputedStyle) SetJustifyItems(v pr.Strings) { +func (s *ComputedStyle) SetJustifyItems(v pr.JustifyOrAlign) { s.propsCache.known[pr.PJustifyItems] = v } -func (s *AnonymousStyle) GetJustifyItems() pr.Strings { - return s.Get(pr.PJustifyItems.Key()).(pr.Strings) +func (s *AnonymousStyle) GetJustifyItems() pr.JustifyOrAlign { + return s.Get(pr.PJustifyItems.Key()).(pr.JustifyOrAlign) } -func (s *AnonymousStyle) SetJustifyItems(v pr.Strings) { +func (s *AnonymousStyle) SetJustifyItems(v pr.JustifyOrAlign) { s.propsCache.known[pr.PJustifyItems] = v } -func (s *ComputedStyle) GetJustifySelf() pr.Strings { - return s.Get(pr.PJustifySelf.Key()).(pr.Strings) +func (s *ComputedStyle) GetJustifySelf() pr.JustifyOrAlign { + return s.Get(pr.PJustifySelf.Key()).(pr.JustifyOrAlign) } -func (s *ComputedStyle) SetJustifySelf(v pr.Strings) { +func (s *ComputedStyle) SetJustifySelf(v pr.JustifyOrAlign) { s.propsCache.known[pr.PJustifySelf] = v } -func (s *AnonymousStyle) GetJustifySelf() pr.Strings { - return s.Get(pr.PJustifySelf.Key()).(pr.Strings) +func (s *AnonymousStyle) GetJustifySelf() pr.JustifyOrAlign { + return s.Get(pr.PJustifySelf.Key()).(pr.JustifyOrAlign) } -func (s *AnonymousStyle) SetJustifySelf(v pr.Strings) { +func (s *AnonymousStyle) SetJustifySelf(v pr.JustifyOrAlign) { s.propsCache.known[pr.PJustifySelf] = v }