import type { RowAlignment, RowSpan } from '@variance-authority/raster'; import type { DecodedImage } from './mask.js'; /** * Which row of the before image each row of the after image shows. * * A full-page capture is a column of rows, and the content of a document flows: * a paragraph inserted near the top pushes everything under it down. Compared * position by position, every row under the insertion sits against the row that * used to be there, and a 1,155-pixel insertion paints the whole tail of a * 45,000-pixel page as changed. A reviewer then sees one change as the entire * page, and the regions under it are attributed to every node it pushed. * * So the rows are diffed the way lines of text are. Each row is hashed, runs of * identical rows become one token, and Myers' algorithm finds the shortest edit * between the two token columns. The result is a pairing, not a verdict: the * caller still compares each after row with the before row it is paired with, * pixel by pixel, and every row that moved, came or went is itself a change, so * no pairing can make a page read as unchanged. A row with no partner is * reported, never paired with white. Where two paired runs meet, the before * rows on either side were not neighbours, and pixelmatch's anti-aliasing test, * which reads neighbours, may count a pixel on that seam differently. * * Myers is O((N+M)·D) in time and keeps O(D²) of trace, where N and M count runs * rather than rows and D is the size of the edit in runs. A page's runs are * about two thirds of its rows, and an insertion is one edit once the common * head and tail are trimmed, so an ordinary change costs one hashing pass. D * grows with every edit on the page, not only the largest: a rewritten section * and the lines it reflowed further down came to 3,031 runs on a 28,519-row * page. Past `limit` the search stops and the columns are split at runs each * side holds once ({@link edits}), so the rows an edit only moved still pair, * and a stretch that shares no such run, or that the split reaches after * spending its work bound, is compared by position within it. * * Only whole rows are matched. Content that moves in one column beside a column * that stays put does not move whole rows, and is compared where it sits. */ export interface AlignedRows extends RowAlignment { /** For each after row, the before row it is compared against, or `-1` for none. */ readonly source: Int32Array; /** * The inserted rows that repeat the run of identical rows they grew: a gap or a * padding that got taller. They add no content; they move what follows. */ readonly grown: readonly RowSpan[]; /** The removed rows a run of identical rows lost, the other way round. */ readonly shrunk: readonly (RowSpan & { readonly at: number; })[]; } /** The rounds, in runs, one Myers search takes before the columns are split at runs each side holds once. */ export declare const ALIGNMENT_LIMIT = 2000; /** * The pairing, or `undefined` when there is none to make: the widths differ, so * no row of one is a row of the other, or the pairing leaves no fewer pixels * differing than position does. */ export declare function alignRows(before: DecodedImage, after: DecodedImage, limit?: number): AlignedRows | undefined; //# sourceMappingURL=align.d.ts.map