about summary refs log tree commit diff stats
path: root/src/css
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2021-12-14 17:31:00 +0100
committerbptato <nincsnevem662@gmail.com>2021-12-14 17:31:00 +0100
commit72e171f6bee469ecc0086357f83fe4dc678023f3 (patch)
tree4b02726798aa961c3562a0f44293dafcf28dd179 /src/css
parent8edf12e933f490a5adf268a101f320ace8120997 (diff)
downloadchawan-72e171f6bee469ecc0086357f83fe4dc678023f3.tar.gz
Add lists, function selector fixes
Diffstat (limited to 'src/css')
-rw-r--r--src/css/selector.nim33
-rw-r--r--src/css/style.nim36
-rw-r--r--src/css/values.nim42
3 files changed, 83 insertions, 28 deletions
diff --git a/src/css/selector.nim b/src/css/selector.nim
index 7cfbf328..13131f80 100644
--- a/src/css/selector.nim
+++ b/src/css/selector.nim
@@ -48,7 +48,7 @@ type
       elem*: string
     of FUNC_SELECTOR:
       name*: string
-      fsels*: SelectorList
+      fsels*: seq[SelectorList]
     of COMBINATOR_SELECTOR:
       ct*: CombinatorType
       csels*: seq[SelectorList]
@@ -77,13 +77,14 @@ func getSpecificity(sel: Selector): int =
     case sel.name
     of "is":
       var best = 0
-      for child in sel.fsels.sels:
+      for child in sel.fsels:
         let s = getSpecificity(child)
         if s > best:
           best = s
       result += best
     of "not":
-      result += getSpecificity(sel.fsels)
+      for child in sel.fsels:
+        result += getSpecificity(child)
     else: discard
   of UNIVERSAL_SELECTOR:
     discard
@@ -129,6 +130,12 @@ proc addSelector(state: var SelectorParser, sel: Selector) =
   else:
     state.selectors[^1].add(sel)
 
+proc getLastSel(state: SelectorParser): Selector =
+  if state.combinator != nil:
+    return state.combinator.csels[^1].sels[^1]
+  else:
+    return state.selectors[^1].sels[^1]
+
 proc addSelectorList(state: var SelectorParser) =
   if state.combinator != nil:
     state.selectors[^1].add(state.combinator)
