Add superscript and subscript, and make highlighting stronger [#54]

This commit is contained in:
David Evans 2018-05-06 00:32:42 +01:00
parent 5deec319df
commit fc3e11ab5a
9 changed files with 109 additions and 15 deletions

View File

@ -92,17 +92,17 @@
'type': 'linear',
}),
this.svg.el('feFuncG').attrs({
'intercept': 0.9375,
'intercept': 0.875,
'slope': 0,
'type': 'linear',
}),
this.svg.el('feFuncB').attrs({
'intercept': 0.09375,
'intercept': 0,
'slope': 0,
'type': 'linear',
}),
this.svg.el('feFuncA').attrs({
'slope': 0.7,
'slope': 0.8,
'type': 'linear',
})
),
@ -4201,6 +4201,14 @@
attrs: {'text-decoration': 'underline'},
begin: {matcher: /<u>/g, skip: 0},
end: {matcher: /<\/u>/g, skip: 0},
}, {
attrs: {'baseline-shift': '70%', 'font-size': '0.6em'},
begin: {matcher: /<sup>/g, skip: 0},
end: {matcher: /<\/sup>/g, skip: 0},
}, {
attrs: {'baseline-shift': '-20%', 'font-size': '0.6em'},
begin: {matcher: /<sub>/g, skip: 0},
end: {matcher: /<\/sub>/g, skip: 0},
}, {
attrs: {'fill': '#DD0000'},
begin: {matcher: /<red>/g, skip: 0},

File diff suppressed because one or more lines are too long

View File

@ -92,17 +92,17 @@
'type': 'linear',
}),
this.svg.el('feFuncG').attrs({
'intercept': 0.9375,
'intercept': 0.875,
'slope': 0,
'type': 'linear',
}),
this.svg.el('feFuncB').attrs({
'intercept': 0.09375,
'intercept': 0,
'slope': 0,
'type': 'linear',
}),
this.svg.el('feFuncA').attrs({
'slope': 0.7,
'slope': 0.8,
'type': 'linear',
})
),
@ -4201,6 +4201,14 @@
attrs: {'text-decoration': 'underline'},
begin: {matcher: /<u>/g, skip: 0},
end: {matcher: /<\/u>/g, skip: 0},
}, {
attrs: {'baseline-shift': '70%', 'font-size': '0.6em'},
begin: {matcher: /<sup>/g, skip: 0},
end: {matcher: /<\/sup>/g, skip: 0},
}, {
attrs: {'baseline-shift': '-20%', 'font-size': '0.6em'},
begin: {matcher: /<sub>/g, skip: 0},
end: {matcher: /<\/sub>/g, skip: 0},
}, {
attrs: {'fill': '#DD0000'},
begin: {matcher: /<red>/g, skip: 0},
@ -10630,6 +10638,21 @@
return variant.getAdvanceWidth(text, size, OPENTYPE_OPTIONS);
}
function combineAttrs$1(base, next) {
if(!next) {
return base;
}
const result = Object.assign({}, base, next);
const nextSize = next['font-size'];
if(typeof nextSize === 'string' && nextSize.endsWith('em')) {
const ratio = Number.parseFloat(
nextSize.substr(0, nextSize.length - 2)
);
result['font-size'] = base['font-size'] * ratio;
}
return result;
}
class VirtualTextSizer {
baseline({attrs}) {
return getFontSize(attrs);
@ -10655,7 +10678,8 @@
if(!part.text) {
continue;
}
len += measure(Object.assign({}, attrs, part.attrs), part.text);
const combinedAttrs = combineAttrs$1(attrs, part.attrs);
len += measure(combinedAttrs, part.text);
}
return len;
}

View File

