diff options
author | bptato <nincsnevem662@gmail.com> | 2023-12-09 13:14:15 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2023-12-09 13:16:27 +0100 |
commit | fd8e1b2ecbd4403c98fb6dc0f68d821bb395139c (patch) | |
tree | 9eb539f5df760af1f0b32808462d5c1bfdd4cea1 | |
parent | fad4d3a044080eb068cd9adaa476a893ad69897c (diff) | |
download | chawan-fd8e1b2ecbd4403c98fb6dc0f68d821bb395139c.tar.gz |
sheet: fix a correctness issue, misc refactorings
* Fix a bug where rules would be sorted incorrectly if retrieved from the cache. * Use withValue where possible * camelCase some variables, de-extern some functions, etc.
-rw-r--r-- | src/css/cascade.nim | 4 | ||||
-rw-r--r-- | src/css/sheet.nim | 110 |
2 files changed, 63 insertions, 51 deletions
diff --git a/src/css/cascade.nim b/src/css/cascade.nim index c96e9c52..39bf9eb9 100644 --- a/src/css/cascade.nim +++ b/src/css/cascade.nim @@ -91,7 +91,7 @@ proc calcRule(tosorts: var ToSorts, styledNode: StyledNode, rule: CSSRuleDef) = func calcRules(styledNode: StyledNode, sheet: CSSStylesheet): DeclarationList = var tosorts: ToSorts let elem = Element(styledNode.node) - for rule in sheet.gen_rules(elem.tagType, elem.id, elem.classList.toks): + for rule in sheet.genRules(elem.tagType, elem.id, elem.classList.toks): tosorts.calcRule(styledNode, rule) for i in PseudoElem: tosorts[i].sort((proc(x, y: (int, seq[CSSDeclaration])): int = @@ -277,7 +277,7 @@ proc applyDeclarations(pseudo: PseudoElem, styledParent: StyledNode, func applyMediaQuery(ss: CSSStylesheet, window: Window): CSSStylesheet = if ss == nil: return nil result = ss - for mq in ss.mq_list: + for mq in ss.mqList: if mq.query.applies(window): result.add(mq.children.applyMediaQuery(window)) diff --git a/src/css/sheet.nim b/src/css/sheet.nim index d3cd011f..0929d7f9 100644 --- a/src/css/sheet.nim +++ b/src/css/sheet.nim @@ -1,3 +1,4 @@ +import algorithm import streams import tables @@ -13,6 +14,9 @@ type CSSRuleDef* = ref object of CSSRuleBase sels*: SelectorList decls*: seq[CSSDeclaration] + # Absolute position in the stylesheet; used for sorting rules after + # retrieval from the cache. + idx: int CSSConditionalDef* = ref object of CSSRuleBase children*: CSSStylesheet @@ -21,12 +25,12 @@ type query*: MediaQueryList CSSStylesheet* = ref object - mq_list*: seq[CSSMediaQueryDef] - tag_table*: array[TagType, seq[CSSRuleDef]] - id_table*: Table[string, seq[CSSRuleDef]] - class_table*: Table[string, seq[CSSRuleDef]] - general_list*: seq[CSSRuleDef] - len*: int + mqList*: seq[CSSMediaQueryDef] + tagTable: array[TagType, seq[CSSRuleDef]] + idTable: Table[string, seq[CSSRuleDef]] + classTable: Table[string, seq[CSSRuleDef]] + generalList: seq[CSSRuleDef] + len: int type SelectorHashes = object tag: TagType @@ -36,9 +40,9 @@ type SelectorHashes = object func newStylesheet*(cap: int): CSSStylesheet = let bucketsize = cap div 2 return CSSStylesheet( - id_table: initTable[string, seq[CSSRuleDef]](bucketsize), - class_table: initTable[string, seq[CSSRuleDef]](bucketsize), - general_list: newSeqOfCap[CSSRuleDef](bucketsize) + idTable: initTable[string, seq[CSSRuleDef]](bucketsize), + classTable: initTable[string, seq[CSSRuleDef]](bucketsize), + generalList: newSeqOfCap[CSSRuleDef](bucketsize) ) proc getSelectorIds(hashes: var SelectorHashes, sel: Selector): bool @@ -111,18 +115,26 @@ proc getSelectorIds(hashes: var SelectorHashes, sel: Selector): bool = if hashes.tag != TAG_UNKNOWN or hashes.id != "" or hashes.class != "": return true -iterator gen_rules*(sheet: CSSStylesheet, tag: TagType, id: string, classes: seq[string]): CSSRuleDef = - for rule in sheet.tag_table[tag]: - yield rule +proc ruleDefCmp(a, b: CSSRuleDef): int = + cmp(a.idx, b.idx) + +iterator genRules*(sheet: CSSStylesheet, tag: TagType, id: string, + classes: seq[string]): CSSRuleDef = + var rules: seq[CSSRuleDef] + for rule in sheet.tagTable[tag]: + rules.add(rule) if id != "": - sheet.id_table.withValue(id, v): + sheet.idTable.withValue(id, v): for rule in v[]: - yield rule + rules.add(rule) for class in classes: - sheet.class_table.withValue(class, v): + sheet.classTable.withValue(class, v): for rule in v[]: - yield rule - for rule in sheet.general_list: + rules.add(rule) + for rule in sheet.generalList: + rules.add(rule) + rules.sort(ruleDefCmp, order = Ascending) + for rule in rules: yield rule proc add(sheet: var CSSStylesheet, rule: CSSRuleDef) = @@ -130,47 +142,45 @@ proc add(sheet: var CSSStylesheet, rule: CSSRuleDef) = for cxsel in rule.sels: hashes.getSelectorIds(cxsel) if hashes.tag != TAG_UNKNOWN: - sheet.tag_table[hashes.tag].add(rule) + sheet.tagTable[hashes.tag].add(rule) elif hashes.id != "": - if hashes.id notin sheet.id_table: - sheet.id_table[hashes.id] = newSeq[CSSRuleDef]() - sheet.id_table[hashes.id].add(rule) + sheet.idTable.withValue(hashes.id, p): + p[].add(rule) + do: + sheet.idTable[hashes.id] = @[rule] elif hashes.class != "": - if hashes.class notin sheet.class_table: - sheet.class_table[hashes.class] = newSeq[CSSRuleDef]() - sheet.class_table[hashes.class].add(rule) + sheet.classTable.withValue(hashes.class, p): + p[].add(rule) + do: + sheet.classTable[hashes.class] = @[rule] else: - sheet.general_list.add(rule) - -proc add*(sheet: var CSSStylesheet, rule: CSSRuleBase) {.inline.} = - if rule of CSSRuleDef: - sheet.add(CSSRuleDef(rule)) - else: - sheet.mq_list.add(CSSMediaQueryDef(rule)) - inc sheet.len + sheet.generalList.add(rule) -proc add*(sheet: var CSSStylesheet, sheet2: CSSStylesheet) {.inline.} = - sheet.general_list.add(sheet2.general_list) +proc add*(sheet: var CSSStylesheet, sheet2: CSSStylesheet) = + sheet.generalList.add(sheet2.generalList) for tag in TagType: - sheet.tag_table[tag].add(sheet2.tag_table[tag]) - for key, value in sheet2.id_table.pairs: - if key notin sheet.id_table: - sheet.id_table[key] = newSeq[CSSRuleDef]() - sheet.id_table[key].add(value) - for key, value in sheet2.class_table.pairs: - if key notin sheet.class_table: - sheet.class_table[key] = newSeq[CSSRuleDef]() - sheet.class_table[key].add(value) - sheet.len += sheet2.len - -proc getDeclarations(rule: CSSQualifiedRule): seq[CSSDeclaration] {.inline.} = - rule.oblock.value.parseListOfDeclarations2() + sheet.tagTable[tag].add(sheet2.tagTable[tag]) + for key, value in sheet2.idTable.pairs: + sheet.idTable.withValue(key, p): + p[].add(value) + do: + sheet.idTable[key] = value + for key, value in sheet2.classTable.pairs: + sheet.classTable.withValue(key, p): + p[].add(value) + do: + sheet.classTable[key] = value proc addRule(stylesheet: var CSSStylesheet, rule: CSSQualifiedRule) = let sels = parseSelectors(rule.prelude) if sels.len > 0: - let r = CSSRuleDef(sels: sels, decls: rule.getDeclarations()) + let r = CSSRuleDef( + sels: sels, + decls: rule.oblock.value.parseListOfDeclarations2(), + idx: stylesheet.len + ) stylesheet.add(r) + inc stylesheet.len proc addAtRule(stylesheet: var CSSStylesheet, atrule: CSSAtRule) = case atrule.name @@ -180,13 +190,15 @@ proc addAtRule(stylesheet: var CSSStylesheet, atrule: CSSAtRule) = if rules.len > 0: var media = CSSMediaQueryDef() media.children = newStylesheet(rules.len) + media.children.len = stylesheet.len media.query = query for rule in rules: if rule of CSSAtRule: media.children.addAtRule(CSSAtRule(rule)) else: media.children.addRule(CSSQualifiedRule(rule)) - stylesheet.add(media) + stylesheet.mqList.add(media) + stylesheet.len += media.children.len else: discard #TODO proc parseStylesheet*(s: Stream): CSSStylesheet = |