Skip to content

Commit e9b50ce

Browse files
committed
p1
1 parent f4feb3a commit e9b50ce

7 files changed

Lines changed: 991 additions & 797 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 & 51 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
}
@@ -1398,22 +1384,20 @@ export class Inline extends Box {
13981384
return this.style.hasLineRightGap(containingBlock);
13991385
}
14001386

1401-
getInlineSideSize(containingBlock: BoxArea, side: 'pre' | 'post') {
1387+
getInlineStartSize(containingBlock: BoxArea) {
14021388
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-
}
1389+
const marginStart = this.style.getMarginInlineStart(containingBlock, direction);
1390+
return (marginStart === 'auto' ? 0 : marginStart)
1391+
+ this.style.getBorderInlineStartWidth(containingBlock, direction)
1392+
+ this.style.getPaddingInlineStart(containingBlock, direction);
1393+
}
1394+
1395+
getInlineEndSize(containingBlock: BoxArea) {
1396+
const direction = this.getDirectionAsParticipant(containingBlock);
1397+
const marginEnd = this.style.getMarginInlineEnd(containingBlock, direction);
1398+
return (marginEnd === 'auto' ? 0 : marginEnd)
1399+
+ this.style.getBorderInlineEndWidth(containingBlock, direction)
1400+
+ this.style.getPaddingInlineEnd(containingBlock, direction);
14171401
}
14181402

14191403
isInline(): this is Inline {
@@ -1476,9 +1460,12 @@ export class ReplacedBox extends FormattingBox {
14761460
}
14771461

14781462
getLogSymbol() {
1479-
return "◼️";
1463+
if (this.isFloat()) {
1464+
return '●';
1465+
} else {
1466+
return '◼️';
1467+
}
14801468
}
1481-
14821469
hasBackground() {
14831470
return this.style.hasPaint();
14841471
}
@@ -1543,9 +1530,9 @@ export class ReplacedBox extends FormattingBox {
15431530
export type InlineLevel = Inline | Run | Break | BlockContainer | ReplacedBox;
15441531

15451532
type InlineIteratorBuffered = {state: 'pre' | 'post', item: Inline}
1546-
| {state: 'text', item: Run}
1533+
| {state: 'text', item: Run, index: number}
15471534
| {state: 'box', item: BlockLevel}
1548-
| {state: 'break'}
1535+
| {state: 'break', index: number}
15491536
| {state: 'breakop'};
15501537

15511538
type InlineIteratorValue = InlineIteratorBuffered | {state: 'breakspot'};
@@ -1588,6 +1575,9 @@ export function inlineIteratorStateNext(state: InlineIteratorState) {
15881575
state.breakspotIndex = 0;
15891576
state.isInlineBlock = false;
15901577

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

@@ -1599,9 +1589,9 @@ export function inlineIteratorStateNext(state: InlineIteratorState) {
15991589
state.minlevel = state.parents.length;
16001590

16011591
if (item.isRun()) {
1602-
state.buffered.push({state: 'text', item});
1592+
state.buffered.push({state: 'text', item, index: state.index});
16031593
} else if (item.isBreak()) {
1604-
state.buffered.push({state: 'break'});
1594+
state.buffered.push({state: 'break', index: state.index});
16051595
} else {
16061596
if (item.isFloat()) {
16071597
state.buffered.push({state: 'box', item});

0 commit comments

Comments
 (0)