@@ -227,22 +234,24 @@ proc parseSelectorSimpleBlock(state: var SelectorParser, cssblock: CSSSimpleBloc
             state.query = QUERY_DELIM
             state.addSelector(Selector(t: ATTR_SELECTOR, attr: $csstoken.value, rel: ' '))
           of QUERY_VALUE:
-            state.selectors[^1].sels[^1].value = $csstoken.value
+            state.getLastSel().value = $csstoken.value
             break
           else: discard
         of CSS_STRING_TOKEN:
           case state.query
           of QUERY_VALUE:
-            state.selectors[^1].sels[^1].value = $csstoken.value
+            state.getLastSel().value = $csstoken.value
             break
           else: discard
         of CSS_DELIM_TOKEN:
           case csstoken.rvalue
           of Rune('~'), Rune('|'), Rune('^'), Rune('$'), Rune('*'):
             if state.query == QUERY_DELIM:
-              state.selectors[^1].sels[^1].rel = char(csstoken.rvalue)
+              state.getLastSel().rel = char(csstoken.rvalue)
           of Rune('='):
             if state.query == QUERY_DELIM:
+              if state.getLastSel().rel == ' ':
+                state.getLastSel().rel = '='
               state.query = QUERY_VALUE
           else: discard
         else: discard
@@ -257,9 +266,13 @@ proc parseSelectorFunction(state: var SelectorParser, cssfunction: CSSFunction)
     state.query = QUERY_TYPE
   else: return
   var fun = Selector(t: FUNC_SELECTOR, name: $cssfunction.name)
-  fun.fsels = SelectorList(parent: state.selectors[^1])
   state.addSelector(fun)
-  state.selectors[^1] = fun.fsels
+
+  let osels = state.selectors
+  let ocomb = state.combinator
+  state.combinator = nil
+  state.selectors = newSeq[SelectorList]()
+  state.addSelectorList()
   for cval in cssfunction.value:
     if cval of CSSToken:
       state.parseSelectorToken(CSSToken(cval))
@@ -267,7 +280,9 @@ proc parseSelectorFunction(state: var SelectorParser, cssfunction: CSSFunction)
       state.parseSelectorSimpleBlock(CSSSimpleBlock(cval))
     elif cval of CSSFunction:
       state.parseSelectorFunction(CSSFunction(cval))
-  state.selectors[^1] = fun.fsels.parent
+  fun.fsels = state.selectors
+  state.selectors = osels
+  state.combinator = ocomb
 
 func parseSelectors*(cvals: seq[CSSComponentValue]): seq[SelectorList] =
   var state = SelectorParser()
diff --git a/src/css/style.nim b/src/css/style.nim
index e2bf2347..efffb8c6 100644
--- a/src/css/style.nim
+++ b/src/css/style.nim
@@ -53,6 +53,22 @@ func pseudoElemSelectorMatches(elem: Element, sel: Selector): SelectResult =
 
 func selectorsMatch(elem: Element, selectors: SelectorList): SelectResult
 
+func funcSelectorMatches(elem: Element, sel: Selector): SelectResult =
+  case sel.name
+  of "not":
+    for slist in sel.fsels:
+      let res = elem.selectorsMatch(slist)
+      if res.success:
+        return selectres(false)
+    return selectres(true)
+  of "is", "where":
+    for slist in sel.fsels:
+      let res = elem.selectorsMatch(slist)
+      if not res.success:
+        return selectres(false)
+    return selectres(true)
+  else: discard
+
 func selectorMatches(elem: Element, sel: Selector): SelectResult =
   case sel.t
   of TYPE_SELECTOR:
@@ -70,7 +86,7 @@ func selectorMatches(elem: Element, sel: Selector): SelectResult =
   of UNIVERSAL_SELECTOR:
     return selectres(true)
   of FUNC_SELECTOR:
-    return selectres(false)
+    return funcSelectorMatches(elem, sel)
   of COMBINATOR_SELECTOR:
     #combinator without at least two members makes no sense
     assert sel.csels.len > 1
@@ -110,7 +126,6 @@ func selectorMatches(elem: Element, sel: Selector): SelectResult =
             return selectres(false)
 
           if not res.success:
-            eprint "fail", e.tagType
             return selectres(false)
           dec i
           e = e.previousElementSibling
@@ -157,12 +172,7 @@ func selectElems(document: Document, sel: Selector): seq[Element] =
   of PSELEM_SELECTOR:
     return document.all_elements.filter((elem) => pseudoElemSelectorMatches(elem, sel))
   of FUNC_SELECTOR:
-    case sel.name
-    of "not":
-      return document.all_elements.filter((elem) => not selectorsMatch(elem, sel.fsels).psuccess)
-    of "is", "where":
-      return document.all_elements.filter((elem) => selectorsMatch(elem, sel.fsels).psuccess)
-    return newSeq[Element]()
+    return document.all_elements.filter((elem) => selectorMatches(elem, sel))
   of COMBINATOR_SELECTOR:
     return document.all_elements.filter((elem) => selectorMatches(elem, sel))
 
@@ -173,15 +183,7 @@ func selectElems(document: Document, selectors: SelectorList): seq[Element] =
   var i = 1
 
   while i < sellist.len:
-    if sellist[i].t == FUNC_SELECTOR:
-      case sellist[i].name
-      of "not":
-        result = result.filter((elem) => not selectorsMatch(elem, sellist[i].fsels).psuccess)
-      of "is", "where":
-        result = result.filter((elem) => selectorsMatch(elem, sellist[i].fsels).psuccess)
-      else: discard
-    else:
-      result = result.filter((elem) => selectorMatches(elem, sellist[i]).psuccess)
+    result = result.filter((elem) => selectorMatches(elem, sellist[i]).psuccess)
     inc i
 
 proc querySelector*(document: Document, q: string): seq[Element] =
diff --git a/src/css/values.nim b/src/css/values.nim
index 7d5d5bc5..b55869f7 100644
--- a/src/css/values.nim
+++ b/src/css/values.nim
@@ -39,6 +39,8 @@ type
       textdecoration*: CSSTextDecoration
     of VALUE_WORD_BREAK:
       wordbreak*: CSSWordBreak
+    of VALUE_LIST_STYLE_TYPE:
+      liststyletype*: CSSListStyleType
     of VALUE_NONE: discard
 
   CSSComputedValues* = ref array[low(CSSPropertyType)..high(CSSPropertyType), CSSComputedValue]
@@ -66,6 +68,7 @@ const PropertyNames = {
   "word-break": PROPERTY_WORD_BREAK,
   "width": PROPERTY_WIDTH,
   "height": PROPERTY_HEIGHT,
+  "list-style-type": PROPERTY_LIST_STYLE_TYPE,
 }.toTable()
 
 const ValueTypes = [
@@ -86,11 +89,13 @@ const ValueTypes = [
   PROPERTY_WORD_BREAK: VALUE_WORD_BREAK,
   PROPERTY_WIDTH: VALUE_LENGTH,
   PROPERTY_HEIGHT: VALUE_LENGTH,
+  PROPERTY_LIST_STYLE_TYPE: VALUE_LIST_STYLE_TYPE,
 ]
 
 const InheritedProperties = {
   PROPERTY_COLOR, PROPERTY_FONT_STYLE, PROPERTY_WHITE_SPACE,
-  PROPERTY_FONT_WEIGHT, PROPERTY_TEXT_DECORATION, PROPERTY_WORD_BREAK
+  PROPERTY_FONT_WEIGHT, PROPERTY_TEXT_DECORATION, PROPERTY_WORD_BREAK,
+  PROPERTY_LIST_STYLE_TYPE
 }
 
 func getPropInheritedArray(): array[low(CSSPropertyType)..high(CSSPropertyType), bool] =
@@ -123,6 +128,15 @@ func cells*(l: CSSLength): int =
     #TODO
     return int(l.num / 8)
 
+func listMarker*(t: CSSListStyleType, i: int): string =
+  case t
+  of LIST_STYLE_TYPE_NONE: return ""
+  of LIST_STYLE_TYPE_DISC: return "* "
+  of LIST_STYLE_TYPE_CIRCLE: return "o "
+  of LIST_STYLE_TYPE_SQUARE: return "O "
+  of LIST_STYLE_TYPE_DECIMAL: return $i & ". "
+  of LIST_STYLE_TYPE_JAPANESE_INFORMAL: return japaneseNumber(i) & "、"
+
 func r(c: CSSColor): int =
   return c.rgba.r
 
@@ -436,8 +450,8 @@ func cssDisplay(d: CSSDeclaration): CSSDisplay =
       case $tok.value
       of "block": return DISPLAY_BLOCK
       of "inline": return DISPLAY_INLINE
+      of "list-item": return DISPLAY_LIST_ITEM
       # of "inline-block": return DISPLAY_INLINE_BLOCK
-      # of "list-item": return DISPLAY_LIST_ITEM
       # of "table": return DISPLAY_TABLE
       # of "table-row-group": return DISPLAY_TABLE_ROW_GROUP
       # of "table-header-group": return DISPLAY_TABLE_HEADER_GROUP
@@ -511,6 +525,19 @@ func cssWordBreak(d: CSSDeclaration): CSSWordBreak =
       of "keep-all": return WORD_BREAK_KEEP_ALL
   raise newException(CSSValueError, "Invalid text decoration")
 
+func cssListStyleType(d: CSSDeclaration): CSSListStyleType =
+  if isToken(d):
+    let tok = getToken(d)
+    if tok.tokenType == CSS_IDENT_TOKEN:
+      case $tok.value
+      of "none": return LIST_STYLE_TYPE_NONE
+      of "disc": return LIST_STYLE_TYPE_DISC
+      of "circle": return LIST_STYLE_TYPE_CIRCLE
+      of "square": return LIST_STYLE_TYPE_SQUARE
+      of "decimal": return LIST_STYLE_TYPE_DECIMAL
+      of "japanese-informal": return LIST_STYLE_TYPE_JAPANESE_INFORMAL
+  raise newException(CSSValueError, "Invalid list style")
+
 func getSpecifiedValue*(d: CSSDeclaration): CSSSpecifiedValue =
   let name = $d.name
   let ptype = propertyType(name)
@@ -529,6 +556,7 @@ func getSpecifiedValue*(d: CSSDeclaration): CSSSpecifiedValue =
         result.integer = cssFontWeight(d)
     of VALUE_TEXT_DECORATION: result.textdecoration = cssTextDecoration(d)
     of VALUE_WORD_BREAK: result.wordbreak = cssWordBreak(d)
+    of VALUE_LIST_STYLE_TYPE: result.liststyletype = cssListStyleType(d)
     of VALUE_NONE: discard
   except CSSValueError:
     result.globalValue = VALUE_UNSET
@@ -611,6 +639,8 @@ func getComputedValue*(prop: CSSSpecifiedValue, current: CSSComputedValues): CSS
     return CSSComputedValue(t: prop.t, v: VALUE_TEXT_DECORATION, textdecoration: prop.textdecoration)
   of VALUE_WORD_BREAK:
     return CSSComputedValue(t: prop.t, v: VALUE_WORD_BREAK, wordbreak: prop.wordbreak)
+  of VALUE_LIST_STYLE_TYPE:
+    return CSSComputedValue(t: prop.t, v: VALUE_LIST_STYLE_TYPE, liststyletype: prop.liststyletype)
   of VALUE_NONE: return CSSComputedValue(t: prop.t, v: VALUE_NONE)
 
 func getComputedValue*(d: CSSDeclaration, current: CSSComputedValues): CSSComputedValue =
@@ -629,3 +659,11 @@ proc inheritProperties*(vals: var CSSComputedValues, parent: CSSComputedValues)
       vals[prop] = getDefault(prop)
     if inherited(prop) and parent[prop] != nil and vals[prop] == getDefault(prop):
       vals[prop] = parent[prop]
+
+func inheritProperties*(parent: CSSComputedValues): CSSComputedValues =
+  new(result)
+  for prop in low(CSSPropertyType)..high(CSSPropertyType):
+    if inherited(prop) and parent[prop] != nil:
+      result[prop] = parent[prop]
+    else:
+      result[prop] = getDefault(prop)