about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-11-26 22:54:21 +0100
committerbptato <nincsnevem662@gmail.com>2024-11-26 23:05:49 +0100
commit58da6cf90ce80f0bfc77a5ebd6603bec0cbc240c (patch)
tree978921e212763eb5cfc034a64876edbb88f4bc4f /src
parent14c4a11eaaea5dfa13afb6f44ab9531a90445f36 (diff)
downloadchawan-58da6cf90ce80f0bfc77a5ebd6603bec0cbc240c.tar.gz
buffer: optimize hover switching
Fixed a bug that would lead to styles unnecessarily being recalculated
if the root element had a :hover dependency.
Diffstat (limited to 'src')
-rw-r--r--src/css/match.nim6
-rw-r--r--src/server/buffer.nim11
2 files changed, 15 insertions, 2 deletions
diff --git a/src/css/match.nim b/src/css/match.nim
index 51dd9a6e..695f2404 100644
--- a/src/css/match.nim
+++ b/src/css/match.nim
@@ -77,6 +77,12 @@ func pseudoSelectorMatches(element: Element; sel: Selector;
     return element.parentNode.firstElementChild == element and
       element.parentNode.lastElementChild == element
   of pcHover:
+    #TODO this is somewhat problematic.
+    # e.g. if there is a rule like ".class :hover", then you set
+    # dtHover for basically every element, even if most of them are not
+    # a .class descendant.
+    # Ideally we should try to match the rest of the selector before
+    # attaching dependencies in general.
     depends.add(element, dtHover)
     return element.hover
   of pcRoot: return element == element.document.documentElement
diff --git a/src/server/buffer.nim b/src/server/buffer.nim
index 846191a7..41b1ec1e 100644
--- a/src/server/buffer.nim
+++ b/src/server/buffer.nim
@@ -893,10 +893,10 @@ proc updateHover*(buffer: Buffer; cursorx, cursory: int): UpdateHoverResult
   let prevNode = buffer.prevHover
   if thisNode != prevNode and (thisNode == nil or prevNode == nil or
       thisNode != prevNode):
+    var oldHover: seq[Element] = @[]
     for element in prevNode.branchElems:
       if element.hover:
-        element.setHover(false)
-        repaint = true
+        oldHover.add(element)
     for ht in HoverType:
       let s = HoverFun[ht](buffer, thisNode)
       if buffer.hoverText[ht] != s:
@@ -906,6 +906,13 @@ proc updateHover*(buffer: Buffer; cursorx, cursory: int): UpdateHoverResult
       if not element.hover:
         element.setHover(true)
         repaint = true
+      elif (let i = oldHover.find(element); i != -1):
+        # branches converged
+        oldHover.setLen(i)
+        break
+    for element in oldHover:
+      element.setHover(false)
+      repaint = true
   if repaint:
     buffer.reshape()
   buffer.prevHover = thisNode