fix: aggregate large ink groups safely
This commit is contained in:
@@ -623,7 +623,7 @@ function parseInk(
|
|||||||
id: exGuidKey(object.id),
|
id: exGuidKey(object.id),
|
||||||
strokes: [],
|
strokes: [],
|
||||||
children,
|
children,
|
||||||
boundingBox: unionBoundingBoxes(
|
boundingBox: unionInkBoundingBoxes(
|
||||||
children.map((child) => child.boundingBox)
|
children.map((child) => child.boundingBox)
|
||||||
),
|
),
|
||||||
layout: parseLayout(object),
|
layout: parseLayout(object),
|
||||||
@@ -915,18 +915,24 @@ function boundingBoxFromStrokes(
|
|||||||
: undefined;
|
: undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function unionBoundingBoxes(
|
/** @internal Exported so the bounded aggregation path can be stress-tested. */
|
||||||
|
export function unionInkBoundingBoxes(
|
||||||
boxes: readonly (OneNoteInkBoundingBox | undefined)[]
|
boxes: readonly (OneNoteInkBoundingBox | undefined)[]
|
||||||
): OneNoteInkBoundingBox | undefined {
|
): OneNoteInkBoundingBox | undefined {
|
||||||
const present = boxes.filter(
|
let x = Infinity;
|
||||||
(box): box is OneNoteInkBoundingBox => box !== undefined
|
let y = Infinity;
|
||||||
);
|
let x2 = -Infinity;
|
||||||
if (present.length === 0) return undefined;
|
let y2 = -Infinity;
|
||||||
const x = Math.min(...present.map((box) => box.x));
|
for (const box of boxes) {
|
||||||
const y = Math.min(...present.map((box) => box.y));
|
if (!box) continue;
|
||||||
const x2 = Math.max(...present.map((box) => box.x + box.width));
|
x = Math.min(x, box.x);
|
||||||
const y2 = Math.max(...present.map((box) => box.y + box.height));
|
y = Math.min(y, box.y);
|
||||||
return { x, y, width: x2 - x, height: y2 - y };
|
x2 = Math.max(x2, box.x + box.width);
|
||||||
|
y2 = Math.max(y2, box.y + box.height);
|
||||||
|
}
|
||||||
|
return Number.isFinite(x)
|
||||||
|
? { x, y, width: x2 - x, height: y2 - y }
|
||||||
|
: undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseLayout(object: StoreObject): OneNoteLayout {
|
function parseLayout(object: StoreObject): OneNoteLayout {
|
||||||
|
|||||||
@@ -15,7 +15,10 @@ import {
|
|||||||
type OneNoteTextBlock,
|
type OneNoteTextBlock,
|
||||||
} from '../src/onenote/index.js';
|
} from '../src/onenote/index.js';
|
||||||
import type { ParserDiagnostic } from '../src/onenote/model/diagnostics.js';
|
import type { ParserDiagnostic } from '../src/onenote/model/diagnostics.js';
|
||||||
import { parseContentObjects } from '../src/onenote/one/content.js';
|
import {
|
||||||
|
parseContentObjects,
|
||||||
|
unionInkBoundingBoxes,
|
||||||
|
} from '../src/onenote/one/content.js';
|
||||||
import { JCID, PROPERTY } from '../src/onenote/one/constants.js';
|
import { JCID, PROPERTY } from '../src/onenote/one/constants.js';
|
||||||
import type {
|
import type {
|
||||||
ExGuid,
|
ExGuid,
|
||||||
@@ -209,6 +212,22 @@ describe('OneNote rich-content model', () => {
|
|||||||
expect(parsedPoints).toBeLessThanOrEqual(100);
|
expect(parsedPoints).toBeLessThanOrEqual(100);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('combines a large number of child ink bounds without argument spreading', () => {
|
||||||
|
const boxes = Array.from({ length: 200_000 }, (_, index) => ({
|
||||||
|
x: index,
|
||||||
|
y: -index,
|
||||||
|
width: 2,
|
||||||
|
height: 3,
|
||||||
|
}));
|
||||||
|
|
||||||
|
expect(unionInkBoundingBoxes([undefined, ...boxes])).toEqual({
|
||||||
|
x: 0,
|
||||||
|
y: -199_999,
|
||||||
|
width: 200_001,
|
||||||
|
height: 200_002,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('bounds retained rich text across content blocks', () => {
|
it('bounds retained rich text across content blocks', () => {
|
||||||
const guid = '{33333333-3333-3333-3333-333333333333}';
|
const guid = '{33333333-3333-3333-3333-333333333333}';
|
||||||
const firstId = id(guid, 1);
|
const firstId = id(guid, 1);
|
||||||
|
|||||||
Reference in New Issue
Block a user