diff options
author | bptato <nincsnevem662@gmail.com> | 2025-01-15 01:15:37 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2025-01-15 01:22:32 +0100 |
commit | 7ea0ed47932550c5316887f7f606e70df1c49da3 (patch) | |
tree | 8e6a67bbb512b1d06812253baab3683d398b792a /src | |
parent | cda6b6b2089291eb79fcf3d819b917fc59ed8181 (diff) | |
download | chawan-7ea0ed47932550c5316887f7f606e70df1c49da3.tar.gz |
cascade, stylednode: remove parent field from StyledNode
Now StyledNode has an "element" reference, which refers to the element it was derived from. This reduces the object's size, removes the need for casting around the "node" field, and also gets rid of a pointless cycle.
Diffstat (limited to 'src')
-rw-r--r-- | src/css/cascade.nim | 224 | ||||
-rw-r--r-- | src/css/stylednode.nim | 38 | ||||
-rw-r--r-- | src/server/buffer.nim | 21 |
3 files changed, 140 insertions, 143 deletions
diff --git a/src/css/cascade.nim b/src/css/cascade.nim index 5043b02e..0bdd4116 100644 --- a/src/css/cascade.nim +++ b/src/css/cascade.nim @@ -46,10 +46,10 @@ proc calcRule(tosorts: var ToSorts; element: Element; else: tosorts[sel.pseudo].add((sel.specificity, rule)) -func calcRules(map: RuleListMap; styledNode: StyledNode; sheet: CSSStylesheet; +func calcRules0(map: RuleListMap; styledNode: StyledNode; sheet: CSSStylesheet; origin: CSSOrigin) = var tosorts = ToSorts.default - let element = Element(styledNode.node) + let element = styledNode.element var rules: seq[CSSRuleDef] = @[] sheet.tagTable.withValue(element.localName, v): rules.add(v[]) @@ -245,7 +245,7 @@ func applyDeclarations0(rules: RuleList; parent: CSSValues; element: Element; proc applyDeclarations(styledNode: StyledNode; parent: CSSValues; map: RuleListMap; window: Window; pseudo = peNone) = - let element = Element(styledNode.node) + let element = if styledNode.pseudo == peNone: styledNode.element else: nil styledNode.computed = map.rules[pseudo].applyDeclarations0(parent, element, window) if element != nil and window.settings.scripting == smApp: @@ -270,21 +270,20 @@ func applyMediaQuery(ss: CSSStylesheet; window: Window): CSSStylesheet = func calcRules(styledNode: StyledNode; ua, user: CSSStylesheet; author: seq[CSSStylesheet]; window: Window): RuleListMap = let map = RuleListMap() - map.calcRules(styledNode, ua, coUserAgent) + map.calcRules0(styledNode, ua, coUserAgent) if user != nil: - map.calcRules(styledNode, user, coUser) + map.calcRules0(styledNode, user, coUser) for rule in author: - map.calcRules(styledNode, rule, coAuthor) - if styledNode.node != nil: - let style = Element(styledNode.node).cachedStyle - if window.styling and style != nil: - for decl in style.decls: - let vals = parseComputedValues(decl.name, decl.value, window.attrsp[], - window.factory) - if decl.important: - map.rules[peNone][coAuthor].important.add(vals) - else: - map.rules[peNone][coAuthor].normal.add(vals) + map.calcRules0(styledNode, rule, coAuthor) + let style = styledNode.element.cachedStyle + if window.styling and style != nil: + for decl in style.decls: + let vals = parseComputedValues(decl.name, decl.value, window.attrsp[], + window.factory) + if decl.important: + map.rules[peNone][coAuthor].important.add(vals) + else: + map.rules[peNone][coAuthor].normal.add(vals) return map type CascadeFrame = object @@ -311,7 +310,6 @@ proc applyRulesFrameValid(frame: var CascadeFrame): StyledNode = # * create new seq, assuming capacity == len of the previous pass frame.cachedChildren = move(cachedChild.children) cachedChild.children = newSeqOfCap[StyledNode](frame.cachedChildren.len) - cachedChild.parent = styledParent if styledParent != nil: styledParent.children.add(cachedChild) return cachedChild @@ -319,106 +317,118 @@ proc applyRulesFrameValid(frame: var CascadeFrame): StyledNode = proc applyRulesFrameInvalid(frame: CascadeFrame; ua, user: CSSStylesheet; author: seq[CSSStylesheet]; map: var RuleListMap; window: Window): StyledNode = - var styledChild: StyledNode = nil let pseudo = frame.pseudo let styledParent = frame.styledParent let child = frame.child - if frame.pseudo != peNone: - case pseudo - of peBefore, peAfter: - let map = frame.parentMap - if map.rules[pseudo].hasValues(): - let styledPseudo = styledParent.newStyledElement(pseudo) - styledPseudo.applyDeclarations(styledParent.computed, map, nil, pseudo) - if styledPseudo.computed{"content"}.len > 0: - for content in styledPseudo.computed{"content"}: - let child = styledPseudo.newStyledReplacement(content, peNone) - styledPseudo.children.add(child) - styledParent.children.add(styledPseudo) - of peInputText: - let s = HTMLInputElement(styledParent.node).inputString() - if s.len > 0: - let content = styledParent.node.document.newText(s) - let styledText = styledParent.newStyledText(content) - # Note: some pseudo-elements (like input text) generate text nodes - # directly, so we have to cache them like this. - styledText.pseudo = pseudo - styledParent.children.add(styledText) - of peTextareaText: - let s = HTMLTextAreaElement(styledParent.node).textAreaString() - if s.len > 0: - let content = styledParent.node.document.newText(s) - let styledText = styledParent.newStyledText(content) - styledText.pseudo = pseudo - styledParent.children.add(styledText) - of peImage: - let content = CSSContent( - t: ContentImage, - bmp: HTMLImageElement(styledParent.node).bitmap - ) - let styledText = styledParent.newStyledReplacement(content, pseudo) + case pseudo + of peNone: # not a pseudo-element, but a real one + assert child != nil + if child of Element: + let element = Element(child) + let styledChild = newStyledElement(element) + map = styledChild.calcRules(ua, user, author, window) + if styledParent == nil: # root element + styledChild.applyDeclarations(rootProperties(), map, window) + else: + styledParent.children.add(styledChild) + styledChild.applyDeclarations(styledParent.computed, map, window) + return styledChild + elif child of Text: + let text = Text(child) + let styledChild = styledParent.newStyledText(text) + styledParent.children.add(styledChild) + return styledChild + of peBefore, peAfter: + let map = frame.parentMap + if map.rules[pseudo].hasValues(): + let styledPseudo = styledParent.newStyledElement(pseudo) + styledPseudo.applyDeclarations(styledParent.computed, map, nil, pseudo) + if styledPseudo.computed{"content"}.len > 0: + for content in styledPseudo.computed{"content"}: + let child = styledPseudo.newStyledReplacement(content, peNone) + styledPseudo.children.add(child) + styledParent.children.add(styledPseudo) + of peInputText: + let s = HTMLInputElement(styledParent.element).inputString() + if s.len > 0: + let content = styledParent.element.document.newText(s) + let styledText = styledParent.newStyledText(content) + # Note: some pseudo-elements (like input text) generate text nodes + # directly, so we have to cache them like this. + styledText.pseudo = pseudo + styledParent.children.add(styledText) + of peTextareaText: + let s = HTMLTextAreaElement(styledParent.element).textAreaString() + if s.len > 0: + let content = styledParent.element.document.newText(s) + let styledText = styledParent.newStyledText(content) + styledText.pseudo = pseudo styledParent.children.add(styledText) - of peSVG: + of peImage: + let content = CSSContent( + t: ContentImage, + bmp: HTMLImageElement(styledParent.element).bitmap + ) + let styledText = styledParent.newStyledReplacement(content, pseudo) + styledParent.children.add(styledText) + of peSVG: + let content = CSSContent( + t: ContentImage, + bmp: SVGSVGElement(styledParent.element).bitmap + ) + let styledText = styledParent.newStyledReplacement(content, pseudo) + styledParent.children.add(styledText) + of peCanvas: + let bmp = HTMLCanvasElement(styledParent.element).bitmap + if bmp != nil and bmp.cacheId != 0: let content = CSSContent( t: ContentImage, - bmp: SVGSVGElement(styledParent.node).bitmap + bmp: bmp ) let styledText = styledParent.newStyledReplacement(content, pseudo) styledParent.children.add(styledText) - of peCanvas: - let bmp = HTMLCanvasElement(styledParent.node).bitmap - if bmp != nil and bmp.cacheId != 0: - let content = CSSContent( - t: ContentImage, - bmp: bmp - ) - let styledText = styledParent.newStyledReplacement(content, pseudo) - styledParent.children.add(styledText) - of peVideo: - let content = CSSContent(t: ContentVideo) - let styledText = styledParent.newStyledReplacement(content, pseudo) - styledParent.children.add(styledText) - of peAudio: - let content = CSSContent(t: ContentAudio) - let styledText = styledParent.newStyledReplacement(content, pseudo) - styledParent.children.add(styledText) - of peIFrame: - let content = CSSContent(t: ContentIFrame) - let styledText = styledParent.newStyledReplacement(content, pseudo) - styledParent.children.add(styledText) - of peNewline: - let content = CSSContent(t: ContentNewline) - let styledText = styledParent.newStyledReplacement(content, pseudo) - styledParent.children.add(styledText) - of peNone: assert false - else: - assert child != nil - if styledParent != nil: - if child of Element: - let element = Element(child) - styledChild = styledParent.newStyledElement(element) - styledParent.children.add(styledChild) - map = styledChild.calcRules(ua, user, author, window) - styledChild.applyDeclarations(styledParent.computed, map, window) - elif child of Text: - let text = Text(child) - styledChild = styledParent.newStyledText(text) - styledParent.children.add(styledChild) - else: - # Root element - let element = Element(child) - styledChild = newStyledElement(element) - map = styledChild.calcRules(ua, user, author, window) - styledChild.applyDeclarations(rootProperties(), map, window) - return styledChild + of peVideo: + let content = CSSContent(t: ContentVideo) + let styledText = styledParent.newStyledReplacement(content, pseudo) + styledParent.children.add(styledText) + of peAudio: + let content = CSSContent(t: ContentAudio) + let styledText = styledParent.newStyledReplacement(content, pseudo) + styledParent.children.add(styledText) + of peIFrame: + let content = CSSContent(t: ContentIFrame) + let styledText = styledParent.newStyledReplacement(content, pseudo) + styledParent.children.add(styledText) + of peNewline: + let content = CSSContent(t: ContentNewline) + let styledText = styledParent.newStyledReplacement(content, pseudo) + styledParent.children.add(styledText) + return nil proc stackAppend(styledStack: var seq[CascadeFrame]; frame: CascadeFrame; - styledParent: StyledNode; child: Node; i: var int) = + styledParent: StyledNode; child: Element; i: var int) = var cached: StyledNode = nil if frame.cachedChildren.len > 0: for j in countdown(i, 0): let it = frame.cachedChildren[j] - if it.node == child: + if it.t == stElement and it.pseudo == peNone and it.element == child: + i = j - 1 + cached = it + break + styledStack.add(CascadeFrame( + styledParent: styledParent, + child: child, + pseudo: peNone, + cachedChild: cached + )) + +proc stackAppend(styledStack: var seq[CascadeFrame]; frame: CascadeFrame; + styledParent: StyledNode; child: Text; i: var int) = + var cached: StyledNode = nil + if frame.cachedChildren.len > 0: + for j in countdown(i, 0): + let it = frame.cachedChildren[j] + if it.t == stText and it.text == child: i = j - 1 cached = it break @@ -467,7 +477,7 @@ proc appendChildren(styledStack: var seq[CascadeFrame]; frame: CascadeFrame; styledChild: StyledNode; parentMap: RuleListMap) = # i points to the child currently being inspected. var idx = frame.cachedChildren.len - 1 - let element = Element(styledChild.node) + let element = styledChild.element # reset invalid flag here to avoid a type conversion above element.invalid = false styledStack.stackAppend(frame, styledChild, peAfter, idx, parentMap) @@ -485,8 +495,10 @@ proc appendChildren(styledStack: var seq[CascadeFrame]; frame: CascadeFrame; else: for i in countdown(element.childList.high, 0): let child = element.childList[i] - if child of Element or child of Text: - styledStack.stackAppend(frame, styledChild, child, idx) + if child of Element: + styledStack.stackAppend(frame, styledChild, Element(child), idx) + elif child of Text: + styledStack.stackAppend(frame, styledChild, Text(child), idx) if element.tagType == TAG_INPUT: styledStack.stackAppend(frame, styledChild, peInputText, idx) styledStack.stackAppend(frame, styledChild, peBefore, idx, parentMap) @@ -521,7 +533,7 @@ proc applyRules(document: Document; ua, user: CSSStylesheet; if styledParent == nil: # Root element root = styledChild - if styledChild.t == stElement and styledChild.node != nil: + if styledChild.t == stElement and styledChild.pseudo == peNone: # note: following resets styledChild.node's invalid flag styledStack.appendChildren(frame, styledChild, map) for element in toReset: diff --git a/src/css/stylednode.nim b/src/css/stylednode.nim index c1a4cbc8..5572b949 100644 --- a/src/css/stylednode.nim +++ b/src/css/stylednode.nim @@ -45,12 +45,11 @@ type items: seq[DependencyInfoItem] StyledNode* = ref object - parent*: StyledNode - node*: Node + element*: Element pseudo*: PseudoElement case t*: StyledType of stText: - discard + text*: CharacterData of stElement: computed*: CSSValues children*: seq[StyledNode] @@ -61,7 +60,7 @@ type content*: CSSContent template textData*(styledNode: StyledNode): string = - CharacterData(styledNode.node).data + styledNode.text.data when defined(debug): func `$`*(node: StyledNode): string = @@ -71,22 +70,21 @@ when defined(debug): of stText: return "#text " & node.textData of stElement: - if node.node != nil: - return $node.node - return $node.pseudo + if node.pseudo != peNone: + return "#" & $node.pseudo & "::" & $node.element + return $node.element of stReplacement: return "#replacement" proc isValid*(styledNode: StyledNode; toReset: var seq[Element]): bool = if styledNode.t in {stText, stReplacement}: return true - if styledNode.node != nil: - let element = Element(styledNode.node) + # pseudo elements do not have selector dependencies + if styledNode.pseudo == peNone: + let element = styledNode.element if element.invalid: toReset.add(element) return false - # pseudo elements do not have selector dependencies, so we can skip - # this if node is nil. for it in styledNode.depends.items: if it.t in it.element.invalidDeps: toReset.add(it.element) @@ -101,31 +99,27 @@ proc merge*(a: var DependencyInfo; b: DependencyInfo) = if it notin a.items: a.items.add(it) -func newStyledElement*(parent: StyledNode; element: Element): StyledNode = - return StyledNode(t: stElement, node: element, parent: parent) - -# Root func newStyledElement*(element: Element): StyledNode = - return StyledNode(t: stElement, node: element) + return StyledNode(t: stElement, element: element) func newStyledElement*(parent: StyledNode; pseudo: PseudoElement): StyledNode = return StyledNode( t: stElement, pseudo: pseudo, - parent: parent + element: parent.element ) func newStyledText*(parent: StyledNode; text: Text): StyledNode = - return StyledNode(t: stText, node: text, parent: parent) + return StyledNode(t: stText, text: text, element: parent.element) -func newStyledText*(text: string): StyledNode = - return StyledNode(t: stText, node: CharacterData(data: text)) +func newStyledText*(text: sink string): StyledNode = + return StyledNode(t: stText, text: CharacterData(data: text)) -func newStyledReplacement*(parent: StyledNode; content: CSSContent; +func newStyledReplacement*(parent: StyledNode; content: sink CSSContent; pseudo: PseudoElement): StyledNode = return StyledNode( t: stReplacement, - parent: parent, + element: parent.element, content: content, pseudo: pseudo ) diff --git a/src/server/buffer.nim b/src/server/buffer.nim index 8a037464..e8533b1a 100644 --- a/src/server/buffer.nim +++ b/src/server/buffer.nim @@ -346,12 +346,9 @@ proc getClickable(element: Element): Element = return nil proc getClickable(styledNode: StyledNode): Element = - var styledNode = styledNode - while styledNode != nil: - if styledNode.node of Element: - return Element(styledNode.node).getClickable() - styledNode = styledNode.parent - return nil + if styledNode == nil: + return nil + return styledNode.element.getClickable() func canSubmitOnClick(fae: FormAssociatedElement): bool = if fae.form == nil: @@ -427,13 +424,7 @@ func getCursorElement(buffer: Buffer; cursorx, cursory: int): Element = let styledNode = buffer.getCursorStyledNode(cursorx, cursory) if styledNode == nil: return nil - if styledNode.node != nil: - if styledNode.t == stElement: - return Element(styledNode.node) - return styledNode.node.parentElement - if styledNode.parent != nil and styledNode.parent.t == stElement: - return Element(styledNode.parent.node) - return nil + return styledNode.element proc getCursorClickable(buffer: Buffer; cursorx, cursory: int): Element = let element = buffer.getCursorElement(cursorx, cursory) @@ -699,7 +690,7 @@ proc findAnchor(box: InlineBox; anchor: Element): Offset = let off = child.findAnchor(anchor) if off.y >= 0: return off - if box.node != nil and box.node.node == anchor: + if box.node.element == anchor: return box.render.offset return offset(-1, -1) @@ -712,7 +703,7 @@ proc findAnchor(box: BlockBox; anchor: Element): Offset = let off = child.findAnchor(anchor) if off.y >= 0: return off - if box.node != nil and box.node.node == anchor: + if box.node.element == anchor: return box.render.offset return offset(-1, -1) |