about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2021-12-29 22:11:04 +0100
committerbptato <nincsnevem662@gmail.com>2021-12-31 12:41:12 +0100
commitc5375d2a5d45294efa91530c5a0f9d055e09438f (patch)
tree337c591d99cf55ded8d62df0478e4203f95df458 /src
parent7bea2f7026ed69737abdb09ccc73ff920d75c525 (diff)
downloadchawan-c5375d2a5d45294efa91530c5a0f9d055e09438f.tar.gz
Small cascade optimizations
Diffstat (limited to 'src')
-rw-r--r--src/css/cascade.nim52
-rw-r--r--src/css/parser.nim39
-rw-r--r--src/css/sheet.nim9
-rw-r--r--src/css/values.nim20
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