fix: publish inherited native paint updates
This commit is contained in:
parent
722791a01e
commit
54b3514668
@ -9824,6 +9824,10 @@ role, and outside-complement compatibility before publication."
|
|||||||
(setq overrides
|
(setq overrides
|
||||||
(plist-put overrides :native-removed-node-ids
|
(plist-put overrides :native-removed-node-ids
|
||||||
(plist-get prepared :removed-node-ids)))
|
(plist-get prepared :removed-node-ids)))
|
||||||
|
(setq overrides
|
||||||
|
(plist-put overrides :native-inherited-dirty-node-ids
|
||||||
|
(plist-get candidate-state
|
||||||
|
:native-inherited-dirty-node-ids)))
|
||||||
(setq overrides
|
(setq overrides
|
||||||
(plist-put
|
(plist-put
|
||||||
overrides :native-topology-stable-p
|
overrides :native-topology-stable-p
|
||||||
|
|||||||
@ -32,6 +32,7 @@
|
|||||||
(declare-function ebox--literal-root-pixel-width "ebox" (box))
|
(declare-function ebox--literal-root-pixel-width "ebox" (box))
|
||||||
(declare-function ebox-get "ebox" (box key))
|
(declare-function ebox-get "ebox" (box key))
|
||||||
(declare-function ebox-style-cascade-active-p "ebox-style" ())
|
(declare-function ebox-style-cascade-active-p "ebox-style" ())
|
||||||
|
(declare-function ebox-style-property "ebox-style" (name))
|
||||||
(declare-function ebox-tree-node-key "ebox-tree" (source-index node))
|
(declare-function ebox-tree-node-key "ebox-tree" (source-index node))
|
||||||
(declare-function ebox-tree--children-raw "ebox-tree" (node))
|
(declare-function ebox-tree--children-raw "ebox-tree" (node))
|
||||||
(declare-function ebox--node-direct-viewport-width-dependent-p
|
(declare-function ebox--node-direct-viewport-width-dependent-p
|
||||||
@ -105,6 +106,17 @@
|
|||||||
(setq node-id (and parents (gethash node-id parents))))))
|
(setq node-id (and parents (gethash node-id parents))))))
|
||||||
(nreverse result)))
|
(nreverse result)))
|
||||||
|
|
||||||
|
(defun ebox-native-commit-inherited-dirty-node-ids (prepared)
|
||||||
|
"Return nodes whose PREPARED changes can alter descendant computed style."
|
||||||
|
(cl-loop
|
||||||
|
for entry in (plist-get prepared :dirty-set)
|
||||||
|
when (cl-some
|
||||||
|
(lambda (key)
|
||||||
|
(when-let* ((property (ebox-style-property key)))
|
||||||
|
(plist-get property :inherits)))
|
||||||
|
(plist-get entry :changed-keys))
|
||||||
|
collect (plist-get entry :node-id)))
|
||||||
|
|
||||||
(defun ebox-native-commit--node-position-table (state)
|
(defun ebox-native-commit--node-position-table (state)
|
||||||
"Return NODE-ID to `(PARENT-ID . POSITION)' table for STATE."
|
"Return NODE-ID to `(PARENT-ID . POSITION)' table for STATE."
|
||||||
(let ((nodes (plist-get state :node-table))
|
(let ((nodes (plist-get state :node-table))
|
||||||
@ -325,6 +337,8 @@ the committed text/fragment bases, compiler postorder, and projection support."
|
|||||||
old-state candidate-state))
|
old-state candidate-state))
|
||||||
(plist-put candidate-state :native-topology-stable-p stable)
|
(plist-put candidate-state :native-topology-stable-p stable)
|
||||||
(plist-put candidate-state :native-touched-node-ids layout-touched)
|
(plist-put candidate-state :native-touched-node-ids layout-touched)
|
||||||
|
(plist-put candidate-state :native-inherited-dirty-node-ids
|
||||||
|
(ebox-native-commit-inherited-dirty-node-ids prepared))
|
||||||
(when context-axes-stable
|
(when context-axes-stable
|
||||||
(plist-put candidate-state :viewport-dependent-node-ids-ready t)
|
(plist-put candidate-state :viewport-dependent-node-ids-ready t)
|
||||||
(plist-put candidate-state :viewport-dependent-node-ids
|
(plist-put candidate-state :viewport-dependent-node-ids
|
||||||
|
|||||||
@ -53,6 +53,8 @@
|
|||||||
(declare-function ebox-layout-config-props "ebox-layout-config" (config))
|
(declare-function ebox-layout-config-props "ebox-layout-config" (config))
|
||||||
(declare-function ebox-tree-node-children "ebox-tree" (node))
|
(declare-function ebox-tree-node-children "ebox-tree" (node))
|
||||||
(declare-function ebox-buffer--font-face "ebox-buffer-backend" (style))
|
(declare-function ebox-buffer--font-face "ebox-buffer-backend" (style))
|
||||||
|
(declare-function ebox-buffer--text-decoration-face
|
||||||
|
"ebox-buffer-backend" (style))
|
||||||
(declare-function ebox--propertize-typography
|
(declare-function ebox--propertize-typography
|
||||||
"ebox-buffer-backend" (string style))
|
"ebox-buffer-backend" (string style))
|
||||||
(declare-function ebox--ensure-node-id "ebox" (node))
|
(declare-function ebox--ensure-node-id "ebox" (node))
|
||||||
@ -71,6 +73,7 @@
|
|||||||
(declare-function ebox--layout-children "ebox-tree" (node))
|
(declare-function ebox--layout-children "ebox-tree" (node))
|
||||||
(declare-function ebox-tree-layout-children "ebox-tree" (node))
|
(declare-function ebox-tree-layout-children "ebox-tree" (node))
|
||||||
(declare-function ebox-tree-node-local-source-signature "ebox-tree" (node))
|
(declare-function ebox-tree-node-local-source-signature "ebox-tree" (node))
|
||||||
|
(declare-function ebox-source--index-record "ebox-source" (index handle))
|
||||||
(declare-function ebox-buffer-side-border-face
|
(declare-function ebox-buffer-side-border-face
|
||||||
"ebox-buffer-backend" (color))
|
"ebox-buffer-backend" (color))
|
||||||
(declare-function ebox--space-pixel-width "ebox-measure" ())
|
(declare-function ebox--space-pixel-width "ebox-measure" ())
|
||||||
@ -2419,7 +2422,7 @@ per call, and no call recursively visits the captured Ebox tree."
|
|||||||
(vconcat (nreverse nodes))))
|
(vconcat (nreverse nodes))))
|
||||||
|
|
||||||
(defun ebox-native-reflow--retained-layout-signature
|
(defun ebox-native-reflow--retained-layout-signature
|
||||||
(node child-revisions flex-content-min-widths)
|
(node child-revisions flex-content-min-widths source-index)
|
||||||
"Return exact retained compiler signature for NODE and CHILD-REVISIONS."
|
"Return exact retained compiler signature for NODE and CHILD-REVISIONS."
|
||||||
(let ((wrapper (and (eq (plist-get node :ebox-type) 'flex)
|
(let ((wrapper (and (eq (plist-get node :ebox-type) 'flex)
|
||||||
(plist-get node :box))))
|
(plist-get node :box))))
|
||||||
@ -2430,6 +2433,12 @@ per call, and no call recursively visits the captured Ebox tree."
|
|||||||
(and wrapper (plist-get wrapper :region-id)))
|
(and wrapper (plist-get wrapper :region-id)))
|
||||||
(ebox-tree-node-local-source-signature node)
|
(ebox-tree-node-local-source-signature node)
|
||||||
(and wrapper (ebox-tree-node-local-source-signature wrapper))
|
(and wrapper (ebox-tree-node-local-source-signature wrapper))
|
||||||
|
(and source-index
|
||||||
|
(when-let* ((handle (plist-get node :ebox-source-handle)))
|
||||||
|
(ebox-source--index-record source-index handle)))
|
||||||
|
(and source-index wrapper
|
||||||
|
(when-let* ((handle (plist-get wrapper :ebox-source-handle)))
|
||||||
|
(ebox-source--index-record source-index handle)))
|
||||||
child-revisions
|
child-revisions
|
||||||
(and (eq (plist-get node :ebox-type) 'flex)
|
(and (eq (plist-get node :ebox-type) 'flex)
|
||||||
(mapcar
|
(mapcar
|
||||||
@ -2455,12 +2464,18 @@ per call, and no call recursively visits the captured Ebox tree."
|
|||||||
0))
|
0))
|
||||||
(flex-content-min-widths
|
(flex-content-min-widths
|
||||||
(plist-get state :flex-content-min-widths))
|
(plist-get state :flex-content-min-widths))
|
||||||
|
(source-index (plist-get state :source-index))
|
||||||
(touched-ids (plist-get state :native-touched-node-ids))
|
(touched-ids (plist-get state :native-touched-node-ids))
|
||||||
|
(inherited-dirty-ids
|
||||||
|
(plist-get state :native-inherited-dirty-node-ids))
|
||||||
(touched-set
|
(touched-set
|
||||||
(and (plist-get state :native-topology-stable-p)
|
(and (plist-get state :native-topology-stable-p)
|
||||||
(plist-member state :native-touched-node-ids)
|
(plist-member state :native-touched-node-ids)
|
||||||
(proper-list-p touched-ids)
|
(proper-list-p touched-ids)
|
||||||
(make-hash-table :test 'equal)))
|
(make-hash-table :test 'equal)))
|
||||||
|
(inherited-touched-set
|
||||||
|
(and touched-set inherited-dirty-ids
|
||||||
|
(make-hash-table :test 'equal)))
|
||||||
(retained-fast-p
|
(retained-fast-p
|
||||||
(and touched-set
|
(and touched-set
|
||||||
(= (hash-table-count old-cache) (length postorder))
|
(= (hash-table-count old-cache) (length postorder))
|
||||||
@ -2488,6 +2503,24 @@ per call, and no call recursively visits the captured Ebox tree."
|
|||||||
(make-hash-table :test 'eq)))
|
(make-hash-table :test 'eq)))
|
||||||
(dolist (node-id touched-ids)
|
(dolist (node-id touched-ids)
|
||||||
(when touched-set (puthash node-id t touched-set)))
|
(when touched-set (puthash node-id t touched-set)))
|
||||||
|
(when (and touched-set inherited-dirty-ids)
|
||||||
|
(let ((inherited-set (make-hash-table :test 'equal)))
|
||||||
|
(dolist (node-id inherited-dirty-ids)
|
||||||
|
(puthash node-id t inherited-set))
|
||||||
|
(cl-labels
|
||||||
|
((mark
|
||||||
|
(current inherited-p)
|
||||||
|
(let* ((node-id (plist-get current :node-id))
|
||||||
|
(inherited-p
|
||||||
|
(or inherited-p (gethash node-id inherited-set))))
|
||||||
|
(when inherited-p (puthash node-id t touched-set))
|
||||||
|
(when inherited-p
|
||||||
|
(puthash node-id t inherited-touched-set))
|
||||||
|
(dolist (child
|
||||||
|
(ebox-native-reflow--retained-layout-children
|
||||||
|
current))
|
||||||
|
(mark child inherited-p)))))
|
||||||
|
(mark node nil))))
|
||||||
(cl-loop
|
(cl-loop
|
||||||
for template in ebox-native-reflow--compile-property-templates
|
for template in ebox-native-reflow--compile-property-templates
|
||||||
for index from 0
|
for index from 0
|
||||||
@ -2521,9 +2554,12 @@ per call, and no call recursively visits the captured Ebox tree."
|
|||||||
children))
|
children))
|
||||||
(signature
|
(signature
|
||||||
(ebox-native-reflow--retained-layout-signature
|
(ebox-native-reflow--retained-layout-signature
|
||||||
current child-revisions flex-content-min-widths))
|
current child-revisions flex-content-min-widths
|
||||||
|
source-index))
|
||||||
fragment entry)
|
fragment entry)
|
||||||
(if (and cached
|
(if (and cached
|
||||||
|
(not (and inherited-touched-set
|
||||||
|
(gethash node-id inherited-touched-set)))
|
||||||
(equal signature (plist-get cached :signature)))
|
(equal signature (plist-get cached :signature)))
|
||||||
(setq fragment (plist-get cached :fragment)
|
(setq fragment (plist-get cached :fragment)
|
||||||
entry cached)
|
entry cached)
|
||||||
|
|||||||
@ -1458,6 +1458,14 @@ the projection roots a second time."
|
|||||||
(ebox-tree-clear-author-style-pending root))
|
(ebox-tree-clear-author-style-pending root))
|
||||||
projection))
|
projection))
|
||||||
|
|
||||||
|
(defun ebox-surface--native-full-frame-p (state projection-kind)
|
||||||
|
"Return non-nil when STATE owns a complete native surface frame."
|
||||||
|
(and (eq projection-kind 'native-frame)
|
||||||
|
(plist-get state :native-topology-stable-p)
|
||||||
|
(let ((frame (plist-get state :native-render-frame)))
|
||||||
|
(and (plist-get frame :native-frame)
|
||||||
|
(not (plist-get frame :native-patch))))))
|
||||||
|
|
||||||
(defun ebox-surface--projection-result
|
(defun ebox-surface--projection-result
|
||||||
(context projection state output &optional projection-kind)
|
(context projection state output &optional projection-kind)
|
||||||
"Complete CONTEXT PROJECTION for STATE from rendered OUTPUT."
|
"Complete CONTEXT PROJECTION for STATE from rendered OUTPUT."
|
||||||
@ -1468,13 +1476,14 @@ the projection roots a second time."
|
|||||||
(owner-id (plist-get state :span-patch-owner-id))
|
(owner-id (plist-get state :span-patch-owner-id))
|
||||||
(scroll-fast-p (and (eq projection-kind 'scroll-patch)
|
(scroll-fast-p (and (eq projection-kind 'scroll-patch)
|
||||||
(plist-get state :scroll-fast-window-p)))
|
(plist-get state :scroll-fast-window-p)))
|
||||||
(full-surface-p
|
|
||||||
(and scroll-fast-p
|
|
||||||
(plist-get state :retained-scroll-content-p)
|
|
||||||
root-id owner-id (= root-id owner-id)))
|
|
||||||
(native-retained-p
|
(native-retained-p
|
||||||
(and (eq projection-kind 'native-frame)
|
(and (eq projection-kind 'native-frame)
|
||||||
(plist-get state :native-topology-stable-p)))
|
(plist-get state :native-topology-stable-p)))
|
||||||
|
(full-surface-p
|
||||||
|
(or (and scroll-fast-p
|
||||||
|
(plist-get state :retained-scroll-content-p)
|
||||||
|
root-id owner-id (= root-id owner-id))
|
||||||
|
(ebox-surface--native-full-frame-p state projection-kind)))
|
||||||
(previous-owned-ranges
|
(previous-owned-ranges
|
||||||
(plist-get state :previous-surface-owned-ranges))
|
(plist-get state :previous-surface-owned-ranges))
|
||||||
(node-objects
|
(node-objects
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
(require 'ert)
|
(require 'ert)
|
||||||
(require 'ebox)
|
(require 'ebox)
|
||||||
(require 'ebox-native-commit)
|
(require 'ebox-native-commit)
|
||||||
|
(require 'ebox-native-reflow)
|
||||||
|
|
||||||
;; These tests lock the named Elisp projection proofs. Native commit has its
|
;; These tests lock the named Elisp projection proofs. Native commit has its
|
||||||
;; own focused contract tests below; disable runtime module discovery here so
|
;; own focused contract tests below; disable runtime module discovery here so
|
||||||
@ -2091,6 +2092,71 @@ remain retained identities."
|
|||||||
(should-not mixed-output)))
|
(should-not mixed-output)))
|
||||||
(when (buffer-live-p buffer) (kill-buffer buffer)))))
|
(when (buffer-live-p buffer) (kill-buffer buffer)))))
|
||||||
|
|
||||||
|
(ert-deftest ebox-native-inherited-dirty-domain-is-schema-owned ()
|
||||||
|
"Native invalidation derives inherited propagation from the style schema."
|
||||||
|
(should
|
||||||
|
(equal '(7)
|
||||||
|
(ebox-native-commit-inherited-dirty-node-ids
|
||||||
|
'(:dirty-set
|
||||||
|
((:node-id 7 :dirty-kind paint :changed-keys (:color)))))))
|
||||||
|
(should-not
|
||||||
|
(ebox-native-commit-inherited-dirty-node-ids
|
||||||
|
'(:dirty-set
|
||||||
|
((:node-id 7 :dirty-kind paint
|
||||||
|
:changed-keys (:background-color)))))))
|
||||||
|
|
||||||
|
(ert-deftest ebox-native-retained-compiler-refreshes-inherited-descendants ()
|
||||||
|
"An inherited parent paint change cannot reuse a stale child fragment."
|
||||||
|
(require 'ebox-native-reflow)
|
||||||
|
(let* ((input
|
||||||
|
(ebox-test-box
|
||||||
|
:color "#111111"
|
||||||
|
(ebox-test-text "Paint" :color "#111111")))
|
||||||
|
(root (ebox-test-root input))
|
||||||
|
(_ids (ebox--runtime-node-ids root))
|
||||||
|
(source-index (ebox-test-source-index input))
|
||||||
|
(session
|
||||||
|
(ebox-native-reflow--make-session
|
||||||
|
:handle 'test :generation 0 :styles nil :layout-package nil
|
||||||
|
:layout-fragment-cache (make-hash-table :test 'equal)
|
||||||
|
:layout-fragment-revision 0))
|
||||||
|
(initial-state
|
||||||
|
(list :native-node-postorder
|
||||||
|
(ebox-native-reflow--retained-layout-postorder root)
|
||||||
|
:native-topology-stable-p nil
|
||||||
|
:source-index source-index))
|
||||||
|
(initial-package
|
||||||
|
(ebox-native-reflow--compile-retained-layout-package
|
||||||
|
session initial-state root))
|
||||||
|
(next (copy-tree root))
|
||||||
|
(next-child (car (ebox-tree-node-children next))))
|
||||||
|
(setf (ebox-native-reflow-session-styles session)
|
||||||
|
(plist-get initial-package :styles)
|
||||||
|
(ebox-native-reflow-session-layout-package session)
|
||||||
|
initial-package)
|
||||||
|
;; Model a candidate computed-style projection: the child source record is
|
||||||
|
;; unchanged, while its inherited runtime color follows the parent.
|
||||||
|
(plist-put next :color "#222222")
|
||||||
|
(plist-put next-child :color "#222222")
|
||||||
|
(let* ((root-id (plist-get next :node-id))
|
||||||
|
(next-state
|
||||||
|
(list :native-node-postorder
|
||||||
|
(ebox-native-reflow--retained-layout-postorder next)
|
||||||
|
:native-topology-stable-p t
|
||||||
|
:native-touched-node-ids (list root-id)
|
||||||
|
:native-inherited-dirty-node-ids (list root-id)
|
||||||
|
:source-index source-index))
|
||||||
|
(package
|
||||||
|
(ebox-native-reflow--compile-retained-layout-package
|
||||||
|
session next-state next))
|
||||||
|
(document-root (plist-get (plist-get package :document) :root))
|
||||||
|
(style-id (plist-get document-root :content-foreground-style))
|
||||||
|
(styles (plist-get package :styles)))
|
||||||
|
(should (integerp style-id))
|
||||||
|
(should
|
||||||
|
(equal '(:foreground "#222222")
|
||||||
|
(plist-get (aref styles style-id) :face))))))
|
||||||
|
|
||||||
(provide 'ebox-commit-tests)
|
(provide 'ebox-commit-tests)
|
||||||
|
|
||||||
;;; ebox-commit-tests.el ends here
|
;;; ebox-commit-tests.el ends here
|
||||||
|
|||||||
@ -2995,6 +2995,24 @@ participant and rollback contract without creating a real frame."
|
|||||||
(when (buffer-live-p buffer)
|
(when (buffer-live-p buffer)
|
||||||
(kill-buffer buffer))))
|
(kill-buffer buffer))))
|
||||||
|
|
||||||
|
(ert-deftest ebox-surface-native-full-frame-owns-full-publication-scope ()
|
||||||
|
"A complete native frame is authoritative for the whole TP surface."
|
||||||
|
(should
|
||||||
|
(ebox-surface--native-full-frame-p
|
||||||
|
'(:native-topology-stable-p t
|
||||||
|
:native-render-frame (:native-frame t :native-patch nil))
|
||||||
|
'native-frame))
|
||||||
|
(should-not
|
||||||
|
(ebox-surface--native-full-frame-p
|
||||||
|
'(:native-topology-stable-p t
|
||||||
|
:native-render-frame (:native-frame t :native-patch t))
|
||||||
|
'native-frame))
|
||||||
|
(should-not
|
||||||
|
(ebox-surface--native-full-frame-p
|
||||||
|
'(:native-topology-stable-p t
|
||||||
|
:native-render-frame (:native-frame t :native-patch nil))
|
||||||
|
'paint)))
|
||||||
|
|
||||||
(provide 'ebox-surface-tests)
|
(provide 'ebox-surface-tests)
|
||||||
|
|
||||||
;;; ebox-surface-tests.el ends here
|
;;; ebox-surface-tests.el ends here
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user