Skip to content

Commit 5a9bac8

Browse files
committed
remove unnecessary color splitting
goodness, ea50917 actually ended up removing a lot of code. things were overcomplicated!
1 parent 45917cf commit 5a9bac8

5 files changed

Lines changed: 25 additions & 139 deletions

File tree

src/layout-flow.ts

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,29 +1576,6 @@ export function createInlineIterator(inline: IfcInline) {
15761576
return {next};
15771577
}
15781578

1579-
export function createPreorderInlineIterator(inline: Inline) {
1580-
const stack: InlineLevel[] = inline.children.slice().reverse();
1581-
1582-
function next(): {done: true} | {done: false, value: Inline | Run} {
1583-
while (stack.length) {
1584-
const item = stack.pop()!;
1585-
1586-
if (item.isInline()) {
1587-
for (let i = item.children.length - 1; i >= 0; --i) {
1588-
stack.push(item.children[i]);
1589-
}
1590-
return {done: false, value: item};
1591-
} else if (item.isRun()) {
1592-
return {done: false, value: item};
1593-
}
1594-
}
1595-
1596-
return {done: true};
1597-
}
1598-
1599-
return {next};
1600-
}
1601-
16021579
interface ParagraphText {
16031580
value: string;
16041581
}

src/layout-text.ts

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {binarySearchTuple, basename, loggableText, Logger} from './util.ts';
1+
import {basename, loggableText, Logger} from './util.ts';
22
import {Box, FormattingBox, RenderItem} from './layout-box.ts';
33
import {Style} from './style.ts';
44
import {
@@ -8,7 +8,6 @@ import {
88
IfcVacancy,
99
Inline,
1010
createInlineIterator,
11-
createPreorderInlineIterator,
1211
layoutFloatBox
1312
} from './layout-flow.ts';
1413
import LineBreak, {HardBreaker} from './text-line-break.ts';
@@ -21,7 +20,7 @@ import {createItemizeState, itemizeNext} from './text-itemize.ts';
2120
import type {LoadedFontFace} from './text-font.ts';
2221
import type {HbFace, HbFont, AllocatedUint16Array} from './text-harfbuzz.ts';
2322
import type {RenderItemLogOptions} from './layout-box.ts';
24-
import type {Color, TextAlign, WhiteSpace} from './style.ts';
23+
import type {TextAlign, WhiteSpace} from './style.ts';
2524
import type {BlockLevel, InlineLevel, LayoutContext} from './layout-flow.ts';
2625

2726
const lineFeedCharacter = 0x000a;
@@ -778,22 +777,6 @@ export class ShapedItem implements IfcRenderItem {
778777
}
779778
}
780779

781-
// used in shaping
782-
colorsStart(colors: [Color, number][]) {
783-
const s = binarySearchTuple(colors, this.offset);
784-
if (s === colors.length) return s - 1;
785-
if (colors[s][1] !== this.offset) return s - 1;
786-
return s;
787-
}
788-
789-
// used in shaping
790-
colorsEnd(colors: [Color, number][]) {
791-
const s = binarySearchTuple(colors, this.end() - 1);
792-
if (s === colors.length) return s;
793-
if (colors[s][1] !== this.end() - 1) return s;
794-
return s + 1;
795-
}
796-
797780
end() {
798781
return this.offset + this.length;
799782
}
@@ -1805,38 +1788,6 @@ export class Paragraph {
18051788
}
18061789
}
18071790

