Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/layout-engine/contracts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ export type BreakRun = {
pmStart?: number;
pmEnd?: number;
sdt?: SdtMetadata;
trackedChange?: TrackedChangeMeta;
};

/**
Expand Down
76 changes: 1 addition & 75 deletions packages/layout-engine/layout-bridge/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export type { HeaderFooterLayoutResult, IncrementalLayoutResult } from './increm
export { computeDisplayPageNumber } from '@superdoc/layout-engine';
export type { DisplayPageInfo, HeaderFooterConstraints } from '@superdoc/layout-engine';
export { remeasureParagraph } from './remeasure';
export { measureCharacterX } from './text-measurement';
export { measureCharacterX, sliceRunsForLine } from './text-measurement';
export { clickToPositionDom, findPageElement } from './dom-mapping';
export { isListItem, getWordLayoutConfig, calculateTextStartIndent, extractParagraphIndent } from './list-indent-utils';
export type { TextIndentCalculationParams } from './list-indent-utils';
Expand Down Expand Up @@ -144,10 +144,6 @@ export type { FallbackReason, SafetyConfig } from './safety-net';
export { FocusWatchdog } from './focus-watchdog';
export type { FocusWatchdogConfig } from './focus-watchdog';

// Benchmarks
export { TypingPerfBenchmark } from './benchmarks';
export type { BenchmarkResult, BenchmarkScenario } from './benchmarks';

// Paragraph Hash Utilities
export {
hashParagraphBorder,
Expand Down Expand Up @@ -1539,74 +1535,4 @@ const mapPmToX = (
return measureCharacterX(block, line, offset, availableWidth, alignmentOverride);
};

const _sliceRunsForLine = (block: FlowBlock, line: Line): Run[] => {
const result: Run[] = [];

if (block.kind !== 'paragraph') return result;

for (let runIndex = line.fromRun; runIndex <= line.toRun; runIndex += 1) {
const run = block.runs[runIndex];
if (!run) continue;

if (run.kind === 'tab') {
result.push(run);
continue;
}

// FIXED: ImageRun handling - images are atomic units, no slicing needed
if ('src' in run) {
result.push(run);
continue;
}

// LineBreakRun handling - line breaks are atomic units, no slicing needed
if (run.kind === 'lineBreak') {
result.push(run);
continue;
}

// BreakRun handling - breaks are atomic units, no slicing needed
if (run.kind === 'break') {
result.push(run);
continue;
}

// FieldAnnotationRun handling - field annotations are atomic units, no slicing needed
if (run.kind === 'fieldAnnotation') {
result.push(run);
continue;
}

// MathRun handling - math runs are atomic units, no slicing needed
if (run.kind === 'math') {
result.push(run);
continue;
}

const text = run.text ?? '';
const isFirstRun = runIndex === line.fromRun;
const isLastRun = runIndex === line.toRun;

if (isFirstRun || isLastRun) {
const start = isFirstRun ? line.fromChar : 0;
const end = isLastRun ? line.toChar : text.length;
const slice = text.slice(start, end);
const pmStart =
run.pmStart != null ? run.pmStart + start : run.pmEnd != null ? run.pmEnd - (text.length - start) : undefined;
const pmEnd =
run.pmStart != null ? run.pmStart + end : run.pmEnd != null ? run.pmEnd - (text.length - end) : undefined;
result.push({
...run,
text: slice,
pmStart,
pmEnd,
});
} else {
result.push(run);
}
}

return result;
};

// isRtlBlock is now in position-hit.ts and re-exported above.
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ export function sliceRunsForLine(block: FlowBlock, line: Line): Run[] {
const start = isFirstRun ? line.fromChar : 0;
const end = isLastRun ? line.toChar : text.length;
const slice = text.slice(start, end);
if (!slice) continue;
const pmStart =
run.pmStart != null ? run.pmStart + start : run.pmEnd != null ? run.pmEnd - (text.length - start) : undefined;
const pmEnd =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/

import { describe, it, expect, beforeEach } from 'vitest';
import { TypingPerfBenchmark } from '../src/benchmarks';
import { TypingPerfBenchmark } from './benchmarks';

describe('TypingPerfBenchmark', () => {
let benchmark: TypingPerfBenchmark;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { LayoutOptions } from '@superdoc/layout-engine';
import { measureBlock } from '@superdoc/measuring-dom';
import { createDomPainter } from '@superdoc/painter-dom';
import { layoutDocument } from '@superdoc/layout-engine';
import { incrementalLayout, measureCache, resolveMeasurementConstraints } from '../incrementalLayout';
import { incrementalLayout, measureCache, resolveMeasurementConstraints } from '../../src/incrementalLayout';

const LETTER_LAYOUT: LayoutOptions = {
pageSize: { w: 612, h: 792 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { describe, it, expect, beforeAll } from 'vitest';
import { resolveCanvas } from '../../measuring/dom/src/canvas-resolver.js';
import { installNodeCanvasPolyfill } from '../../measuring/dom/src/setup.ts';
import { runBenchmarkSuite } from '../src/benchmarks/index';
import { runBenchmarkSuite } from './benchmarks/index';

const { Canvas, usingStub } = resolveCanvas();

Expand Down
2 changes: 2 additions & 0 deletions packages/layout-engine/painters/dom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
"@superdoc/dom-contract": "workspace:*",
"@superdoc/font-utils": "workspace:*",
"@superdoc/layout-resolved": "workspace:*",
"@superdoc/layout-bridge": "workspace:*",
"@superdoc/pm-adapter": "workspace:*",
"@superdoc/preset-geometry": "workspace:*",
"@superdoc/url-validation": "workspace:*"
},
Expand Down
89 changes: 89 additions & 0 deletions packages/layout-engine/painters/dom/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11357,6 +11357,95 @@ describe('applyRunDataAttributes', () => {
}).not.toThrow();
});

it('renders all lines when measure indices come from inline-newline expansion', () => {
const inlineNewlineBlock: FlowBlock = {
kind: 'paragraph',
id: 'inline-newline-slice',
runs: [{ text: 'first\nsecond\nthird', fontFamily: 'Arial', fontSize: 16, pmStart: 0, pmEnd: 18 }],
};

// Measurer expands inline '\n' into: text, break, text, break, text.
const inlineNewlineMeasure: ParagraphMeasure = {
kind: 'paragraph',
lines: [
{
fromRun: 0,
fromChar: 0,
toRun: 0,
toChar: 5,
width: 40,
ascent: 12,
descent: 4,
lineHeight: 20,
},
{
fromRun: 2,
fromChar: 0,
toRun: 2,
toChar: 6,
width: 50,
ascent: 12,
descent: 4,
lineHeight: 20,
},
{
fromRun: 4,
fromChar: 0,
toRun: 4,
toChar: 5,
width: 40,
ascent: 12,
descent: 4,
lineHeight: 20,
},
],
totalHeight: 60,
};

const inlineNewlineLayout: Layout = {
pageSize: { w: 400, h: 500 },
pages: [
{
number: 1,
fragments: [
{
kind: 'para',
blockId: 'inline-newline-slice',
fromLine: 0,
toLine: 3,
x: 20,
y: 20,
width: 300,
},
],
},
],
};

const painter = createTestPainter({
blocks: [inlineNewlineBlock],
measures: [inlineNewlineMeasure],
});

expect(() => {
painter.paint(inlineNewlineLayout, mount);
}).not.toThrow();

const fragment = mount.querySelector<HTMLElement>('.superdoc-fragment');
expect(fragment).not.toBeNull();
expect(fragment?.textContent).toContain('first');
expect(fragment?.textContent).toContain('second');
expect(fragment?.textContent).toContain('third');
const lines = fragment?.querySelectorAll<HTMLElement>('.superdoc-line');
expect(lines?.length).toBe(3);
expect(lines?.[0].dataset.pmStart).toEqual('0');
expect(lines?.[0].dataset.pmEnd).toEqual('5');
expect(lines?.[1].dataset.pmStart).toEqual('6');
expect(lines?.[1].dataset.pmEnd).toEqual('12');
expect(lines?.[2].dataset.pmStart).toEqual('13');
expect(lines?.[2].dataset.pmEnd).toEqual('18');
});

it('preserves PM positions for lineBreak runs', () => {
const lineBreakBlock: FlowBlock = {
kind: 'paragraph',
Expand Down
Loading
Loading