Skip to content

Commit 9db4e52

Browse files
committed
Add preliminary tatweel RTL support
Tatweels still don't always work correctly
1 parent 170db12 commit 9db4e52

File tree

8 files changed

+165
-5
lines changed

8 files changed

+165
-5
lines changed

dist/byzhtml.js

Lines changed: 76 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/byzhtml.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/byzhtml.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/byzhtml.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/byzhtml.default.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
src: url('Neanes.otf');
44
}
55

6+
@font-face {
7+
font-family: 'NeanesRTL';
8+
src: url('NeanesRTL.otf');
9+
}
10+
611
:root {
712
/*
813
Set the width of the vareia spacer for your font.

examples/server.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ server = http.createServer(function (req, res) {
101101
pipeFileToResponse(res, '../dist/Neanes.otf', 'text/javascript');
102102
return;
103103
}
104+
if (/NeanesRTL\.otf$/.test(url)) {
105+
pipeFileToResponse(res, '../dist/NeanesRTL.otf', 'text/javascript');
106+
return;
107+
}
104108
if (/byzhtml\.default\.css$/.test(url)) {
105109
pipeFileToResponse(res, './byzhtml.default.css', 'text/javascript');
106110
return;

lib/byzhtml.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const fontService = new FontService();
77
const options = {
88
defaultFontFamily: 'Neanes',
99
useWebkitPositioning: false,
10+
melkiteRtl: false,
1011
};
1112

1213
export default {

lib/util/MelismaProcessor.js

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import byzhtml from '../byzhtml.js';
12
import { CssVars } from './CssVars.js';
23
import { TextMetrics } from './TextMetrics.js';
34

5+
const TATWEEL = '\u0640';
6+
47
function isElementInOrNearViewport(el) {
58
const rect = el.getBoundingClientRect();
69

@@ -122,6 +125,76 @@ function processAutoMelisma(melisma) {
122125
return change;
123126
}
124127

128+
function processAutoMelismaRtl(melisma) {
129+
let change;
130+
const parentNote = melisma.closest('x-note, x-n');
131+
const siblingLyrics = parentNote.querySelector('x-lyric, x-ly');
132+
const siblingLyricsRect = siblingLyrics.getBoundingClientRect();
133+
134+
let nextNote = parentNote.nextElementSibling;
135+
let nextLyrics;
136+
let depth = 0;
137+
let melismaWidth;
138+
let lastNoteLeft;
139+
140+
while (
141+
nextNote &&
142+
(nextNote.nodeName === 'X-NOTE' || nextNote.nodeName === 'X-N') &&
143+
depth < 100
144+
) {
145+
nextLyrics = nextNote.querySelector('x-lyric, x-ly');
146+
147+
const nextNoteRect = nextNote.getBoundingClientRect();
148+
149+
if (lastNoteLeft < nextNoteRect.left && lastNoteLeft !== undefined) {
150+
// We have wrapped around. Extend the melisma to the end of the last note
151+
// that was on the same line
152+
melismaWidth = siblingLyricsRect.left - lastNoteLeft;
153+
break;
154+
}
155+
156+
if (nextLyrics && nextLyrics.innerText != TATWEEL) {
157+
// We've found lyrics. Extend the melisma to the start of the lyrics.
158+
const nextLyricsRect = nextLyrics.getBoundingClientRect();
159+
160+
melismaWidth = siblingLyricsRect.left - nextLyricsRect.right;
161+
162+
break;
163+
}
164+
165+
lastNoteLeft = nextNoteRect.left;
166+
nextNote = nextNote.nextElementSibling;
167+
168+
depth++;
169+
}
170+
171+
if (melismaWidth) {
172+
change = { melisma };
173+
174+
const melismaStyle = getComputedStyle(melisma);
175+
const fontFamily = melismaStyle.getPropertyValue(CssVars.LyricFontFamily);
176+
const fontSize = melismaStyle.getPropertyValue(CssVars.LyricFontSize);
177+
const font = `${fontSize} ${fontFamily}`;
178+
179+
let text = '';
180+
181+
const widthOfTatweel = TextMetrics.getTextWidthFromCache(TATWEEL, font);
182+
183+
const numberOfTatweelsNeeded = Math.ceil(melismaWidth / widthOfTatweel);
184+
185+
for (let i = 0; i < numberOfTatweelsNeeded; i++) {
186+
text += TATWEEL;
187+
}
188+
189+
change.width = `${melismaWidth}px`;
190+
191+
change.textContent = text;
192+
} else {
193+
console.log('zero width');
194+
}
195+
return change;
196+
}
197+
125198
export function processAutoMelismas() {
126199
const melismas = document.querySelectorAll(
127200
'x-melisma[auto], x-mel[auto], x-melisma[a], x-mel[a]',
@@ -158,7 +231,9 @@ export function processAutoMelismas() {
158231

159232
// Calculate the changes
160233
for (let melisma of melismasInViewPort) {
161-
let change = processAutoMelisma(melisma);
234+
let change = byzhtml.options.melkiteRtl
235+
? processAutoMelismaRtl(melisma)
236+
: processAutoMelisma(melisma);
162237

163238
if (change) {
164239
changes.push(change);

0 commit comments

Comments
 (0)