diff options
author | bptato <nincsnevem662@gmail.com> | 2024-12-15 16:44:53 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2024-12-15 16:44:53 +0100 |
commit | 8a586beaa26fa7ad4dbc4573e655927f8f32e158 (patch) | |
tree | cad39d5751c769bbdaf5b0bc5403322c63ebefc2 /src | |
parent | 2dc6b651e60604e1fe139ede00ff9c172535a939 (diff) | |
download | chawan-8a586beaa26fa7ad4dbc4573e655927f8f32e158.tar.gz |
dom, css: fix case-insensitive class/id/attr matching
Uses an additional lower-case map for O(1) case-insensitive comparisons.
Diffstat (limited to 'src')
-rw-r--r-- | src/css/cascade.nim | 16 | ||||
-rw-r--r-- | src/css/match.nim | 8 | ||||
-rw-r--r-- | src/css/selectorparser.nim | 11 | ||||
-rw-r--r-- | src/css/sheet.nim | 2 | ||||
-rw-r--r-- | src/html/catom.nim | 28 | ||||
-rw-r--r-- | src/html/dom.nim | 16 |
6 files changed, 53 insertions, 28 deletions
diff --git a/src/css/cascade.nim b/src/css/cascade.nim index e5652781..c2ac7f9a 100644 --- a/src/css/cascade.nim +++ b/src/css/cascade.nim @@ -88,20 +88,16 @@ func calcRules(styledNode: StyledNode; sheet: CSSStylesheet): RuleList = let element = Element(styledNode.node) var rules: seq[CSSRuleDef] = @[] sheet.tagTable.withValue(element.localName, v): - for rule in v[]: - rules.add(rule) + rules.add(v[]) if element.id != CAtomNull: - sheet.idTable.withValue(element.id, v): - for rule in v[]: - rules.add(rule) + sheet.idTable.withValue(sheet.factory.toLowerAscii(element.id), v): + rules.add(v[]) for class in element.classList.toks: - sheet.classTable.withValue(class, v): - for rule in v[]: - rules.add(rule) + sheet.classTable.withValue(sheet.factory.toLowerAscii(class), v): + rules.add(v[]) for attr in element.attrs: sheet.attrTable.withValue(attr.qualifiedName, v): - for rule in v[]: - rules.add(rule) + rules.add(v[]) for rule in sheet.generalList: rules.add(rule) rules.sort(ruleDefCmp, order = Ascending) diff --git a/src/css/match.nim b/src/css/match.nim index 05564600..9cdf23c4 100644 --- a/src/css/match.nim +++ b/src/css/match.nim @@ -156,9 +156,13 @@ func selectorMatches(element: Element; sel: Selector; of stType: return element.localName == sel.tag of stClass: - return sel.class in element.classList + let factory = element.document.factory + for it in element.classList.toks: + if sel.class == factory.toLowerAscii(it): + return true + return false of stId: - return sel.id == element.id + return sel.id == element.document.factory.toLowerAscii(element.id) of stAttr: return element.attrSelectorMatches(sel) of stPseudoClass: diff --git a/src/css/selectorparser.nim b/src/css/selectorparser.nim index b4db5a84..33302068 100644 --- a/src/css/selectorparser.nim +++ b/src/css/selectorparser.nim @@ -398,7 +398,7 @@ proc parseAttributeSelector(state: var SelectorParser; if not state2.has(): return Selector( t: stAttr, - attr: state.factory.toAtom(attr.value), + attr: state.factory.toAtomLower(attr.value), rel: SelectorRelation(t: rtExists) ) let delim = get_tok state2.consume() @@ -441,7 +441,7 @@ proc parseClassSelector(state: var SelectorParser): Selector = if not state.has(): fail let tok = get_tok state.consume() if tok.t != cttIdent: fail - let class = state.factory.toAtom(tok.value) + let class = state.factory.toAtomLower(tok.value) result = Selector(t: stClass, class: class) when defined(debug): result.classs = tok.value @@ -455,18 +455,17 @@ proc parseCompoundSelector(state: var SelectorParser): CompoundSelector = case tok.t of cttIdent: inc state.at - let s = tok.value.toLowerAscii() - let tag = state.factory.toAtom(s) + let tag = state.factory.toAtomLower(tok.value) let sel = Selector(t: stType, tag: tag) when defined(debug): - sel.tags = s + sel.tags = tok.value result.add(sel) of cttColon: inc state.at result.add(state.parsePseudoSelector()) of cttHash: inc state.at - let id = state.factory.toAtom(tok.value) + let id = state.factory.toAtomLower(tok.value) result.add(Selector(t: stId, id: id)) when defined(debug): result[^1].ids = tok.value diff --git a/src/css/sheet.nim b/src/css/sheet.nim index 248033af..0793e903 100644 --- a/src/css/sheet.nim +++ b/src/css/sheet.nim @@ -35,7 +35,7 @@ type generalList*: seq[CSSRuleDef] importList*: seq[URL] len: int - factory: CAtomFactory + factory*: CAtomFactory type SelectorHashes = object tag: CAtom diff --git a/src/html/catom.nim b/src/html/catom.nim index 9b3041b7..8d1696be 100644 --- a/src/html/catom.nim +++ b/src/html/catom.nim @@ -148,6 +148,7 @@ type CAtomFactoryObj = object strMap: array[CAtomFactoryStrMapLength, seq[CAtom]] atomMap: seq[string] + lowerMap: seq[CAtom] #TODO could be a ptr probably CAtomFactory* = ref CAtomFactoryObj @@ -160,7 +161,8 @@ func hash*(atom: CAtom): Hash {.borrow.} func `$`*(a: CAtom): string {.borrow.} -func toAtom(factory: var CAtomFactoryObj; s: string): CAtom = +func toAtom(factory: var CAtomFactoryObj; s: string; + isInit: static bool = false): CAtom = let h = s.hash() let i = h and (factory.strMap.len - 1) for atom in factory.strMap[i]: @@ -170,6 +172,12 @@ func toAtom(factory: var CAtomFactoryObj; s: string): CAtom = # Not found let atom = CAtom(factory.atomMap.len) factory.atomMap.add(s) + when not isInit: + let lower = if AsciiUpperAlpha notin s: + atom + else: + factory.toAtom(s.toLowerAscii()) + factory.lowerMap.add(lower) factory.strMap[i].add(atom) return atom @@ -177,9 +185,16 @@ const factoryInit = (func(): CAtomFactoryInit = var init = CAtomFactoryInit() # Null atom init.obj.atomMap.add("") + init.obj.lowerMap.add(CAtom(0)) # StaticAtom includes TagType too. for sa in StaticAtom(1) .. StaticAtom.high: - discard init.obj.toAtom($sa) + discard init.obj.toAtom($sa, isInit = true) + for sa in StaticAtom(1) .. StaticAtom.high: + let atom = init.obj.toAtom(($sa).toLowerAscii(), isInit = true) + init.obj.lowerMap.add(atom) + # fill slots of newly added lower mappings + while init.obj.lowerMap.len < init.obj.atomMap.len: + init.obj.lowerMap.add(CAtom(init.obj.lowerMap.len)) return init )() @@ -188,6 +203,12 @@ proc newCAtomFactory*(): CAtomFactory = factory[] = factoryInit.obj return factory +func toLowerAscii*(factory: CAtomFactory; a: CAtom): CAtom = + return factory.lowerMap[int32(a)] + +func equalsIgnoreCase*(factory: CAtomFactory; a, b: CAtom): bool = + return factory.lowerMap[int32(a)] == factory.lowerMap[int32(b)] + func toAtom*(factory: CAtomFactory; s: string): CAtom = return factory[].toAtom(s) @@ -199,6 +220,9 @@ func toAtom*(factory: CAtomFactory; attrType: StaticAtom): CAtom = assert attrType != atUnknown return CAtom(attrType) +func toAtomLower*(factory: CAtomFactory; s: string): CAtom = + return factory.lowerMap[int32(factory.toAtom(s))] + func toStr*(factory: CAtomFactory; atom: CAtom): string = return factory.atomMap[int(atom)] diff --git a/src/html/dom.nim b/src/html/dom.nim index ec01acc2..41f37744 100644 --- a/src/html/dom.nim +++ b/src/html/dom.nim @@ -1043,6 +1043,9 @@ proc toStr*(window: Window; atom: CAtom): string = proc toAtom*(document: Document; s: string): CAtom = return document.factory.toAtom(s) +proc toAtomLower*(document: Document; s: string): CAtom = + return document.factory.toAtomLower(s) + proc toAtom*(document: Document; at: StaticAtom): CAtom = return document.factory.toAtom(at) @@ -1927,7 +1930,7 @@ proc getAttr(map: NamedNodeMap; dataIdx: int): Attr = func normalizeAttrQName(element: Element; qualifiedName: string): CAtom = if element.namespace == Namespace.HTML and not element.document.isxml: - return element.document.toAtom(qualifiedName.toLowerAscii()) + return element.document.toAtomLower(qualifiedName) return element.document.toAtom(qualifiedName) func hasAttributes(element: Element): bool {.jsfunc.} = @@ -2300,7 +2303,7 @@ func getElementsByTagName0(root: Node; tagName: string): HTMLCollection = childonly = false ) let localName = root.document.toAtom(tagName) - let localNameLower = root.document.toAtom(tagName.toLowerAscii()) + let localNameLower = root.document.factory.toLowerAscii(localName) return newCollection[HTMLCollection]( root, func(node: Node): bool = @@ -2328,7 +2331,7 @@ func getElementsByClassName0(node: Node; classNames: string): HTMLCollection = let isquirks = document.mode == QUIRKS if isquirks: for class in classNames.split(AsciiWhitespace): - classAtoms.add(document.toAtom(class.toLowerAscii())) + classAtoms.add(document.toAtomLower(class)) else: for class in classNames.split(AsciiWhitespace): classAtoms.add(document.toAtom(class)) @@ -2339,8 +2342,7 @@ func getElementsByClassName0(node: Node; classNames: string): HTMLCollection = if isquirks: var cl = newSeq[CAtom]() for tok in element.classList.toks: - let s = document.toStr(tok) - cl.add(document.toAtom(s.toLowerAscii())) + cl.add(document.factory.toLowerAscii(tok)) for class in classAtoms: if class notin cl: return false @@ -3700,7 +3702,7 @@ proc setAttribute(element: Element; qualifiedName, value: string): ?validateAttributeName(qualifiedName) let qualifiedName = if element.namespace == Namespace.HTML and not element.document.isxml: - element.document.toAtom(qualifiedName.toLowerAscii()) + element.document.toAtomLower(qualifiedName) else: element.document.toAtom(qualifiedName) element.attr(qualifiedName, value) @@ -4489,7 +4491,7 @@ proc createElement(document: Document; localName: string): return errDOMException("Invalid character in element name", "InvalidCharacterError") let localName = if not document.isxml: - document.toAtom(localName.toLowerAscii()) + document.toAtomLower(localName) else: document.toAtom(localName) let namespace = if not document.isxml: |