1808-
getColors() {
1809-
const colors: [Color, number][] = [[this.ifc.style.color, 0]];
1810-
1811-
if (this.ifc.hasColoredInline()) {
1812-
const inlineIterator = createPreorderInlineIterator(this.ifc);
1813-
let inline = inlineIterator.next();
1814-
1815-
while (!inline.done) {
1816-
const [, lastColorOffset] = colors[colors.length - 1];
1817-
if (inline.value.isRun()) {
1818-
const style = inline.value.style;
1819-
const color = colors[colors.length - 1];
1820-
1821-
if (lastColorOffset === inline.value.start) {
1822-
color[0] = style.color;
1823-
} else if (
1824-
style.color.r !== color[0].r ||
1825-
style.color.g !== color[0].g ||
1826-
style.color.b !== color[0].b ||
1827-
style.color.a !== color[0].a
1828-
) {
1829-
colors.push([style.color, inline.value.start]);
1830-
}
1831-
}
1832-
1833-
inline = inlineIterator.next();
1834-
}
1835-
}
1836-
1837-
return colors;
1838-
}
1839-
18401791
postShapeLoadHyphens() {
18411792
let itemIndex = 0;
18421793
for (let textOffset = 0; textOffset < this.string.length; textOffset++) {

src/paint.ts

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {Box, FormattingBox} from './layout-box.ts';
66
import {binarySearchOf} from './util.ts';
77

88
import type {InlineLevel, BlockLevel} from './layout-flow.ts';
9-
import type {InlineFragment} from './layout-text.ts';
9+
import type {InlineFragment, Run} from './layout-text.ts';
1010
import type {Color} from './style.ts';
1111
import type {LoadedFontFace} from './text-font.ts';
1212

@@ -70,7 +70,7 @@ function getTextOffsetsForUncollapsedGlyphs(item: ShapedItem) {
7070

7171
function drawText(
7272
item: ShapedItem,
73-
colors: [Color, number][],
73+
run: Run,
7474
textStart: number,
7575
textEnd: number,
7676
b: PaintBackend
@@ -81,8 +81,6 @@ function drawText(
8181
// Sadly this seems to only work in Firefox and only when the font doesn't do
8282
// any normalizination, so I could probably stop trying to support it
8383
// https://github.com/w3c/csswg-drafts/issues/699
84-
const colorEnd = item.colorsEnd(colors);
85-
let colorIndex = item.colorsStart(colors);
8684
let tx = item.x;
8785
const collapsed = getTextOffsetsForUncollapsedGlyphs(item);
8886
textStart = Math.max(textStart, collapsed.textStart);
@@ -95,32 +93,23 @@ function drawText(
9593
tx += item.measure(textStart, 1, state).advance;
9694
}
9795

98-
while (colorIndex !== colorEnd) {
99-
const [color, offset] = colors[colorIndex];
100-
const colorStart = offset;
101-
const colorEnd = colorIndex + 1 < colors.length ? colors[colorIndex + 1][1] : textEnd;
102-
const start = Math.max(colorStart, textStart);
103-
const end = Math.min(colorEnd, textEnd);
96+
if (textStart < textEnd) {
97+
// TODO: should really have isStartColorBoundary, isEndColorBoundary
98+
const isColorBoundary = textStart !== item.offset && textStart === run.start
99+
|| textEnd !== item.end() && textEnd === run.end;
100+
const ax = item.measure(textEnd, 1, state).advance;
104101

105-
if (start < end) {
106-
// TODO: should really have isStartColorBoundary, isEndColorBoundary
107-
const isColorBoundary = start !== item.offset && start === colorStart
108-
|| end !== item.end() && end === colorEnd;
109-
const ax = item.measure(end, 1, state).advance;
102+
if (item.attrs.level & 1) tx -= ax;
110103

111-
if (item.attrs.level & 1) tx -= ax;
104+
b.fillColor = run.style.color;
105+
b.fontSize = style.fontSize;
106+
b.font = item.face;
107+
b.direction = item.attrs.level & 1 ? 'rtl' : 'ltr';
108+
b.text(tx, item.y, item, textStart, textEnd, isColorBoundary);
112109

113-
b.fillColor = color;
114-
b.fontSize = style.fontSize;
115-
b.font = item.face;
116-
b.direction = item.attrs.level & 1 ? 'rtl' : 'ltr';
117-
b.text(tx, item.y, item, start, end, isColorBoundary);
118-
119-
if (!(item.attrs.level & 1)) tx += ax;
120-
}
121-
122-
colorIndex += 1;
110+
if (!(item.attrs.level & 1)) tx += ax;
123111
}
112+
124113
}
125114

126115
/**
@@ -321,11 +310,11 @@ function paintInline(
321310
paragraph: Paragraph,
322311
b: PaintBackend
323312
) {
324-
const colors = paragraph.getColors();
325313
const items = paragraph.items;
326314
const stack: InlineLevel[] = [inlineRoot];
327315
let lastMark = inlineRoot.start;
328316
let inlineMark = inlineRoot.start;
317+
let run: Run | undefined = undefined;
329318
let mark = inlineRoot.start;
330319
let itemIndex = 0; // common case, adjusted below if necessary
331320
let itemEnd = items.length; // common case, adjusted below
@@ -341,7 +330,7 @@ function paintInline(
341330
while (itemIndex < itemEnd || stack.length) {
342331
// paint lastMark..mark
343332
if (itemIndex < itemEnd) {
344-
if (lastMark < mark) drawText(items[itemIndex], colors, lastMark, mark, b);
333+
if (lastMark < mark) drawText(items[itemIndex], run!, lastMark, mark, b);
345334
if (mark === items[itemIndex].end()) itemIndex++;
346335
}
347336

@@ -375,6 +364,7 @@ function paintInline(
375364
}
376365
}
377366
} else if (box.isRun()) {
367+
run = box;
378368
inlineMark = box.end;
379369
}
380370
}

src/util.ts

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -50,30 +50,6 @@ export function binarySearchOf<T>(
5050
}
5151
}
5252

53-
/**
54-
* Binary search that returns the position `x` should be in, using the second
55-
* value in a tuple in the `a` array
56-
*/
57-
export function binarySearchTuple<T>(a: [T, number][], x: number): number {
58-
let l = 0, r = a.length - 1;
59-
60-
if (r < 0) return -1;
61-
62-
while (true) {
63-
let i = Math.floor((l+r)/2);
64-
65-
if (a[i][1] < x) {
66-
l = i + 1;
67-
if (l > r) return l;
68-
} else if (a[i][1] > x) {
69-
r = i - 1;
70-
if (r < l) return i;
71-
} else {
72-
return i;
73-
}
74-
}
75-
}
76-
7753
let _id = 0;
7854
export function id(): string {
7955
return String(_id++);

test/text.spec.js

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -851,26 +851,18 @@ describe('Lines', function () {
851851

852852
it('carries over colors and line heights correctly', function () {
853853
this.layout(`
854-
<div style="width: 0; line-height: 32px;">
854+
<div style="width: 0; line-height: 32px; font: 10px Ahem;">
855855
break
856856
it
857857
<span style="color: red; line-height: 64px;">down</span>
858858
</div>
859859
`);
860860

861-
/** @type import('../src/layout-flow.ts').IfcInline[] */
862-
const [ifc] = this.get(0).children;
863-
const colors = ifc.paragraph.getColors();
864-
865-
expect(colors).to.deep.equal([
866-
[{r: 0, g: 0, b: 0, a: 1}, 0],
867-
[{r: 255, g: 0, b: 0, a: 1}, 10],
868-
[{r: 0, g: 0, b: 0, a: 1}, 14]
861+
expect(this.paint().getCalls()).to.deep.equal([
862+
{t: 'text', x: 0, y: 8, text: 'break', fillColor: '#000'},
863+
{t: 'text', x: 0, y: 18, text: 'it', fillColor: '#000'},
864+
{t: 'text', x: 0, y: 55, text: 'down', fillColor: '#f00'}
869865
]);
870-
871-
expect(ifc.paragraph.lineboxes[0].head.value.colorsStart(colors)).to.deep.equal(0);
872-
expect(ifc.paragraph.lineboxes[1].head.value.colorsStart(colors)).to.deep.equal(0);
873-
expect(ifc.paragraph.lineboxes[2].head.value.colorsStart(colors)).to.deep.equal(1);
874866
});
875867

876868
it('takes strut into account', function () {

0 commit comments

Comments
 (0)