diff --git a/src/calibre/gui2/tweak_book/boss.py b/src/calibre/gui2/tweak_book/boss.py index e4e7d60b88..c5c0a82af6 100644 --- a/src/calibre/gui2/tweak_book/boss.py +++ b/src/calibre/gui2/tweak_book/boss.py @@ -28,7 +28,7 @@ from calibre.gui2.tweak_book import set_current_container, current_container, tp from calibre.gui2.tweak_book.undo import GlobalUndoHistory from calibre.gui2.tweak_book.file_list import NewFileDialog from calibre.gui2.tweak_book.save import SaveManager -from calibre.gui2.tweak_book.preview import parse_worker +from calibre.gui2.tweak_book.preview import parse_worker, font_cache from calibre.gui2.tweak_book.toc import TOCEditor from calibre.gui2.tweak_book.editor import editor_from_syntax, syntax_from_mime @@ -114,6 +114,7 @@ class Boss(QObject): parse_worker.clear() container = job.result set_current_container(container) + font_cache.remove_fonts() self.current_metadata = self.gui.current_metadata = container.mi self.global_undo.open_book(container) self.gui.update_window_title() diff --git a/src/calibre/gui2/tweak_book/preview.py b/src/calibre/gui2/tweak_book/preview.py index 73e15b29c0..645d65a9da 100644 --- a/src/calibre/gui2/tweak_book/preview.py +++ b/src/calibre/gui2/tweak_book/preview.py @@ -12,15 +12,17 @@ from base64 import b64encode from future_builtins import map from threading import Thread from Queue import Queue, Empty +from collections import namedtuple from PyQt4.Qt import ( QWidget, QVBoxLayout, QApplication, QSize, QNetworkAccessManager, QMenu, QIcon, QNetworkReply, QTimer, QNetworkRequest, QUrl, Qt, QNetworkDiskCache, QToolBar, - pyqtSlot, pyqtSignal) + pyqtSlot, pyqtSignal, QFontDatabase) from PyQt4.QtWebKit import QWebView, QWebInspector, QWebPage from calibre import prints 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.base import serialize, OEB_DOCS from calibre.ptempfile import PersistentTemporaryDirectory @@ -38,6 +40,31 @@ def get_data(name): return editors[name].get_raw_data() 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 {{{ def parse_html(raw): root = parse(raw, decoder=lambda x:x.decode('utf-8'), line_numbers=True, linenumber_attribute='data-lnum') @@ -149,6 +176,12 @@ class NetworkReply(QNetworkReply): self.setHeader(QNetworkRequest.ContentTypeHeader, mime_type) self.setHeader(QNetworkRequest.ContentLengthHeader, len(self.__data)) 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): if self._aborted: