From 91cd92f92f401c05b98602feb68a30670b491a28 Mon Sep 17 00:00:00 2001 From: David Richardson Date: Sat, 24 Oct 2026 15:34:32 -0600 Subject: [PATCH] AppKit: Correct screen positioning for rescued line fragment views and spans during edits When CPLayoutManager retained and repositioned unchanged line fragments below an edit, `_CPLineFragment` incorrectly modified attachment view frames directly and assigned an unused property to text spans. Consequently, moved views remained visually stationary on screen because subsequent layout-pass `setFrameOrigin:` calls detected matching origins, causing asynchronously loaded elements (such as pasted tables combined with images) to render at incorrect offsets until forced by a scroll or resize event. * AppKit/CPTextView/CPLayoutManager.j: - Update attachment view relocation to correctly trigger `setFrameOrigin:`. - Shift rendered text spans via their style coordinate top properties. * Tests/Manual/TextEditor/WORKLIST.md: - Mark composite paste workflows (text containing both images and tables) as tested. Attachment views and text spans now immediately track their corresponding line fragments when text is inserted or modified above them. --- AppKit/CPTextView/CPLayoutManager.j | 14 +++++++++++--- Tests/Manual/TextEditor/WORKLIST.md | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/AppKit/CPTextView/CPLayoutManager.j b/AppKit/CPTextView/CPLayoutManager.j index 8d3572a35..dbcc6e294 100644 --- a/AppKit/CPTextView/CPLayoutManager.j +++ b/AppKit/CPTextView/CPLayoutManager.j @@ -1541,11 +1541,19 @@ var _objectsInRange = function(aList, aRange) if (verticalOffset) { + // An attachment view is moved through setFrameOrigin:, which also moves it on the + // screen. Changing its frame directly would leave it in place, because the next draw's + // setFrameOrigin: would then find it already at the new origin and do nothing. if (_runs[i].view) - _runs[i].view._frame.origin.y += verticalOffset; + { + var viewOrigin = [_runs[i].view frameOrigin]; - if (_runs[i].elem) - _runs[i].elem.top = (_runs[i].elem.top + verticalOffset) + 'px'; + [_runs[i].view setFrameOrigin:CGPointMake(viewOrigin.x, viewOrigin.y + verticalOffset)]; + } + + // A span that has been placed moves with its line. One that has not is placed when drawn. + if (_runs[i].elem && _runs[i].elem.style.top) + _runs[i].elem.style.top = (parseFloat(_runs[i].elem.style.top) + verticalOffset) + 'px'; _runs[i].DOMpatched = YES; } diff --git a/Tests/Manual/TextEditor/WORKLIST.md b/Tests/Manual/TextEditor/WORKLIST.md index 71b258ce6..d9e2ac21d 100644 --- a/Tests/Manual/TextEditor/WORKLIST.md +++ b/Tests/Manual/TextEditor/WORKLIST.md @@ -90,4 +90,5 @@ How the text system works, for the entries below: `CPTextView` does not use CSS - Edit > Insert Table Example: the sample table appears between the surrounding sentences, with its header row and its bold and italic cells. - Copy and paste within TextEditor with Command-C and Command-V, in one document and between documents: images, tables, including text edited in their cells, and lists are kept. - Table cells can be edited, as a first pass. +- Pasting text with several images and a table: the table appears in place at once, and tables, images and text below a change move with their lines. - Builds with both the legacy toolchain and capp-build.