mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-25 18:47:22 -06:00
Changing one character in a paragraph rewrote every row of it from the text state. A row whose width came from TJ kerning or justification gaps was then squeezed back to that width with a `Tz` stretch, and the TJ gaps became literal double spaces, so copying and searching saw "justified text". A typo fix in the last line of a justified paragraph stretched the glyphs of all the lines above it. `rewrite_styled_block` now compares each output row with the source row at the same position. When every character in it comes from the source unchanged, no style range covers it and the paragraph-wide formatting, width and position are untouched, that row keeps its own operators and only the other rows are drawn again. The new drawing goes where the first rewritten row was, so the existing ET/BT split restores the text matrix for the rows kept after it. Rows are rewritten as before when: - an earlier row wrapped and pushed them down (they no longer line up with a source row); - a rewritten row used `'` or `"`, whose move to the next line the rows after it depend on; - the first rewritten row is drawn in a different space from the paragraph's first row; - a source run contains a line break, so editor rows can't be paired with visual rows. Tests: a justified paragraph edited in its first, middle and last row keeps the other two rows' TJ operators byte for byte and every row's position; colouring a word in the last row keeps the rows above. The first test fails without this change. A second test pins the `'` case (a row-leading `'` that is rewritten would lift the kept rows by one line) and checks that a wrapping row shows each word once. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com>