Skip to content

Commit

Permalink
feat: relayout check
Browse files Browse the repository at this point in the history
  • Loading branch information
Jocs committed Nov 11, 2024
1 parent c68d09b commit 767ee10
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 66 deletions.
3 changes: 2 additions & 1 deletion mockdata/src/docs/default-document.data-simple.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const exampleTables = [
['Academic Senate Meeting', 'May 25, 2205', 'Building 99 Room 1'],
['Commencement Meeting ', 'December 15, 2205', 'Building 42 Room 10'],
['Dean\'s Council', 'February 1, 2206', 'Building 35 Room 5'],
['Faculty Council', 'March 1, 2206', 'Building 35 Room 5'],
];

const title = 'Examples of Accessible Data Tables\r';
Expand Down Expand Up @@ -218,7 +219,7 @@ const table: ITable = {
dist: {
distB: 5,
distL: 5,
distR: 5,
distR: 10,
distT: 5,
},
cellMargin: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import type {
} from '../../../../../basics/i-document-skeleton-cached';
import type { IParagraphConfig, IParagraphTableCache, ISectionBreakConfig } from '../../../../../basics/interfaces';
import type {
IFloatObject,
ILayoutContext,
} from '../../tools';
import { BooleanNumber, DataStreamTreeTokenType, GridType, ObjectRelativeFromV, PositionedObjectLayoutType, SpacingRule, TableTextWrapType } from '@univerjs/core';
Expand All @@ -44,6 +45,7 @@ import {
import { createSkeletonPage } from '../../model/page';
import { setColumnFullState } from '../../model/section';
import {
FloatObjectType,
getCharSpaceApply,
getCharSpaceConfig,
getLastLineByColumn,
Expand Down Expand Up @@ -547,7 +549,7 @@ function _lineOperator(
}

if (skeTablesInParagraph != null && skeTablesInParagraph.length > 0) {
needOpenNewPageByTableLayout = _updateAndPositionTable(lineTop, lineHeight, lastPage, column, section, skeTablesInParagraph, pDrawingAnchor?.get(paragraphIndex)?.top);
needOpenNewPageByTableLayout = _updateAndPositionTable(ctx, lineTop, lineHeight, lastPage, column, section, skeTablesInParagraph, paragraphConfig.paragraphIndex, pDrawingAnchor?.get(paragraphIndex)?.top);
}

const newLineTop = calculateLineTopByDrawings(
Expand Down Expand Up @@ -578,8 +580,8 @@ function _lineOperator(
lastPage.skeDrawings.delete(drawing.drawingId);
}

if (ctx.drawingsCache.has(drawing.drawingId)) {
ctx.drawingsCache.delete(drawing.drawingId);
if (ctx.floatObjectsCache.has(drawing.drawingId)) {
ctx.floatObjectsCache.delete(drawing.drawingId);
ctx.isDirty = false;
ctx.layoutStartPointer[segmentId] = null;
}
Expand Down Expand Up @@ -673,14 +675,71 @@ function __updateAndPositionDrawings(
return;
}

_reLayoutCheck(ctx, drawings, column, paragraphIndex);
const floatObjects: IFloatObject[] = [...drawings.values()]
.filter((drawing) => {
const layoutType = drawing.drawingOrigin.layoutType;

return layoutType !== PositionedObjectLayoutType.INLINE && layoutType !== PositionedObjectLayoutType.WRAP_NONE;
})
.map((drawing) => {
const { drawingOrigin, drawingId: id, aTop: top, aLeft: left, width, height, angle } = drawing;
const positionV = drawingOrigin.docTransform.positionV;

return {
id,
top,
left,
width,
height,
angle,
type: FloatObjectType.IMAGE,
positionV,
};
});

_reLayoutCheck(ctx, floatObjects, column, paragraphIndex);

__updateDrawingPosition(
column,
drawings
);
}

function __updateWrapTablePosition(
ctx: ILayoutContext,
table: IDocumentSkeletonTable,
lineTop: number,
lineHeight: number,
column: IDocumentSkeletonColumn,
paragraphIndex: number,
drawingAnchorTop?: number
) {
const wrapTablePosition = __getWrapTablePosition(table, column, lineTop, lineHeight, drawingAnchorTop);

if (wrapTablePosition == null) {
return;
}

const { tableId: id, width, height, tableSource } = table;
const { left, top } = wrapTablePosition;

const floatObject: IFloatObject = {
id,
top,
left,
width,
height,
angle: 0,
type: FloatObjectType.TABLE,
positionV: tableSource.position.positionV,
};

_reLayoutCheck(ctx, [floatObject], column, paragraphIndex);

table.top = top;
table.left = left;
}

function __getWrapTablePosition(
table: IDocumentSkeletonTable,
column: IDocumentSkeletonColumn,
Expand All @@ -689,34 +748,31 @@ function __getWrapTablePosition(
drawingAnchorTop?: number
) {
const page = column.parent?.parent;
let left = 0;
let top = 0;
if (page == null) {
return {
left,
top,
};
return;
}

const isPageBreak = __checkPageBreak(column);
const { tableSource, width, height } = table;
const { positionH, positionV } = tableSource.position;

left = getPositionHorizon(positionH, column, page, width, isPageBreak) ?? 0;
top = getPositionVertical(
const left = getPositionHorizon(positionH, column, page, width, isPageBreak) ?? 0;
const top = getPositionVertical(
positionV, page, lineTop, lineHeight, height, drawingAnchorTop, isPageBreak
) ?? 0;

return { left, top };
}

function _updateAndPositionTable(
ctx: ILayoutContext,
lineTop: number,
lineHeight: number,
page: IDocumentSkeletonPage,
column: IDocumentSkeletonColumn,
section: IDocumentSkeletonSection,
skeTablesInParagraph: IParagraphTableCache[],
paragraphIndex: number,
drawingAnchorTop?: number
): boolean {
if (skeTablesInParagraph.length === 0) {
Expand All @@ -739,10 +795,15 @@ function _updateAndPositionTable(
break;
}
case TableTextWrapType.WRAP: {
const { left, top } = __getWrapTablePosition(table, column, lineTop, lineHeight, drawingAnchorTop);

table.top = top;
table.left = left;
__updateWrapTablePosition(
ctx,
table,
lineTop,
lineHeight,
column,
paragraphIndex,
drawingAnchorTop
);
break;
}
default: {
Expand Down Expand Up @@ -862,35 +923,33 @@ function _getCustomBlockIdsInLine(line: IDocumentSkeletonLine) {

function _reLayoutCheck(
ctx: ILayoutContext,
drawings: Map<string, IDocumentSkeletonDrawing>,
floatObjects: IFloatObject[],
column: IDocumentSkeletonColumn,
paragraphIndex: number
) {
const page = column.parent?.parent;
const needUpdatedDrawings = new Map([...drawings]);

if (drawings.size === 0 || page == null) {
return drawings;
if (floatObjects.length === 0 || page == null) {
return;
}

let needBreakLineIterator = false;

// Handle situations where an image anchor paragraph is squeezed to the next page.
for (const drawing of drawings.values()) {
const drawingCache = ctx.drawingsCache.get(drawing.drawingId);
if (drawingCache == null || drawingCache.page.segmentId !== page.segmentId) {
for (const floatObject of floatObjects) {
const floatObjectCache = ctx.floatObjectsCache.get(floatObject.id);
if (floatObjectCache == null || floatObjectCache.page.segmentId !== page.segmentId) {
continue;
}
// TODO: 如何判断 drawing 是否在同一页???
const cachePageStartParagraphIndex = drawingCache.page.sections[0]?.columns[0]?.lines[0]?.paragraphIndex;
const cachePageStartParagraphIndex = floatObjectCache.page.sections[0]?.columns[0]?.lines[0]?.paragraphIndex;
const startIndex = page.sections[0]?.columns[0]?.lines[0]?.paragraphIndex;
if (drawingCache.page && cachePageStartParagraphIndex && startIndex && cachePageStartParagraphIndex !== startIndex) {
drawingCache.page.skeDrawings.delete(drawing.drawingId);
ctx.drawingsCache.delete(drawing.drawingId);
// console.log(paragraphIndex);
// console.log('cache page: ', cachePageStartParagraphIndex, 'page', startIndex);

lineIterator([drawingCache.page], (line) => {
if (floatObjectCache.page && cachePageStartParagraphIndex && startIndex && cachePageStartParagraphIndex !== startIndex) {
floatObjectCache.page.skeDrawings.delete(floatObject.id);
ctx.floatObjectsCache.delete(floatObject.id);

lineIterator([floatObjectCache.page], (line) => {
const { lineHeight, top } = line;
const column = line.parent;

Expand All @@ -899,12 +958,12 @@ function _reLayoutCheck(
}

const { width: columnWidth, left: columnLeft } = column;
const collision = collisionDetection(drawingCache.drawing, lineHeight, top, columnLeft, columnWidth);
const collision = collisionDetection(floatObjectCache.floatObject, lineHeight, top, columnLeft, columnWidth);
if (collision) {
// No need to loop next line.
needBreakLineIterator = true;
ctx.isDirty = true;
ctx.layoutStartPointer[drawingCache.page.segmentId] = Math.min(line.paragraphIndex, ctx.layoutStartPointer[drawingCache.page.segmentId] ?? Number.POSITIVE_INFINITY);
ctx.layoutStartPointer[floatObjectCache.page.segmentId] = Math.min(line.paragraphIndex, ctx.layoutStartPointer[floatObjectCache.page.segmentId] ?? Number.POSITIVE_INFINITY);
ctx.paragraphsOpenNewPage.add(paragraphIndex);
}
});
Expand All @@ -921,25 +980,25 @@ function _reLayoutCheck(
return;
}

for (const drawing of drawings.values()) {
let targetDrawing = drawing;
for (const floatObject of floatObjects.values()) {
let targetObject = floatObject;

if (ctx.drawingsCache.has(drawing.drawingId)) {
const drawingCache = ctx.drawingsCache.get(drawing.drawingId);
const needRePosition = checkRelativeDrawingNeedRePosition(ctx, drawing);
if (ctx.floatObjectsCache.has(floatObject.id)) {
const drawingCache = ctx.floatObjectsCache.get(floatObject.id);
const needRePosition = checkRelativeDrawingNeedRePosition(ctx, floatObject);

if (drawingCache?.page.segmentId !== page.segmentId) {
continue;
}

if (needRePosition) {
targetDrawing = drawingCache?.drawing ?? drawing;
targetObject = drawingCache?.floatObject ?? floatObject;
} else {
continue;
}
}

const collision = collisionDetection(targetDrawing, lineHeight, top, columnLeft, columnWidth);
const collision = collisionDetection(targetObject, lineHeight, top, columnLeft, columnWidth);
if (collision) {
// console.log(page, line.top + line.lineHeight, line.divides[0].glyphGroup[0].content);
// console.log('drawing: ', targetDrawing, 'lineHeight: ', lineHeight, 'top: ', top, 'width: ', width);
Expand All @@ -949,41 +1008,39 @@ function _reLayoutCheck(
ctx.isDirty = true;
ctx.layoutStartPointer[page.segmentId] = Math.min(line.paragraphIndex, ctx.layoutStartPointer[page.segmentId] ?? Number.POSITIVE_INFINITY);

let drawingCache = ctx.drawingsCache.get(drawing.drawingId);
let drawingCache = ctx.floatObjectsCache.get(floatObject.id);
if (drawingCache == null) {
drawingCache = {
count: 0,
drawing,
floatObject,
page,
};

ctx.drawingsCache.set(drawing.drawingId, drawingCache);
ctx.floatObjectsCache.set(floatObject.id, drawingCache);
}

drawingCache.count++;
drawingCache.drawing = drawing;
drawingCache.floatObject = floatObject;
drawingCache.page = page;
}
}
});

return needUpdatedDrawings;
}

// Detect the relative positioning of the image, whether the position needs to be repositioned.
function checkRelativeDrawingNeedRePosition(ctx: ILayoutContext, drawing: IDocumentSkeletonDrawing) {
const { relativeFrom } = drawing.drawingOrigin.docTransform.positionV;
const drawingCache = ctx.drawingsCache.get(drawing.drawingId);
function checkRelativeDrawingNeedRePosition(ctx: ILayoutContext, floatObject: IFloatObject) {
const { relativeFrom } = floatObject.positionV;
const drawingCache = ctx.floatObjectsCache.get(floatObject.id);

if (drawingCache == null) {
return false;
}

if (relativeFrom === ObjectRelativeFromV.PARAGRAPH || relativeFrom === ObjectRelativeFromV.LINE) {
const { count, drawing: prevDrawing } = drawingCache;
const { count, floatObject: prevObject } = drawingCache;
// Floating elements can be positioned no more than 5 times,
// and when the error is within 5 pixels, there is no need to re-layout
if (count < 5 && Math.abs(drawing.aTop - prevDrawing.aTop) > 5) {
if (count < 5 && Math.abs(floatObject.top - prevObject.top) > 5) {
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1046,7 +1046,7 @@ export class DocumentSkeleton extends Skeleton {
'': null, // '' is the main document.
},
isDirty: false,
drawingsCache: new Map(),
floatObjectsCache: new Map(),
paragraphConfigCache: new Map(),
sectionBreakConfigCache: new Map(),
paragraphsOpenNewPage: new Set(),
Expand Down
15 changes: 4 additions & 11 deletions packages/engine-render/src/components/docs/layout/model/line.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import type {
IDocumentSkeletonTable,
LineType,
} from '../../../../basics/i-document-skeleton-cached';
import type { IFloatObject } from '../tools';
import { PositionedObjectLayoutType, TableTextWrapType, WrapTextType } from '@univerjs/core';
import { Path2 } from '../../../../basics/path2';
import { Transform } from '../../../../basics/transform';
Expand Down Expand Up @@ -311,23 +312,15 @@ export function setLineMarginBottom(line: IDocumentSkeletonLine, marginBottom: n
}

export function collisionDetection(
drawing: IDocumentSkeletonDrawing,
floatObject: IFloatObject,
lineHeight: number,
lineTop: number,
columnLeft: number,
columnWidth: number
) {
const { aTop, height: oHeight, aLeft, width: oWidth, angle = 0, drawingOrigin } = drawing;
const { layoutType } = drawingOrigin;

if (
layoutType === PositionedObjectLayoutType.WRAP_NONE ||
layoutType === PositionedObjectLayoutType.INLINE // drawing will never be inline here, just double check here.
) {
return false;
}
const { top: oTop, height: oHeight, left: oLeft, width: oWidth, angle = 0 } = floatObject;

const { top = 0, left = 0, width = 0, height = 0 } = getBoundingBox(angle, aLeft, oWidth, aTop, oHeight);
const { top = 0, left = 0, width = 0, height = 0 } = getBoundingBox(angle, oLeft, oWidth, oTop, oHeight);

if (top + height < lineTop || top > lineHeight + lineTop) {
return false;
Expand Down
Loading

0 comments on commit 767ee10

Please sign in to comment.