@ -43,6 +43,14 @@ const STYLES = [
attrs: {'text-decoration': 'underline'},
begin: {matcher: /<u>/g, skip: 0},
end: {matcher: /<\/u>/g, skip: 0},
}, {
attrs: {'baseline-shift': '70%', 'font-size': '0.6em'},
begin: {matcher: /<sup>/g, skip: 0},
end: {matcher: /<\/sup>/g, skip: 0},
}, {
attrs: {'baseline-shift': '-20%', 'font-size': '0.6em'},
begin: {matcher: /<sub>/g, skip: 0},
end: {matcher: /<\/sub>/g, skip: 0},
}, {
attrs: {'fill': '#DD0000'},
begin: {matcher: /<red>/g, skip: 0},

View File

@ -143,6 +143,32 @@ describe('Markdown Parser', () => {
]]);
});
it('recognises superscript styling', () => {
const formatted = parser('a <sup>b</sup> c');
expect(formatted).toEqual([[
{attrs: null, text: 'a '},
{
attrs: {'baseline-shift': '70%', 'font-size': '0.6em'},
text: 'b',
},
{attrs: null, text: ' c'},
]]);
});
it('recognises subscript styling', () => {
const formatted = parser('a <sub>b</sub> c');
expect(formatted).toEqual([[
{attrs: null, text: 'a '},
{
attrs: {'baseline-shift': '-20%', 'font-size': '0.6em'},
text: 'b',
},
{attrs: null, text: ' c'},
]]);
});
it('recognises red styling', () => {
const formatted = parser('a <red>b</red> c');

View File

@ -89,17 +89,17 @@ export default class BaseTheme {
'type': 'linear',
}),
this.svg.el('feFuncG').attrs({
'intercept': 0.9375,
'intercept': 0.875,
'slope': 0,
'type': 'linear',
}),
this.svg.el('feFuncB').attrs({
'intercept': 0.09375,
'intercept': 0,
'slope': 0,
'type': 'linear',
}),
this.svg.el('feFuncA').attrs({
'slope': 0.7,
'slope': 0.8,
'type': 'linear',
})
),

View File

