Skip to content

Commit 19d5559

Browse files
committed
finish hyphen TODO
this will allow me to remove paragraph.string, which is now redundant with ifc.text
1 parent bf285f7 commit 19d5559

3 files changed

Lines changed: 27 additions & 14 deletions

File tree

src/layout-text.ts

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ export interface ShapingAttrs {
257257
style: Style;
258258
}
259259

260-
const hyphenCache = new Map<string, Int32Array>();
260+
const hyphenCache = new Map<string, {glyphs: Int32Array; codepoint: string}>();
261261

262262
export function getFontMetrics(inline: Inline) {
263263
const strutCascade = getLangCascade(inline.style, 'en');
@@ -277,18 +277,18 @@ function loadHyphen(item: ShapedItem) {
277277
const key = createHyphenCacheKey(item);
278278

279279
if (!hyphenCache.has(key)) {
280-
hyphenCache.set(key, new Int32Array(0));
280+
hyphenCache.set(key, {codepoint: '', glyphs: new Int32Array(0)});
281281

282-
for (const hyphen of HyphenCodepointsToTry) {
282+
for (const codepoint of HyphenCodepointsToTry) {
283283
const buf = hb.createBuffer();
284284
buf.setClusterLevel(1);
285-
buf.addText(hyphen);
285+
buf.addText(codepoint);
286286
buf.guessSegmentProperties();
287287
hb.shape(item.face.hbfont, buf);
288288
const glyphs = buf.extractGlyphs();
289289
buf.destroy();
290290
if (glyphs[G_ID]) {
291-
hyphenCache.set(key, glyphs);
291+
hyphenCache.set(key, {codepoint, glyphs});
292292
break;
293293
}
294294
}
@@ -1700,7 +1700,24 @@ export class Paragraph {
17001700
this.buffer = EmptyBuffer;
17011701
}
17021702

1703-
slice(start: number, end: number) {
1703+
sliceRenderText(item: ShapedItem, start: number, end: number) {
1704+
if (this.ifc.hasSoftHyphen()) {
1705+
const mark = item.end() - 1;
1706+
const hyphen = getHyphen(item);
1707+
if (
1708+
mark >= start &&
1709+
mark < end &&
1710+
this.string[mark] === '\u00ad' && // softHyphenCharacter
1711+
hyphen
1712+
) {
1713+
const first = this.string.slice(start, mark);
1714+
const second = this.string.slice(mark + 1, end);
1715+
const glyphIndex = item.attrs.level & 1 ? 0 : item.glyphs.length - G_SZ;
1716+
if (hyphen.glyphs[G_ID] === item.glyphs[glyphIndex + G_ID]) {
1717+
return first + hyphen.codepoint + second;
1718+
}
1719+
}
1720+
}
17041721
return this.string.slice(start, end);
17051722
}
17061723

@@ -1715,7 +1732,7 @@ export class Paragraph {
17151732

17161733
this.items.splice(itemIndex + 1, 0, right);
17171734
if (this.string[offset - 1] === '\u00ad' /* softHyphenCharacter */) {
1718-
const hyphen = getHyphen(left);
1735+
const hyphen = getHyphen(left)?.glyphs;
17191736
if (hyphen?.length) {
17201737
const glyphs = new Int32Array(left.glyphs.length + hyphen.length);
17211738
if (left.attrs.level & 1) {
@@ -1733,10 +1750,6 @@ export class Paragraph {
17331750
}
17341751
left.glyphs = glyphs;
17351752
}
1736-
// TODO 1: this sucks, but it's probably still better than using a Uint16Array
1737-
// and having to convert back to strings for the browser canvas backend
1738-
// TODO 2: the hyphen character could also be HYPHEN MINUS
1739-
this.string = this.string.slice(0, offset - 1) + /* U+2010 */ '‐' + this.string.slice(offset);
17401753
}
17411754
}
17421755

@@ -2303,7 +2316,7 @@ export class Paragraph {
23032316
bfc.getLocalVacancyForLine(bfc, blockOffset, blockSize, vacancy);
23042317

23052318
if (this.string[mark.position - 1] === '\u00ad' && !mark.isBreakForced) {
2306-
const glyphs = getHyphen(item);
2319+
const glyphs = getHyphen(item)?.glyphs;
23072320
const {face: {hbface: {upem}}, attrs: {style: {fontSize}}} = item;
23082321
if (glyphs?.length) {
23092322
let w = 0;

src/paint-canvas.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export default class CanvasPaintBackend implements PaintBackend {
150150
}
151151

152152
fastText(x: number, y: number, item: ShapedItem, textStart: number, textEnd: number) {
153-
const text = item.paragraph.slice(textStart, textEnd);
153+
const text = item.paragraph.sliceRenderText(item, textStart, textEnd);
154154
const {r, g, b, a} = this.fillColor;
155155
this.ctx.save();
156156
this.ctx.direction = item.attrs.level & 1 ? 'rtl' : 'ltr';

test/paint-spy.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export default class PaintSpy {
4343

4444
text(x, y, item, textStart, textEnd) {
4545
const fillColor = this.fillColor;
46-
const text = item.paragraph.slice(textStart, textEnd);
46+
const text = item.paragraph.sliceRenderText(item, textStart, textEnd);
4747
this.calls.push({t: 'text', x, y, text, fillColor});
4848
}
4949

0 commit comments

Comments
 (0)