diff options
author | bptato <nincsnevem662@gmail.com> | 2021-12-29 22:11:04 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2021-12-31 12:41:12 +0100 |
commit | c5375d2a5d45294efa91530c5a0f9d055e09438f (patch) | |
tree | 337c591d99cf55ded8d62df0478e4203f95df458 /src | |
parent | 7bea2f7026ed69737abdb09ccc73ff920d75c525 (diff) | |
download | chawan-c5375d2a5d45294efa91530c5a0f9d055e09438f.tar.gz |
Small cascade optimizations
Diffstat (limited to 'src')
-rw-r--r-- | src/css/cascade.nim | 52 | ||||
-rw-r--r-- | src/css/parser.nim | 39 | ||||
-rw-r--r-- | src/css/sheet.nim | 9 | ||||
-rw-r--r-- | src/css/values.nim | 20 |
4 files changed, 76 insertions, 44 deletions
diff --git a/src/css/cascade.nim b/src/css/cascade.nim index 1b246821..249f15ce 100644 --- a/src/css/cascade.nim +++ b/src/css/cascade.nim @@ -16,7 +16,7 @@ type ApplyResult = object normal: seq[CSSDeclaration] important: seq[CSSDeclaration] - RuleList* = array[PseudoElem, seq[CSSSimpleBlock]] + RuleList* = array[PseudoElem, seq[CSSDeclaration]] proc applyProperty(elem: Element, d: CSSDeclaration, pseudo: PseudoElem) = var parent: CSSSpecifiedValues @@ -69,14 +69,16 @@ func applies(mqlist: MediaQueryList): bool = return true return false -func calcRule(tosorts: var array[PseudoElem, seq[tuple[s:int,b:CSSSimpleBlock]]], elem: Element, rule: CSSRuleBase) = +type ToSorts = array[PseudoElem, seq[(int, seq[CSSDeclaration])]] + +proc calcRule(tosorts: var ToSorts, elem: Element, rule: CSSRuleBase) = if rule of CSSRuleDef: let rule = CSSRuleDef(rule) for sel in rule.sels: let match = elem.selectorsMatch(sel) if match.success: let spec = getSpecificity(sel) - tosorts[match.pseudo].add((spec,rule.oblock)) + tosorts[match.pseudo].add((spec,rule.decls)) elif rule of CSSMediaQueryDef: let def = CSSMediaQueryDef(rule) if def.query.applies(): @@ -84,45 +86,35 @@ func calcRule(tosorts: var array[PseudoElem, seq[tuple[s:int,b:CSSSimpleBlock]]] tosorts.calcRule(elem, child) func calcRules(elem: Element, rules: CSSStylesheet): RuleList = - var tosorts: array[PseudoElem, seq[tuple[s:int,b:CSSSimpleBlock]]] + var tosorts: ToSorts for rule in rules: tosorts.calcRule(elem, rule) for i in PseudoElem: - tosorts[i].sort((x, y) => cmp(x.s,y.s)) - result[i] = tosorts[i].map((x) => x.b) - -proc applyItems(ares: var ApplyResult, decls: seq[CSSParsedItem]) = - for item in decls: - if item of CSSDeclaration: - let decl = CSSDeclaration(item) - if decl.important: - ares.important.add(decl) - else: - ares.normal.add(decl) + tosorts[i].sort((x, y) => cmp(x[0], y[0])) + result[i] = collect(newSeq): + for item in tosorts[i]: + for dl in item[1]: + dl + +proc applyItems(ares: var ApplyResult, decls: seq[CSSDeclaration]) = + for decl in decls: + if decl.important: + ares.important.add(decl) + else: + ares.normal.add(decl) proc applyRules(element: Element, ua, user, author: RuleList, pseudo: PseudoElem) = var ares: ApplyResult - let rules_user_agent = ua[pseudo] - for rule in rules_user_agent: - let decls = parseListOfDeclarations(rule.value) - ares.applyItems(decls) - - let rules_user = user[pseudo] - for rule in rules_user: - let decls = parseListOfDeclarations(rule.value) - ares.applyItems(decls) - - let rules_author = author[pseudo] - for rule in rules_author: - let decls = parseListOfDeclarations(rule.value) - ares.applyItems(decls) + ares.applyItems(ua[pseudo]) + ares.applyItems(user[pseudo]) + ares.applyItems(author[pseudo]) if pseudo == PSEUDO_NONE: let style = element.attr("style") if style.len > 0: - let inline_rules = newStringStream(style).parseListOfDeclarations() + let inline_rules = newStringStream(style).parseListOfDeclarations2() ares.applyItems(inline_rules) for rule in ares.normal: diff --git a/src/css/parser.nim b/src/css/parser.nim index a3668739..f71ed033 100644 --- a/src/css/parser.nim +++ b/src/css/parser.nim @@ -594,6 +594,7 @@ proc consumeDeclaration(state: var CSSParseState): Option[CSSDeclaration] = #> and at-rules, as CSS 2.1 does for @page. Unexpected at-rules (which could be #> all of them, in a given context) are invalid and should be ignored by the #> consumer. +#So we have two versions, one with at rules and one without. proc consumeListOfDeclarations(state: var CSSParseState): seq[CSSParsedItem] = while state.has(): let t = state.consume() @@ -617,6 +618,29 @@ proc consumeListOfDeclarations(state: var CSSParseState): seq[CSSParsedItem] = if state.curr() != CSS_SEMICOLON_TOKEN: discard state.consumeComponentValue() +proc consumeListOfDeclarations2(state: var CSSParseState): seq[CSSDeclaration] = + while state.has(): + let t = state.consume() + if t == CSS_wHITESPACE_TOKEN or t == CSS_SEMICOLON_TOKEN: + continue + elif t == CSS_AT_KEYWORD_TOKEN: + state.reconsume() + discard state.consumeAtRule() + elif t == CSS_IDENT_TOKEN: + var tempList: seq[CSSParsedItem] + tempList.add(CSSToken(t)) + while state.has() and state.curr() != CSS_SEMICOLON_TOKEN: + tempList.add(state.consumeComponentValue()) + + var tempState = CSSParseState(at: 0, tokens: tempList) + let decl = tempState.consumeDeclaration() + if decl.isSome: + result.add(decl.get) + else: + state.reconsume() + if state.curr() != CSS_SEMICOLON_TOKEN: + discard state.consumeComponentValue() + proc consumeListOfRules(state: var CSSParseState): seq[CSSRule] = while state.at < state.tokens.len: let t = state.consume() @@ -717,6 +741,21 @@ proc parseListOfDeclarations*(inputStream: Stream): seq[CSSParsedItem] = state.tokens = tokenizeCSS(inputStream) return state.parseListOfDeclarations() +proc parseListOfDeclarations2(state: var CSSParseState): seq[CSSDeclaration] = + return state.consumeListOfDeclarations2() + +proc parseListOfDeclarations2*(cvals: seq[CSSComponentValue]): seq[CSSDeclaration] = + var state: CSSParseState + state.tokens = collect(newSeq): + for cval in cvals: + CSSParsedItem(cval) + return state.consumeListOfDeclarations2() + +proc parseListOfDeclarations2*(inputStream: Stream): seq[CSSDeclaration] = + var state: CSSParseState + state.tokens = tokenizeCSS(inputStream) + return state.parseListOfDeclarations2() + proc parseComponentValue(state: var CSSParseState): CSSComponentValue = while state.has() and state.curr() == CSS_WHITESPACE_TOKEN: discard state.consume() diff --git a/src/css/sheet.nim b/src/css/sheet.nim index 44e923cb..76b8c55f 100644 --- a/src/css/sheet.nim +++ b/src/css/sheet.nim @@ -10,7 +10,7 @@ type CSSRuleDef* = ref object of CSSRuleBase sels*: seq[SelectorList] - oblock*: CSSSimpleBlock + decls*: seq[CSSDeclaration] CSSConditionalDef* = ref object of CSSRuleBase children*: CSSStylesheet @@ -20,10 +20,13 @@ type CSSStylesheet* = seq[CSSRuleBase] +proc getDeclarations(rule: CSSQualifiedRule): seq[CSSDeclaration] {.inline.} = + rule.oblock.value.parseListOfDeclarations2() + proc addRule(stylesheet: var CSSStylesheet, rule: CSSQualifiedRule) = let sels = parseSelectors(rule.prelude) if sels.len > 1 or sels[^1].len > 0: - let r = CSSRuleDef(sels: sels, oblock: rule.oblock) + let r = CSSRuleDef(sels: sels, decls: rule.getDeclarations()) stylesheet.add(r) proc addAtRule(stylesheet: var CSSStylesheet, atrule: CSSAtRule) = @@ -38,7 +41,7 @@ proc addAtRule(stylesheet: var CSSStylesheet, atrule: CSSAtRule) = if rule of CSSAtRule: media.children.addAtRule(CSSAtRule(rule)) else: - media.children.addRule(CSSQualifiedRule(rule)) #qualified rule + media.children.addRule(CSSQualifiedRule(rule)) stylesheet.add(media) else: discard #TODO diff --git a/src/css/values.nim b/src/css/values.nim index 6992b9d2..46c49ef5 100644 --- a/src/css/values.nim +++ b/src/css/values.nim @@ -181,7 +181,7 @@ func propertyType(s: string): CSSPropertyType = func valueType(prop: CSSPropertyType): CSSValueType = return ValueTypes[prop] -macro `{}`*(vals: CSSSpecifiedValues, s: typed): untyped = +macro `{}`*(vals: CSSSpecifiedValues, s: string): untyped = let t = propertyType($s) let vs = $valueType(t) let s = vs.split(Rune('_'))[1..^1].join("_").tolower() @@ -230,7 +230,7 @@ func listMarker*(t: CSSListStyleType, i: int): string = of LIST_STYLE_TYPE_LOWER_ROMAN: return romanNumber_lower(i) & ". " of LIST_STYLE_TYPE_JAPANESE_INFORMAL: return japaneseNumber(i) & "、" -const colors = { +const Colors = { "aliceblue": 0xf0f8ff, "antiquewhite": 0xfaebd7, "aqua": 0x00ffff, @@ -381,7 +381,7 @@ const colors = { "rebeccapurple": 0x663399, }.map((a) => (a[0], CSSColor(rgba: RGBAColor(a[1])))).toTable() -const units = { +const Units = { "%": UNIT_PERC, "cm": UNIT_CM, "mm": UNIT_MM, @@ -401,8 +401,8 @@ const units = { }.toTable() func cssLength(val: float64, unit: string): CSSLength = - if unit in units: - CSSLength(num: val, unit: units[unit]) + if unit in Units: + CSSLength(num: val, unit: Units[unit]) else: raise newException(CSSValueError, "Invalid unit") @@ -439,8 +439,8 @@ func cssColor(d: CSSDeclaration): CSSColor = raise newException(CSSValueError, "Invalid color") of CSS_IDENT_TOKEN: let s = tok.value - if $s in colors: - return colors[$s] + if $s in Colors: + return Colors[$s] else: raise newException(CSSValueError, "Invalid color") else: @@ -475,8 +475,6 @@ func cssColor(d: CSSDeclaration): CSSColor = raise newException(CSSValueError, "Invalid color") func cellColor*(color: CSSColor): CellColor = - #TODO better would be to store color names and return term colors on demand - #option) return CellColor(rgb: true, rgbcolor: RGBColor(color.rgba)) func cssLength(d: CSSDeclaration): CSSLength = @@ -635,9 +633,9 @@ proc getValueFromDecl(val: CSSSpecifiedValue, d: CSSDeclaration, vtype: CSSValue func getInitialColor(t: CSSPropertyType): CSSColor = case t of PROPERTY_COLOR: - return colors["white"] + return Colors["white"] else: - return colors["black"] + return Colors["black"] func getInitialLength(t: CSSPropertyType): CSSLength = case t |