@ -93,6 +93,21 @@ function measure(attrs, text) {
return variant.getAdvanceWidth(text, size, OPENTYPE_OPTIONS);
}
function combineAttrs(base, next) {
if(!next) {
return base;
}
const result = Object.assign({}, base, next);
const nextSize = next['font-size'];
if(typeof nextSize === 'string' && nextSize.endsWith('em')) {
const ratio = Number.parseFloat(
nextSize.substr(0, nextSize.length - 2)
);
result['font-size'] = base['font-size'] * ratio;
}
return result;
}
export default class VirtualTextSizer {
baseline({attrs}) {
return getFontSize(attrs);
@ -118,7 +133,8 @@ export default class VirtualTextSizer {
if(!part.text) {
continue;
}
len += measure(Object.assign({}, attrs, part.attrs), part.text);
const combinedAttrs = combineAttrs(attrs, part.attrs);
len += measure(combinedAttrs, part.text);
}
return len;
}

View File

@ -77,6 +77,18 @@ describe('VirtualTextSizer', () => {
expect(sizeMonoBold.width).toBeNear(sizeMono.width, 1e-1);
});
it('uses relative font sizes', () => {
const size = safeMeasure(attrs, [[
{text: 'bar'},
]]);
const sizeSmall = safeMeasure(attrs, [[
{attrs: {'font-size': '0.5em'}, text: 'bar'},
]]);
expect(sizeSmall.width).toBeNear(size.width / 2, 1e-1);
});
it('returns 0, 0 for empty content', () => {
const size = safeMeasure(attrs, []);

View File

@ -1,5 +1,5 @@
<svg width="96.6966781616211" height="124" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-48.34833908081055 -119 96.6966781616211 124"><metadata>title "Foo **Bar**
_Baz_ `Zig`
<svg width="103.81134033203125" height="124" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-51.905670166015625 -119 103.81134033203125 124"><metadata>title "Foo **Bar** I&lt;sup&gt;2&lt;/sup&gt;
_Baz_ `Zig` I&lt;sub&gt;2&lt;/sub&gt;
**_`Zag`_** &lt;u&gt;&lt;o&gt;~Abc~&lt;/o&gt;&lt;/u&gt;
&lt;highlight&gt;Back&lt;/highlight&gt; &lt;red&gt;Text&lt;/red&gt;"
</metadata><defs><filter id="R0highlight"><feMorphology in="SourceAlpha" operator="dilate" radius="4"></feMorphology><feGaussianBlur edgeMode="none" stdDeviation="3, 1.5"></feGaussianBlur><feComponentTransfer><feFuncA intercept="-70" slope="100" type="linear"></feFuncA></feComponentTransfer><feComponentTransfer><feFuncR intercept="1" slope="0" type="linear"></feFuncR><feFuncG intercept="0.9375" slope="0" type="linear"></feFuncG><feFuncB intercept="0.09375" slope="0" type="linear"></feFuncB><feFuncA slope="0.7" type="linear"></feFuncA></feComponentTransfer><feMerge><feMergeNode></feMergeNode><feMergeNode in="SourceGraphic"></feMergeNode></feMerge></filter></defs><defs><mask id="R0FullMask" maskUnits="userSpaceOnUse"><rect fill="#FFFFFF" height="124" width="96.6966781616211" x="-48.34833908081055" y="-119"></rect></mask><mask id="R0LineMask" maskUnits="userSpaceOnUse"><rect fill="#FFFFFF" height="124" width="96.6966781616211" x="-48.34833908081055" y="-119"></rect></mask></defs><g></g><g><text x="0" class="title" font-family="Helvetica,Arial,Liberation Sans,sans-serif" font-size="20" line-height="1.3" text-anchor="middle" y="-94">Foo <tspan font-weight="bolder">Bar</tspan></text><text x="0" class="title" font-family="Helvetica,Arial,Liberation Sans,sans-serif" font-size="20" line-height="1.3" text-anchor="middle" y="-68"><tspan font-style="italic">Baz</tspan> <tspan font-family="Courier New,Liberation Mono,monospace">Zig</tspan></text><text x="0" class="title" font-family="Helvetica,Arial,Liberation Sans,sans-serif" font-size="20" line-height="1.3" text-anchor="middle" y="-42"><tspan font-style="italic" font-weight="bolder" font-family="Courier New,Liberation Mono,monospace">Zag</tspan> <tspan text-decoration="line-through overline underline">Abc</tspan></text><text x="0" class="title" font-family="Helvetica,Arial,Liberation Sans,sans-serif" font-size="20" line-height="1.3" text-anchor="middle" y="-16"><tspan filter="url(#R0highlight)">Back</tspan> <tspan fill="#DD0000">Text</tspan></text></g><g></g><g mask="url(#R0FullMask)"><g mask="url(#R0LineMask)"></g><g></g><g></g></g></svg>
</metadata><defs><filter id="R0highlight"><feMorphology in="SourceAlpha" operator="dilate" radius="4"></feMorphology><feGaussianBlur edgeMode="none" stdDeviation="3, 1.5"></feGaussianBlur><feComponentTransfer><feFuncA intercept="-70" slope="100" type="linear"></feFuncA></feComponentTransfer><feComponentTransfer><feFuncR intercept="1" slope="0" type="linear"></feFuncR><feFuncG intercept="0.875" slope="0" type="linear"></feFuncG><feFuncB intercept="0" slope="0" type="linear"></feFuncB><feFuncA slope="0.8" type="linear"></feFuncA></feComponentTransfer><feMerge><feMergeNode></feMergeNode><feMergeNode in="SourceGraphic"></feMergeNode></feMerge></filter></defs><defs><mask id="R0FullMask" maskUnits="userSpaceOnUse"><rect fill="#FFFFFF" height="124" width="103.81134033203125" x="-51.905670166015625" y="-119"></rect></mask><mask id="R0LineMask" maskUnits="userSpaceOnUse"><rect fill="#FFFFFF" height="124" width="103.81134033203125" x="-51.905670166015625" y="-119"></rect></mask></defs><g></g><g><text x="0" class="title" font-family="Helvetica,Arial,Liberation Sans,sans-serif" font-size="20" line-height="1.3" text-anchor="middle" y="-94">Foo <tspan font-weight="bolder">Bar</tspan> I<tspan baseline-shift="70%" font-size="0.6em">2</tspan></text><text x="0" class="title" font-family="Helvetica,Arial,Liberation Sans,sans-serif" font-size="20" line-height="1.3" text-anchor="middle" y="-68"><tspan font-style="italic">Baz</tspan> <tspan font-family="Courier New,Liberation Mono,monospace">Zig</tspan> I<tspan baseline-shift="-20%" font-size="0.6em">2</tspan></text><text x="0" class="title" font-family="Helvetica,Arial,Liberation Sans,sans-serif" font-size="20" line-height="1.3" text-anchor="middle" y="-42"><tspan font-style="italic" font-weight="bolder" font-family="Courier New,Liberation Mono,monospace">Zag</tspan> <tspan text-decoration="line-through overline underline">Abc</tspan></text><text x="0" class="title" font-family="Helvetica,Arial,Liberation Sans,sans-serif" font-size="20" line-height="1.3" text-anchor="middle" y="-16"><tspan filter="url(#R0highlight)">Back</tspan> <tspan fill="#DD0000">Text</tspan></text></g><g></g><g mask="url(#R0FullMask)"><g mask="url(#R0LineMask)"></g><g></g><g></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB