Skip to content

Commit 1d16278

Browse files
committed
p1
1 parent f4feb3a commit 1d16278

7 files changed

Lines changed: 991 additions & 800 deletions

File tree

examples/images-1.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ const rootElement = flow.dom(
4040
flow.h('html', {style: rootStyle, attrs: {'x-dropflow-log': 'true'}}, [
4141
flow.h('img', {
4242
style: image1Style,
43-
attrs: {src: 'https://chearon.github.io/dropflow/assets/images/frogmage.gif'}
43+
attrs: {id: 'img', src: 'file:///Users/caleb/Code/dropflow/assets/images/frogmage.gif'}
4444
}),
4545
flow.h('p', `
4646
Dropflow now supports images! These are loaded by calling flow.load()
@@ -57,7 +57,7 @@ const rootElement = flow.dom(
5757
of Ada Lovelace, the well-tempered Great Pyrenees mix as an inline image: `,
5858
flow.h('img', {
5959
style: image2Style,
60-
attrs: {src: 'https://chearon.github.io/dropflow/assets/images/ada.png'}
60+
attrs: {src: 'file:///Users/caleb/Code/dropflow/assets/images/ada.png'}
6161
}),
6262
' after'
6363
]),
@@ -66,12 +66,11 @@ const rootElement = flow.dom(
6666
`),
6767
flow.h('img', {
6868
style: image3Style,
69-
attrs: {src: 'https://chearon.github.io/dropflow/assets/images/tiramisu.jpeg'}
69+
attrs: {src: 'file:///Users/caleb/Code/dropflow/assets/images/tiramisu.jpeg'}
7070
})
7171
])
7272
);
7373

74-
7574
// Normal layout, logging
7675
await flow.load(rootElement);
7776
const layout = flow.layout(rootElement);

src/layout-flow.ts

Lines changed: 41 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
getIfcContribution,
1111
createIfcShapedItems,
1212
createIfcLineboxes,
13-
positionIfcItems,
1413
sliceIfcRenderText,
1514
collapseWhitespace
1615
} from './layout-text.ts';
@@ -832,16 +831,14 @@ export class BlockContainerOfInlines extends BlockContainerBase {
832831
text: string;
833832
buffer: AllocatedUint16Array;
834833
items: ShapedItem[];
835-
lineboxes: Linebox[];
836-
fragments: Map<Inline, InlineFragment[]>;
834+
fragments: InlineFragment[];
837835

838836
constructor(style: Style, attrs: number) {
839837
super(style, attrs);
840838
this.text = '';
841839
this.buffer = EmptyBuffer;
842840
this.items = [];
843-
this.lineboxes = [];
844-
this.fragments = new Map();
841+
this.fragments = [];
845842
}
846843

847844
prelayoutPostorder(layout: Layout, ctx: PrelayoutContext) {
@@ -851,12 +848,12 @@ export class BlockContainerOfInlines extends BlockContainerBase {
851848
this.buffer.destroy();
852849
this.buffer = createIfcBuffer(this.text);
853850
this.items = createIfcShapedItems(layout, this, inline);
854-
this.fragments.clear();
851+
this.fragments = [];
855852
}
856853
}
857854

858855
positionItemsPostlayout(layout: Layout) {
859-
const inlineShifts: Map<Inline, {dx: number; dy: number}> = new Map();
856+
const inlineShifts: Map<number, {dx: number; dy: number}> = new Map();
860857
const parents: Inline[] = [];
861858
const contentArea = this.getContentArea();
862859
const rootInline = layout.tree[this.treeStart + 1];
@@ -876,7 +873,7 @@ export class BlockContainerOfInlines extends BlockContainerBase {
876873
dy += box.getRelativeVerticalShift(containingBlock);
877874
}
878875

879-
inlineShifts.set(box, {dx, dy});
876+
inlineShifts.set(box.treeStart, {dx, dy});
880877
parents.push(box);
881878
} else {
882879
if (box.isBox()) i = box.treeFinal;
@@ -912,14 +909,11 @@ export class BlockContainerOfInlines extends BlockContainerBase {
912909
}
913910
}
914911

915-
for (const [inline, fragments] of this.fragments) {
916-
const {dx, dy} = inlineShifts.get(inline)!;
917-
918-
for (const fragment of fragments) {
919-
fragment.blockOffset += contentArea.y + dy;
920-
fragment.start += contentArea.x + dx;
921-
fragment.end += contentArea.x + dx;
922-
}
912+
for (const fragment of this.fragments) {
913+
const {dx, dy} = inlineShifts.get(fragment.treeIndex)!;
914+
fragment.blockOffset += contentArea.y + dy;
915+
fragment.left += contentArea.x + dx;
916+
fragment.right += contentArea.x + dx;
923917
}
924918
}
925919

@@ -960,6 +954,7 @@ export class BlockContainerOfInlines extends BlockContainerBase {
960954
let ml = i;
961955
let mr = i;
962956

957+
// TODO this is wrong!
963958
while (mr < r && !layout.tree[mr].isRun() && !layout.tree[mr].isInline()) mr++;
964959
while (ml > l && !layout.tree[ml].isRun() && !layout.tree[ml].isInline()) ml--;
965960

@@ -981,15 +976,6 @@ export class BlockContainerOfInlines extends BlockContainerBase {
981976
return sliceIfcRenderText(layout, this, item, start, end);
982977
}
983978

984-
getLineboxHeight() {
985-
if (this.lineboxes.length) {
986-
const line = this.lineboxes.at(-1)!;
987-
return line.blockOffset + line.height();
988-
} else {
989-
return 0;
990-
}
991-
}
992-
993979
shouldLayoutContent(layout: Layout) {
994980
const inline = layout.tree[this.treeStart + 1];
995981
if (!inline.isInline()) throw new Error('Assertion failed');
@@ -1003,11 +989,11 @@ export class BlockContainerOfInlines extends BlockContainerBase {
1003989
const containingBlock = this.getContainingBlock();
1004990
const blockSize = this.style.getBlockSize(containingBlock);
1005991
if (this.shouldLayoutContent(layout)) {
1006-
this.lineboxes = createIfcLineboxes(layout, this, ctx);
1007-
positionIfcItems(layout, this);
1008-
}
1009-
if (blockSize === 'auto') {
1010-
this.setBlockSize(containingBlock, this.getLineboxHeight());
992+
const ifc = createIfcLineboxes(layout, this, ctx);
993+
if (blockSize === 'auto' && ifc.lines.length) {
994+
const line = ifc.lines[ifc.lines.length - 1];
995+
this.setBlockSize(containingBlock, line.blockOffset + line.height());
996+
}
1011997
}
1012998
}
1013999
}
@@ -1302,7 +1288,6 @@ export class Break extends TreeNode {
13021288
}
13031289

13041290
export class Inline extends Box {
1305-
public nshaped: number;
13061291
public metrics: InlineMetrics;
13071292
public textStart: number;
13081293
public textEnd: number;
@@ -1313,13 +1298,11 @@ export class Inline extends Box {
13131298
this.textEnd = 0;
13141299
this.treeStart = 0;
13151300
this.treeFinal = 0;
1316-
this.nshaped = 0;
13171301
this.metrics = EmptyInlineMetrics;
13181302
}
13191303

13201304
prelayoutPreorder(ctx: PrelayoutContext) {
13211305
super.prelayoutPreorder(ctx);
1322-
this.nshaped = 0;
13231306
this.metrics = getFontMetrics(this);
13241307
}
13251308

@@ -1398,22 +1381,20 @@ export class Inline extends Box {
13981381
return this.style.hasLineRightGap(containingBlock);
13991382
}
14001383

1401-
getInlineSideSize(containingBlock: BoxArea, side: 'pre' | 'post') {
1384+
getInlineStartSize(containingBlock: BoxArea) {
14021385
const direction = this.getDirectionAsParticipant(containingBlock);
1403-
if (
1404-
direction === 'ltr' && side === 'pre' ||
1405-
direction === 'rtl' && side === 'post'
1406-
) {
1407-
const marginLineLeft = this.style.getMarginLineLeft(containingBlock);
1408-
return (marginLineLeft === 'auto' ? 0 : marginLineLeft)
1409-
+ this.style.getBorderLineLeftWidth(containingBlock)
1410-
+ this.style.getPaddingLineLeft(containingBlock);
1411-
} else {
1412-
const marginLineRight = this.style.getMarginLineRight(containingBlock);
1413-
return (marginLineRight === 'auto' ? 0 : marginLineRight)
1414-
+ this.style.getBorderLineRightWidth(containingBlock)
1415-
+ this.style.getPaddingLineRight(containingBlock);
1416-
}
1386+
const marginStart = this.style.getMarginInlineStart(containingBlock, direction);
1387+
return (marginStart === 'auto' ? 0 : marginStart)
1388+
+ this.style.getBorderInlineStartWidth(containingBlock, direction)
1389+
+ this.style.getPaddingInlineStart(containingBlock, direction);
1390+
}
1391+
1392+
getInlineEndSize(containingBlock: BoxArea) {
1393+
const direction = this.getDirectionAsParticipant(containingBlock);
1394+
const marginEnd = this.style.getMarginInlineEnd(containingBlock, direction);
1395+
return (marginEnd === 'auto' ? 0 : marginEnd)
1396+
+ this.style.getBorderInlineEndWidth(containingBlock, direction)
1397+
+ this.style.getPaddingInlineEnd(containingBlock, direction);
14171398
}
14181399

14191400
isInline(): this is Inline {
@@ -1476,9 +1457,12 @@ export class ReplacedBox extends FormattingBox {
14761457
}
14771458

14781459
getLogSymbol() {
1479-
return "◼️";
1460+
if (this.isFloat()) {
1461+
return '●';
1462+
} else {
1463+
return '◼️';
1464+
}
14801465
}
1481-
14821466
hasBackground() {
14831467
return this.style.hasPaint();
14841468
}
@@ -1543,9 +1527,9 @@ export class ReplacedBox extends FormattingBox {
15431527
export type InlineLevel = Inline | Run | Break | BlockContainer | ReplacedBox;
15441528

15451529
type InlineIteratorBuffered = {state: 'pre' | 'post', item: Inline}
1546-
| {state: 'text', item: Run}
1530+
| {state: 'text', item: Run, index: number}
15471531
| {state: 'box', item: BlockLevel}
1548-
| {state: 'break'}
1532+
| {state: 'break', index: number}
15491533
| {state: 'breakop'};
15501534

15511535
type InlineIteratorValue = InlineIteratorBuffered | {state: 'breakspot'};
@@ -1588,6 +1572,9 @@ export function inlineIteratorStateNext(state: InlineIteratorState) {
15881572
state.breakspotIndex = 0;
15891573
state.isInlineBlock = false;
15901574

1575+
// This body of this loop consumes (pre | post)* atomic? post*,
1576+
// where atomic is a <br>, an inline-block, or a float, and pre/post
1577+
// are sides of an inline.
15911578
while (state.index <= state.block.treeFinal && !foundAtomic) {
15921579
const item = state.layout.tree[state.index];
15931580

@@ -1599,9 +1586,9 @@ export function inlineIteratorStateNext(state: InlineIteratorState) {
15991586
state.minlevel = state.parents.length;
16001587

16011588
if (item.isRun()) {
1602-
state.buffered.push({state: 'text', item});
1589+
state.buffered.push({state: 'text', item, index: state.index});
16031590
} else if (item.isBreak()) {
1604-
state.buffered.push({state: 'break'});
1591+
state.buffered.push({state: 'break', index: state.index});
16051592
} else {
16061593
if (item.isFloat()) {
16071594
state.buffered.push({state: 'box', item});

0 commit comments

Comments
 (0)