Keep layer move publication patches disjoint
Some checks are pending
CI / test (29.1) (push) Waiting to run
CI / test (30.2) (push) Waiting to run
CI / native-build (macos-latest) (push) Waiting to run
CI / native-build (ubuntu-latest) (push) Waiting to run
CI / native-build (windows-latest) (push) Waiting to run
CI / native-msrv (macos-latest) (push) Waiting to run
CI / native-msrv (ubuntu-latest) (push) Waiting to run
CI / native-msrv (windows-latest) (push) Waiting to run

This commit is contained in:
Kinneyzhang 2026-09-11 15:40:02 +08:00
parent 01b1a86bb3
commit 96b91ea468
2 changed files with 92 additions and 27 deletions

View File

@ -2154,8 +2154,17 @@ function composes those retained facts into TP's standard validated commit
batch without asking TP to rediscover the same diff from a full plan.
PROPERTY-CONTRIBUTIONS add ordered target paint. RETAINED-ORIGIN is the live
surface origin when an exact ownership proof permits indexed owner lookup.
This proof step does not register objects in the active prepare context."
This proof step does not register objects in the active prepare context.
Layer recomposition has a stronger damage proof than ordinary owner-scoped
updates: `:content-coordinate-patches' already contains every row whose text
or paint properties changed. In that mode, keep those intervals discrete;
adding the owner's enclosing mount would turn two distant damaged rows into
one large replacement and needlessly rewrite the rows between them."
(let* ((proof (plist-get state :mixed-owner-proof))
(layer-damage-only-p
(and (plist-get state :layer-recompose-p)
(null property-contributions)))
(owner-ids
(or (plist-get proof :owner-ids)
(mapcar (lambda (owner-proof)
@ -2189,32 +2198,33 @@ This proof step does not register objects in the active prepare context."
:new-start (plist-get patch :new-start)
:new-end (plist-get patch :new-end)))
coordinate-patches))
(if retained-origin
;; The strict retained-property witness preserves the complete
;; mount projection. Read just the changed owners from TP's
;; existing index, including baseline-only paint removals.
(maphash
(lambda (object _present)
(dolist (mount (tp-object-mounts object))
(let ((start (- (plist-get mount :start) retained-origin))
(end (- (plist-get mount :end) retained-origin)))
(push (list :old-start start :old-end end
:new-start start :new-end end)
intervals))))
owner-set)
(dolist (range previous-owned-ranges)
(when (gethash (plist-get range :object) owner-set)
(when-let* ((new-start
(ebox-surface--rebase-coordinate
(plist-get range :start) coordinate-patches))
(new-end
(ebox-surface--rebase-coordinate
(plist-get range :end) coordinate-patches)))
(push (list :old-start (plist-get range :start)
:old-end (plist-get range :end)
:new-start (car new-start)
:new-end (car new-end))
intervals)))))
(unless layer-damage-only-p
(if retained-origin
;; The strict retained-property witness preserves the complete
;; mount projection. Read just the changed owners from TP's
;; existing index, including baseline-only paint removals.
(maphash
(lambda (object _present)
(dolist (mount (tp-object-mounts object))
(let ((start (- (plist-get mount :start) retained-origin))
(end (- (plist-get mount :end) retained-origin)))
(push (list :old-start start :old-end end
:new-start start :new-end end)
intervals))))
owner-set)
(dolist (range previous-owned-ranges)
(when (gethash (plist-get range :object) owner-set)
(when-let* ((new-start
(ebox-surface--rebase-coordinate
(plist-get range :start) coordinate-patches))
(new-end
(ebox-surface--rebase-coordinate
(plist-get range :end) coordinate-patches)))
(push (list :old-start (plist-get range :start)
:old-end (plist-get range :end)
:new-start (car new-start)
:new-end (car new-end))
intervals))))))
(setq intervals
(sort intervals
(lambda (left right)

View File

@ -219,6 +219,61 @@ including all text properties."
(should-not (eq (nth 1 moved) (nth 1 first)))
(should-not (eq (nth 2 moved) (nth 2 first)))))
(ert-deftest ebox-layer-publication-drag-publishes-only-damaged-rows ()
"A distant layer move publishes two disjoint row patches.
The retained compositor already limits recomposition to the old and new rows.
This regression checks the next boundary too: TP must receive two disjoint
content patches, so the untouched rows between them never enter a buffer
delete/insert operation."
(ebox-layer-publication-test--with-buffer
(let ((input
(ebox-build
'(column :id "root" :width (ch 12) :height (lh 8)
(box :id "before" "Before")
(box :id "host" :width (ch 8) :height (lh 5)
(box :id "base0" :width (ch 8) :height (lh 1) "BASE0000")
(box :id "base1" :width (ch 8) :height (lh 1) "BASE1111")
(box :id "base2" :width (ch 8) :height (lh 1) "BASE2222")
(box :id "base3" :width (ch 8) :height (lh 1) "BASE3333")
(box :id "base4" :width (ch 8) :height (lh 1) "BASE4444")
(box :id "upper" :position absolute :left (px 0)
:top (lh 0) :width (ch 8) :height (lh 1)
:z-index 1 "UPPER001"))
(box :id "after" "After")))))
(ebox-render-to-buffer (current-buffer) input)
(let* ((before (buffer-string))
(old-start (+ (point-min) (string-match "UPPER001" before)))
(new-start (+ (point-min) (string-match "BASE4444" before)))
(batch-patches nil)
(changes nil)
(apply-patches (symbol-function 'tp--commit-batch-apply-patches))
(ranges (list (cons old-start (+ old-start 8))
(cons new-start (+ new-start 8)))))
(add-hook 'before-change-functions
(lambda (beg end) (push (cons beg end) changes)) nil t)
(cl-letf (((symbol-function 'tp--commit-batch-apply-patches)
(lambda (surface batch)
(setq batch-patches (tp-commit-batch-patches batch))
(funcall apply-patches surface batch))))
(ebox-region-update "upper" :top '(lh 4)))
(should (equal
'((8 . 16) (48 . 56))
(mapcar (lambda (patch)
(cons (plist-get patch :old-start)
(plist-get patch :old-end)))
batch-patches)))
(should changes)
(should
(cl-every
(lambda (change)
(cl-some (lambda (range)
(and (<= (car range) (car change))
(<= (cdr change) (cdr range))))
ranges))
changes))
(ebox-layer-publication-test--assert-fresh-render)))))
(ert-deftest ebox-layer-publication-rejected-hidden-commit-rolls-back ()
"Rejected hidden updates leave retained input, revision and text unchanged."
(ebox-layer-publication-test--with-buffer