mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Remove the workarounds for the Qt WebKit embedded font bug as the bug has been fixed in Qt 5
This commit is contained in:
parent
d66702e77a
commit
7d0a047026
@ -75,8 +75,7 @@ class EbookIterator(BookmarksMixin):
|
|||||||
return i
|
return i
|
||||||
|
|
||||||
def __enter__(self, processed=False, only_input_plugin=False,
|
def __enter__(self, processed=False, only_input_plugin=False,
|
||||||
run_char_count=True, read_anchor_map=True, view_kepub=False,
|
run_char_count=True, read_anchor_map=True, view_kepub=False):
|
||||||
extract_embedded_fonts_for_qt=False):
|
|
||||||
''' Convert an ebook file into an exploded OEB book suitable for
|
''' Convert an ebook file into an exploded OEB book suitable for
|
||||||
display in viewers/preprocessing etc. '''
|
display in viewers/preprocessing etc. '''
|
||||||
|
|
||||||
@ -178,16 +177,6 @@ class EbookIterator(BookmarksMixin):
|
|||||||
|
|
||||||
self.read_bookmarks()
|
self.read_bookmarks()
|
||||||
|
|
||||||
if extract_embedded_fonts_for_qt:
|
|
||||||
from calibre.ebooks.oeb.iterator.extract_fonts import extract_fonts
|
|
||||||
try:
|
|
||||||
extract_fonts(self.opf, self.log)
|
|
||||||
except:
|
|
||||||
ol = self.log.filter_level
|
|
||||||
self.log.filter_level = self.log.DEBUG
|
|
||||||
self.log.exception('Failed to extract fonts')
|
|
||||||
self.log.filter_level = ol
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
|
@ -1,115 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
|
|
||||||
from __future__ import (unicode_literals, division, absolute_import,
|
|
||||||
print_function)
|
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
import re, os, logging
|
|
||||||
from functools import partial
|
|
||||||
from future_builtins import map
|
|
||||||
|
|
||||||
class FamilyMap(dict):
|
|
||||||
|
|
||||||
def __init__(self, log):
|
|
||||||
dict.__init__(self)
|
|
||||||
self.replace_map = {}
|
|
||||||
self.added_fonts = set()
|
|
||||||
self.log = log
|
|
||||||
|
|
||||||
def __call__(self, basedir, match):
|
|
||||||
self.read_font_fule(basedir, match.group())
|
|
||||||
return b''
|
|
||||||
|
|
||||||
def finalize(self):
|
|
||||||
if self.replace_map:
|
|
||||||
self.pat = re.compile(br'(font-family.*?)(' +
|
|
||||||
b'|'.join([re.escape(x) for x in
|
|
||||||
self.replace_map.iterkeys()])+b')', re.I)
|
|
||||||
|
|
||||||
def replace_font_families(self, raw):
|
|
||||||
if self.replace_map:
|
|
||||||
def sub(m):
|
|
||||||
k = m.group(2).lower()
|
|
||||||
for q, val in self.replace_map.iteritems():
|
|
||||||
if q.lower() == k.lower():
|
|
||||||
return m.group().replace(m.group(2), val)
|
|
||||||
return m.group()
|
|
||||||
|
|
||||||
return self.pat.sub(sub, raw)
|
|
||||||
|
|
||||||
def read_font_fule(self, basedir, css):
|
|
||||||
from PyQt5.Qt import QFontDatabase
|
|
||||||
import cssutils
|
|
||||||
cssutils.log.setLevel(logging.ERROR)
|
|
||||||
try:
|
|
||||||
sheet = cssutils.parseString(css, validate=False)
|
|
||||||
except:
|
|
||||||
return
|
|
||||||
for rule in sheet.cssRules:
|
|
||||||
try:
|
|
||||||
s = rule.style
|
|
||||||
src = s.getProperty('src').propertyValue[0].uri
|
|
||||||
font_family = s.getProperty('font-family').propertyValue[0].value
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
if not src or not font_family:
|
|
||||||
continue
|
|
||||||
font_file = os.path.normcase(os.path.abspath(os.path.join(basedir,
|
|
||||||
src)))
|
|
||||||
if font_file not in self.added_fonts:
|
|
||||||
self.added_fonts.add(font_file)
|
|
||||||
if not os.path.exists(font_file):
|
|
||||||
from calibre.ebooks.oeb.base import urlunquote
|
|
||||||
ff = urlunquote(font_file, error_handling='replace')
|
|
||||||
if os.path.exists(ff):
|
|
||||||
font_file = ff
|
|
||||||
if os.path.exists(font_file):
|
|
||||||
with open(font_file, 'rb') as f:
|
|
||||||
idx = QFontDatabase.addApplicationFontFromData(f.read())
|
|
||||||
if idx > -1:
|
|
||||||
family = map(unicode,
|
|
||||||
QFontDatabase.applicationFontFamilies(idx)).next()
|
|
||||||
self.log('Extracted embedded font:', family, 'from',
|
|
||||||
os.path.basename(font_file))
|
|
||||||
if (family and family != font_family and
|
|
||||||
family not in self.replace_map):
|
|
||||||
self.log('Replacing font family value:',
|
|
||||||
font_family, 'with', family)
|
|
||||||
self.replace_map[font_family.encode('utf-8')] = \
|
|
||||||
family.encode('utf-8')
|
|
||||||
|
|
||||||
def extract_fonts(opf, log):
|
|
||||||
'''
|
|
||||||
Extract embedded fonts from the ebook and add them explicitly to the Qt
|
|
||||||
font database to workaround https://bugs.webkit.org/show_bug.cgi?id=29433
|
|
||||||
|
|
||||||
Only works if the font-face and font-family rules are all contained in the
|
|
||||||
CSS files (Also processing the HTML files would be too much of a
|
|
||||||
performance hit, to do robustly).
|
|
||||||
'''
|
|
||||||
css_files = {}
|
|
||||||
font_family_map = FamilyMap(log)
|
|
||||||
pat = re.compile(br'^\s*@font-face\s*{[^}]+}', re.M)
|
|
||||||
|
|
||||||
for item in opf.manifest:
|
|
||||||
if item.mime_type and item.mime_type.lower() in {
|
|
||||||
'text/css', 'text/x-oeb1-css', 'text/x-oeb-css'}:
|
|
||||||
try:
|
|
||||||
with open(item.path, 'rb') as f:
|
|
||||||
raw = f.read()
|
|
||||||
except EnvironmentError:
|
|
||||||
continue
|
|
||||||
css_files[item.path] = pat.sub(partial(font_family_map,
|
|
||||||
os.path.dirname(item.path)), raw)
|
|
||||||
|
|
||||||
font_family_map.finalize()
|
|
||||||
|
|
||||||
if font_family_map.added_fonts:
|
|
||||||
for path, raw in css_files.iteritems():
|
|
||||||
with open(path, 'wb') as f:
|
|
||||||
nraw = font_family_map.replace_font_families(raw) or raw
|
|
||||||
f.write(nraw)
|
|
||||||
|
|
@ -18,7 +18,7 @@ from calibre import prints, isbytestring
|
|||||||
from calibre.ptempfile import PersistentTemporaryDirectory, TemporaryDirectory
|
from calibre.ptempfile import PersistentTemporaryDirectory, TemporaryDirectory
|
||||||
from calibre.ebooks.oeb.base import urlnormalize
|
from calibre.ebooks.oeb.base import urlnormalize
|
||||||
from calibre.ebooks.oeb.polish.main import SUPPORTED, tweak_polish
|
from calibre.ebooks.oeb.polish.main import SUPPORTED, tweak_polish
|
||||||
from calibre.ebooks.oeb.polish.container import get_container as _gc, clone_container, guess_type, OEB_FONTS, OEB_DOCS, OEB_STYLES
|
from calibre.ebooks.oeb.polish.container import get_container as _gc, clone_container, guess_type, OEB_DOCS, OEB_STYLES
|
||||||
from calibre.ebooks.oeb.polish.cover import mark_as_cover, mark_as_titlepage, set_cover
|
from calibre.ebooks.oeb.polish.cover import mark_as_cover, mark_as_titlepage, set_cover
|
||||||
from calibre.ebooks.oeb.polish.css import filter_css
|
from calibre.ebooks.oeb.polish.css import filter_css
|
||||||
from calibre.ebooks.oeb.polish.pretty import fix_all_html, pretty_all
|
from calibre.ebooks.oeb.polish.pretty import fix_all_html, pretty_all
|
||||||
@ -34,7 +34,7 @@ from calibre.gui2.tweak_book import (
|
|||||||
from calibre.gui2.tweak_book.undo import GlobalUndoHistory
|
from calibre.gui2.tweak_book.undo import GlobalUndoHistory
|
||||||
from calibre.gui2.tweak_book.file_list import NewFileDialog
|
from calibre.gui2.tweak_book.file_list import NewFileDialog
|
||||||
from calibre.gui2.tweak_book.save import SaveManager, save_container, find_first_existing_ancestor
|
from calibre.gui2.tweak_book.save import SaveManager, save_container, find_first_existing_ancestor
|
||||||
from calibre.gui2.tweak_book.preview import parse_worker, font_cache
|
from calibre.gui2.tweak_book.preview import parse_worker
|
||||||
from calibre.gui2.tweak_book.toc import TOCEditor
|
from calibre.gui2.tweak_book.toc import TOCEditor
|
||||||
from calibre.gui2.tweak_book.editor import editor_from_syntax, syntax_from_mime
|
from calibre.gui2.tweak_book.editor import editor_from_syntax, syntax_from_mime
|
||||||
from calibre.gui2.tweak_book.editor.insert_resource import get_resource_data, NewBook
|
from calibre.gui2.tweak_book.editor.insert_resource import get_resource_data, NewBook
|
||||||
@ -50,14 +50,6 @@ _diff_dialogs = []
|
|||||||
def get_container(*args, **kwargs):
|
def get_container(*args, **kwargs):
|
||||||
kwargs['tweak_mode'] = True
|
kwargs['tweak_mode'] = True
|
||||||
container = _gc(*args, **kwargs)
|
container = _gc(*args, **kwargs)
|
||||||
# We preload the embedded fonts from this book, so that the preview panel
|
|
||||||
# works
|
|
||||||
font_cache.remove_fonts()
|
|
||||||
for name, mt in container.mime_map.iteritems():
|
|
||||||
if mt in OEB_FONTS and container.exists(name):
|
|
||||||
with container.open(name, 'rb') as f:
|
|
||||||
raw = f.read()
|
|
||||||
font_cache.add_font(raw)
|
|
||||||
return container
|
return container
|
||||||
|
|
||||||
def setup_cssutils_serialization():
|
def setup_cssutils_serialization():
|
||||||
|
@ -12,19 +12,17 @@ from base64 import b64encode
|
|||||||
from future_builtins import map
|
from future_builtins import map
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from Queue import Queue, Empty
|
from Queue import Queue, Empty
|
||||||
from collections import namedtuple
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from urlparse import urlparse
|
from urlparse import urlparse
|
||||||
|
|
||||||
from PyQt5.Qt import (
|
from PyQt5.Qt import (
|
||||||
QWidget, QVBoxLayout, QApplication, QSize, QNetworkAccessManager, QMenu, QIcon,
|
QWidget, QVBoxLayout, QApplication, QSize, QNetworkAccessManager, QMenu, QIcon,
|
||||||
QNetworkReply, QTimer, QNetworkRequest, QUrl, Qt, QNetworkDiskCache, QToolBar,
|
QNetworkReply, QTimer, QNetworkRequest, QUrl, Qt, QNetworkDiskCache, QToolBar,
|
||||||
pyqtSlot, pyqtSignal, QFontDatabase)
|
pyqtSlot, pyqtSignal)
|
||||||
from PyQt5.QtWebKitWidgets import QWebView, QWebInspector, QWebPage
|
from PyQt5.QtWebKitWidgets import QWebView, QWebInspector, QWebPage
|
||||||
|
|
||||||
from calibre import prints
|
from calibre import prints
|
||||||
from calibre.constants import iswindows
|
from calibre.constants import iswindows
|
||||||
from calibre.ebooks.oeb.polish.container import OEB_FONTS
|
|
||||||
from calibre.ebooks.oeb.polish.parsing import parse
|
from calibre.ebooks.oeb.polish.parsing import parse
|
||||||
from calibre.ebooks.oeb.base import serialize, OEB_DOCS
|
from calibre.ebooks.oeb.base import serialize, OEB_DOCS
|
||||||
from calibre.ptempfile import PersistentTemporaryDirectory
|
from calibre.ptempfile import PersistentTemporaryDirectory
|
||||||
@ -43,31 +41,6 @@ def get_data(name):
|
|||||||
return editors[name].get_raw_data()
|
return editors[name].get_raw_data()
|
||||||
return current_container().raw_data(name)
|
return current_container().raw_data(name)
|
||||||
|
|
||||||
class FontCache(object):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.cache = {}
|
|
||||||
self.entry = namedtuple('Entry', 'size hash families')
|
|
||||||
|
|
||||||
def remove_fonts(self):
|
|
||||||
for font_id in self.cache:
|
|
||||||
QFontDatabase.removeApplicationFont(font_id)
|
|
||||||
self.cache.clear()
|
|
||||||
|
|
||||||
def add_font(self, data):
|
|
||||||
existing = None
|
|
||||||
for font_id, entry in self.cache.iteritems():
|
|
||||||
if entry.size == len(data) and entry.hash == hash(data):
|
|
||||||
existing = entry
|
|
||||||
break
|
|
||||||
if existing is None:
|
|
||||||
font_id = QFontDatabase.addApplicationFontFromData(data)
|
|
||||||
if font_id > -1:
|
|
||||||
families = frozenset(map(lambda x:icu_lower(unicode(x)), QFontDatabase.applicationFontFamilies(font_id)))
|
|
||||||
self.cache[font_id] = self.entry(len(data), hash(data), families)
|
|
||||||
|
|
||||||
font_cache = FontCache()
|
|
||||||
|
|
||||||
# Parsing of html to add linenumbers {{{
|
# Parsing of html to add linenumbers {{{
|
||||||
def parse_html(raw):
|
def parse_html(raw):
|
||||||
root = parse(raw, decoder=lambda x:x.decode('utf-8'), line_numbers=True, linenumber_attribute='data-lnum')
|
root = parse(raw, decoder=lambda x:x.decode('utf-8'), line_numbers=True, linenumber_attribute='data-lnum')
|
||||||
@ -182,12 +155,6 @@ class NetworkReply(QNetworkReply):
|
|||||||
self.setHeader(QNetworkRequest.ContentTypeHeader, mime_type)
|
self.setHeader(QNetworkRequest.ContentTypeHeader, mime_type)
|
||||||
self.setHeader(QNetworkRequest.ContentLengthHeader, len(self.__data))
|
self.setHeader(QNetworkRequest.ContentLengthHeader, len(self.__data))
|
||||||
QTimer.singleShot(0, self.finalize_reply)
|
QTimer.singleShot(0, self.finalize_reply)
|
||||||
if mime_type in OEB_FONTS:
|
|
||||||
font_cache.add_font(data)
|
|
||||||
# We prevent the use of the embedded font because of the the
|
|
||||||
# bug in Qt WebKit,
|
|
||||||
# https://bugs.webkit.org/show_bug.cgi?id=29433
|
|
||||||
self.__data = b''
|
|
||||||
|
|
||||||
def check_for_parse(self):
|
def check_for_parse(self):
|
||||||
if self._aborted:
|
if self._aborted:
|
||||||
@ -422,8 +389,8 @@ class WebView(QWebView):
|
|||||||
|
|
||||||
<p style="font-size:x-small; color: gray">Note that this is a quick preview
|
<p style="font-size:x-small; color: gray">Note that this is a quick preview
|
||||||
only, it is not intended to simulate an actual ebook reader. Some
|
only, it is not intended to simulate an actual ebook reader. Some
|
||||||
aspects of your ebook will not work, such as, page breaks,
|
aspects of your ebook will not work, such as, page breaks and
|
||||||
page margins and embedded fonts that use font name aliasing.
|
page margins.
|
||||||
|
|
||||||
'''))
|
'''))
|
||||||
self.page().current_root = None
|
self.page().current_root = None
|
||||||
|
@ -774,8 +774,7 @@ class EbookViewer(MainWindow):
|
|||||||
self.iterator.__exit__()
|
self.iterator.__exit__()
|
||||||
self.iterator = EbookIterator(pathtoebook)
|
self.iterator = EbookIterator(pathtoebook)
|
||||||
self.open_progress_indicator(_('Loading ebook...'))
|
self.open_progress_indicator(_('Loading ebook...'))
|
||||||
worker = Worker(target=partial(self.iterator.__enter__,
|
worker = Worker(target=partial(self.iterator.__enter__, view_kpepub=True))
|
||||||
extract_embedded_fonts_for_qt=True, view_kepub=True))
|
|
||||||
worker.start()
|
worker.start()
|
||||||
while worker.isAlive():
|
while worker.isAlive():
|
||||||
worker.join(0.1)
|
worker.join(0.1)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user