PDF Output: Workaround for broken Qt font-variant handling

PDF Output: Workaround a bug in the library calibre uses to render HTML
to PDF that caused text in some documents that used small-caps fonts to
not render correctly. Fixes #1216354 [Private bug](https://bugs.launchpad.net/calibre/+bug/1216354)
This commit is contained in:
Kovid Goyal 2013-09-05 16:03:02 +05:30
parent 0aeec73eae
commit 8e009161b1
2 changed files with 46 additions and 2 deletions

View File

@ -285,5 +285,49 @@ class PDFOutput(OutputFormatPlugin):
if close:
out_stream.close()
def specialize_css_for_output(self, log, opts, item, stylizer):
''' Qt WebKit (4.8.x) cannot handle font-variant: small-caps. It tries to fake the small caps,
which is ok, but the faking continues on to subsequent text that should not be in small-caps.
So we workaround the problem by faking small caps ourselves. A minimal example that Qt chokes on:
<html><body>
<p style="font-variant:small-caps">Some Small-caps Text</p>
<p style="text-align:justify">Some non small-caps text with enough text for at least one
full line and justification enabled. Both of these are needed for the example to work.</p>
</body></html> '''
from calibre.ebooks.oeb.base import XHTML
import itertools, string
if not hasattr(item.data, 'xpath'):
return
ws = unicode(string.whitespace)
def fake_small_caps(elem):
spans = []
for lowercase, textiter in itertools.groupby(elem.text, lambda x:x not in ws and icu_lower(x)==x):
text = ''.join(textiter)
if lowercase:
text = icu_upper(text)
span = elem.makeelement(XHTML('span'))
span.text = text
style = stylizer.style(span)
if lowercase:
style.set('font-size', '0.65em')
spans.append(span)
elem.text = None
elem[0:] = spans
def process_elem(elem, parent_fv=None):
children = tuple(elem)
style = stylizer.style(elem)
fv = style.drop('font-variant')
if not fv or fv.lower() == 'inherit':
fv = parent_fv
if fv and fv.lower() in {'smallcaps', 'small-caps'}:
if elem.text:
fake_small_caps(elem)
for child in children:
if hasattr(getattr(child, 'tag', None), 'lower'):
process_elem(child, parent_fv=fv)
for body in item.data.xpath('//*[local-name()="body"]'):
process_elem(body)

View File

@ -569,8 +569,8 @@ class Style(object):
def set(self, prop, val):
self._style[prop] = val
def drop(self, prop):
self._style.pop(prop, None)
def drop(self, prop, default=None):
return self._style.pop(prop, default)
def _update_cssdict(self, cssdict):
self._style.update(cssdict)